diff --git a/store/src/game.rs b/store/src/game.rs index 0f0e5ec..1486dad 100644 --- a/store/src/game.rs +++ b/store/src/game.rs @@ -373,13 +373,50 @@ impl GameState { return false; } - // ------- exit rules ---------- - // -- toutes les dames doivent être dans le jan de retour - // -- si on peut sortir, on doit sortir - // -- priorité : - // - dame se trouvant sur la flêche correspondant au dé - // - dame se trouvant plus loin de la sortie que la flêche (point défaillant) - // - dame se trouvant plus près que la flêche (point exédant) + // check exit rules + let exit_moves_count = if moves.0.get_to() == 0 && moves.1.get_to() == 0 { + 2 + } else if moves.0.get_to() == 0 || moves.1.get_to() == 0 { + 1 + } else { + 0 + }; + if exit_moves_count > 0 { + // toutes les dames doivent être dans le jan de retour + let has_outsiders = !self + .board + .get_color_fields(*color) + .iter() + .filter(|(field, _count)| { + (*color == Color::White && *field < 19) + || (*color == Color::Black && *field > 6) + }) + .collect::>() + .is_empty(); + if has_outsiders { + return false; + } + + // les sorties directes sont autorisées + let direct_exit_moves = self.get_direct_exit_moves(color); + if direct_exit_moves.contains(&moves.0) && direct_exit_moves.contains(&moves.1) { + return true; + } + + // détermination du nombre de sorties par excédant + let mut excedant_count = exit_moves_count; + if direct_exit_moves.contains(&moves.0) && moves.0.get_to() == 0 { + excedant_count -= 1; + } + if direct_exit_moves.contains(&moves.1) && moves.1.get_to() == 0 { + excedant_count -= 1; + } + + // on ne peut pas sortir une dame en excédant si on peut en jouer une en défaillant + // - on ne doit pas jouer le premier nombre de manière à ce que le second soit excédant (si possible) + // - si on ne peut pas jouer un nombre défaillant parce que la place d'arrivée est prise + // par une dame adverse, il n'est pas possible de jouer ce nombre en excédant + } // --- remplir cadran si possible ---- // --- conserver cadran rempli si possible ---- @@ -388,6 +425,50 @@ impl GameState { true } + fn get_direct_exit_moves(&self, color: &Color) -> Vec { + let mut moves = Vec::new(); + let (dice1, dice2) = self.dice.values; + + // sorties directes simples + let (field1_candidate, field2_candidate) = if color == &Color::White { + (25 - dice1 as usize, 25 - dice2 as usize) + } else { + (dice1 as usize, dice2 as usize) + }; + let (count1, col1) = self.board.get_field_checkers(field1_candidate).unwrap(); + let (count2, col2) = self.board.get_field_checkers(field2_candidate).unwrap(); + if count1 > 0 { + moves.push(CheckerMove::new(field1_candidate, 0).unwrap()); + } + if dice2 != dice1 { + if count2 > 0 { + moves.push(CheckerMove::new(field2_candidate, 0).unwrap()); + } + } else if count1 > 1 { + // doublet et deux dames disponibles + moves.push(CheckerMove::new(field1_candidate, 0).unwrap()); + } + + // sortie directe tout d'une + let fieldall_candidate = if color == &Color::White { + 25 - dice1 - dice2 + } else { + dice1 + dice2 + } as usize; + let (countall, _col) = self.board.get_field_checkers(fieldall_candidate).unwrap(); + if countall > 0 { + if col1.is_none() || col1 == Some(color) { + moves.push(CheckerMove::new(fieldall_candidate, field1_candidate).unwrap()); + moves.push(CheckerMove::new(field1_candidate, 0).unwrap()); + } + if col2.is_none() || col2 == Some(color) { + moves.push(CheckerMove::new(fieldall_candidate, field2_candidate).unwrap()); + moves.push(CheckerMove::new(field2_candidate, 0).unwrap()); + } + } + moves + } + fn is_move_by_puissance(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool { let (dice1, dice2) = self.dice.values; let (move1, move2): &(CheckerMove, CheckerMove) = moves; @@ -596,7 +677,7 @@ mod tests { use super::*; #[test] - fn test_to_string_id() { + fn to_string_id() { let mut state = GameState::default(); state.add_player(1, Player::new("player1".into(), Color::White)); state.add_player(2, Player::new("player2".into(), Color::Black)); @@ -606,7 +687,7 @@ mod tests { } #[test] - fn test_moves_possible() { + fn moves_possible() { let mut state = GameState::default(); let player1 = Player::new("player1".into(), Color::White); let player_id = 1; @@ -639,7 +720,7 @@ mod tests { } #[test] - fn test_moves_follow_dices() { + fn moves_follow_dices() { let mut state = GameState::default(); let player1 = Player::new("player1".into(), Color::White); let player_id = 1; @@ -664,7 +745,7 @@ mod tests { } #[test] - fn test_can_take_corner_by_effect() { + fn can_take_corner_by_effect() { let mut state = GameState::default(); let player1 = Player::new("player1".into(), Color::White); let player_id = 1; @@ -698,7 +779,7 @@ mod tests { } #[test] - fn test_prise_en_puissance() { + fn prise_en_puissance() { let mut state = GameState::default(); let player1 = Player::new("player1".into(), Color::White); let player_id = 1; @@ -744,7 +825,7 @@ mod tests { } #[test] - fn test_exit() { + fn exit() { let mut state = GameState::default(); let player1 = Player::new("player1".into(), Color::White); let player_id = 1; @@ -778,5 +859,16 @@ mod tests { CheckerMove::new(20, 0).unwrap(), ); assert!(!state.moves_allowed(&Color::White, &moves)); + + // on ne peut pas sortir une dame avec un nombre excédant si on peut en jouer une avec un nombre défaillant + state.board.set_positions([ + 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); + let moves = ( + CheckerMove::new(20, 0).unwrap(), + CheckerMove::new(23, 0).unwrap(), + ); + assert!(!state.moves_allowed(&Color::White, &moves)); } }