From fb5e954b85d4eeb8ca58c6cd63534e4a62f5e9fd Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Sun, 23 Jun 2024 11:38:03 +0200 Subject: [PATCH] =?UTF-8?q?passage=20interm=C3=A9diaire=20sur=20coin=20de?= =?UTF-8?q?=20repos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/refs/tutorial_academieDesJeux.md | 1 + store/src/board.rs | 21 ++++++++++++--- store/src/game_rules_moves.rs | 38 ++++++++++++++++++++++------ store/src/game_rules_points.rs | 3 +++ 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/doc/refs/tutorial_academieDesJeux.md b/doc/refs/tutorial_academieDesJeux.md index 10317f6..e00fe90 100644 --- a/doc/refs/tutorial_academieDesJeux.md +++ b/doc/refs/tutorial_academieDesJeux.md @@ -64,6 +64,7 @@ Si on doit passer par une case occupée par deux dames adverses ou plus pour att Remarques - on peut "passer" sur une dame adverse (donc battue) pour battre une seconde dame adverse (avec la somme des deux dés). +- comme pour les déplacements, il est possible de passer par le coin de repos vide de l'adversaire pour battre à vrai une dame en "tout d'une" (c'est s'arrêter sur le coin de repos qui est interdit) - même s'il ne reste que deux dames dans son coin de repos (et qu'en théorie elle ne peuvent en sortir qu'en même temps), elles peuvent tout de même battre une dame adverse (à vrai et à faux). En revanche elles ne peuvent pas participer au battage du coin adverse (cf. prochain paragraphe). Autre jan de récompense : diff --git a/store/src/board.rs b/store/src/board.rs index 2c1686e..d077492 100644 --- a/store/src/board.rs +++ b/store/src/board.rs @@ -300,6 +300,13 @@ impl Board { /// Check if a field is blocked for a player pub fn blocked(&self, color: &Color, field: Field) -> Result { + // the square is blocked on the opponent rest corner + let opp_corner_field = if color == &Color::White { 13 } else { 12 }; + self.passage_blocked(color, field) + .map(|blocked| blocked || opp_corner_field == field) + } + + pub fn passage_blocked(&self, color: &Color, field: Field) -> Result { if 24 < field { return Err(Error::FieldInvalid); } @@ -309,9 +316,13 @@ impl Board { return Ok(false); } - // the square is blocked on the opponent rest corner or if there are opponent's men on the square - let opp_corner_field = if color == &Color::White { 13 } else { 12 }; - Ok(field == opp_corner_field || self.positions[field - 1] < 0) + // the square is blocked if there are opponent's men on the square + let blocked = if color == &Color::White { + self.positions[field - 1] < 0 + } else { + self.positions[field - 1] > 0 + }; + Ok(blocked) } pub fn get_field_checkers(&self, field: Field) -> Result<(u8, Option<&Color>), Error> { @@ -412,6 +423,10 @@ impl Board { moves } + pub fn passage_possible(&self, color: &Color, cmove: &CheckerMove) -> bool { + !self.passage_blocked(color, cmove.to).unwrap_or(true) + } + pub fn move_possible(&self, color: &Color, cmove: &CheckerMove) -> bool { let blocked = self.blocked(color, cmove.to).unwrap_or(true); // Check if there is a player's checker on the 'from' square diff --git a/store/src/game_rules_moves.rs b/store/src/game_rules_moves.rs index a0bbcfb..7a483d1 100644 --- a/store/src/game_rules_moves.rs +++ b/store/src/game_rules_moves.rs @@ -61,17 +61,17 @@ impl MoveRules { /// ---- moves_possibles : First of three checks for moves fn moves_possible(&self, moves: &(CheckerMove, CheckerMove)) -> bool { let color = &Color::White; - // Check move is physically possible - if !self.board.move_possible(color, &moves.0) { - return false; - } - - // Chained_move : "Tout d'une" if let Ok(chained_move) = moves.0.chain(moves.1) { - if !self.board.move_possible(color, &chained_move) { + // Check intermediary move and chained_move : "Tout d'une" + if !self.board.passage_possible(color, &moves.0) + || !self.board.move_possible(color, &chained_move) + { return false; } - } else if !self.board.move_possible(color, &moves.1) { + } else if !self.board.move_possible(color, &moves.0) + || !self.board.move_possible(color, &moves.1) + { + // Move is not physically possible return false; } true @@ -739,6 +739,28 @@ mod tests { ); } + #[test] + fn move_rest_corner_toutdune() { + let mut state = MoveRules::default(); + // We can't go to the occupied rest corner as an intermediary step + state.board.set_positions([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]); + state.dice.values = (2, 1); + let moves = ( + CheckerMove::new(11, 13).unwrap(), + CheckerMove::new(13, 14).unwrap(), + ); + assert!(!state.moves_possible(&moves)); + + // We can use the empty rest corner as an intermediary step + state.board.set_positions([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]); + assert!(state.moves_possible(&moves)); + assert!(state.moves_allowed(&moves).is_ok()); + } + #[test] fn move_play_stronger_dice() { let mut state = MoveRules::default(); diff --git a/store/src/game_rules_points.rs b/store/src/game_rules_points.rs index 3f98d44..0704f62 100644 --- a/store/src/game_rules_points.rs +++ b/store/src/game_rules_points.rs @@ -304,6 +304,9 @@ mod tests { jans.merge(jans_revert_dices); assert_eq!(1, jans.len()); // print!("jans (2) : {:?}", jans.get(&Jan::TrueHit)); + + // battage à faux : ne pas prendre en compte si en inversant l'ordre des dés il y a battage + // à vrai } #[test]