rules: factorize move/take checks

This commit is contained in:
dece 2020-06-20 19:56:00 +02:00
parent d958e617d0
commit b62dd1c076

View file

@ -148,7 +148,7 @@ fn get_pawn_moves(
let diag = sq(f - 1, forward_r); let diag = sq(f - 1, forward_r);
if !board.is_empty(diag) { if !board.is_empty(diag) {
let diag_color = board.get_color_on(diag); let diag_color = board.get_color_on(diag);
if let Some(m) = move_if_enemy(color, square, diag_color, diag, true) { if let Some(m) = get_capture_move(color, square, diag_color, diag, true) {
if can_register(commit, board, game_state, &m) { if can_register(commit, board, game_state, &m) {
moves.push(m); moves.push(m);
} }
@ -161,7 +161,7 @@ fn get_pawn_moves(
let diag = sq(f + 1, forward_r); let diag = sq(f + 1, forward_r);
if !board.is_empty(diag) { if !board.is_empty(diag) {
let diag_color = board.get_color_on(diag); let diag_color = board.get_color_on(diag);
if let Some(m) = move_if_enemy(color, square, diag_color, diag, true) { if let Some(m) = get_capture_move(color, square, diag_color, diag, true) {
if can_register(commit, board, game_state, &m) { if can_register(commit, board, game_state, &m) {
moves.push(m); moves.push(m);
} }
@ -203,19 +203,11 @@ fn get_bishop_moves(
} }
let ray_square = sq(ray_f, ray_r); let ray_square = sq(ray_f, ray_r);
if board.is_empty(ray_square) { match get_move_type(board, game_state, square, ray_square, color, commit) {
let m = Move::new(square, ray_square); MoveType::Simple(m) => { moves.push(m) }
if can_register(commit, board, game_state, &m) { MoveType::Capture(m) => { moves.push(m); views[dir] = false; }
moves.push(m); MoveType::CantTakeFriend => { views[dir] = false; }
} _ => {}
} else {
let ray_color = board.get_color_on(ray_square);
if let Some(m) = move_if_enemy(color, square, ray_color, ray_square, false) {
if can_register(commit, board, game_state, &m) {
moves.push(m);
}
}
views[dir] = false;
} }
} }
} }
@ -242,18 +234,9 @@ fn get_knight_moves(
} }
let ray_square = sq(ray_f, ray_r); let ray_square = sq(ray_f, ray_r);
if board.is_empty(ray_square) { match get_move_type(board, game_state, square, ray_square, color, commit) {
let m = Move::new(square, ray_square); MoveType::Simple(m) | MoveType::Capture(m) => moves.push(m),
if can_register(commit, board, game_state, &m) { _ => {}
moves.push(m);
}
} else {
let ray_color = board.get_color_on(ray_square);
if let Some(m) = move_if_enemy(color, square, ray_color, ray_square, false) {
if can_register(commit, board, game_state, &m) {
moves.push(m);
}
}
} }
} }
moves moves
@ -287,19 +270,11 @@ fn get_rook_moves(
} }
let ray_square = sq(ray_f, ray_r); let ray_square = sq(ray_f, ray_r);
if board.is_empty(ray_square) { match get_move_type(board, game_state, square, ray_square, color, commit) {
let m = Move::new(square, ray_square); MoveType::Simple(m) => { moves.push(m) }
if can_register(commit, board, game_state, &m) { MoveType::Capture(m) => { moves.push(m); views[dir] = false; }
moves.push(m); MoveType::CantTakeFriend => { views[dir] = false; }
} _ => {}
} else {
let ray_color = board.get_color_on(ray_square);
if let Some(m) = move_if_enemy(color, square, ray_color, ray_square, false) {
if can_register(commit, board, game_state, &m) {
moves.push(m);
}
}
views[dir] = false; // Stop looking in that direction.
} }
} }
} }
@ -340,18 +315,9 @@ fn get_king_moves(
} }
let ray_square = sq(ray_f, ray_r); let ray_square = sq(ray_f, ray_r);
if board.is_empty(ray_square) { match get_move_type(board, game_state, square, ray_square, color, commit) {
let m = Move::new(square, ray_square); MoveType::Simple(m) | MoveType::Capture(m) => moves.push(m),
if can_register(commit, board, game_state, &m) { _ => {}
moves.push(m);
}
} else {
let ray_color = board.get_color_on(ray_square);
if let Some(m) = move_if_enemy(color, square, ray_color, ray_square, false) {
if can_register(commit, board, game_state, &m) {
moves.push(m);
}
}
} }
} }
@ -417,6 +383,47 @@ fn get_king_moves(
moves moves
} }
/// Accept or ignore a move from `square` to `ray_square`.
fn get_move_type(
board: &Board,
game_state: &GameState,
square: Square,
ray_square: Square,
color: Color,
commit: bool
) -> MoveType {
if board.is_empty(ray_square) {
let m = Move::new(square, ray_square);
if can_register(commit, board, game_state, &m) {
MoveType::Simple(m)
} else {
MoveType::CantRegister
}
} else {
let ray_color = board.get_color_on(ray_square);
if let Some(m) = get_capture_move(color, square, ray_color, ray_square, false) {
if can_register(commit, board, game_state, &m) {
MoveType::Capture(m)
} else {
MoveType::CantRegister
}
} else {
MoveType::CantTakeFriend
}
}
}
enum MoveType {
/// Move to an empty square.
Simple(Move),
/// Capture an enemy piece.
Capture(Move),
/// May be illegal, or should not be committed, e.g. to test rays.
CantRegister,
/// Can't capture a friend piece.
CantTakeFriend,
}
/// Return true if `commit` is false, or the move is not illegal, /// Return true if `commit` is false, or the move is not illegal,
/// ///
/// Committing a move means that it can be safely played afterwards. /// Committing a move means that it can be safely played afterwards.
@ -429,7 +436,7 @@ fn can_register(commit: bool, board: &Board, game_state: &GameState, m: &Move) -
} }
/// Return a move from `square1` to `square2` if colors are opposite. /// Return a move from `square1` to `square2` if colors are opposite.
fn move_if_enemy( fn get_capture_move(
color1: Color, color1: Color,
square1: Square, square1: Square,
color2: Color, color2: Color,
@ -455,13 +462,13 @@ fn move_if_enemy(
/// Check if a move is illegal. /// Check if a move is illegal.
fn is_illegal(board: &Board, game_state: &GameState, m: &Move) -> bool { fn is_illegal(board: &Board, game_state: &GameState, m: &Move) -> bool {
if let Some(mut king_square) = board.find_king(game_state.color) { if let Some(mut king_square) = board.find_king(game_state.color) {
// Rule 1: a move is illegal if the king ends up in check. let mut hypothetic_board = board.clone();
m.apply_to_board(&mut hypothetic_board);
// A move is illegal if the king ends up in check.
// If king moves, use its new position. // If king moves, use its new position.
if m.source == king_square { if m.source == king_square {
king_square = m.dest king_square = m.dest
} }
let mut hypothetic_board = board.clone();
m.apply_to_board(&mut hypothetic_board);
// Check if the move makes the player king in check. // Check if the move makes the player king in check.
if is_attacked(&hypothetic_board, &game_state, king_square) { if is_attacked(&hypothetic_board, &game_state, king_square) {
return true return true