From 8c99b228d3eb86abbf44d8599dc3f064fdde721f Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Sat, 3 Feb 2024 22:16:14 +0100 Subject: [PATCH] store : validation : check dices --- store/src/dice.rs | 10 ++--- store/src/game.rs | 104 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 90 insertions(+), 24 deletions(-) diff --git a/store/src/dice.rs b/store/src/dice.rs index a4336eb..4401ff3 100644 --- a/store/src/dice.rs +++ b/store/src/dice.rs @@ -19,9 +19,7 @@ impl Dices { let v = (between.sample(&mut rng), between.sample(&mut rng)); - Dices { - values: (v.0, v.1), - } + Dices { values: (v.0, v.1) } } /// Heads or tails @@ -31,7 +29,6 @@ impl Dices { between.sample(&mut rng) == 1 } - pub fn to_bits_string(self) -> String { format!("{:0>3b}{:0>3b}", self.values.0, self.values.1) } @@ -51,7 +48,7 @@ impl Dices { /// Trait to roll the dices pub trait Roll { /// Roll the dices - fn roll(&mut self) -> Result<&mut Self, Error>; + fn roll(&mut self) -> &mut Self; } #[cfg(test)] @@ -67,8 +64,7 @@ mod tests { #[test] fn test_to_bits_string() { - let dices = Dices { values: (4, 2)}; + let dices = Dices { values: (4, 2) }; assert!(dices.to_bits_string() == "100010"); } - } diff --git a/store/src/game.rs b/store/src/game.rs index ad9f255..c9aafbf 100644 --- a/store/src/game.rs +++ b/store/src/game.rs @@ -75,9 +75,9 @@ impl GameState { GameState::default() } - fn add_player(&mut self, player_id: PlayerId, player: Player) { - self.players.insert(player_id, player); - } + // ------------------------------------------------------------------------- + // accessors + // ------------------------------------------------------------------------- /// Calculate game state id : pub fn to_string_id(&self) -> String { @@ -148,16 +148,6 @@ impl GameState { .next() } - pub fn switch_active_player(&mut self) { - let other_player_id = self - .players - .iter() - .filter(|(id, _player)| **id != self.active_player_id) - .map(|(id, _player)| *id) - .next(); - self.active_player_id = other_player_id.unwrap_or(0); - } - pub fn player_id_by_color(&self, color: Color) -> Option<&PlayerId> { self.players .iter() @@ -174,6 +164,10 @@ impl GameState { .next() } + // ---------------------------------------------------------------------------------- + // Rules checks + // ---------------------------------------------------------------------------------- + /// Determines whether an event is valid considering the current GameState pub fn validate(&self, event: &GameEvent) -> bool { use GameEvent::*; @@ -220,6 +214,16 @@ impl GameState { return false; } } + Mark { player_id, points } => { + // Check player exists + if !self.players.contains_key(player_id) { + return false; + } + // Check player is currently the one making their move + if self.active_player_id != *player_id { + return false; + } + } Move { player_id, moves } => { // Check player exists if !self.players.contains_key(player_id) { @@ -231,9 +235,14 @@ impl GameState { error!("Player not active : {}", self.active_player_id); return false; } + let color = &self.players[player_id].color; + + // Check moves conforms to the dices + if !self.moves_follows_dices(color, moves) { + return false; + } // Check move is physically possible - let color = &self.players[player_id].color; if !self.board.move_possible(color, &moves.0) { return false; } @@ -259,6 +268,14 @@ impl GameState { true } + fn moves_follows_dices(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool { + // basic : same number + // prise de coin par puissance + // sorties + // no rule was broken + false + } + fn moves_allowed(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool { // ------- corner rules ---------- let corner_field: Field = self.board.get_color_corner(color); @@ -294,6 +311,23 @@ impl GameState { true } + // ---------------------------------------------------------------------------------- + // State updates + // ---------------------------------------------------------------------------------- + + fn add_player(&mut self, player_id: PlayerId, player: Player) { + self.players.insert(player_id, player); + } + + pub fn switch_active_player(&mut self) { + let other_player_id = self + .players + .iter() + .filter(|(id, _player)| **id != self.active_player_id) + .map(|(id, _player)| *id) + .next(); + self.active_player_id = other_player_id.unwrap_or(0); + } /// Consumes an event, modifying the GameState and adding the event to its history /// NOTE: consume assumes the event to have already been validated and will accept *any* event passed to it pub fn consume(&mut self, valid_event: &GameEvent) { @@ -302,6 +336,7 @@ impl GameState { BeginGame { goes_first } => { self.active_player_id = *goes_first; self.stage = Stage::InGame; + self.turn_stage = TurnStage::RollDice; } EndGame { reason: _ } => self.stage = Stage::Ended, PlayerJoined { player_id, name } => { @@ -325,7 +360,16 @@ impl GameState { PlayerDisconnected { player_id } => { self.players.remove(player_id); } - Roll { player_id: _ } => {} + Roll { player_id: _ } => { + self.roll(); + self.turn_stage = TurnStage::MarkPoints; + } + Mark { player_id, points } => { + self.mark_points(*player_id, *points); + if self.stage != Stage::Ended { + self.turn_stage = TurnStage::Move; + } + } Move { player_id, moves } => { let player = self.players.get(player_id).unwrap(); self.board.move_checker(&player.color, moves.0).unwrap(); @@ -346,6 +390,10 @@ impl GameState { pub fn determine_winner(&self) -> Option { None } + + fn mark_points(&mut self, player_id: PlayerId, points: u8) { + todo!() + } } /// The reasons why a game could end @@ -376,6 +424,10 @@ pub enum GameEvent { Roll { player_id: PlayerId, }, + Mark { + player_id: PlayerId, + points: u8, + }, Move { player_id: PlayerId, moves: (CheckerMove, CheckerMove), @@ -383,7 +435,7 @@ pub enum GameEvent { } impl Roll for GameState { - fn roll(&mut self) -> Result<&mut Self, Error> { + fn roll(&mut self) -> &mut Self { self.dices = self.dices.roll(); if self.who_plays().is_none() { let active_color = match self.dices.coin() { @@ -395,7 +447,7 @@ impl Roll for GameState { self.active_player_id = *color_player_id.unwrap(); } } - Ok(self) + self } } @@ -490,4 +542,22 @@ mod tests { let event: GameEvent = GameEvent::Move { player_id, moves }; assert!(!state.validate(&event)); } + + #[test] + fn test_moves_follow_dices() { + let mut state = GameState::default(); + let player1 = Player::new("player1".into(), Color::White); + let player_id = 1; + state.add_player(player_id, player1); + state.add_player(2, Player::new("player2".into(), Color::Black)); + state.consume(&GameEvent::BeginGame { + goes_first: player_id, + }); + state.consume(&GameEvent::Roll { player_id }); + let moves = ( + CheckerMove::new(1, 5).unwrap(), + CheckerMove::new(6, 9).unwrap(), + ); + assert!(state.moves_follows_dices(&Color::White, &moves)); + } }