From 17605efe767c774c4c6cd29ee38a80298dfe0a5d Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Sun, 22 Sep 2024 16:11:42 +0200 Subject: [PATCH] feat: calcul automatique des points #3 --- bot/src/lib.rs | 11 ++++--- client_cli/src/app.rs | 30 +++++++++++++---- store/src/game.rs | 59 ++++++++++++++++++++++++++++++---- store/src/game_rules_points.rs | 5 ++- 4 files changed, 87 insertions(+), 18 deletions(-) diff --git a/bot/src/lib.rs b/bot/src/lib.rs index c53c5b1..a585dc7 100644 --- a/bot/src/lib.rs +++ b/bot/src/lib.rs @@ -9,6 +9,7 @@ pub struct Bot { pub game: GameState, pub player_id: PlayerId, color: Color, + schools_enabled: bool, } impl Default for Bot { @@ -17,6 +18,7 @@ impl Default for Bot { game: GameState::default(), player_id: 1, color: Color::Black, + schools_enabled: false, } } } @@ -29,7 +31,7 @@ impl Bot { /// ```let mut bot = Bot::new(Color::Black); /// assert_eq!(bot.game.stage, Stage::PreGame); /// ``` - pub fn new(color: Color) -> Self { + pub fn new(color: Color, schools_enabled: bool) -> Self { let mut game = GameState::default(); game.init_player("p1"); game.init_player("p2"); @@ -43,6 +45,7 @@ impl Bot { game, player_id, color, + schools_enabled: false, } } @@ -107,13 +110,13 @@ mod tests { #[test] fn test_new() { - let bot = Bot::new(Color::Black); + let bot = Bot::new(Color::Black, false); assert_eq!(bot.game.stage, Stage::PreGame); } #[test] fn test_consume() { - let mut bot = Bot::new(Color::Black); + let mut bot = Bot::new(Color::Black, false); let mut event = bot.handle_event(&GameEvent::BeginGame { goes_first: 2 }); assert_eq!(event, Some(GameEvent::Roll { player_id: 2 })); @@ -124,6 +127,6 @@ mod tests { player_id: 2, dice: Dice { values: (2, 3) }, }); - assert_eq!(bot.game.turn_stage, TurnStage::MarkPoints); + assert_eq!(bot.game.turn_stage, TurnStage::Move); } } diff --git a/client_cli/src/app.rs b/client_cli/src/app.rs index 20f5207..0dfe5da 100644 --- a/client_cli/src/app.rs +++ b/client_cli/src/app.rs @@ -2,7 +2,9 @@ use itertools::Itertools; use bot::Bot; use pretty_assertions::assert_eq; -use store::{CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, Stage, TurnStage}; +use store::{ + CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, PointsRules, Stage, TurnStage, +}; #[derive(Debug, Default)] pub struct AppArgs { @@ -21,14 +23,14 @@ pub struct Game { impl Game { // Constructs a new instance of [`App`]. - pub fn new(seed: Option) -> Self { - let mut state = GameState::default(); + pub fn new(schools_enabled: bool, seed: Option) -> Self { + let mut state = GameState::new(schools_enabled); // local : player let player_id: Option = state.init_player("myself"); // bot let bot_id: PlayerId = state.init_player("bot").unwrap(); let bot_color = state.player_color_by_id(&bot_id).unwrap(); - let bot: Bot = Bot::new(bot_color); + let bot: Bot = Bot::new(bot_color, schools_enabled); let mut game = Self { state, @@ -77,20 +79,23 @@ impl Game { pub struct App { // should the application exit? pub should_quit: bool, + pub schools_enabled: bool, pub game: Game, } impl App { // Constructs a new instance of [`App`]. pub fn new(args: AppArgs) -> Self { + let schools_enabled = false; Self { - game: Game::new(args.seed.map(|s| s as u64)), + game: Game::new(schools_enabled, args.seed.map(|s| s as u64)), should_quit: false, + schools_enabled, } } pub fn start(&mut self) { - self.game.state = GameState::new(); + self.game.state = GameState::new(self.schools_enabled); } pub fn input(&mut self, input: &str) { @@ -130,6 +135,17 @@ impl App { return; } let dice = self.game.dice_roller.roll(); + + // get correct points for these board and dice + let points_rules = PointsRules::new( + &self + .game + .state + .player_color_by_id(&self.game.player_id.unwrap()) + .unwrap(), + &self.game.state.board, + dice, + ); self.game.handle_event(&GameEvent::RollResult { player_id: self.game.player_id.unwrap(), dice, @@ -247,7 +263,7 @@ Rolled dice : 0 & 0 #[test] fn test_move() { let expected = "------------------------------- -InGame > myself > RollDice +InGame > myself > MarkAdvPoints Rolled dice : 4 & 6 Player :: holes :: points diff --git a/store/src/game.rs b/store/src/game.rs index 1bb7c7d..8b5cc1b 100644 --- a/store/src/game.rs +++ b/store/src/game.rs @@ -42,8 +42,12 @@ pub struct GameState { pub history: Vec, /// last dice pair rolled pub dice: Dice, + /// players points computed for the last dice pair rolled + dice_points: (u8, u8), /// true if player needs to roll first roll_first: bool, + // NOTE: add to a Setting struct if other fields needed + pub schools_enabled: bool, } // implement Display trait @@ -71,15 +75,33 @@ impl Default for GameState { players: HashMap::new(), history: Vec::new(), dice: Dice::default(), + dice_points: (0, 0), roll_first: true, + schools_enabled: false, } } } impl GameState { /// Create a new default game - pub fn new() -> Self { - GameState::default() + pub fn new(schools_enabled: bool) -> Self { + let mut gs = GameState::default(); + gs.set_schools_enabled(schools_enabled); + gs + } + + fn set_schools_enabled(&mut self, schools_enabled: bool) { + self.schools_enabled = schools_enabled; + } + + fn get_opponent_id(&self) -> Option { + self.players + .keys() + .map(|k| *k) + .filter(|k| k != &self.active_player_id) + .collect::>() + .first() + .copied() } // ------------------------------------------------------------------------- @@ -358,11 +380,30 @@ impl GameState { self.players.remove(player_id); } Roll { player_id: _ } => { - self.turn_stage = TurnStage::RollWaiting; + // Opponent has moved, we can mark pending points earned during opponent's turn + self.mark_points(self.active_player_id, self.dice_points.1); + if self.stage != Stage::Ended { + self.turn_stage = TurnStage::RollWaiting; + } } - RollResult { player_id: _, dice } => { + RollResult { player_id, dice } => { self.dice = *dice; self.turn_stage = TurnStage::MarkPoints; + // We compute points for the move + let points_rules = PointsRules::new( + &self.player_color_by_id(&self.active_player_id).unwrap(), + &self.board, + *dice, + ); + self.dice_points = points_rules.get_points(); + if !self.schools_enabled { + // Schools are not enabled. We mark points automatically + // the points earned by the opponent will be marked on its turn + self.mark_points(self.active_player_id, self.dice_points.0); + if self.stage != Stage::Ended { + self.turn_stage = TurnStage::Move; + } + } } Mark { player_id, points } => { self.mark_points(*player_id, *points); @@ -379,7 +420,11 @@ impl GameState { self.board.move_checker(&player.color, moves.0).unwrap(); self.board.move_checker(&player.color, moves.1).unwrap(); self.active_player_id = *self.players.keys().find(|id| *id != player_id).unwrap(); - self.turn_stage = TurnStage::MarkAdvPoints; + self.turn_stage = if self.schools_enabled { + TurnStage::MarkAdvPoints + } else { + TurnStage::RollDice + }; } } @@ -393,7 +438,9 @@ impl GameState { fn mark_points(&mut self, player_id: PlayerId, points: u8) { self.players.get_mut(&player_id).map(|p| { - p.points += points; + let sum_points = p.points + points; + p.points = sum_points % 12; + p.holes += sum_points / 12; p }); } diff --git a/store/src/game_rules_points.rs b/store/src/game_rules_points.rs index 5d7c43a..b1f10e0 100644 --- a/store/src/game_rules_points.rs +++ b/store/src/game_rules_points.rs @@ -443,10 +443,13 @@ impl PointsRules { pub fn get_points(&self) -> (u8, u8) { let jans = self.get_jans(&self.board); + // if !jans.is_empty() { + // println!("get points : {:?}", jans); + // } let (points, adv_points) = jans .into_iter() .fold((0, 0), |acc: (i8, i8), (jan, moves)| { - println!("get_points : {:?}", jan); + // println!("get_points : {:?}", jan); let is_double = if jan == Jan::HelplessMan { moves[0] == (CheckerMove::default(), CheckerMove::default()) } else {