From 9b48dea435c116f9d5f24865e2bdad31653e45d7 Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Tue, 21 May 2024 21:22:04 +0200 Subject: [PATCH] wip fix moves rules --- store/src/board.rs | 7 +++ store/src/game_rules_moves.rs | 92 ++++++++++++++++++++++++++++++---- store/src/game_rules_points.rs | 9 ++++ 3 files changed, 97 insertions(+), 11 deletions(-) diff --git a/store/src/board.rs b/store/src/board.rs index 6ad884a..33f025f 100644 --- a/store/src/board.rs +++ b/store/src/board.rs @@ -64,6 +64,10 @@ impl CheckerMove { pub fn get_to(&self) -> Field { self.to } + + pub fn is_exit(&self) -> bool { + self.to == 0 && self != &EMPTY_MOVE + } } /// Represents the Tric Trac board @@ -457,6 +461,9 @@ impl Board { } pub fn remove_checker(&mut self, color: &Color, field: Field) -> Result<(), Error> { + if field == 0 { + return Ok(()); + } let checker_color = self.get_checkers_color(field)?; if Some(color) != checker_color { return Err(Error::FieldInvalid); diff --git a/store/src/game_rules_moves.rs b/store/src/game_rules_moves.rs index c2c455b..0f5f33f 100644 --- a/store/src/game_rules_moves.rs +++ b/store/src/game_rules_moves.rs @@ -24,6 +24,10 @@ pub enum MoveError { OpponentCanFillQuarter, // remplir cadran si possible & conserver cadran rempli si possible ---- MustFillQuarter, + // On n'a pas le droit de jouer d'une manière qui empêche de jouer les deux dés si on a la possibilité de les jouer. + MustPlayAllDice, + // Si on ne peut jouer qu'un seul dé, on doit jouer le plus fort si possible. + MustPlayStrongerDie, } pub trait MoveRules { @@ -140,8 +144,16 @@ pub trait MoveRules { return Err(MoveError::CornerByEffectPossible); } + // Si possible, les deux dés doivent être joués + let possible_moves_sequences = self.get_possible_moves_sequences(color, true); + if !possible_moves_sequences.contains(moves) && !possible_moves_sequences.is_empty() { + println!(">>{:?}<<", moves); + println!("{:?}", possible_moves_sequences); + return Err(MoveError::MustPlayAllDice); + } + // check exit rules - if moves.0.get_to() == 0 || moves.1.get_to() == 0 { + if moves.0.is_exit() || moves.1.is_exit() { // toutes les dames doivent être dans le jan de retour let has_outsiders = !self .board() @@ -157,8 +169,8 @@ pub trait MoveRules { return Err(MoveError::ExitNeedsAllCheckersOnLastQuarter); } - // toutes les sorties directes sont autorisées, ainsi que les nombre défaillants - let possible_moves_sequences = self.get_possible_moves_sequences(color); + // toutes les sorties directes sont autorisées, ainsi que les nombres défaillants + let possible_moves_sequences = self.get_possible_moves_sequences(color, false); if !possible_moves_sequences.contains(moves) { // À ce stade au moins un des déplacements concerne un nombre en excédant // - si d'autres séquences de mouvements sans nombre en excédant étaient possibles, on @@ -245,10 +257,16 @@ pub trait MoveRules { Ok(()) } - fn get_possible_moves_sequences(&self, color: &Color) -> Vec<(CheckerMove, CheckerMove)> { + fn get_possible_moves_sequences( + &self, + color: &Color, + with_excedents: bool, + ) -> Vec<(CheckerMove, CheckerMove)> { let (dice1, dice2) = self.dice().values; - let mut moves_seqs = self.get_possible_moves_sequences_by_dices(color, dice1, dice2); - let mut moves_seqs_order2 = self.get_possible_moves_sequences_by_dices(color, dice1, dice2); + let mut moves_seqs = + self.get_possible_moves_sequences_by_dices(color, dice1, dice2, with_excedents); + let mut moves_seqs_order2 = + self.get_possible_moves_sequences_by_dices(color, dice2, dice1, with_excedents); moves_seqs.append(&mut moves_seqs_order2); moves_seqs } @@ -258,7 +276,7 @@ pub trait MoveRules { color: &Color, ) -> Vec<(CheckerMove, CheckerMove)> { let mut moves_seqs = Vec::new(); - for moves in self.get_possible_moves_sequences(color) { + for moves in self.get_possible_moves_sequences(color, true) { let mut board = self.board().clone(); board.move_checker(color, moves.0).unwrap(); board.move_checker(color, moves.1).unwrap(); @@ -274,9 +292,13 @@ pub trait MoveRules { color: &Color, dice1: u8, dice2: u8, + with_excedents: bool, ) -> Vec<(CheckerMove, CheckerMove)> { let mut moves_seqs = Vec::new(); - for first_move in self.board().get_possible_moves(*color, dice1, false) { + for first_move in self + .board() + .get_possible_moves(*color, dice1, with_excedents) + { let mut board2 = self.board().clone(); if board2.move_checker(color, first_move).is_err() { println!("err move"); @@ -284,14 +306,14 @@ pub trait MoveRules { } if board2.get_color_fields(*color).is_empty() { // no checkers left : empty move - println!("empty move"); moves_seqs.push((first_move, EMPTY_MOVE)); } else { - for second_move in board2.get_possible_moves(*color, dice2, false) { + for second_move in board2.get_possible_moves(*color, dice2, with_excedents) { moves_seqs.push((first_move, second_move)); } } } + // TODO : ajouter la prise de son coin de repos (directement et par puissance) moves_seqs } @@ -513,7 +535,7 @@ mod tests { ); let moves = ( CheckerMove::new(20, 0).unwrap(), - CheckerMove::new(20, 0).unwrap(), + CheckerMove::new(21, 0).unwrap(), ); assert!(state.moves_allowed(&Color::White, &moves).is_ok()); @@ -597,6 +619,54 @@ mod tests { assert!(state.moves_allowed(&Color::White, &moves).is_ok()); } + #[test] + fn move_play_all_dice() { + let mut state = GameState::default(); + state.board.set_positions([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + ]); + state.dice.values = (1, 3); + let moves = ( + CheckerMove::new(22, 0).unwrap(), + CheckerMove::new(0, 0).unwrap(), + ); + + let poss = state.get_possible_moves_sequences(&Color::White, true); + println!("{:?}", poss); + + assert_eq!( + Err(MoveError::MustPlayAllDice), + state.moves_allowed(&Color::White, &moves) + ); + let moves = ( + CheckerMove::new(22, 23).unwrap(), + CheckerMove::new(23, 0).unwrap(), + ); + assert!(state.moves_allowed(&Color::White, &moves).is_ok()); + } + + #[test] + fn move_play_stronger_dice() { + let mut state = GameState::default(); + state.board.set_positions([ + 0, 0, 0, 0, 0, 3, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]); + state.dice.values = (2, 3); + let moves = ( + CheckerMove::new(6, 8).unwrap(), + CheckerMove::new(0, 0).unwrap(), + ); + assert_eq!( + Err(MoveError::MustPlayStrongerDie), + state.moves_allowed(&Color::White, &moves) + ); + let moves = ( + CheckerMove::new(6, 9).unwrap(), + CheckerMove::new(0, 0).unwrap(), + ); + assert!(state.moves_allowed(&Color::White, &moves).is_ok()); + } + #[test] fn moves_possible() { let state = GameState::default(); diff --git a/store/src/game_rules_points.rs b/store/src/game_rules_points.rs index 40195ab..c68107a 100644 --- a/store/src/game_rules_points.rs +++ b/store/src/game_rules_points.rs @@ -4,6 +4,15 @@ use crate::dice::Dice; #[derive(std::cmp::PartialEq, Debug)] pub enum PointsRule { FilledQuarter, + // jans de récompense : + // - battre une dame seule (par autant de façons de le faire, y compris + // utilisant une dame du coin de repos) + // - battre le coin adverse : si deux dames (hormis les deux dernière de son propre coin de + // repos) peuvent battre le coin vide adverse + // jans qui ne peut (pts pour l'adversaire) : + // - battre à faux : si on passe par une case pleine pour atteindre la + // case que l'on peut battre + // - si on ne peut pas jouer ses deux dés } pub trait PointsRules {