castling: simplify castle updates

This commit is contained in:
dece 2020-06-20 21:05:54 +02:00
parent b62dd1c076
commit 8b0f4c9255
4 changed files with 45 additions and 124 deletions

View file

@ -1,19 +1,21 @@
//! Castling flags.
pub const CASTLING_WH_K: u8 = 0b00000001;
pub const CASTLING_WH_Q: u8 = 0b00000010;
pub const CASTLING_WH_MASK: u8 = 0b00000011;
pub const CASTLING_BL_K: u8 = 0b00000100;
pub const CASTLING_BL_Q: u8 = 0b00001000;
pub const CASTLING_BL_MASK: u8 = 0b00001100;
pub const CASTLING_K_MASK: u8 = 0b00000101;
pub const CASTLING_Q_MASK: u8 = 0b00001010;
pub const CASTLING_MASK: u8 = 0b00001111;
pub type Castle = u8;
pub const CASTLING_WH_K: Castle = 0b00000001;
pub const CASTLING_WH_Q: Castle = 0b00000010;
pub const CASTLING_WH_MASK: Castle = 0b00000011;
pub const CASTLING_BL_K: Castle = 0b00000100;
pub const CASTLING_BL_Q: Castle = 0b00001000;
pub const CASTLING_BL_MASK: Castle = 0b00001100;
pub const CASTLING_K_MASK: Castle = 0b00000101;
pub const CASTLING_Q_MASK: Castle = 0b00001010;
pub const CASTLING_MASK: Castle = 0b00001111;
/// Castling sides parameters.
///
/// For both sides, the 3-uple contains files that should be empty
/// and not attacked, an optional file that should be empty for
/// queen-side, and the castling side-mask.
pub const CASTLING_SIDES: [([i8; 2], Option<i8>, u8); 2] =
pub const CASTLING_SIDES: [([i8; 2], Option<i8>, Castle); 2] =
[([5i8, 6i8], None, CASTLING_K_MASK), ([3i8, 2i8], Some(1i8), CASTLING_Q_MASK)];

View file

@ -6,9 +6,6 @@ use crate::board::*;
use crate::castling::*;
use crate::rules::GameState;
const START_WH_K_POS: Square = E1;
const START_BL_K_POS: Square = E8;
/// A movement, with before/after positions and optional promotion.
#[derive(Clone, PartialEq)]
pub struct Move {
@ -39,119 +36,50 @@ impl Move {
/// Apply this move to `board` and `game_state`.
pub fn apply_to(&self, board: &mut Board, game_state: &mut GameState) {
// If a rook is taken, remove its castling option. Needs to be checked before we update
// board. Note that we only check for a piece going to rook's initial position: it means
// the rook either moved previously, or it has been taken.
match self.source {
A1 => { game_state.castling &= !CASTLING_WH_Q; }
H1 => { game_state.castling &= !CASTLING_WH_K; }
A8 => { game_state.castling &= !CASTLING_BL_Q; }
H8 => { game_state.castling &= !CASTLING_BL_K; }
_ => {}
}
// If a king moves, remove it from castling options.
if self.source == E1 { game_state.castling &= !CASTLING_WH_MASK; }
else if self.source == E8 { game_state.castling &= !CASTLING_BL_MASK; }
// Same for rooks.
if self.source == A1 || self.dest == A1 { game_state.castling &= !CASTLING_WH_Q; }
else if self.source == H1 || self.dest == H1 { game_state.castling &= !CASTLING_WH_K; }
else if self.source == A8 || self.dest == A8 { game_state.castling &= !CASTLING_BL_Q; }
else if self.source == H8 || self.dest == H8 { game_state.castling &= !CASTLING_BL_K; }
// Update board and game state.
self.apply_to_board(board);
game_state.color = opposite(game_state.color);
// If the move is a castle, remove it from castling options.
if let Some(castle) = self.get_castle() {
match castle {
CASTLING_WH_K | CASTLING_WH_Q => game_state.castling &= !CASTLING_WH_MASK,
CASTLING_BL_K | CASTLING_BL_Q => game_state.castling &= !CASTLING_BL_MASK,
_ => {}
};
}
// Else, check if the king or a rook moved to update castling options.
else {
let color = board.get_color_on(self.dest);
if color == WHITE && game_state.castling & CASTLING_WH_MASK != 0 {
match board.get_piece_on(self.dest) {
KING => {
if self.source == E1 {
game_state.castling &= !CASTLING_WH_MASK;
}
}
ROOK => {
if self.source == A1 {
game_state.castling &= !CASTLING_WH_Q;
} else if self.source == H1 {
game_state.castling &= !CASTLING_WH_K;
}
}
_ => {}
}
} else if color == BLACK && game_state.castling & CASTLING_BL_MASK != 0 {
match board.get_piece_on(self.dest) {
KING => {
if self.source == E8 {
game_state.castling &= !CASTLING_BL_MASK;
}
}
ROOK => {
if self.source == A8 {
game_state.castling &= !CASTLING_BL_Q;
} else if self.source == H8 {
game_state.castling &= !CASTLING_BL_K;
}
}
_ => {}
}
}
}
}
/// Apply the move into `board`.
pub fn apply_to_board(&self, board: &mut Board) {
if let Some(castle) = self.get_castle() {
match castle {
CASTLING_WH_K => {
board.move_square(START_WH_K_POS, G1);
board.move_square(H1, F1);
let piece = board.get_piece_on(self.source);
// If a king is castling, apply special move.
if piece == KING {
if let Some(castle) = self.get_castle() {
match castle {
CASTLING_WH_K => { board.move_square(E1, G1); board.move_square(H1, F1); }
CASTLING_WH_Q => { board.move_square(E1, C1); board.move_square(A1, D1); }
CASTLING_BL_K => { board.move_square(E8, G8); board.move_square(H8, F8); }
CASTLING_BL_Q => { board.move_square(E8, C8); board.move_square(A8, D8); }
_ => { panic!("Invalid castle.") }
}
CASTLING_WH_Q => {
board.move_square(START_WH_K_POS, C1);
board.move_square(A1, D1);
}
CASTLING_BL_K => {
board.move_square(START_BL_K_POS, G8);
board.move_square(H8, F8);
}
CASTLING_BL_Q => {
board.move_square(START_BL_K_POS, C8);
board.move_square(A8, D8);
}
_ => {}
}
} else {
board.move_square(self.source, self.dest);
if let Some(piece) = self.promotion {
let color = board.get_color_on(self.dest);
board.set_square(self.dest, color, piece);
return
}
}
board.move_square(self.source, self.dest);
if let Some(piece) = self.promotion {
let color = board.get_color_on(self.dest);
board.set_square(self.dest, color, piece);
}
}
/// Get the corresponding castling flag for this move.
pub fn get_castle(&self) -> Option<u8> {
if self.source == E1 {
if self.dest == C1 {
Some(CASTLING_WH_Q)
} else if self.dest == G1 {
Some(CASTLING_WH_K)
} else {
None
}
} else if self.source == E8 {
if self.dest == C8 {
Some(CASTLING_BL_Q)
} else if self.dest == G8 {
Some(CASTLING_BL_K)
} else {
None
}
} else {
None
pub fn get_castle(&self) -> Option<Castle> {
match (self.source, self.dest) {
(E1, C1) => Some(CASTLING_WH_Q),
(E1, G1) => Some(CASTLING_WH_K),
(E8, C8) => Some(CASTLING_BL_Q),
(E8, G8) => Some(CASTLING_BL_K),
_ => None,
}
}

View file

@ -54,11 +54,6 @@ impl fmt::Display for Node {
let mut s = vec!();
self.board.draw(&mut s);
let board_drawing = String::from_utf8_lossy(&s).to_string();
write!(
f,
"* Board:\n{}\n\
* Game state:\n{}",
board_drawing, self.game_state
)
write!(f, "* Board:\n{}\nGame state: {}", board_drawing, self.game_state)
}
}

View file

@ -43,11 +43,7 @@ impl std::fmt::Display for GameState {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"- color: {}\n\
- castling: {:04b}\n\
- en_passant: {}\n\
- halfmove: {}\n\
- fullmove: {}",
"[color: {}, castling: {:04b}, en_passant: {}, halfmove: {}, fullmove: {}]",
color_to_string(self.color), self.castling,
fen::en_passant_to_string(self.en_passant),
self.halfmove, self.fullmove