wip prise en puissance

This commit is contained in:
Henri Bourcereau 2024-05-08 21:17:13 +02:00
parent 33ad73103b
commit 46bc300867
3 changed files with 93 additions and 4 deletions

View file

@ -93,6 +93,11 @@ impl Board {
Board::default() Board::default()
} }
/// Globally set pieces on board ( for tests )
pub fn set_positions(&mut self, positions: [i8; 24]) {
self.positions = positions;
}
// maybe todo : operate on bits (cf. https://github.com/bungogood/bkgm/blob/a2fb3f395243bcb0bc9f146df73413f73f5ea1e0/src/position.rs#L217) // maybe todo : operate on bits (cf. https://github.com/bungogood/bkgm/blob/a2fb3f395243bcb0bc9f146df73413f73f5ea1e0/src/position.rs#L217)
pub fn to_gnupg_pos_id(&self) -> String { pub fn to_gnupg_pos_id(&self) -> String {
// Pieces placement -> 77bits (24 + 23 + 30 max) // Pieces placement -> 77bits (24 + 23 + 30 max)

View file

@ -298,18 +298,48 @@ impl GameState {
let dist1 = (move1.get_to() as i8 - move1.get_from() as i8).abs() as u8; let dist1 = (move1.get_to() as i8 - move1.get_from() as i8).abs() as u8;
let dist2 = (move2.get_to() as i8 - move2.get_from() as i8).abs() as u8; let dist2 = (move2.get_to() as i8 - move2.get_from() as i8).abs() as u8;
// print!("{}, {}, {}, {}", dist1, dist2, dice1, dice2); // print!("{}, {}, {}, {}", dist1, dist2, dice1, dice2);
// basic : same number // exceptions
// - prise de coin par puissance
if self.is_move_by_puissance(color, moves) {
return true;
}
// - sorties
// default : must be same number
if cmp::min(dist1, dist2) != cmp::min(dice1, dice2) if cmp::min(dist1, dist2) != cmp::min(dice1, dice2)
|| cmp::max(dist1, dist2) != cmp::max(dice1, dice2) || cmp::max(dist1, dist2) != cmp::max(dice1, dice2)
{ {
return false; return false;
} }
// prise de coin par puissance
// sorties
// no rule was broken // no rule was broken
true true
} }
fn is_move_by_puissance(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool {
let (dice1, dice2) = self.dice.values;
let (move1, move2): &(CheckerMove, CheckerMove) = moves.into();
let dist1 = (move1.get_to() as i8 - move1.get_from() as i8).abs() as u8;
let dist2 = (move2.get_to() as i8 - move2.get_from() as i8).abs() as u8;
// Opponent corner must be empty
let opponent_corner_field: Field = self.board.get_color_corner(&color.opponent_color());
let (opponent_corner_count, _color) = self
.board
.get_field_checkers(opponent_corner_field)
.unwrap();
if opponent_corner_count > 0 {
return false;
}
move1.get_to() == move2.get_to()
&& move1.get_to() == self.board.get_color_corner(color)
&& ((*color == Color::White
&& cmp::min(dist1, dist2) == cmp::min(dice1, dice2) - 1
&& cmp::max(dist1, dist2) == cmp::max(dice1, dice2) - 1)
|| (*color == Color::Black
&& cmp::min(dist1, dist2) == cmp::min(dice1, dice2) + 1
&& cmp::max(dist1, dist2) == cmp::max(dice1, dice2) + 1))
}
fn moves_allowed(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool { fn moves_allowed(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool {
// ------- corner rules ---------- // ------- corner rules ----------
let corner_field: Field = self.board.get_color_corner(color); let corner_field: Field = self.board.get_color_corner(color);
@ -325,7 +355,7 @@ impl GameState {
return false; return false;
} }
// the lat 2 checkers of a corner must leave at the same time // the last 2 checkers of a corner must leave at the same time
if (from0 == corner_field || from1 == corner_field) && (from0 != from1) && corner_count == 2 if (from0 == corner_field || from1 == corner_field) && (from0 != from1) && corner_count == 2
{ {
return false; return false;
@ -579,4 +609,49 @@ mod tests {
); );
assert!(!state.moves_follows_dices(&Color::White, &badmoves)); assert!(!state.moves_follows_dices(&Color::White, &badmoves));
} }
#[test]
fn test_prise_en_puissance() {
let mut state = GameState::default();
let player1 = Player::new("player1".into(), Color::White);
let player_id = 1;
state.add_player(player_id, player1);
state.add_player(2, Player::new("player2".into(), Color::Black));
state.consume(&GameEvent::BeginGame {
goes_first: player_id,
});
state.consume(&GameEvent::Roll { player_id });
// prise par puissance ok
state.board.set_positions([
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);
let moves = (
CheckerMove::new(8, 12).unwrap(),
CheckerMove::new(8, 12).unwrap(),
);
assert!(state.is_move_by_puissance(&Color::White, &moves));
assert!(state.moves_follows_dices(&Color::White, &moves));
assert!(state.moves_allowed(&Color::White, &moves));
// 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(&Color::White, &moves));
assert!(!state.moves_follows_dices(&Color::White, &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([
5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15,
]);
assert!(!state.moves_follows_dices(&Color::White, &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, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15,
]);
assert!(!state.moves_follows_dices(&Color::White, &moves));
}
} }

View file

@ -10,6 +10,15 @@ pub enum Color {
Black, Black,
} }
impl Color {
pub fn opponent_color(&self) -> Self {
match self {
Self::White => Self::Black,
Self::Black => Self::White,
}
}
}
/// Struct for storing player related data. /// Struct for storing player related data.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Player { pub struct Player {