passage intermédiaire sur coin de repos

This commit is contained in:
Henri Bourcereau 2024-06-23 11:38:03 +02:00
parent bfd58cc399
commit fb5e954b85
4 changed files with 52 additions and 11 deletions

View file

@ -64,6 +64,7 @@ Si on doit passer par une case occupée par deux dames adverses ou plus pour att
Remarques Remarques
- on peut "passer" sur une dame adverse (donc battue) pour battre une seconde dame adverse (avec la somme des deux dés). - on peut "passer" sur une dame adverse (donc battue) pour battre une seconde dame adverse (avec la somme des deux dés).
- comme pour les déplacements, il est possible de passer par le coin de repos vide de l'adversaire pour battre à vrai une dame en "tout d'une" (c'est s'arrêter sur le coin de repos qui est interdit)
- même s'il ne reste que deux dames dans son coin de repos (et qu'en théorie elle ne peuvent en sortir qu'en même temps), elles peuvent tout de même battre une dame adverse (à vrai et à faux). En revanche elles ne peuvent pas participer au battage du coin adverse (cf. prochain paragraphe). - même s'il ne reste que deux dames dans son coin de repos (et qu'en théorie elle ne peuvent en sortir qu'en même temps), elles peuvent tout de même battre une dame adverse (à vrai et à faux). En revanche elles ne peuvent pas participer au battage du coin adverse (cf. prochain paragraphe).
Autre jan de récompense : Autre jan de récompense :

View file

@ -300,6 +300,13 @@ impl Board {
/// Check if a field is blocked for a player /// Check if a field is blocked for a player
pub fn blocked(&self, color: &Color, field: Field) -> Result<bool, Error> { pub fn blocked(&self, color: &Color, field: Field) -> Result<bool, Error> {
// the square is blocked on the opponent rest corner
let opp_corner_field = if color == &Color::White { 13 } else { 12 };
self.passage_blocked(color, field)
.map(|blocked| blocked || opp_corner_field == field)
}
pub fn passage_blocked(&self, color: &Color, field: Field) -> Result<bool, Error> {
if 24 < field { if 24 < field {
return Err(Error::FieldInvalid); return Err(Error::FieldInvalid);
} }
@ -309,9 +316,13 @@ impl Board {
return Ok(false); return Ok(false);
} }
// the square is blocked on the opponent rest corner or if there are opponent's men on the square // the square is blocked if there are opponent's men on the square
let opp_corner_field = if color == &Color::White { 13 } else { 12 }; let blocked = if color == &Color::White {
Ok(field == opp_corner_field || self.positions[field - 1] < 0) self.positions[field - 1] < 0
} else {
self.positions[field - 1] > 0
};
Ok(blocked)
} }
pub fn get_field_checkers(&self, field: Field) -> Result<(u8, Option<&Color>), Error> { pub fn get_field_checkers(&self, field: Field) -> Result<(u8, Option<&Color>), Error> {
@ -412,6 +423,10 @@ impl Board {
moves moves
} }
pub fn passage_possible(&self, color: &Color, cmove: &CheckerMove) -> bool {
!self.passage_blocked(color, cmove.to).unwrap_or(true)
}
pub fn move_possible(&self, color: &Color, cmove: &CheckerMove) -> bool { pub fn move_possible(&self, color: &Color, cmove: &CheckerMove) -> bool {
let blocked = self.blocked(color, cmove.to).unwrap_or(true); let blocked = self.blocked(color, cmove.to).unwrap_or(true);
// Check if there is a player's checker on the 'from' square // Check if there is a player's checker on the 'from' square

View file

@ -61,17 +61,17 @@ impl MoveRules {
/// ---- moves_possibles : First of three checks for moves /// ---- moves_possibles : First of three checks for moves
fn moves_possible(&self, moves: &(CheckerMove, CheckerMove)) -> bool { fn moves_possible(&self, moves: &(CheckerMove, CheckerMove)) -> bool {
let color = &Color::White; let color = &Color::White;
// Check move is physically possible
if !self.board.move_possible(color, &moves.0) {
return false;
}
// Chained_move : "Tout d'une"
if let Ok(chained_move) = moves.0.chain(moves.1) { if let Ok(chained_move) = moves.0.chain(moves.1) {
if !self.board.move_possible(color, &chained_move) { // Check intermediary move and chained_move : "Tout d'une"
if !self.board.passage_possible(color, &moves.0)
|| !self.board.move_possible(color, &chained_move)
{
return false; return false;
} }
} else if !self.board.move_possible(color, &moves.1) { } else if !self.board.move_possible(color, &moves.0)
|| !self.board.move_possible(color, &moves.1)
{
// Move is not physically possible
return false; return false;
} }
true true
@ -739,6 +739,28 @@ mod tests {
); );
} }
#[test]
fn move_rest_corner_toutdune() {
let mut state = MoveRules::default();
// We can't go to the occupied rest corner as an intermediary step
state.board.set_positions([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]);
state.dice.values = (2, 1);
let moves = (
CheckerMove::new(11, 13).unwrap(),
CheckerMove::new(13, 14).unwrap(),
);
assert!(!state.moves_possible(&moves));
// We can use the empty rest corner as an intermediary step
state.board.set_positions([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]);
assert!(state.moves_possible(&moves));
assert!(state.moves_allowed(&moves).is_ok());
}
#[test] #[test]
fn move_play_stronger_dice() { fn move_play_stronger_dice() {
let mut state = MoveRules::default(); let mut state = MoveRules::default();

View file

@ -304,6 +304,9 @@ mod tests {
jans.merge(jans_revert_dices); jans.merge(jans_revert_dices);
assert_eq!(1, jans.len()); assert_eq!(1, jans.len());
// print!("jans (2) : {:?}", jans.get(&Jan::TrueHit)); // print!("jans (2) : {:?}", jans.get(&Jan::TrueHit));
// battage à faux : ne pas prendre en compte si en inversant l'ordre des dés il y a battage
// à vrai
} }
#[test] #[test]