I'm human
This commit is contained in:
parent
b47325a0dc
commit
c31fb7d0ff
@ -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());
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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 })
|
||||
}
|
||||
|
@ -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(),
|
||||
},
|
||||
}
|
||||
|
@ -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>
|
||||
|
15
frontend/src/functions/doAction.ts
Normal file
15
frontend/src/functions/doAction.ts
Normal 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();
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
@apply bg-blue-950 text-white;
|
||||
}
|
||||
|
74
frontend/src/lib/Blackjack.svelte
Normal file
74
frontend/src/lib/Blackjack.svelte
Normal 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>
|
@ -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>
|
11
frontend/src/lib/PlayerHand.svelte
Normal file
11
frontend/src/lib/PlayerHand.svelte
Normal 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}
|
22
frontend/src/types/Action.ts
Normal file
22
frontend/src/types/Action.ts
Normal 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;
|
@ -1,6 +1,6 @@
|
||||
export enum CardSuit {
|
||||
Spades = "Spades",
|
||||
Clubs = "Clubs",
|
||||
Hearts = "Hearts",
|
||||
Diamonds = "Diamonds",
|
||||
Spades = "S",
|
||||
Clubs = "C",
|
||||
Hearts = "H",
|
||||
Diamonds = "D",
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user