rules: factorize move/take checks
This commit is contained in:
parent
d958e617d0
commit
b62dd1c076
119
src/rules.rs
119
src/rules.rs
|
@ -148,7 +148,7 @@ fn get_pawn_moves(
|
|||
let diag = sq(f - 1, forward_r);
|
||||
if !board.is_empty(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) {
|
||||
moves.push(m);
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ fn get_pawn_moves(
|
|||
let diag = sq(f + 1, forward_r);
|
||||
if !board.is_empty(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) {
|
||||
moves.push(m);
|
||||
}
|
||||
|
@ -203,19 +203,11 @@ fn get_bishop_moves(
|
|||
}
|
||||
let ray_square = sq(ray_f, ray_r);
|
||||
|
||||
if board.is_empty(ray_square) {
|
||||
let m = Move::new(square, ray_square);
|
||||
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);
|
||||
}
|
||||
}
|
||||
views[dir] = false;
|
||||
match get_move_type(board, game_state, square, ray_square, color, commit) {
|
||||
MoveType::Simple(m) => { moves.push(m) }
|
||||
MoveType::Capture(m) => { moves.push(m); views[dir] = false; }
|
||||
MoveType::CantTakeFriend => { views[dir] = false; }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -242,18 +234,9 @@ fn get_knight_moves(
|
|||
}
|
||||
let ray_square = sq(ray_f, ray_r);
|
||||
|
||||
if board.is_empty(ray_square) {
|
||||
let m = Move::new(square, ray_square);
|
||||
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);
|
||||
}
|
||||
}
|
||||
match get_move_type(board, game_state, square, ray_square, color, commit) {
|
||||
MoveType::Simple(m) | MoveType::Capture(m) => moves.push(m),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
moves
|
||||
|
@ -287,19 +270,11 @@ fn get_rook_moves(
|
|||
}
|
||||
let ray_square = sq(ray_f, ray_r);
|
||||
|
||||
if board.is_empty(ray_square) {
|
||||
let m = Move::new(square, ray_square);
|
||||
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);
|
||||
}
|
||||
}
|
||||
views[dir] = false; // Stop looking in that direction.
|
||||
match get_move_type(board, game_state, square, ray_square, color, commit) {
|
||||
MoveType::Simple(m) => { moves.push(m) }
|
||||
MoveType::Capture(m) => { moves.push(m); views[dir] = false; }
|
||||
MoveType::CantTakeFriend => { views[dir] = false; }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,18 +315,9 @@ fn get_king_moves(
|
|||
}
|
||||
let ray_square = sq(ray_f, ray_r);
|
||||
|
||||
if board.is_empty(ray_square) {
|
||||
let m = Move::new(square, ray_square);
|
||||
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);
|
||||
}
|
||||
}
|
||||
match get_move_type(board, game_state, square, ray_square, color, commit) {
|
||||
MoveType::Simple(m) | MoveType::Capture(m) => moves.push(m),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,6 +383,47 @@ fn get_king_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,
|
||||
///
|
||||
/// 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.
|
||||
fn move_if_enemy(
|
||||
fn get_capture_move(
|
||||
color1: Color,
|
||||
square1: Square,
|
||||
color2: Color,
|
||||
|
@ -455,13 +462,13 @@ fn move_if_enemy(
|
|||
/// Check if a move is illegal.
|
||||
fn is_illegal(board: &Board, game_state: &GameState, m: &Move) -> bool {
|
||||
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 m.source == king_square {
|
||||
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.
|
||||
if is_attacked(&hypothetic_board, &game_state, king_square) {
|
||||
return true
|
||||
|
|
Reference in a new issue