I'm human

This commit is contained in:
Niklas Kapelle 2024-05-24 23:15:28 +02:00
parent b47325a0dc
commit c31fb7d0ff
Signed by: niklas
GPG Key ID: 4EB651B36D841D16
13 changed files with 214 additions and 44 deletions

View File

@ -190,6 +190,10 @@ impl BlackjackGame {
}
(GameState::Over, PlayMoves::Deal { players })
| (GameState::Starting, PlayMoves::Deal { players }) => {
// Reset everything
self.dealer_hand = Hand::new();
self.players = Vec::new();
// Create players
for _ in 0..players {
self.players.push(Player::new());

View File

@ -4,9 +4,13 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Serialize, Deserialize)]
pub enum CardSuit {
#[serde(rename = "S")]
Spades,
#[serde(rename = "C")]
Clubs,
#[serde(rename = "H")]
Hearts,
#[serde(rename = "D")]
Diamonds,
}

View File

@ -122,7 +122,6 @@ impl<'de> Deserialize<'de> for Hand {
where
D: Deserializer<'de>,
{
// Deserialize into a Vec directly and wrap it in MyVecWrapper
let cards = Vec::<Card>::deserialize(deserializer)?;
Ok(Hand { cards })
}

View File

@ -6,10 +6,15 @@ use rocket::{
Build, Rocket, State,
};
use crate::{blackjack::{blackjack_game::BlackjackGame, gamestate::GameState, play_moves::PlayMoves, player::Player}, cards::card::Card};
use crate::{
blackjack::{
blackjack_game::BlackjackGame, gamestate::GameState, play_moves::PlayMoves, player::Player,
},
cards::{card::Card, hand::Hand},
};
#[get("/state")]
fn get_state(state: &State<MyState>) -> Json<GamestateJson> {
fn get_state(state: &State<MyState>) -> Json<ExtendedGameState> {
Json(gamestate_as_json(&state.game.lock().unwrap()))
}
@ -17,8 +22,8 @@ fn get_state(state: &State<MyState>) -> Json<GamestateJson> {
fn post_move(
state: &State<MyState>,
request: Json<PlayMoves>,
) -> Result<Json<GamestateJson>, Status> {
let action = request.0;
) -> Result<Json<ExtendedGameState>, Status> {
let action = request.into_inner();
if state.game.lock().unwrap().play(action) {
Ok(Json(gamestate_as_json(&state.game.lock().unwrap())))
@ -32,23 +37,35 @@ struct MyState {
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct GamestateJson {
state: GameState,
dealer_upcard: Option<Card>,
#[serde(tag = "type", rename_all = "camelCase", rename_all_fields = "camelCase")]
enum ExtendedGameState {
Over {
dealer_hand: Hand,
players: Vec<Player>,
},
Playing {
dealer_upcard: Card,
player_turn: usize,
hand_turn: usize,
players: Vec<Player>,
},
Starting,
}
fn gamestate_as_json(game: &BlackjackGame) -> GamestateJson {
fn gamestate_as_json(game: &BlackjackGame) -> ExtendedGameState {
match game.get_state() {
GameState::Starting => GamestateJson {
state: *game.get_state(),
dealer_upcard: None,
players: Vec::new(),
GameState::Starting => ExtendedGameState::Starting,
GameState::Over => ExtendedGameState::Over {
dealer_hand: game.get_dealer_hand().clone(),
players: game.get_players().clone(),
},
GameState::Over | GameState::PlayerTurn { .. } => GamestateJson {
state: *game.get_state(),
dealer_upcard: game.get_dealer_upcard().copied(),
GameState::PlayerTurn {
player_index,
hand_index,
} => ExtendedGameState::Playing {
dealer_upcard: *game.get_dealer_upcard().unwrap(),
player_turn: *player_index,
hand_turn: *hand_index,
players: game.get_players().clone(),
},
}

View File

@ -1,22 +1,9 @@
<script lang="ts">
import {fetchState} from "./functions/fetchState";
import { CardSuit } from "./types/CardSuit";
import Blackjack from "./lib/Blackjack.svelte";
async function getState() {
let state = await fetchState();
console.debug(state);
if (state.dealerUpcard.suit == CardSuit.Spades){
console.debug("Heureka");
}else{
console.debug("FUCK");
}
}
</script>
<main>
<div>Hello world</div>
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" on:click={getState}>Get state</button>
<Blackjack/>
</main>

View File

@ -0,0 +1,15 @@
import type { Action } from "../types/Action";
import type { Gamestate } from "../types/Gamestate";
export async function doAction(action: Action): Promise<Gamestate> {
let res = await fetch("/api/state", {
method: "POST",
body: JSON.stringify(action),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
});
return await res.json();
}

View File

@ -1,3 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
@apply bg-blue-950 text-white;
}

View File

@ -0,0 +1,74 @@
<script lang="ts">
import { onMount } from "svelte";
import { doAction } from "../functions/doAction";
import type { Action } from "../types/Action";
import type { Gamestate } from "./../types/Gamestate";
import { fetchState } from "../functions/fetchState";
import Card from "./Card.svelte";
import PlayerHand from "./PlayerHand.svelte";
let state: Gamestate;
onMount(async () => {
state = await fetchState();
});
async function actionBtn(action: Action) {
state = await doAction(action);
}
</script>
{#if state}
{#if state.type == "starting"}
Game has not yet started. Press "Deal" to start.
{:else if state.type == "over"}
Game over. Press "Deal" to start again.
<br>
Player:
{#each state.players as player}
{#each player.hands as hand}
<PlayerHand playingHand={hand}/>
{/each}
{/each}
{:else if state.type == "playing"}
Dealer: <Card card={state.dealerUpcard} />
Player:
{#each state.players as player}
{#each player.hands as hand}
<PlayerHand playingHand={hand}/>
{/each}
{/each}
{/if}
{:else}
Loading...
{/if}
<div>
<button
class="action-btn bg-blue-700 hover:bg-blue-600"
on:click={() => actionBtn({ type: "Deal", players: 1 })}>Deal</button
>
<button
class="action-btn bg-green-700 hover:bg-green-600"
on:click={() => actionBtn({ type: "Hit" })}>Hit</button
>
<button
class="action-btn bg-red-700 hover:bg-red-600"
on:click={() => actionBtn({ type: "Stand" })}>Stand</button
>
<button
class="action-btn bg-orange-700 hover:bg-orange-600"
on:click={() => actionBtn({ type: "DoubleDown" })}>Double down</button
>
<button
class="action-btn bg-cyan-700 hover:bg-cyan-600"
on:click={() => actionBtn({ type: "Split" })}>Split</button
>
</div>
<style>
.action-btn {
@apply py-2 px-4 rounded text-white;
}
</style>

View File

@ -2,8 +2,9 @@
import type { Card } from "../types/Card";
export let card: Card;
console.debug(card);
</script>
<div class="w-2 h-5">
I am a {card.index} of {card.suit}!
<div class="w-32 h-36 bg-slate-400 m-1 p-2">
{card.index} of {card.suit}
</div>

View File

@ -0,0 +1,11 @@
<script lang="ts">
import type { PlayingHand } from "../types/Gamestate";
import Card from "./Card.svelte";
export let playingHand: PlayingHand;
</script>
{#each playingHand.hand as hand}
<Card card={hand}/>
{/each}

View File

@ -0,0 +1,22 @@
export interface Deal {
type: "Deal",
players: Number
}
export interface Hit {
type: "Hit"
}
export interface Stand {
type: "Stand"
}
export interface DoubleDown{
type: "DoubleDown"
}
export interface Split {
type: "Split"
}
export type Action = Deal | Hit | Stand | DoubleDown | Split;

View File

@ -1,6 +1,6 @@
export enum CardSuit {
Spades = "Spades",
Clubs = "Clubs",
Hearts = "Hearts",
Diamonds = "Diamonds",
Spades = "S",
Clubs = "C",
Hearts = "H",
Diamonds = "D",
}

View File

@ -1,5 +1,37 @@
import type { Card } from "./Card";
export interface Gamestate{
dealerUpcard: Card,
export interface Player {
hands: [PlayingHand]
}
export enum PlayingHandState {
Playing = "Playing",
Standing = "Standing",
DoubleDown = "DoubleDown",
Busted = "Busted",
Blackjack = "Blackjack",
Maxed = "Maxed",
}
export interface PlayingHand {
state: PlayingHandState,
hand: [Card]
}
export interface Over {
type: "over",
dealerHand: [Card],
players: [Player],
}
export interface Starting {
type: "starting",
}
export interface Playing {
type: "playing",
dealerUpcard: Card,
players: [Player],
}
export type Gamestate = Over | Starting | Playing;