I'm human
This commit is contained in:
parent
b47325a0dc
commit
c31fb7d0ff
@ -190,6 +190,10 @@ impl BlackjackGame {
|
|||||||
}
|
}
|
||||||
(GameState::Over, PlayMoves::Deal { players })
|
(GameState::Over, PlayMoves::Deal { players })
|
||||||
| (GameState::Starting, PlayMoves::Deal { players }) => {
|
| (GameState::Starting, PlayMoves::Deal { players }) => {
|
||||||
|
// Reset everything
|
||||||
|
self.dealer_hand = Hand::new();
|
||||||
|
self.players = Vec::new();
|
||||||
|
|
||||||
// Create players
|
// Create players
|
||||||
for _ in 0..players {
|
for _ in 0..players {
|
||||||
self.players.push(Player::new());
|
self.players.push(Player::new());
|
||||||
|
@ -4,9 +4,13 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||||
pub enum CardSuit {
|
pub enum CardSuit {
|
||||||
|
#[serde(rename = "S")]
|
||||||
Spades,
|
Spades,
|
||||||
|
#[serde(rename = "C")]
|
||||||
Clubs,
|
Clubs,
|
||||||
|
#[serde(rename = "H")]
|
||||||
Hearts,
|
Hearts,
|
||||||
|
#[serde(rename = "D")]
|
||||||
Diamonds,
|
Diamonds,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,6 @@ impl<'de> Deserialize<'de> for Hand {
|
|||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
// Deserialize into a Vec directly and wrap it in MyVecWrapper
|
|
||||||
let cards = Vec::<Card>::deserialize(deserializer)?;
|
let cards = Vec::<Card>::deserialize(deserializer)?;
|
||||||
Ok(Hand { cards })
|
Ok(Hand { cards })
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,15 @@ use rocket::{
|
|||||||
Build, Rocket, State,
|
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")]
|
#[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()))
|
Json(gamestate_as_json(&state.game.lock().unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,8 +22,8 @@ fn get_state(state: &State<MyState>) -> Json<GamestateJson> {
|
|||||||
fn post_move(
|
fn post_move(
|
||||||
state: &State<MyState>,
|
state: &State<MyState>,
|
||||||
request: Json<PlayMoves>,
|
request: Json<PlayMoves>,
|
||||||
) -> Result<Json<GamestateJson>, Status> {
|
) -> Result<Json<ExtendedGameState>, Status> {
|
||||||
let action = request.0;
|
let action = request.into_inner();
|
||||||
|
|
||||||
if state.game.lock().unwrap().play(action) {
|
if state.game.lock().unwrap().play(action) {
|
||||||
Ok(Json(gamestate_as_json(&state.game.lock().unwrap())))
|
Ok(Json(gamestate_as_json(&state.game.lock().unwrap())))
|
||||||
@ -32,23 +37,35 @@ struct MyState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(tag = "type", rename_all = "camelCase", rename_all_fields = "camelCase")]
|
||||||
struct GamestateJson {
|
enum ExtendedGameState {
|
||||||
state: GameState,
|
Over {
|
||||||
dealer_upcard: Option<Card>,
|
dealer_hand: Hand,
|
||||||
players: Vec<Player>,
|
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() {
|
match game.get_state() {
|
||||||
GameState::Starting => GamestateJson {
|
GameState::Starting => ExtendedGameState::Starting,
|
||||||
state: *game.get_state(),
|
GameState::Over => ExtendedGameState::Over {
|
||||||
dealer_upcard: None,
|
dealer_hand: game.get_dealer_hand().clone(),
|
||||||
players: Vec::new(),
|
players: game.get_players().clone(),
|
||||||
},
|
},
|
||||||
GameState::Over | GameState::PlayerTurn { .. } => GamestateJson {
|
GameState::PlayerTurn {
|
||||||
state: *game.get_state(),
|
player_index,
|
||||||
dealer_upcard: game.get_dealer_upcard().copied(),
|
hand_index,
|
||||||
|
} => ExtendedGameState::Playing {
|
||||||
|
dealer_upcard: *game.get_dealer_upcard().unwrap(),
|
||||||
|
player_turn: *player_index,
|
||||||
|
hand_turn: *hand_index,
|
||||||
players: game.get_players().clone(),
|
players: game.get_players().clone(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {fetchState} from "./functions/fetchState";
|
import Blackjack from "./lib/Blackjack.svelte";
|
||||||
import { CardSuit } from "./types/CardSuit";
|
|
||||||
|
|
||||||
async function getState() {
|
|
||||||
let state = await fetchState();
|
|
||||||
console.debug(state);
|
|
||||||
|
|
||||||
if (state.dealerUpcard.suit == CardSuit.Spades){
|
|
||||||
console.debug("Heureka");
|
|
||||||
}else{
|
|
||||||
console.debug("FUCK");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<div>Hello world</div>
|
<Blackjack/>
|
||||||
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" on:click={getState}>Get state</button>
|
|
||||||
</main>
|
</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 base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@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";
|
import type { Card } from "../types/Card";
|
||||||
|
|
||||||
export let card: Card;
|
export let card: Card;
|
||||||
|
console.debug(card);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="w-2 h-5">
|
<div class="w-32 h-36 bg-slate-400 m-1 p-2">
|
||||||
I am a {card.index} of {card.suit}!
|
{card.index} of {card.suit}
|
||||||
</div>
|
</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 {
|
export enum CardSuit {
|
||||||
Spades = "Spades",
|
Spades = "S",
|
||||||
Clubs = "Clubs",
|
Clubs = "C",
|
||||||
Hearts = "Hearts",
|
Hearts = "H",
|
||||||
Diamonds = "Diamonds",
|
Diamonds = "D",
|
||||||
}
|
}
|
@ -1,5 +1,37 @@
|
|||||||
import type { Card } from "./Card";
|
import type { Card } from "./Card";
|
||||||
|
|
||||||
export interface Gamestate{
|
export interface Player {
|
||||||
dealerUpcard: Card,
|
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