From 46bc30086729355c5d0a4c301e9b788f24e27fac Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Wed, 8 May 2024 21:17:13 +0200 Subject: [PATCH] wip prise en puissance --- store/src/board.rs | 5 +++ store/src/game.rs | 83 ++++++++++++++++++++++++++++++++++++++++++--- store/src/player.rs | 9 +++++ 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/store/src/board.rs b/store/src/board.rs index 5b1f44b..3b03281 100644 --- a/store/src/board.rs +++ b/store/src/board.rs @@ -93,6 +93,11 @@ impl Board { Board::default() } + /// Globally set pieces on board ( for tests ) + pub fn set_positions(&mut self, positions: [i8; 24]) { + self.positions = positions; + } + // maybe todo : operate on bits (cf. https://github.com/bungogood/bkgm/blob/a2fb3f395243bcb0bc9f146df73413f73f5ea1e0/src/position.rs#L217) pub fn to_gnupg_pos_id(&self) -> String { // Pieces placement -> 77bits (24 + 23 + 30 max) diff --git a/store/src/game.rs b/store/src/game.rs index 1b2294a..9140544 100644 --- a/store/src/game.rs +++ b/store/src/game.rs @@ -298,18 +298,48 @@ impl GameState { 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 + // exceptions + // - prise de coin par puissance + if self.is_move_by_puissance(color, moves) { + return true; + } + // - sorties + // default : must be same number if cmp::min(dist1, dist2) != cmp::min(dice1, dice2) || cmp::max(dist1, dist2) != cmp::max(dice1, dice2) { return false; } - // prise de coin par puissance - // sorties // no rule was broken true } + fn is_move_by_puissance(&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() 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; + + // Opponent corner must be empty + let opponent_corner_field: Field = self.board.get_color_corner(&color.opponent_color()); + let (opponent_corner_count, _color) = self + .board + .get_field_checkers(opponent_corner_field) + .unwrap(); + if opponent_corner_count > 0 { + return false; + } + + move1.get_to() == move2.get_to() + && move1.get_to() == self.board.get_color_corner(color) + && ((*color == Color::White + && cmp::min(dist1, dist2) == cmp::min(dice1, dice2) - 1 + && cmp::max(dist1, dist2) == cmp::max(dice1, dice2) - 1) + || (*color == Color::Black + && cmp::min(dist1, dist2) == cmp::min(dice1, dice2) + 1 + && cmp::max(dist1, dist2) == cmp::max(dice1, dice2) + 1)) + } + fn moves_allowed(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool { // ------- corner rules ---------- let corner_field: Field = self.board.get_color_corner(color); @@ -325,7 +355,7 @@ impl GameState { return false; } - // the lat 2 checkers of a corner must leave at the same time + // the last 2 checkers of a corner must leave at the same time if (from0 == corner_field || from1 == corner_field) && (from0 != from1) && corner_count == 2 { return false; @@ -579,4 +609,49 @@ mod tests { ); assert!(!state.moves_follows_dices(&Color::White, &badmoves)); } + + #[test] + fn test_prise_en_puissance() { + 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 }); + + // prise par puissance ok + state.board.set_positions([ + 10, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, + ]); + state.dice.values = (5, 5); + let moves = ( + CheckerMove::new(8, 12).unwrap(), + CheckerMove::new(8, 12).unwrap(), + ); + assert!(state.is_move_by_puissance(&Color::White, &moves)); + assert!(state.moves_follows_dices(&Color::White, &moves)); + assert!(state.moves_allowed(&Color::White, &moves)); + + // opponent corner must be empty + state.board.set_positions([ + 10, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -13, + ]); + assert!(!state.is_move_by_puissance(&Color::White, &moves)); + assert!(!state.moves_follows_dices(&Color::White, &moves)); + + // Si on a la possibilité de prendre son coin à la fois par effet, c'est à dire naturellement, et aussi par puissance, on doit le prendre par effet + state.board.set_positions([ + 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, + ]); + assert!(!state.moves_follows_dices(&Color::White, &moves)); + + // on a déjà pris son coin : on ne peux plus y deplacer des dames par puissance + state.board.set_positions([ + 8, 0, 0, 0, 0, 0, 0, 5, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, + ]); + assert!(!state.moves_follows_dices(&Color::White, &moves)); + } } diff --git a/store/src/player.rs b/store/src/player.rs index d728c66..1e7d062 100644 --- a/store/src/player.rs +++ b/store/src/player.rs @@ -10,6 +10,15 @@ pub enum Color { Black, } +impl Color { + pub fn opponent_color(&self) -> Self { + match self { + Self::White => Self::Black, + Self::Black => Self::White, + } + } +} + /// Struct for storing player related data. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Player {