From 6ceefe01ab87f88bcb4ed029a5a1d9f0d9daec6e Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Wed, 27 Mar 2024 21:10:15 +0100 Subject: [PATCH] roll bot dice --- bot/src/lib.rs | 6 ++- client_cli/src/app.rs | 102 ++++++++++++++++++++++++------------------ store/src/board.rs | 27 +++++++---- store/src/game.rs | 22 ++++++--- 4 files changed, 98 insertions(+), 59 deletions(-) diff --git a/bot/src/lib.rs b/bot/src/lib.rs index 08ec998..816c5bb 100644 --- a/bot/src/lib.rs +++ b/bot/src/lib.rs @@ -5,7 +5,7 @@ use store::{CheckerMove, Color, Dice, GameEvent, GameState, Player, PlayerId, St #[derive(Debug)] pub struct Bot { pub game: GameState, - player_id: PlayerId, + pub player_id: PlayerId, color: Color, } @@ -46,7 +46,8 @@ impl Bot { pub fn consume(&mut self, event: &GameEvent) -> Option { self.game.consume(event); - // println!("{:?}", self.game); + println!("bot game {:?}", self.game); + println!("bot player_id {:?}", self.player_id); if self.game.active_player_id == self.player_id { return match self.game.turn_stage { TurnStage::RollDice => Some(GameEvent::Roll { @@ -60,6 +61,7 @@ impl Bot { player_id: self.player_id, moves: self.choose_move(), }), + _ => None, }; } None diff --git a/client_cli/src/app.rs b/client_cli/src/app.rs index 6e1f1f6..21c2088 100644 --- a/client_cli/src/app.rs +++ b/client_cli/src/app.rs @@ -1,6 +1,6 @@ use bot::Bot; use pretty_assertions::assert_eq; -use store::{CheckerMove, Color, Dice, DiceRoller, GameEvent, GameState, PlayerId}; +use store::{CheckerMove, Color, Dice, DiceRoller, GameEvent, GameState, PlayerId, TurnStage}; #[derive(Debug, Default)] pub struct AppArgs { @@ -43,15 +43,31 @@ impl Game { pub fn consume(&mut self, event: &GameEvent) -> Option { if self.state.validate(event) { + println!("consuming {:?}", event); self.state.consume(event); - return self + // chain all successive bot actions + let bot_event = self .bot .consume(event) .map(|evt| self.consume(&evt)) .flatten(); + // roll dice for bot if needed + if self.bot_needs_dice_roll() { + let dice = self.dice_roller.roll(); + return self.consume(&GameEvent::RollResult { + player_id: self.bot.player_id, + dice, + }); + } + return bot_event; } None } + + fn bot_needs_dice_roll(&self) -> bool { + self.state.active_player_id == self.bot.player_id + && self.state.turn_stage == TurnStage::RollWaiting + } } // Application. @@ -156,27 +172,27 @@ mod tests { Rolled dice : 0 & 0 ------------------------------- - 13 14 15 16 17 18 19 20 21 22 23 24 + 13 14 15 16 17 18 19 20 21 22 23 24 ---------------------------------------------------------------- - | | | X | - | | | X | - | | | X | - | | | X | - | | | X | - | | | X | - | | | X | - | | | X | - | | | 15 | - |----------------------------- | | ------------------------------| - | | | 15 | - | | | O | - | | | O | - | | | O | - | | | O | - | | | O | - | | | O | - | | | O | - | | | O | + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | 15 | + |------------------------------ | | -----------------------------| + | | | 15 | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | ---------------------------------------------------------------- 12 11 10 9 8 7 6 5 4 3 2 1 "; @@ -187,30 +203,30 @@ Rolled dice : 0 & 0 #[test] fn test_move() { let expected = "------------------------------- -Rolled dice : 2 & 3 +Rolled dice : 4 & 6 ------------------------------- - 13 14 15 16 17 18 19 20 21 22 23 24 + 13 14 15 16 17 18 19 20 21 22 23 24 ---------------------------------------------------------------- - | | | X | - | | | X | - | | | X | - | | | X | - | | | X | - | | | X | - | | | X | - | | | X | - | | | 15 | - |----------------------------- | | ------------------------------| - | | | 13 | - | | | O | - | | | O | - | | | O | - | | | O | - | | | O | - | | | O | - | | | O | - | | | O O O | + | X | | X X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | 13 | + |------------------------------ | | -----------------------------| + | | | 13 | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O O O | ---------------------------------------------------------------- 12 11 10 9 8 7 6 5 4 3 2 1 "; diff --git a/store/src/board.rs b/store/src/board.rs index a3d365c..1a5d7db 100644 --- a/store/src/board.rs +++ b/store/src/board.rs @@ -35,9 +35,10 @@ impl CheckerMove { return Err(Error::FieldInvalid); } // check that the destination is after the origin field - if to < from && to != 0 { - return Err(Error::MoveInvalid); - } + // --> not applicable for black moves + // if to < from && to != 0 { + // return Err(Error::MoveInvalid); + // } Ok(Self { from, to }) } @@ -183,18 +184,18 @@ impl Board { .collect(); let mut output = " - 13 14 15 16 17 18 19 20 21 22 23 24 + 13 14 15 16 17 18 19 20 21 22 23 24 ----------------------------------------------------------------\n" .to_owned(); for mut line in upper { // add middle bar - line.replace_range(30..30, "| |"); + line.replace_range(31..31, "| |"); output = output + " |" + &line + " |\n"; } - output = output + " |----------------------------- | | ------------------------------|\n"; + output = output + " |------------------------------ | | -----------------------------|\n"; for mut line in lower { // add middle bar - line.replace_range(30..30, "| |"); + line.replace_range(31..31, "| |"); output = output + " |" + &line + " |\n"; } output = output @@ -345,7 +346,11 @@ impl Board { if Some(color) != checker_color { return Err(Error::FieldInvalid); } - self.positions[field - 1] -= 1; + let unit = match color { + Color::White => 1, + Color::Black => -1, + }; + self.positions[field - 1] -= unit; Ok(()) } @@ -355,7 +360,11 @@ impl Board { if None != checker_color && Some(color) != checker_color { return Err(Error::FieldInvalid); } - self.positions[field - 1] += 1; + let unit = match color { + Color::White => 1, + Color::Black => -1, + }; + self.positions[field - 1] += unit; Ok(()) } } diff --git a/store/src/game.rs b/store/src/game.rs index 2b9d6d9..6d1cf00 100644 --- a/store/src/game.rs +++ b/store/src/game.rs @@ -25,6 +25,7 @@ pub enum Stage { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum TurnStage { RollDice, + RollWaiting, MarkPoints, Move, } @@ -102,9 +103,10 @@ impl GameState { // step -> 2 bits let step_bits = match self.turn_stage { + TurnStage::RollWaiting => "00", TurnStage::RollDice => "01", - TurnStage::MarkPoints => "01", - TurnStage::Move => "10", + TurnStage::MarkPoints => "10", + TurnStage::Move => "11", }; pos_bits.push_str(step_bits); @@ -288,8 +290,8 @@ impl GameState { fn moves_follows_dices(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool { let (dice1, dice2) = self.dice.values; let (move1, move2): &(CheckerMove, CheckerMove) = moves.into(); - let dist1 = (move1.get_to() - move1.get_from()) as u8; - let dist2 = (move2.get_to() - move2.get_from()) as u8; + let dist1 = (move1.get_to() as i8 - move1.get_from() as i8).abs() as u8; + let dist2 = (move2.get_to() as i8 - move2.get_from() as i8).abs() as u8; print!("{}, {}, {}, {}", dist1, dist2, dice1, dice2); // basic : same number if cmp::min(dist1, dist2) != cmp::min(dice1, dice2) @@ -415,7 +417,9 @@ impl GameState { PlayerDisconnected { player_id } => { self.players.remove(player_id); } - Roll { player_id: _ } => {} + Roll { player_id: _ } => { + self.turn_stage = TurnStage::RollWaiting; + } RollResult { player_id: _, dice } => { self.dice = *dice; self.turn_stage = TurnStage::MarkPoints; @@ -436,6 +440,7 @@ impl GameState { .find(|id| *id != player_id) .unwrap() .clone(); + self.turn_stage = TurnStage::RollDice; } } @@ -585,6 +590,13 @@ mod tests { CheckerMove::new(6, 9).unwrap(), ); assert!(!state.moves_possible(&Color::White, &moves)); + + // black moves + let moves = ( + CheckerMove::new(24, 20).unwrap(), + CheckerMove::new(20, 19).unwrap(), + ); + assert!(state.moves_possible(&Color::Black, &moves)); } #[test]