From c31fb7d0ff28157976e11b456d17491c167704e5 Mon Sep 17 00:00:00 2001 From: Niklas Kapelle Date: Fri, 24 May 2024 23:15:28 +0200 Subject: [PATCH] I'm human --- backend/src/blackjack/blackjack_game.rs | 4 ++ backend/src/cards/card_suit.rs | 4 ++ backend/src/cards/hand.rs | 1 - backend/src/webserver.rs | 51 +++++++++++------ frontend/src/App.svelte | 19 +------ frontend/src/functions/doAction.ts | 15 +++++ frontend/src/index.css | 6 +- frontend/src/lib/Blackjack.svelte | 74 +++++++++++++++++++++++++ frontend/src/lib/Card.svelte | 7 ++- frontend/src/lib/PlayerHand.svelte | 11 ++++ frontend/src/types/Action.ts | 22 ++++++++ frontend/src/types/CardSuit.ts | 8 +-- frontend/src/types/Gamestate.ts | 36 +++++++++++- 13 files changed, 214 insertions(+), 44 deletions(-) create mode 100644 frontend/src/functions/doAction.ts create mode 100644 frontend/src/lib/Blackjack.svelte create mode 100644 frontend/src/lib/PlayerHand.svelte create mode 100644 frontend/src/types/Action.ts diff --git a/backend/src/blackjack/blackjack_game.rs b/backend/src/blackjack/blackjack_game.rs index 9a0bcef..f770120 100644 --- a/backend/src/blackjack/blackjack_game.rs +++ b/backend/src/blackjack/blackjack_game.rs @@ -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()); diff --git a/backend/src/cards/card_suit.rs b/backend/src/cards/card_suit.rs index eeaf4ac..c153456 100644 --- a/backend/src/cards/card_suit.rs +++ b/backend/src/cards/card_suit.rs @@ -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, } diff --git a/backend/src/cards/hand.rs b/backend/src/cards/hand.rs index 4e5a24a..ded3896 100644 --- a/backend/src/cards/hand.rs +++ b/backend/src/cards/hand.rs @@ -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::::deserialize(deserializer)?; Ok(Hand { cards }) } diff --git a/backend/src/webserver.rs b/backend/src/webserver.rs index a49e4bb..6954141 100644 --- a/backend/src/webserver.rs +++ b/backend/src/webserver.rs @@ -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) -> Json { +fn get_state(state: &State) -> Json { Json(gamestate_as_json(&state.game.lock().unwrap())) } @@ -17,8 +22,8 @@ fn get_state(state: &State) -> Json { fn post_move( state: &State, request: Json, -) -> Result, Status> { - let action = request.0; +) -> Result, 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, - players: Vec, +#[serde(tag = "type", rename_all = "camelCase", rename_all_fields = "camelCase")] +enum ExtendedGameState { + Over { + dealer_hand: Hand, + players: Vec, + }, + Playing { + dealer_upcard: Card, + player_turn: usize, + hand_turn: usize, + players: Vec, + }, + 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(), }, } diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 86af541..af58611 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -1,22 +1,9 @@
-
Hello world
- +
diff --git a/frontend/src/functions/doAction.ts b/frontend/src/functions/doAction.ts new file mode 100644 index 0000000..a0c4763 --- /dev/null +++ b/frontend/src/functions/doAction.ts @@ -0,0 +1,15 @@ +import type { Action } from "../types/Action"; +import type { Gamestate } from "../types/Gamestate"; + +export async function doAction(action: Action): Promise { + let res = await fetch("/api/state", { + method: "POST", + body: JSON.stringify(action), + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + }); + + return await res.json(); +} \ No newline at end of file diff --git a/frontend/src/index.css b/frontend/src/index.css index bd6213e..2f33fd7 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,3 +1,7 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; + +body { + @apply bg-blue-950 text-white; +} diff --git a/frontend/src/lib/Blackjack.svelte b/frontend/src/lib/Blackjack.svelte new file mode 100644 index 0000000..e7c74e2 --- /dev/null +++ b/frontend/src/lib/Blackjack.svelte @@ -0,0 +1,74 @@ + + +{#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. +
+ Player: + {#each state.players as player} + {#each player.hands as hand} + + {/each} + {/each} + {:else if state.type == "playing"} + Dealer: + + Player: + {#each state.players as player} + {#each player.hands as hand} + + {/each} + {/each} + {/if} +{:else} + Loading... +{/if} + +
+ + + + + +
+ + diff --git a/frontend/src/lib/Card.svelte b/frontend/src/lib/Card.svelte index 358515f..f7a87c1 100644 --- a/frontend/src/lib/Card.svelte +++ b/frontend/src/lib/Card.svelte @@ -2,8 +2,9 @@ import type { Card } from "../types/Card"; export let card: Card; + console.debug(card); -
- I am a {card.index} of {card.suit}! -
\ No newline at end of file +
+ {card.index} of {card.suit} +
diff --git a/frontend/src/lib/PlayerHand.svelte b/frontend/src/lib/PlayerHand.svelte new file mode 100644 index 0000000..b706750 --- /dev/null +++ b/frontend/src/lib/PlayerHand.svelte @@ -0,0 +1,11 @@ + + +{#each playingHand.hand as hand} + +{/each} diff --git a/frontend/src/types/Action.ts b/frontend/src/types/Action.ts new file mode 100644 index 0000000..0a24f2c --- /dev/null +++ b/frontend/src/types/Action.ts @@ -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; diff --git a/frontend/src/types/CardSuit.ts b/frontend/src/types/CardSuit.ts index 8217fef..05b74ce 100644 --- a/frontend/src/types/CardSuit.ts +++ b/frontend/src/types/CardSuit.ts @@ -1,6 +1,6 @@ export enum CardSuit { - Spades = "Spades", - Clubs = "Clubs", - Hearts = "Hearts", - Diamonds = "Diamonds", + Spades = "S", + Clubs = "C", + Hearts = "H", + Diamonds = "D", } \ No newline at end of file diff --git a/frontend/src/types/Gamestate.ts b/frontend/src/types/Gamestate.ts index 55b4c5f..9633ce8 100644 --- a/frontend/src/types/Gamestate.ts +++ b/frontend/src/types/Gamestate.ts @@ -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;