From 770581bb212762e0a8ab491a5bb684c25bdb5821 Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Tue, 16 May 2023 13:32:46 +0300 Subject: [PATCH] feat(client): ability to insert new actions... ... while parsing existing actions. --- client/src/api/game/mod.rs | 8 +- client/src/game_status/mod.rs | 4 +- client/src/game_status/parser.rs | 155 +++++++++++++++++-------------- 3 files changed, 94 insertions(+), 73 deletions(-) diff --git a/client/src/api/game/mod.rs b/client/src/api/game/mod.rs index c81956b..0ed21ab 100644 --- a/client/src/api/game/mod.rs +++ b/client/src/api/game/mod.rs @@ -31,7 +31,7 @@ pub use create_action::*; mod details; pub use details::*; -#[derive(Deserialize, Serialize, Clone)] +#[derive(Deserialize, Serialize, Clone, PartialEq)] pub enum Command { InitSupplyPile { card: Card, @@ -50,15 +50,17 @@ pub enum Command { Discard { index: usize, }, - /// end the targets turn + /// end the invokers turn, and invoke StartTurn for the target EndTurn {}, + /// start the targets turn + StartTurn {}, /// change player state to another ChangePlayerState { state: PlayerState, }, } -#[derive(Deserialize, Serialize, Clone)] +#[derive(Deserialize, Serialize, Clone, PartialEq)] pub struct Action { pub id: String, pub created_at: chrono::DateTime, diff --git a/client/src/game_status/mod.rs b/client/src/game_status/mod.rs index e8af430..a598c25 100644 --- a/client/src/game_status/mod.rs +++ b/client/src/game_status/mod.rs @@ -14,14 +14,14 @@ use crate::api::game::{Action, Command, Game}; mod parser; -#[derive(Deserialize, Serialize, Clone)] +#[derive(Deserialize, Serialize, Clone, PartialEq)] pub struct CardAction { pub target: String, pub command: Command, pub seed: u64, } -#[derive(Deserialize, Serialize, Clone)] +#[derive(Deserialize, Serialize, Clone, PartialEq)] pub struct Card { pub name: String, /// short details shown on the card, e.g. Draw 2 diff --git a/client/src/game_status/parser.rs b/client/src/game_status/parser.rs index caa13c6..b11fe77 100644 --- a/client/src/game_status/parser.rs +++ b/client/src/game_status/parser.rs @@ -11,8 +11,9 @@ use std::collections::HashMap; use fastrand::Rng; use crate::{ - api::game::{Command, Game}, + api::game::{Action, Command, Game}, game_status::SupplyPile, + seed_gen, }; use super::{GameStatus, PlayerState, PlayerStatus}; @@ -80,80 +81,98 @@ pub fn parse(game: &Game) -> Result { }, ); - // TODO: a system for reparsing if needed, e.g. after something - // modifies the actions Vector. - for action in &game_status.actions { - // invoker: the one who invoked the action - // target: the one who the action affects, may also be the invoker, e.g. draw - let (invoker, target) = - get_invoker_target(&mut game_status.players, &action.invoker, &action.target); - - match &action.command { - Command::InitSupplyPile { card, amount } => { - let pile = SupplyPile { - card: card.clone(), - amount: *amount, - }; - - game_status.supply_piles.push(pile); - } - Command::TakeFromPile { index, for_cost } => { - // 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 -= 1; - - // player should have enough - assert!(*for_cost <= target.currency); - target.currency -= for_cost; - - 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.parse::().unwrap()); - } - - 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)); - } - Command::EndTurn {} => { - // NOTE: target will be the next player + for action in game_status.actions.clone() { + parse_action(&action, game, &mut game_status); + } - // set player to idle - invoker.state = PlayerState::Idle; + Ok(game_status) +} - // set the target to the play phase - target.state = PlayerState::PlayPhase; +fn parse_action(action: &Action, game: &Game, game_status: &mut GameStatus) { + // invoker: the one who invoked the action + // target: the one who the action affects, may also be the invoker, e.g. draw + let (invoker, target) = + get_invoker_target(&mut game_status.players, &action.invoker, &action.target); - // clear currency - invoker.currency = 0; + let Some(action_pos) = game_status.actions.iter().position(|a| *a == action.clone()) else { + panic!("Action was not found in game_status.actions!"); + }; - // other? - } - Command::ChangePlayerState { state } => { - target.state = *state; + match &action.command { + Command::InitSupplyPile { card, amount } => { + let pile = SupplyPile { + card: card.clone(), + amount: *amount, + }; + + game_status.supply_piles.push(pile); + } + Command::TakeFromPile { index, for_cost } => { + // 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 -= 1; + + // player should have enough + assert!(*for_cost <= target.currency); + target.currency -= for_cost; + + 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.parse::().unwrap()); + } + + target + .hand + .push(target.deck.pop().unwrap_or_else(|| unreachable!())); } - #[allow(unreachable_patterns)] - _ => todo!(), } + Command::Discard { index } => { + // index should be within range + assert!(*index <= target.hand.len()); + target.discard.push(target.hand.remove(*index)); + } + Command::EndTurn {} => { + // NOTE: target will be the next player + + // set player to idle + invoker.state = PlayerState::Idle; + + // clear currency + invoker.currency = 0; + + let start_turn_action = Action::new( + &game.id, + &action.invoker, + &action.target, + &Command::StartTurn {}, + seed_gen!(), + ); + game_status + .actions + .insert(action_pos + 1, start_turn_action.clone()); + + parse_action(&start_turn_action, game, game_status); + } + Command::StartTurn {} => { + // set the target to the play phase + target.state = PlayerState::PlayPhase; + } + Command::ChangePlayerState { state } => { + target.state = *state; + } + #[allow(unreachable_patterns)] + _ => todo!(), } - - Ok(game_status) } fn shuffle_discard_to_deck(target: &mut PlayerStatus, seed: u64) { -- 2.44.1