diff --git a/board/src/moves/king.rs b/board/src/moves/king.rs index 327f138..1d2fe97 100644 --- a/board/src/moves/king.rs +++ b/board/src/moves/king.rs @@ -7,9 +7,9 @@ use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet}; use crate::{ bitboard::BitBoard, piece::{Color, Piece, PlacedPiece}, - Move, Position, Square, + position::BoardSide, + Move, Position, }; -use std::collections::BTreeMap; move_generator_declaration!(KingMoveGenerator, struct); move_generator_declaration!(KingMoveGenerator, new); @@ -17,13 +17,21 @@ move_generator_declaration!(KingMoveGenerator, getters); impl<'a> KingMoveGenerator<'a> { #[allow(unused_variables)] - fn king_side_castle(position: &Position) -> Option { + fn king_side_castle(position: &Position, color: Color) -> Option { + if !position.is_castling_allowed(color, BoardSide::King) { + return None; + } + // TODO: Implement king side castle. None } #[allow(unused_variables)] - fn queen_side_castle(position: &Position) -> Option { + fn queen_side_castle(position: &Position, color: Color) -> Option { + if !position.is_castling_allowed(color, BoardSide::Queen) { + return None; + } + // TODO: Implement queen side castle. None } @@ -51,8 +59,8 @@ impl<'pos> MoveGeneratorInternal for KingMoveGenerator<'pos> { let map_to_move = |sq| Move::new(piece, square, sq); - let king_side_castle = Self::king_side_castle(position); - let queen_side_castle = Self::queen_side_castle(position); + let king_side_castle = Self::king_side_castle(position, color); + let queen_side_castle = Self::queen_side_castle(position, color); let quiet_moves = quiet_moves_bb .occupied_squares() .map(map_to_move) diff --git a/board/src/position/mod.rs b/board/src/position/mod.rs index dd7842c..1b9998f 100644 --- a/board/src/position/mod.rs +++ b/board/src/position/mod.rs @@ -1,3 +1,5 @@ +// Eryn Wells + mod diagram_formatter; mod pieces; mod position; @@ -5,3 +7,5 @@ mod position; pub use diagram_formatter::DiagramFormatter; pub use pieces::Pieces; pub use position::Position; + +pub(crate) use position::BoardSide; diff --git a/board/src/position/position.rs b/board/src/position/position.rs index 8868760..32c2aa4 100644 --- a/board/src/position/position.rs +++ b/board/src/position/position.rs @@ -10,10 +10,27 @@ use crate::{ use std::fmt; 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)] pub struct Position { 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. pieces_per_color: [BitBoard; 2], @@ -25,7 +42,8 @@ impl Position { pub fn empty() -> Position { Position { color_to_move: Color::White, - pieces_per_color: [BitBoard::empty(), BitBoard::empty()], + flags: 0b00001111, + pieces_per_color: [BitBoard::empty(); 2], pieces_per_type: [ [ BitBoard::empty(), @@ -69,6 +87,7 @@ impl Position { Position { color_to_move: Color::White, + flags: 0b00001111, pieces_per_color: [ white_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> { let type_bb = self.bitboard_for_piece_mut(piece); @@ -200,4 +249,36 @@ mod tests { .place_piece(piece, square) .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)); + } }