jan qui ne peut
This commit is contained in:
parent
152d2673f7
commit
b528fa3ac6
|
|
@ -367,6 +367,7 @@ impl Board {
|
||||||
dice: u8,
|
dice: u8,
|
||||||
with_excedants: bool,
|
with_excedants: bool,
|
||||||
check_rest_corner_exit: bool,
|
check_rest_corner_exit: bool,
|
||||||
|
forbid_exits: bool,
|
||||||
) -> Vec<CheckerMove> {
|
) -> Vec<CheckerMove> {
|
||||||
let mut moves = Vec::new();
|
let mut moves = Vec::new();
|
||||||
|
|
||||||
|
|
@ -388,8 +389,11 @@ impl Board {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut dest = get_dest(field as i32);
|
let mut dest = get_dest(field as i32);
|
||||||
|
if dest == 0 && forbid_exits {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if !(0..25).contains(&dest) {
|
if !(0..25).contains(&dest) {
|
||||||
if with_excedants {
|
if with_excedants && !forbid_exits {
|
||||||
dest = 0;
|
dest = 0;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -57,20 +57,9 @@ impl MoveRules {
|
||||||
|
|
||||||
pub fn moves_follow_rules(&self) -> bool {
|
pub fn moves_follow_rules(&self) -> bool {
|
||||||
// Check moves possibles on the board
|
// Check moves possibles on the board
|
||||||
if !self.moves_possible() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check moves conforms to the dice
|
// Check moves conforms to the dice
|
||||||
if !self.moves_follows_dices() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check move is allowed by the rules (to desactivate when playing with schools)
|
// Check move is allowed by the rules (to desactivate when playing with schools)
|
||||||
if self.moves_allowed().is_err() {
|
self.moves_possible() && self.moves_follows_dices() && self.moves_allowed().is_ok()
|
||||||
return false;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ---- moves_possibles : First of three checks for moves
|
/// ---- moves_possibles : First of three checks for moves
|
||||||
|
|
@ -158,7 +147,6 @@ impl MoveRules {
|
||||||
fn moves_allowed(&self) -> Result<(), MoveError> {
|
fn moves_allowed(&self) -> Result<(), MoveError> {
|
||||||
self.check_corner_rules(&self.moves)?;
|
self.check_corner_rules(&self.moves)?;
|
||||||
|
|
||||||
let color = &Color::White;
|
|
||||||
if self.is_move_by_puissance() {
|
if self.is_move_by_puissance() {
|
||||||
if self.can_take_corner_by_effect() {
|
if self.can_take_corner_by_effect() {
|
||||||
return Err(MoveError::CornerByEffectPossible);
|
return Err(MoveError::CornerByEffectPossible);
|
||||||
|
|
@ -167,85 +155,33 @@ impl MoveRules {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si possible, les deux dés doivent être joués
|
// Si possible, les deux dés doivent être joués
|
||||||
let possible_moves_sequences = self.get_possible_moves_sequences(true);
|
let (m1, m2) = self.moves;
|
||||||
// TODO : exclure de ces possibilités celles qui devraient provoquer des CornerNeedsTwoCheckers & ExitNeedsAllCheckersOnLastQuarter...
|
if m1.get_from() == 0 || m2.get_from() == 0 {
|
||||||
if !possible_moves_sequences.contains(&self.moves) && !possible_moves_sequences.is_empty() {
|
let mut possible_moves_sequences = self.get_possible_moves_sequences(true);
|
||||||
println!(">>{:?}<<", self.moves);
|
|
||||||
println!("{:?}", possible_moves_sequences);
|
println!("{:?}", possible_moves_sequences);
|
||||||
let empty_removed = possible_moves_sequences
|
possible_moves_sequences.retain(|moves| self.check_exit_rules(moves).is_ok());
|
||||||
.iter()
|
// possible_moves_sequences.retain(|moves| self.check_corner_rules(moves).is_ok());
|
||||||
.filter(|(c1, c2)| *c1 != EMPTY_MOVE && *c2 != EMPTY_MOVE);
|
// TODO : exclure de ces possibilités celles qui devraient provoquer des CornerNeedsTwoCheckers & ExitNeedsAllCheckersOnLastQuarter...
|
||||||
if empty_removed.count() > 0 {
|
if !possible_moves_sequences.contains(&self.moves)
|
||||||
return Err(MoveError::MustPlayAllDice);
|
&& !possible_moves_sequences.is_empty()
|
||||||
|
{
|
||||||
|
if self.moves == (EMPTY_MOVE, EMPTY_MOVE) {
|
||||||
|
return Err(MoveError::MustPlayAllDice);
|
||||||
|
}
|
||||||
|
let empty_removed = possible_moves_sequences
|
||||||
|
.iter()
|
||||||
|
.filter(|(c1, c2)| *c1 != EMPTY_MOVE && *c2 != EMPTY_MOVE);
|
||||||
|
if empty_removed.count() > 0 {
|
||||||
|
return Err(MoveError::MustPlayAllDice);
|
||||||
|
}
|
||||||
|
return Err(MoveError::MustPlayStrongerDie);
|
||||||
}
|
}
|
||||||
return Err(MoveError::MustPlayStrongerDie);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check exit rules
|
// check exit rules
|
||||||
if self.moves.0.is_exit() || self.moves.1.is_exit() {
|
self.check_exit_rules(&self.moves)?;
|
||||||
// toutes les dames doivent être dans le jan de retour
|
|
||||||
let has_outsiders = !self
|
|
||||||
.board
|
|
||||||
.get_color_fields(*color)
|
|
||||||
.iter()
|
|
||||||
.filter(|(field, _count)| *field < 19)
|
|
||||||
.collect::<Vec<&(usize, i8)>>()
|
|
||||||
.is_empty();
|
|
||||||
if has_outsiders {
|
|
||||||
return Err(MoveError::ExitNeedsAllCheckersOnLastQuarter);
|
|
||||||
}
|
|
||||||
|
|
||||||
// toutes les sorties directes sont autorisées, ainsi que les nombres défaillants
|
|
||||||
let possible_moves_sequences = self.get_possible_moves_sequences(false);
|
|
||||||
if !possible_moves_sequences.contains(&self.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
|
|
||||||
// refuse cette séquence
|
|
||||||
if !possible_moves_sequences.is_empty() {
|
|
||||||
return Err(MoveError::ExitByEffectPossible);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - la dame choisie doit être la plus éloignée de la sortie
|
|
||||||
let mut checkers = self.board.get_color_fields(*color);
|
|
||||||
checkers.sort_by(|a, b| b.0.cmp(&a.0));
|
|
||||||
let mut farthest = 24;
|
|
||||||
let mut next_farthest = 24;
|
|
||||||
let mut has_two_checkers = false;
|
|
||||||
if let Some((field, count)) = checkers.first() {
|
|
||||||
farthest = *field;
|
|
||||||
if *count > 1 {
|
|
||||||
next_farthest = *field;
|
|
||||||
has_two_checkers = true;
|
|
||||||
} else if let Some((field, _count)) = checkers.get(1) {
|
|
||||||
next_farthest = *field;
|
|
||||||
has_two_checkers = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// s'il reste au moins deux dames, on vérifie que les plus éloignées soint choisies
|
|
||||||
if has_two_checkers {
|
|
||||||
if self.moves.0.get_to() == 0 && self.moves.1.get_to() == 0 {
|
|
||||||
// Deux coups sortants en excédant
|
|
||||||
if cmp::max(self.moves.0.get_from(), self.moves.1.get_from())
|
|
||||||
> next_farthest
|
|
||||||
{
|
|
||||||
return Err(MoveError::ExitNotFasthest);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Un seul coup sortant en excédant le coup sortant doit concerner la plus éloignée du bord
|
|
||||||
let exit_move_field = if self.moves.0.get_to() == 0 {
|
|
||||||
self.moves.0.get_from()
|
|
||||||
} else {
|
|
||||||
self.moves.1.get_from()
|
|
||||||
};
|
|
||||||
if exit_move_field != farthest {
|
|
||||||
return Err(MoveError::ExitNotFasthest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- interdit de jouer dans cadran que l'adversaire peut encore remplir ----
|
// --- 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(self.moves.0.get_to(), self.moves.1.get_to());
|
||||||
|
|
@ -285,6 +221,75 @@ impl MoveRules {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_checkers_outside_last_quarter(&self) -> bool {
|
||||||
|
!self
|
||||||
|
.board
|
||||||
|
.get_color_fields(Color::White)
|
||||||
|
.iter()
|
||||||
|
.filter(|(field, _count)| *field < 19)
|
||||||
|
.collect::<Vec<&(usize, i8)>>()
|
||||||
|
.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_exit_rules(&self, moves: &(CheckerMove, CheckerMove)) -> Result<(), MoveError> {
|
||||||
|
if !moves.0.is_exit() && !moves.1.is_exit() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
// toutes les dames doivent être dans le jan de retour
|
||||||
|
if self.has_checkers_outside_last_quarter() {
|
||||||
|
return Err(MoveError::ExitNeedsAllCheckersOnLastQuarter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// toutes les sorties directes sont autorisées, ainsi que les nombres défaillants
|
||||||
|
let possible_moves_sequences = self.get_possible_moves_sequences(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
|
||||||
|
// refuse cette séquence
|
||||||
|
if !possible_moves_sequences.is_empty() {
|
||||||
|
return Err(MoveError::ExitByEffectPossible);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - la dame choisie doit être la plus éloignée de la sortie
|
||||||
|
let mut checkers = self.board.get_color_fields(Color::White);
|
||||||
|
checkers.sort_by(|a, b| b.0.cmp(&a.0));
|
||||||
|
let mut farthest = 24;
|
||||||
|
let mut next_farthest = 24;
|
||||||
|
let mut has_two_checkers = false;
|
||||||
|
if let Some((field, count)) = checkers.first() {
|
||||||
|
farthest = *field;
|
||||||
|
if *count > 1 {
|
||||||
|
next_farthest = *field;
|
||||||
|
has_two_checkers = true;
|
||||||
|
} else if let Some((field, _count)) = checkers.get(1) {
|
||||||
|
next_farthest = *field;
|
||||||
|
has_two_checkers = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// s'il reste au moins deux dames, on vérifie que les plus éloignées soint choisies
|
||||||
|
if has_two_checkers {
|
||||||
|
if moves.0.get_to() == 0 && moves.1.get_to() == 0 {
|
||||||
|
// Deux coups sortants en excédant
|
||||||
|
if cmp::max(moves.0.get_from(), moves.1.get_from()) > next_farthest {
|
||||||
|
return Err(MoveError::ExitNotFasthest);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Un seul coup sortant en excédant le coup sortant doit concerner la plus éloignée du bord
|
||||||
|
let exit_move_field = if moves.0.get_to() == 0 {
|
||||||
|
moves.0.get_from()
|
||||||
|
} else {
|
||||||
|
moves.1.get_from()
|
||||||
|
};
|
||||||
|
if exit_move_field != farthest {
|
||||||
|
return Err(MoveError::ExitNotFasthest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_possible_moves_sequences(
|
fn get_possible_moves_sequences(
|
||||||
&self,
|
&self,
|
||||||
with_excedents: bool,
|
with_excedents: bool,
|
||||||
|
|
@ -339,9 +344,10 @@ impl MoveRules {
|
||||||
) -> Vec<(CheckerMove, CheckerMove)> {
|
) -> Vec<(CheckerMove, CheckerMove)> {
|
||||||
let mut moves_seqs = Vec::new();
|
let mut moves_seqs = Vec::new();
|
||||||
let color = &Color::White;
|
let color = &Color::White;
|
||||||
for first_move in self
|
let forbid_exits = self.has_checkers_outside_last_quarter();
|
||||||
.board
|
for first_move in
|
||||||
.get_possible_moves(*color, dice1, with_excedents, false)
|
self.board
|
||||||
|
.get_possible_moves(*color, dice1, with_excedents, false, forbid_exits)
|
||||||
{
|
{
|
||||||
let mut board2 = self.board.clone();
|
let mut board2 = self.board.clone();
|
||||||
if board2.move_checker(color, first_move).is_err() {
|
if board2.move_checker(color, first_move).is_err() {
|
||||||
|
|
@ -350,7 +356,9 @@ impl MoveRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut has_second_dice_move = false;
|
let mut has_second_dice_move = false;
|
||||||
for second_move in board2.get_possible_moves(*color, dice2, with_excedents, true) {
|
for second_move in
|
||||||
|
board2.get_possible_moves(*color, dice2, with_excedents, true, forbid_exits)
|
||||||
|
{
|
||||||
if self.check_corner_rules(&(first_move, second_move)).is_ok() {
|
if self.check_corner_rules(&(first_move, second_move)).is_ok() {
|
||||||
moves_seqs.push((first_move, second_move));
|
moves_seqs.push((first_move, second_move));
|
||||||
has_second_dice_move = true;
|
has_second_dice_move = true;
|
||||||
|
|
@ -709,8 +717,8 @@ mod tests {
|
||||||
CheckerMove::new(0, 0).unwrap(),
|
CheckerMove::new(0, 0).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_follows_dices());
|
assert!(state.moves_follows_dices());
|
||||||
let res = state.moves_allowed();
|
// let res = state.moves_allowed();
|
||||||
println!("{:?}", res);
|
// println!("{:?}", res);
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed().is_ok());
|
||||||
|
|
||||||
state.moves = (
|
state.moves = (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue