castling: simplify castle updates
This commit is contained in:
parent
b62dd1c076
commit
8b0f4c9255
|
@ -1,19 +1,21 @@
|
||||||
//! Castling flags.
|
//! Castling flags.
|
||||||
|
|
||||||
pub const CASTLING_WH_K: u8 = 0b00000001;
|
pub type Castle = u8;
|
||||||
pub const CASTLING_WH_Q: u8 = 0b00000010;
|
|
||||||
pub const CASTLING_WH_MASK: u8 = 0b00000011;
|
pub const CASTLING_WH_K: Castle = 0b00000001;
|
||||||
pub const CASTLING_BL_K: u8 = 0b00000100;
|
pub const CASTLING_WH_Q: Castle = 0b00000010;
|
||||||
pub const CASTLING_BL_Q: u8 = 0b00001000;
|
pub const CASTLING_WH_MASK: Castle = 0b00000011;
|
||||||
pub const CASTLING_BL_MASK: u8 = 0b00001100;
|
pub const CASTLING_BL_K: Castle = 0b00000100;
|
||||||
pub const CASTLING_K_MASK: u8 = 0b00000101;
|
pub const CASTLING_BL_Q: Castle = 0b00001000;
|
||||||
pub const CASTLING_Q_MASK: u8 = 0b00001010;
|
pub const CASTLING_BL_MASK: Castle = 0b00001100;
|
||||||
pub const CASTLING_MASK: u8 = 0b00001111;
|
pub const CASTLING_K_MASK: Castle = 0b00000101;
|
||||||
|
pub const CASTLING_Q_MASK: Castle = 0b00001010;
|
||||||
|
pub const CASTLING_MASK: Castle = 0b00001111;
|
||||||
|
|
||||||
/// Castling sides parameters.
|
/// Castling sides parameters.
|
||||||
///
|
///
|
||||||
/// For both sides, the 3-uple contains files that should be empty
|
/// For both sides, the 3-uple contains files that should be empty
|
||||||
/// and not attacked, an optional file that should be empty for
|
/// and not attacked, an optional file that should be empty for
|
||||||
/// queen-side, and the castling side-mask.
|
/// 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)];
|
[([5i8, 6i8], None, CASTLING_K_MASK), ([3i8, 2i8], Some(1i8), CASTLING_Q_MASK)];
|
||||||
|
|
134
src/movement.rs
134
src/movement.rs
|
@ -6,9 +6,6 @@ use crate::board::*;
|
||||||
use crate::castling::*;
|
use crate::castling::*;
|
||||||
use crate::rules::GameState;
|
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.
|
/// A movement, with before/after positions and optional promotion.
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct Move {
|
pub struct Move {
|
||||||
|
@ -39,119 +36,50 @@ impl Move {
|
||||||
|
|
||||||
/// Apply this move to `board` and `game_state`.
|
/// Apply this move to `board` and `game_state`.
|
||||||
pub fn apply_to(&self, board: &mut Board, game_state: &mut GameState) {
|
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
|
// If a king moves, remove it from castling options.
|
||||||
// board. Note that we only check for a piece going to rook's initial position: it means
|
if self.source == E1 { game_state.castling &= !CASTLING_WH_MASK; }
|
||||||
// the rook either moved previously, or it has been taken.
|
else if self.source == E8 { game_state.castling &= !CASTLING_BL_MASK; }
|
||||||
match self.source {
|
// Same for rooks.
|
||||||
A1 => { game_state.castling &= !CASTLING_WH_Q; }
|
if self.source == A1 || self.dest == A1 { game_state.castling &= !CASTLING_WH_Q; }
|
||||||
H1 => { game_state.castling &= !CASTLING_WH_K; }
|
else if self.source == H1 || self.dest == H1 { game_state.castling &= !CASTLING_WH_K; }
|
||||||
A8 => { game_state.castling &= !CASTLING_BL_Q; }
|
else if self.source == A8 || self.dest == A8 { game_state.castling &= !CASTLING_BL_Q; }
|
||||||
H8 => { game_state.castling &= !CASTLING_BL_K; }
|
else if self.source == H8 || self.dest == H8 { game_state.castling &= !CASTLING_BL_K; }
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update board and game state.
|
// Update board and game state.
|
||||||
self.apply_to_board(board);
|
self.apply_to_board(board);
|
||||||
game_state.color = opposite(game_state.color);
|
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`.
|
/// Apply the move into `board`.
|
||||||
pub fn apply_to_board(&self, board: &mut Board) {
|
pub fn apply_to_board(&self, board: &mut Board) {
|
||||||
if let Some(castle) = self.get_castle() {
|
let piece = board.get_piece_on(self.source);
|
||||||
match castle {
|
// If a king is castling, apply special move.
|
||||||
CASTLING_WH_K => {
|
if piece == KING {
|
||||||
board.move_square(START_WH_K_POS, G1);
|
if let Some(castle) = self.get_castle() {
|
||||||
board.move_square(H1, F1);
|
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 => {
|
return
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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.
|
/// Get the corresponding castling flag for this move.
|
||||||
pub fn get_castle(&self) -> Option<u8> {
|
pub fn get_castle(&self) -> Option<Castle> {
|
||||||
if self.source == E1 {
|
match (self.source, self.dest) {
|
||||||
if self.dest == C1 {
|
(E1, C1) => Some(CASTLING_WH_Q),
|
||||||
Some(CASTLING_WH_Q)
|
(E1, G1) => Some(CASTLING_WH_K),
|
||||||
} else if self.dest == G1 {
|
(E8, C8) => Some(CASTLING_BL_Q),
|
||||||
Some(CASTLING_WH_K)
|
(E8, G8) => Some(CASTLING_BL_K),
|
||||||
} else {
|
_ => None,
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,11 +54,6 @@ impl fmt::Display for Node {
|
||||||
let mut s = vec!();
|
let mut s = vec!();
|
||||||
self.board.draw(&mut s);
|
self.board.draw(&mut s);
|
||||||
let board_drawing = String::from_utf8_lossy(&s).to_string();
|
let board_drawing = String::from_utf8_lossy(&s).to_string();
|
||||||
write!(
|
write!(f, "* Board:\n{}\nGame state: {}", board_drawing, self.game_state)
|
||||||
f,
|
|
||||||
"* Board:\n{}\n\
|
|
||||||
* Game state:\n{}",
|
|
||||||
board_drawing, self.game_state
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,11 +43,7 @@ impl std::fmt::Display for GameState {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"- color: {}\n\
|
"[color: {}, castling: {:04b}, en_passant: {}, halfmove: {}, fullmove: {}]",
|
||||||
- castling: {:04b}\n\
|
|
||||||
- en_passant: {}\n\
|
|
||||||
- halfmove: {}\n\
|
|
||||||
- fullmove: {}",
|
|
||||||
color_to_string(self.color), self.castling,
|
color_to_string(self.color), self.castling,
|
||||||
fen::en_passant_to_string(self.en_passant),
|
fen::en_passant_to_string(self.en_passant),
|
||||||
self.halfmove, self.fullmove
|
self.halfmove, self.fullmove
|
||||||
|
|
Reference in a new issue