From 3879265dceeb9d1e47a7a423b33cb52e96ade221 Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Sat, 25 May 2024 19:56:38 +0200 Subject: [PATCH] wip check jans --- bot/src/lib.rs | 3 +- store/src/game.rs | 31 ++--- store/src/game_rules_moves.rs | 221 ++++++++++++++++----------------- store/src/game_rules_points.rs | 111 +++++++++++++++-- 4 files changed, 229 insertions(+), 137 deletions(-) diff --git a/bot/src/lib.rs b/bot/src/lib.rs index 46c092d..5508f32 100644 --- a/bot/src/lib.rs +++ b/bot/src/lib.rs @@ -70,7 +70,8 @@ impl Bot { } fn calculate_points(&self) -> u8 { - self.game.get_points().iter().map(|r| r.0).sum() + // self.game.get_points().iter().map(|r| r.0).sum() + 0 } fn choose_move(&self) -> (CheckerMove, CheckerMove) { diff --git a/store/src/game.rs b/store/src/game.rs index 060c20c..2ce55bf 100644 --- a/store/src/game.rs +++ b/store/src/game.rs @@ -60,15 +60,6 @@ impl fmt::Display for GameState { } } -impl PointsRules for GameState { - fn board(&self) -> &Board { - &self.board - } - fn dice(&self) -> &Dice { - &self.dice - } -} - impl Default for GameState { fn default() -> Self { Self { @@ -248,10 +239,15 @@ impl GameState { } // Check points are correct - let rules_points: u8 = self.get_points().iter().map(|r| r.0).sum(); - if rules_points != *points { - return false; - } + // let (board, moves) = if *color == Color::Black { + // (board.mirror(), (moves.0.mirror(), moves.1.mirror())) + // } else { + // (board.clone(), *moves) + // }; + // let rules_points: u8 = self.get_points().iter().map(|r| r.0).sum(); + // if rules_points != *points { + // return false; + // } } Move { player_id, moves } => { // Check player exists @@ -266,8 +262,13 @@ impl GameState { } let color = &self.players[player_id].color; - let rules = MoveRules::new(color, &self.board, self.dice, moves); - if !rules.moves_follow_rules() { + let rules = MoveRules::new(color, &self.board, self.dice); + let moves = if *color == Color::Black { + (moves.0.mirror(), moves.1.mirror()) + } else { + *moves + }; + if !rules.moves_follow_rules(&moves) { return false; } } diff --git a/store/src/game_rules_moves.rs b/store/src/game_rules_moves.rs index 25ba84b..067058a 100644 --- a/store/src/game_rules_moves.rs +++ b/store/src/game_rules_moves.rs @@ -36,60 +36,56 @@ pub enum MoveError { pub struct MoveRules { pub board: Board, pub dice: Dice, - pub moves: (CheckerMove, CheckerMove), } impl MoveRules { /// Revert board if color is black - pub fn new( - color: &Color, - board: &Board, - dice: Dice, - moves: &(CheckerMove, CheckerMove), - ) -> Self { - let (board, moves) = if *color == Color::Black { - (board.mirror(), (moves.0.mirror(), moves.1.mirror())) + pub fn new(color: &Color, board: &Board, dice: Dice) -> Self { + let board = if *color == Color::Black { + board.mirror() } else { - (board.clone(), *moves) + board.clone() }; - Self { board, dice, moves } + Self { board, dice } } - pub fn moves_follow_rules(&self) -> bool { + pub fn moves_follow_rules(&self, moves: &(CheckerMove, CheckerMove)) -> bool { // Check moves possibles on the board // Check moves conforms to the dice // Check move is allowed by the rules (to desactivate when playing with schools) - self.moves_possible() && self.moves_follows_dices() && self.moves_allowed().is_ok() + self.moves_possible(moves) + && self.moves_follows_dices(moves) + && self.moves_allowed(moves).is_ok() } /// ---- moves_possibles : First of three checks for moves - fn moves_possible(&self) -> bool { + fn moves_possible(&self, moves: &(CheckerMove, CheckerMove)) -> bool { let color = &Color::White; // Check move is physically possible - if !self.board.move_possible(color, &self.moves.0) { + if !self.board.move_possible(color, &moves.0) { return false; } // Chained_move : "Tout d'une" - if let Ok(chained_move) = self.moves.0.chain(self.moves.1) { + if let Ok(chained_move) = moves.0.chain(moves.1) { if !self.board.move_possible(color, &chained_move) { return false; } - } else if !self.board.move_possible(color, &self.moves.1) { + } else if !self.board.move_possible(color, &moves.1) { return false; } true } /// ----- moves_follows_dices : Second of three checks for moves - fn moves_follows_dices(&self) -> bool { + fn moves_follows_dices(&self, moves: &(CheckerMove, CheckerMove)) -> bool { // Prise de coin par puissance - if self.is_move_by_puissance() { + if self.is_move_by_puissance(moves) { return true; } let (dice1, dice2) = self.dice.values; - let (move1, move2): &(CheckerMove, CheckerMove) = &self.moves; + let (move1, move2): &(CheckerMove, CheckerMove) = &moves; let move1_dices = self.get_move_compatible_dices(move1); if move1_dices.is_empty() { @@ -144,10 +140,10 @@ impl MoveRules { } /// ---- moves_allowed : Third of three checks for moves - fn moves_allowed(&self) -> Result<(), MoveError> { - self.check_corner_rules(&self.moves)?; + fn moves_allowed(&self, moves: &(CheckerMove, CheckerMove)) -> Result<(), MoveError> { + self.check_corner_rules(&moves)?; - if self.is_move_by_puissance() { + if self.is_move_by_puissance(moves) { if self.can_take_corner_by_effect() { return Err(MoveError::CornerByEffectPossible); } else { @@ -157,17 +153,13 @@ impl MoveRules { } // Si possible, les deux dés doivent être joués - let (m1, m2) = self.moves; - if m1.get_from() == 0 || m2.get_from() == 0 { + if moves.0.get_from() == 0 || moves.1.get_from() == 0 { let mut possible_moves_sequences = self.get_possible_moves_sequences(true); println!("{:?}", possible_moves_sequences); possible_moves_sequences.retain(|moves| self.check_exit_rules(moves).is_ok()); // possible_moves_sequences.retain(|moves| self.check_corner_rules(moves).is_ok()); - // TODO : exclure de ces possibilités celles qui devraient provoquer des CornerNeedsTwoCheckers & ExitNeedsAllCheckersOnLastQuarter... - if !possible_moves_sequences.contains(&self.moves) - && !possible_moves_sequences.is_empty() - { - if self.moves == (EMPTY_MOVE, EMPTY_MOVE) { + if !possible_moves_sequences.contains(&moves) && !possible_moves_sequences.is_empty() { + if *moves == (EMPTY_MOVE, EMPTY_MOVE) { return Err(MoveError::MustPlayAllDice); } let empty_removed = possible_moves_sequences @@ -181,10 +173,10 @@ impl MoveRules { } // check exit rules - self.check_exit_rules(&self.moves)?; + self.check_exit_rules(moves)?; // --- interdit de jouer dans cadran que l'adversaire peut encore remplir ---- - let farthest = cmp::max(self.moves.0.get_to(), self.moves.1.get_to()); + let farthest = cmp::max(moves.0.get_to(), moves.1.get_to()); let in_opponent_side = farthest > 12; if in_opponent_side && self.board.is_quarter_fillable(Color::Black, farthest) { return Err(MoveError::OpponentCanFillQuarter); @@ -192,7 +184,7 @@ impl MoveRules { // --- remplir cadran si possible & conserver cadran rempli si possible ---- let filling_moves_sequences = self.get_quarter_filling_moves_sequences(); - if !filling_moves_sequences.contains(&self.moves) && !filling_moves_sequences.is_empty() { + if !filling_moves_sequences.contains(moves) && !filling_moves_sequences.is_empty() { return Err(MoveError::MustFillQuarter); } // no rule was broken @@ -290,7 +282,7 @@ impl MoveRules { Ok(()) } - fn get_possible_moves_sequences( + pub fn get_possible_moves_sequences( &self, with_excedents: bool, ) -> Vec<(CheckerMove, CheckerMove)> { @@ -321,7 +313,7 @@ impl MoveRules { moves_seqs } - fn get_quarter_filling_moves_sequences(&self) -> Vec<(CheckerMove, CheckerMove)> { + pub fn get_quarter_filling_moves_sequences(&self) -> Vec<(CheckerMove, CheckerMove)> { let mut moves_seqs = Vec::new(); let color = &Color::White; for moves in self.get_possible_moves_sequences(true) { @@ -414,11 +406,10 @@ impl MoveRules { moves } - fn is_move_by_puissance(&self) -> bool { + fn is_move_by_puissance(&self, moves: &(CheckerMove, CheckerMove)) -> bool { let (dice1, dice2) = self.dice.values; - let (move1, move2): &(CheckerMove, CheckerMove) = &self.moves; - let dist1 = (move1.get_to() as i8 - move1.get_from() as i8).unsigned_abs(); - let dist2 = (move2.get_to() as i8 - move2.get_from() as i8).unsigned_abs(); + let dist1 = (moves.0.get_to() as i8 - moves.0.get_from() as i8).unsigned_abs(); + let dist2 = (moves.1.get_to() as i8 - moves.1.get_from() as i8).unsigned_abs(); // Both corners must be empty let (count1, _color) = self.board.get_field_checkers(12).unwrap(); @@ -428,8 +419,8 @@ impl MoveRules { } let color = &Color::White; - move1.get_to() == move2.get_to() - && move1.get_to() == self.board.get_color_corner(color) + moves.0.get_to() == moves.1.get_to() + && moves.0.get_to() == self.board.get_color_corner(color) && (cmp::min(dist1, dist2) == cmp::min(dice1, dice2) - 1 && cmp::max(dist1, dist2) == cmp::max(dice1, dice2) - 1) } @@ -487,20 +478,20 @@ mod tests { 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); - state.moves = ( + let moves = ( CheckerMove::new(8, 12).unwrap(), CheckerMove::new(8, 12).unwrap(), ); - assert!(state.is_move_by_puissance()); - assert!(state.moves_follows_dices()); - assert!(state.moves_allowed().is_ok()); + assert!(state.is_move_by_puissance(&moves)); + assert!(state.moves_follows_dices(&moves)); + assert!(state.moves_allowed(&moves).is_ok()); // 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()); - assert!(!state.moves_follows_dices()); + assert!(!state.is_move_by_puissance(&moves)); + assert!(!state.moves_follows_dices(&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([ @@ -508,15 +499,15 @@ mod tests { ]); assert_eq!( Err(MoveError::CornerByEffectPossible), - state.moves_allowed() + state.moves_allowed(&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, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, ]); - assert!(!state.is_move_by_puissance()); - assert!(!state.moves_follows_dices()); + assert!(!state.is_move_by_puissance(&moves)); + assert!(!state.moves_follows_dices(&moves)); } #[test] @@ -527,25 +518,25 @@ mod tests { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, ]); state.dice.values = (5, 5); - state.moves = ( + let moves = ( CheckerMove::new(20, 0).unwrap(), CheckerMove::new(20, 0).unwrap(), ); - assert!(state.moves_follows_dices()); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_follows_dices(&moves)); + assert!(state.moves_allowed(&moves).is_ok()); // toutes les dames doivent être dans le jan de retour state.board.set_positions([ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, ]); state.dice.values = (5, 5); - state.moves = ( + let moves = ( CheckerMove::new(20, 0).unwrap(), CheckerMove::new(20, 0).unwrap(), ); assert_eq!( Err(MoveError::ExitNeedsAllCheckersOnLastQuarter), - state.moves_allowed() + state.moves_allowed(&moves) ); // on ne peut pas sortir une dame avec un nombre excédant si on peut en jouer une avec un nombre défaillant @@ -553,39 +544,42 @@ mod tests { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 2, 0, ]); state.dice.values = (5, 5); - state.moves = ( + let moves = ( CheckerMove::new(20, 0).unwrap(), CheckerMove::new(23, 0).unwrap(), ); - assert_eq!(Err(MoveError::ExitByEffectPossible), state.moves_allowed()); + assert_eq!( + Err(MoveError::ExitByEffectPossible), + state.moves_allowed(&moves) + ); // on doit jouer le nombre excédant le plus éloigné state.board.set_positions([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, ]); state.dice.values = (5, 5); - state.moves = ( + let moves = ( CheckerMove::new(20, 0).unwrap(), CheckerMove::new(23, 0).unwrap(), ); - assert_eq!(Err(MoveError::ExitNotFasthest), state.moves_allowed()); - state.moves = ( + assert_eq!(Err(MoveError::ExitNotFasthest), state.moves_allowed(&moves)); + let moves = ( CheckerMove::new(20, 0).unwrap(), CheckerMove::new(21, 0).unwrap(), ); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_allowed(&moves).is_ok()); // Cas de la dernière dame 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, 0, 1, 0, ]); state.dice.values = (5, 5); - state.moves = ( + let moves = ( CheckerMove::new(23, 0).unwrap(), CheckerMove::new(0, 0).unwrap(), ); - assert!(state.moves_follows_dices()); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_follows_dices(&moves)); + assert!(state.moves_allowed(&moves).is_ok()); } #[test] @@ -595,23 +589,23 @@ mod tests { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, ]); state.dice.values = (5, 5); - state.moves = ( + let moves = ( CheckerMove::new(11, 16).unwrap(), CheckerMove::new(11, 16).unwrap(), ); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_allowed(&moves).is_ok()); state.board.set_positions([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, -12, 0, 0, 0, 0, 1, 0, ]); state.dice.values = (5, 5); - state.moves = ( + let moves = ( CheckerMove::new(11, 16).unwrap(), CheckerMove::new(11, 16).unwrap(), ); assert_eq!( Err(MoveError::OpponentCanFillQuarter), - state.moves_allowed() + state.moves_allowed(&moves) ); } @@ -622,31 +616,31 @@ mod tests { 3, 3, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, ]); state.dice.values = (5, 4); - state.moves = ( + let moves = ( CheckerMove::new(1, 6).unwrap(), CheckerMove::new(2, 6).unwrap(), ); - assert!(state.moves_allowed().is_ok()); - state.moves = ( + assert!(state.moves_allowed(&moves).is_ok()); + let moves = ( CheckerMove::new(1, 5).unwrap(), CheckerMove::new(2, 7).unwrap(), ); - assert_eq!(Err(MoveError::MustFillQuarter), state.moves_allowed()); + assert_eq!(Err(MoveError::MustFillQuarter), state.moves_allowed(&moves)); state.board.set_positions([ 2, 3, 2, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]); state.dice.values = (2, 3); - state.moves = ( + let moves = ( CheckerMove::new(6, 8).unwrap(), CheckerMove::new(6, 9).unwrap(), ); - assert_eq!(Err(MoveError::MustFillQuarter), state.moves_allowed()); - state.moves = ( + assert_eq!(Err(MoveError::MustFillQuarter), state.moves_allowed(&moves)); + let moves = ( CheckerMove::new(2, 4).unwrap(), CheckerMove::new(5, 8).unwrap(), ); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_allowed(&moves).is_ok()); } #[test] @@ -656,17 +650,17 @@ mod tests { 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); - state.moves = ( + let moves = ( CheckerMove::new(22, 0).unwrap(), CheckerMove::new(0, 0).unwrap(), ); - assert_eq!(Err(MoveError::MustPlayAllDice), state.moves_allowed()); - state.moves = ( + assert_eq!(Err(MoveError::MustPlayAllDice), state.moves_allowed(&moves)); + let moves = ( CheckerMove::new(22, 23).unwrap(), CheckerMove::new(23, 0).unwrap(), ); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_allowed(&moves).is_ok()); } #[test] @@ -677,21 +671,21 @@ mod tests { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]); state.dice.values = (2, 1); - state.moves = ( + let moves = ( CheckerMove::new(10, 12).unwrap(), CheckerMove::new(11, 12).unwrap(), ); - assert!(state.moves_follows_dices()); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_follows_dices(&moves)); + assert!(state.moves_allowed(&moves).is_ok()); // par puissance state.dice.values = (3, 2); - state.moves = ( + let moves = ( CheckerMove::new(10, 12).unwrap(), CheckerMove::new(11, 12).unwrap(), ); - assert!(state.moves_follows_dices()); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_follows_dices(&moves)); + assert!(state.moves_allowed(&moves).is_ok()); } #[test] @@ -701,31 +695,31 @@ mod tests { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]); state.dice.values = (2, 1); - state.moves = ( + let moves = ( CheckerMove::new(0, 0).unwrap(), CheckerMove::new(0, 0).unwrap(), ); - assert!(state.moves_follows_dices()); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_follows_dices(&moves)); + assert!(state.moves_allowed(&moves).is_ok()); state.board.set_positions([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, ]); state.dice.values = (2, 1); - state.moves = ( + let moves = ( CheckerMove::new(23, 24).unwrap(), CheckerMove::new(0, 0).unwrap(), ); - assert!(state.moves_follows_dices()); - // let res = state.moves_allowed(); + assert!(state.moves_follows_dices(&moves)); + // let res = state.moves_allowed(&moves); // println!("{:?}", res); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_allowed(&moves).is_ok()); - state.moves = ( + let moves = ( CheckerMove::new(0, 0).unwrap(), CheckerMove::new(0, 0).unwrap(), ); - assert_eq!(Err(MoveError::MustPlayAllDice), state.moves_allowed()); + assert_eq!(Err(MoveError::MustPlayAllDice), state.moves_allowed(&moves)); } #[test] @@ -735,13 +729,13 @@ mod tests { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, ]); state.dice.values = (2, 3); - state.moves = ( + let moves = ( CheckerMove::new(12, 14).unwrap(), CheckerMove::new(1, 4).unwrap(), ); assert_eq!( Err(MoveError::CornerNeedsTwoCheckers), - state.moves_allowed() + state.moves_allowed(&moves) ); } @@ -752,18 +746,21 @@ mod tests { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0, 0, ]); state.dice.values = (2, 3); - state.moves = ( + let moves = ( CheckerMove::new(12, 14).unwrap(), CheckerMove::new(0, 0).unwrap(), ); // let poss = state.get_possible_moves_sequences(&Color::White, true); // println!("{:?}", poss); - assert_eq!(Err(MoveError::MustPlayStrongerDie), state.moves_allowed()); - state.moves = ( + assert_eq!( + Err(MoveError::MustPlayStrongerDie), + state.moves_allowed(&moves) + ); + let moves = ( CheckerMove::new(12, 15).unwrap(), CheckerMove::new(0, 0).unwrap(), ); - assert!(state.moves_allowed().is_ok()); + assert!(state.moves_allowed(&moves).is_ok()); } #[test] @@ -771,29 +768,25 @@ mod tests { let mut state = MoveRules::default(); // Chained moves - state.moves = ( + let moves = ( CheckerMove::new(1, 5).unwrap(), CheckerMove::new(5, 9).unwrap(), ); - assert!(state.moves_possible()); + assert!(state.moves_possible(&moves)); // not chained moves - state.moves = ( + let moves = ( CheckerMove::new(1, 5).unwrap(), CheckerMove::new(6, 9).unwrap(), ); - assert!(!state.moves_possible()); + assert!(!state.moves_possible(&moves)); // black moves - let state = MoveRules::new( - &Color::Black, - &Board::default(), - Dice::default(), - &( - CheckerMove::new(24, 20).unwrap(), - CheckerMove::new(20, 19).unwrap(), - ), + let state = MoveRules::new(&Color::Black, &Board::default(), Dice::default()); + let moves = ( + CheckerMove::new(24, 20).unwrap().mirror(), + CheckerMove::new(20, 19).unwrap().mirror(), ); - assert!(state.moves_possible()); + assert!(state.moves_possible(&moves)); } } diff --git a/store/src/game_rules_points.rs b/store/src/game_rules_points.rs index c68107a..f88e5c5 100644 --- a/store/src/game_rules_points.rs +++ b/store/src/game_rules_points.rs @@ -1,9 +1,12 @@ use crate::board::Board; use crate::dice::Dice; +use crate::game_rules_moves::MoveRules; +use crate::player::Color; +use crate::CheckerMove; #[derive(std::cmp::PartialEq, Debug)] -pub enum PointsRule { - FilledQuarter, +enum Jan { + FilledQuarter { points: u8 }, // 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) @@ -15,11 +18,105 @@ pub enum PointsRule { // - si on ne peut pas jouer ses deux dés } -pub trait PointsRules { - fn board(&self) -> &Board; - fn dice(&self) -> &Dice; +#[derive(Debug)] +struct PossibleJan { + pub jan: Jan, + pub ways: Vec<(CheckerMove, CheckerMove)>, +} - fn get_points(&self) -> Vec<(u8, PointsRule)> { - Vec::new() +/// PointsRules always consider that the current player is White +/// You must use 'mirror' function on board if player is Black +#[derive(Default)] +pub struct PointsRules { + pub board: Board, + pub dice: Dice, + pub move_rules: MoveRules, +} + +impl PointsRules { + /// Revert board if color is black + pub fn new(color: &Color, board: &Board, dice: Dice) -> Self { + let board = if *color == Color::Black { + board.mirror() + } else { + board.clone() + }; + let move_rules = MoveRules::new(color, &board, dice); + + // let move_rules = MoveRules::new(color, &self.board, dice, moves); + Self { + board, + dice, + move_rules, + } + } + + fn get_jans(&self, board: &Board, dices: &Vec) -> Vec { + let mut jans = Vec::new(); + if dices.is_empty() { + return jans; + } + let color = Color::White; + let mut dices = dices.clone(); + let mut board = board.clone(); + let fields = board.get_color_fields(color); + if let Some(dice) = dices.pop() { + for (from, _) in fields { + let to = if from + dice as usize > 24 { + 0 + } else { + from + dice as usize + }; + if let Ok(cmove) = CheckerMove::new(from, to) { + if board.move_checker(&color, cmove).is_ok() { + // TODO : check if it's a jan + let next_dice_jan = self.get_jans(&board, &dices); + // TODO : merge jans du dé courant et du prochain dé + } + } + } + } + // TODO : mouvement en puissance ? + // TODO : tout d'une (sans doublons avec 1 + 1) ? + jans + } + + pub fn get_points(&self) -> usize { + let mut points = 0; + + let jans = self.get_jans(&self.board, &vec![self.dice.values.0, self.dice.values.1]); + + // Jans de remplissage + let filling_moves_sequences = self.move_rules.get_quarter_filling_moves_sequences(); + points += 4 * filling_moves_sequences.len(); + // Points par simple par moyen Points par doublet par moyen Nombre de moyens possibles Bénéficiaire + // « JAN RARE » + // Jan de six tables 4 n/a 1 Joueur + // Jan de deux tables 4 6 1 Joueur + // Jan de mézéas 4 6 1 Joueur + // Contre jan de deux tables 4 6 1 Adversaire + // Contre jan de mézéas 4 6 1 Adversaire + // « JAN DE RÉCOMPENSE » + // Battre à vrai une dame + // située dans la table des grands jans 2 1, 2 ou 3 Joueur + // 4 1 ou 2 Joueur + // Battre à vrai une dame + // située dans la table des petits jans 4 1, 2 ou 3 Joueur + // 6 1 ou 2 Joueur + // Battre le coin adverse 4 6 1 Joueur + // « JAN QUI NE PEUT » + // Battre à faux une dame + // située dans la table des grands jans 2 4 1 Adversaire + // Battre à faux une dame + // située dans la table des petits jans 4 6 1 Adversaire + // Pour chaque dé non jouable (dame impuissante) 2 2 n/a Adversaire + // « JAN DE REMPLISSAGE » + // Faire un petit jan, un grand jan ou un jan de retour 4 1, 2, ou 3 Joueur + // 6 1 ou 2 Joueur + // Conserver un petit jan, un grand jan ou un jan de retour 4 6 1 Joueur + // « AUTRE » + // Sortir le premier toutes ses dames 4 6 n/a Joueur + + points } }