From c5909cd025c1f7ffec7b02fa467ed4a82c2ae6b2 Mon Sep 17 00:00:00 2001 From: skye Date: Mon, 1 May 2023 22:03:24 +0300 Subject: [PATCH] feat(client): semi initial game state and parser --- client/src/api/game/mod.rs | 11 +++-- client/src/game_status/mod.rs | 47 ++++++++++++++++++-- client/src/game_status/parser.rs | 74 ++++++++++++++++++++++++++++++++ client/src/plugins/game/mod.rs | 4 +- 4 files changed, 127 insertions(+), 9 deletions(-) diff --git a/client/src/api/game/mod.rs b/client/src/api/game/mod.rs index 06dd3b2..e7a2f9f 100644 --- a/client/src/api/game/mod.rs +++ b/client/src/api/game/mod.rs @@ -9,6 +9,8 @@ use serde::{Deserialize, Serialize}; use serde_repr::Deserialize_repr; +use crate::game_status::Card; + use super::user::User; mod forming; @@ -31,12 +33,13 @@ pub use details::*; #[derive(Deserialize, Serialize, Clone)] pub enum Command { + InitSupplyPile { card: Card, amount: usize }, + /// take a card from pile N + TakeFromPile { index: usize }, /// draw N amount of cards from deck - Draw { amount: u32 }, + Draw { amount: usize }, /// discard card from hand in slot N - Discard { index: u32 }, - /// shuffle discard pile to deck - ShuffleDiscardToDeck { seed: u32 }, + Discard { index: usize }, } #[derive(Deserialize, Clone)] diff --git a/client/src/game_status/mod.rs b/client/src/game_status/mod.rs index 173d97f..38d53fd 100644 --- a/client/src/game_status/mod.rs +++ b/client/src/game_status/mod.rs @@ -6,17 +6,56 @@ * See LICENSE for licensing information. */ -use crate::api::game::Action; +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use crate::api::game::{Action, Command}; mod parser; +#[derive(Deserialize, Serialize, Clone)] +pub struct CardAction { + pub target: String, + pub command: Command, + pub seed: u64, +} + +#[derive(Deserialize, Serialize, Clone)] +pub struct Card { + pub name: String, + pub cost: u32, + /// if set, use this? + //vp_cost: Option, + pub actions: Vec, +} + +/// a supply pile holds an amount of some card +pub struct SupplyPile { + /// the card type that the supply pile holds + pub card: Card, + /// the amount of cards currently in the pile + pub amount: usize, +} + +pub struct PlayerStatus { + pub hand: Vec, + pub deck: Vec, + pub discard: Vec, +} + /// constructed from a vector of [`Action`]s pub struct GameStatus { - + pub supply_piles: Vec, + /// player ids mapped to statuses + pub players: HashMap, } impl GameStatus { - pub fn new(actions: Vec) -> Self { - Self { } + pub fn new(actions: &Vec) -> Self { + match parser::parse(actions) { + Ok(res) => res, + Err(_) => panic!("parsing actions failed"), + } } } diff --git a/client/src/game_status/parser.rs b/client/src/game_status/parser.rs index c8ca561..5480dde 100644 --- a/client/src/game_status/parser.rs +++ b/client/src/game_status/parser.rs @@ -6,3 +6,77 @@ * See LICENSE for licensing information. */ +use std::collections::HashMap; +use fastrand::Rng; + +use crate::{api::game::{Action, Command}, game_status::SupplyPile}; + +use super::{GameStatus, PlayerStatus, Card}; + +pub fn parse(actions: &Vec) -> Result { + let mut game_status = GameStatus { + supply_piles: vec![], + players: HashMap::new(), + }; + + for action in actions { + // the one who invoked the action + let invoker = game_status.players.get_mut(&action.invoker) + .unwrap_or_else(|| unreachable!()); + + // the one who the action affects, may also be the invoker, e.g. draw + let target = game_status.players.get_mut(&action.target) + .unwrap_or_else(|| unreachable!()); + + match &action.command { + Command::InitSupplyPile { card, amount } => { + let pile = SupplyPile { + card: card.clone(), + amount: *amount, + }; + + game_status.supply_piles.push(pile); + } + Command::TakeFromPile { index } => { + // index should be within range + assert!(*index <= game_status.supply_piles.len()); + let pile = &mut game_status.supply_piles.get_mut(*index) + .unwrap_or_else(|| unreachable!()); + + // pile should not be empty + assert!(pile.amount > 0); + pile.amount = pile.amount - 1; + + target.discard.push(pile.card.clone()); + } + Command::Draw { amount } => { + for _ in 0..*amount { + if target.deck.is_empty() { + shuffle_discard_to_deck(target, action.seed); + } + + target.hand.push(target.deck.pop() + .unwrap_or_else(|| unreachable!())); + } + } + Command::Discard { index } => { + // index should be within range + assert!(*index <= target.hand.len()); + target.discard.push(target.hand.remove(*index)); + } + _ => todo!(), + } + } + + Err(()) +} + +fn shuffle_discard_to_deck(target: &mut PlayerStatus, seed: u64) { + let cards = target.discard.to_vec(); + target.discard.clear(); + + target.deck = cards; + + let rng = Rng::with_seed(seed); + rng.shuffle(&mut target.deck); +} diff --git a/client/src/plugins/game/mod.rs b/client/src/plugins/game/mod.rs index 30f38e5..c8c93d3 100644 --- a/client/src/plugins/game/mod.rs +++ b/client/src/plugins/game/mod.rs @@ -8,7 +8,7 @@ use bevy::prelude::*; -use crate::{api::game::Game, Global, AppState}; +use crate::{api::game::Game, Global, AppState, game_status::GameStatus}; use super::GameDetailsCallEvent; @@ -27,12 +27,14 @@ impl Plugin for GamePlugin { #[derive(Resource)] pub struct GameData { pub game: Option, + pub game_status: Option, } impl Default for GameData { fn default() -> Self { Self { game: None, + game_status: None, } } } -- 2.44.1