fix(store): battage en passant par coin de repos vide

This commit is contained in:
Henri Bourcereau 2026-03-31 22:00:57 +02:00
parent 7383b7d5e8
commit c6031b0ace

View file

@ -417,86 +417,96 @@ fn get_jans_by_ordered_dice(
) -> PossibleJans { ) -> PossibleJans {
let mut jans = PossibleJans::default(); let mut jans = PossibleJans::default();
let mut dices: Vec<u8> = dices.to_vec(); let mut dices: Vec<u8> = dices.to_vec();
if let Some(dice) = dices.pop() { let dice = match dices.pop() {
let color = Color::White; Some(dice) => dice,
let mut board = board_ini.clone(); None => return jans,
let corner_field = board.get_color_corner(&color); };
let adv_corner_field = board.get_color_corner(&Color::Black); let color = Color::White;
let froms = if let Some(from) = only_from { let mut board = board_ini.clone();
vec![from] let corner_field = board.get_color_corner(&color);
let adv_corner_field = board.get_color_corner(&Color::Black);
let froms = if let Some(from) = only_from {
vec![from]
} else {
board
.get_color_fields(color)
.iter()
.map(|cf| cf.0)
.collect()
};
for from in froms {
// for (from, _) in board.get_color_fields(color) {
let to = if from + dice as usize > 24 {
0
} else { } else {
board from + dice as usize
.get_color_fields(color)
.iter()
.map(|cf| cf.0)
.collect()
}; };
for from in froms { if let Ok(cmove) = CheckerMove::new(from, to) {
// for (from, _) in board.get_color_fields(color) { // On vérifie que le mouvement n'est pas interdit par les règles des coins de
let to = if from + dice as usize > 24 { // repos :
0 // - on ne va pas sur le coin de l'adversaire (sauf pour repos d'un tout d'une si vide)
} else { // - ni sur son propre coin de repos avec une seule dame (sauf pour repos d'un tout
from + dice as usize // d'une)
}; // - règle non prise en compte pour le battage des dames : on ne sort pas de son coin de repos s'il n'y reste que deux dames
if let Ok(cmove) = CheckerMove::new(from, to) { let (corner_count, _color) = board.get_field_checkers(corner_field).unwrap();
// print!( let (adv_corner_count, _color) = board.get_field_checkers(adv_corner_field).unwrap();
// " <dice_move dice='{:?}' moves='{:?} -> {:?}'> ", // si only_false_hit est vrai, on est déja dans une tentative tout d'une
// dice, from, to let mut can_try_toutdune = !only_false_hit;
// ); if (to == adv_corner_field && adv_corner_count < 2)
// On vérifie que le mouvement n'est pas interdit par les règles des coins de || to == corner_field && corner_count < 2
// repos : {
// - on ne va pas sur le coin de l'adversaire // Cas d'un tout d'une en passant par un coin de repos non rempli
// - ni sur son propre coin de repos avec une seule dame // on s'assure qu'on est sur le premier dé
// - règle non prise en compte pour le battage des dames : on ne sort pas de son coin de repos s'il n'y reste que deux dames if 0 < dices.len() {
let (corner_count, _color) = board.get_field_checkers(corner_field).unwrap(); can_try_toutdune = true;
if to != adv_corner_field && (to != corner_field || corner_count > 1) { } else {
// si only_false_hit est vrai, on est déja dans une tentative tout d'une continue;
let mut can_try_toutdune = !only_false_hit;
let mut only_falsehit = false;
match board.move_checker(&color, cmove) {
Err(Error::FieldBlockedByOne) => {
let jan = match (Board::is_field_in_small_jan(to), only_false_hit) {
(true, false) => Jan::TrueHitSmallJan,
(true, true) => Jan::FalseHitSmallJan,
(false, false) => Jan::TrueHitBigJan,
(false, true) => Jan::FalseHitBigJan,
};
jans.push(jan, (cmove, EMPTY_MOVE));
}
Err(Error::FieldBlocked) => {
only_falsehit = true;
}
Err(_) => {
can_try_toutdune = false;
// let next_dice_jan = self.get_jans(&board, &dices);
// jans possibles en tout d'une après un battage à vrai :
// truehit
}
Ok(()) => {}
}
if can_try_toutdune {
// Try tout d'une :
// - use original board before first die move
// - use a virtual dice by adding current dice to remaining dice
// - limit the checker to the current one
let next_dice_jan = get_jans_by_ordered_dice(
board_ini,
&dices.iter().map(|d| d + dice).collect::<Vec<u8>>(),
Some(from),
only_falsehit,
);
jans.merge(next_dice_jan);
}
} }
// Second die }
let next_dice_jan = get_jans_by_ordered_dice(board_ini, &dices, None, false); let mut only_falsehit = false;
match board.move_checker(&color, cmove) {
Err(Error::FieldBlockedByOne) => {
let jan = match (Board::is_field_in_small_jan(to), only_false_hit) {
(true, false) => Jan::TrueHitSmallJan,
(true, true) => Jan::FalseHitSmallJan,
(false, false) => Jan::TrueHitBigJan,
(false, true) => Jan::FalseHitBigJan,
};
jans.push(jan, (cmove, EMPTY_MOVE));
}
Err(Error::FieldBlocked) => {
only_falsehit = true;
}
Err(_) => {
can_try_toutdune = false;
// let next_dice_jan = self.get_jans(&board, &dices);
// jans possibles en tout d'une après un battage à vrai :
// truehit
}
Ok(()) => {}
}
if can_try_toutdune {
// Try tout d'une :
// - use original board before first die move
// - use a virtual dice by adding current dice to remaining dice
// - limit the checker to the current one
let next_dice_jan = get_jans_by_ordered_dice(
board_ini,
&dices.iter().map(|d| d + dice).collect::<Vec<u8>>(),
Some(from),
only_falsehit,
);
jans.merge(next_dice_jan); jans.merge(next_dice_jan);
} }
// Second die
let next_dice_jan = get_jans_by_ordered_dice(board_ini, &dices, None, false);
jans.merge(next_dice_jan);
} }
} }
jans jans
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -569,18 +579,6 @@ mod tests {
// corners handling // corners handling
// deux dés bloqués (coin de repos et coin de l'adversaire)
rules.board.set_positions(
&Color::White,
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
);
// le premier dé traité est le dernier du vecteur : 1
let jans = get_jans_by_ordered_dice(&rules.board, &[2, 1], None, false);
// println!("jans (dés bloqués) : {:?}", jans.get(&Jan::TrueHit));
assert_eq!(0, jans.len());
// dé dans son coin de repos : peut tout de même battre à vrai // dé dans son coin de repos : peut tout de même battre à vrai
rules.board.set_positions( rules.board.set_positions(
&Color::White, &Color::White,
@ -591,6 +589,17 @@ mod tests {
let jans = get_jans_by_ordered_dice(&rules.board, &[3, 3], None, false); let jans = get_jans_by_ordered_dice(&rules.board, &[3, 3], None, false);
assert_eq!(1, jans.len()); assert_eq!(1, jans.len());
// case intermédiaire dans coin de repos vide : peut tout de même battre à vrai
rules.board.set_positions(
&Color::White,
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
);
let jans = get_jans_by_ordered_dice(&rules.board, &[4, 1], None, false);
assert_eq!(1, jans.len());
assert_eq!(1, jans.get(&Jan::TrueHitBigJan).unwrap().len());
// premier dé bloqué, mais tout d'une possible en commençant par le second // premier dé bloqué, mais tout d'une possible en commençant par le second
rules.board.set_positions( rules.board.set_positions(
&Color::White, &Color::White,