[board] Implement all the bit twiddling to track whether castling is allowed for each player and side of the board
This commit is contained in:
parent
8cc7e64ba6
commit
31e5771d30
3 changed files with 100 additions and 7 deletions
|
@ -7,9 +7,9 @@ use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||||
use crate::{
|
use crate::{
|
||||||
bitboard::BitBoard,
|
bitboard::BitBoard,
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
Move, Position, Square,
|
position::BoardSide,
|
||||||
|
Move, Position,
|
||||||
};
|
};
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
move_generator_declaration!(KingMoveGenerator, struct);
|
move_generator_declaration!(KingMoveGenerator, struct);
|
||||||
move_generator_declaration!(KingMoveGenerator, new);
|
move_generator_declaration!(KingMoveGenerator, new);
|
||||||
|
@ -17,13 +17,21 @@ move_generator_declaration!(KingMoveGenerator, getters);
|
||||||
|
|
||||||
impl<'a> KingMoveGenerator<'a> {
|
impl<'a> KingMoveGenerator<'a> {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn king_side_castle(position: &Position) -> Option<Move> {
|
fn king_side_castle(position: &Position, color: Color) -> Option<Move> {
|
||||||
|
if !position.is_castling_allowed(color, BoardSide::King) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Implement king side castle.
|
// TODO: Implement king side castle.
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn queen_side_castle(position: &Position) -> Option<Move> {
|
fn queen_side_castle(position: &Position, color: Color) -> Option<Move> {
|
||||||
|
if !position.is_castling_allowed(color, BoardSide::Queen) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Implement queen side castle.
|
// TODO: Implement queen side castle.
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -51,8 +59,8 @@ impl<'pos> MoveGeneratorInternal for KingMoveGenerator<'pos> {
|
||||||
|
|
||||||
let map_to_move = |sq| Move::new(piece, square, sq);
|
let map_to_move = |sq| Move::new(piece, square, sq);
|
||||||
|
|
||||||
let king_side_castle = Self::king_side_castle(position);
|
let king_side_castle = Self::king_side_castle(position, color);
|
||||||
let queen_side_castle = Self::queen_side_castle(position);
|
let queen_side_castle = Self::queen_side_castle(position, color);
|
||||||
let quiet_moves = quiet_moves_bb
|
let quiet_moves = quiet_moves_bb
|
||||||
.occupied_squares()
|
.occupied_squares()
|
||||||
.map(map_to_move)
|
.map(map_to_move)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
mod diagram_formatter;
|
mod diagram_formatter;
|
||||||
mod pieces;
|
mod pieces;
|
||||||
mod position;
|
mod position;
|
||||||
|
@ -5,3 +7,5 @@ mod position;
|
||||||
pub use diagram_formatter::DiagramFormatter;
|
pub use diagram_formatter::DiagramFormatter;
|
||||||
pub use pieces::Pieces;
|
pub use pieces::Pieces;
|
||||||
pub use position::Position;
|
pub use position::Position;
|
||||||
|
|
||||||
|
pub(crate) use position::BoardSide;
|
||||||
|
|
|
@ -10,10 +10,27 @@ use crate::{
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
/// A lateral side of the board relative to the player. Kingside is the side the
|
||||||
|
/// player's king starts on. Queenside is the side of the board the player's
|
||||||
|
/// queen starts on.
|
||||||
|
pub(crate) enum BoardSide {
|
||||||
|
King,
|
||||||
|
Queen,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, Hash, PartialEq)]
|
#[derive(Clone, Eq, Hash, PartialEq)]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
color_to_move: Color,
|
color_to_move: Color,
|
||||||
|
|
||||||
|
/// Position flags indicating various bits of game state. The flags are as
|
||||||
|
/// follows:
|
||||||
|
///
|
||||||
|
/// 0. white can castle king-side
|
||||||
|
/// 1. white can castle queen-side
|
||||||
|
/// 2. black can castle king-side
|
||||||
|
/// 3. black can castle queen-side
|
||||||
|
flags: u8,
|
||||||
|
|
||||||
/// Composite bitboards for all the pieces of a particular color.
|
/// Composite bitboards for all the pieces of a particular color.
|
||||||
pieces_per_color: [BitBoard; 2],
|
pieces_per_color: [BitBoard; 2],
|
||||||
|
|
||||||
|
@ -25,7 +42,8 @@ impl Position {
|
||||||
pub fn empty() -> Position {
|
pub fn empty() -> Position {
|
||||||
Position {
|
Position {
|
||||||
color_to_move: Color::White,
|
color_to_move: Color::White,
|
||||||
pieces_per_color: [BitBoard::empty(), BitBoard::empty()],
|
flags: 0b00001111,
|
||||||
|
pieces_per_color: [BitBoard::empty(); 2],
|
||||||
pieces_per_type: [
|
pieces_per_type: [
|
||||||
[
|
[
|
||||||
BitBoard::empty(),
|
BitBoard::empty(),
|
||||||
|
@ -69,6 +87,7 @@ impl Position {
|
||||||
|
|
||||||
Position {
|
Position {
|
||||||
color_to_move: Color::White,
|
color_to_move: Color::White,
|
||||||
|
flags: 0b00001111,
|
||||||
pieces_per_color: [
|
pieces_per_color: [
|
||||||
white_pieces.iter().fold(BitBoard::empty(), |a, b| a | *b),
|
white_pieces.iter().fold(BitBoard::empty(), |a, b| a | *b),
|
||||||
black_pieces.iter().fold(BitBoard::empty(), |a, b| a | *b),
|
black_pieces.iter().fold(BitBoard::empty(), |a, b| a | *b),
|
||||||
|
@ -77,6 +96,36 @@ impl Position {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the player has the right to castle on the given side of
|
||||||
|
/// the board.
|
||||||
|
///
|
||||||
|
/// The right to castle on a particular side of the board is retained as
|
||||||
|
/// long as the player has not moved their king, or the rook on that side of
|
||||||
|
/// the board.
|
||||||
|
///
|
||||||
|
/// The following requirements must also be met:
|
||||||
|
///
|
||||||
|
/// 1. The spaces between the king and rook must be clear
|
||||||
|
/// 2. The king must not be in check
|
||||||
|
/// 3. In the course of castling on that side, the king must not pass
|
||||||
|
/// through a square that an enemy piece can see
|
||||||
|
pub(crate) fn player_has_right_to_castle(&self, color: Color, side: BoardSide) -> bool {
|
||||||
|
(self.flags & (1 << Self::player_has_right_to_castle_flag_offset(color, side))) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_player_has_right_to_castle_flag(&mut self, color: Color, side: BoardSide) {
|
||||||
|
self.flags |= 1 << Self::player_has_right_to_castle_flag_offset(color, side);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_player_has_right_to_castle_flag(&mut self, color: Color, side: BoardSide) {
|
||||||
|
self.flags &= !(1 << Self::player_has_right_to_castle_flag_offset(color, side));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn player_has_right_to_castle_flag_offset(color: Color, side: BoardSide) -> u8 {
|
||||||
|
((color as u8) << 1) + side as u8
|
||||||
|
}
|
||||||
|
|
||||||
pub fn place_piece(&mut self, piece: Piece, square: Square) -> Result<(), PiecePlacementError> {
|
pub fn place_piece(&mut self, piece: Piece, square: Square) -> Result<(), PiecePlacementError> {
|
||||||
let type_bb = self.bitboard_for_piece_mut(piece);
|
let type_bb = self.bitboard_for_piece_mut(piece);
|
||||||
|
|
||||||
|
@ -200,4 +249,36 @@ mod tests {
|
||||||
.place_piece(piece, square)
|
.place_piece(piece, square)
|
||||||
.expect_err("Placed white queen on e4 a second time?!");
|
.expect_err("Placed white queen on e4 a second time?!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn castle_flags() {
|
||||||
|
assert_eq!(
|
||||||
|
Position::player_has_right_to_castle_flag_offset(Color::White, BoardSide::King),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Position::player_has_right_to_castle_flag_offset(Color::White, BoardSide::Queen),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Position::player_has_right_to_castle_flag_offset(Color::Black, BoardSide::King),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Position::player_has_right_to_castle_flag_offset(Color::Black, BoardSide::Queen),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut pos = Position::starting();
|
||||||
|
assert!(pos.player_has_right_to_castle(Color::White, BoardSide::King));
|
||||||
|
assert!(pos.player_has_right_to_castle(Color::White, BoardSide::Queen));
|
||||||
|
assert!(pos.player_has_right_to_castle(Color::Black, BoardSide::King));
|
||||||
|
assert!(pos.player_has_right_to_castle(Color::Black, BoardSide::Queen));
|
||||||
|
|
||||||
|
pos.clear_player_has_right_to_castle_flag(Color::White, BoardSide::Queen);
|
||||||
|
assert!(pos.player_has_right_to_castle(Color::White, BoardSide::King));
|
||||||
|
assert!(!pos.player_has_right_to_castle(Color::White, BoardSide::Queen));
|
||||||
|
assert!(pos.player_has_right_to_castle(Color::Black, BoardSide::King));
|
||||||
|
assert!(pos.player_has_right_to_castle(Color::Black, BoardSide::Queen));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue