diff --git a/board/src/move_generator/king.rs b/board/src/move_generator/king.rs index be0749b..b3500fd 100644 --- a/board/src/move_generator/king.rs +++ b/board/src/move_generator/king.rs @@ -6,7 +6,7 @@ use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet}; use crate::{ piece::{Color, Piece, PlacedPiece}, - position::BoardSide, + r#move::Castle, BitBoard, Move, MoveBuilder, Position, }; @@ -17,7 +17,7 @@ move_generator_declaration!(KingMoveGenerator, getters); impl<'a> KingMoveGenerator<'a> { #[allow(unused_variables)] fn king_side_castle(position: &Position, color: Color) -> Option { - if !position.player_has_right_to_castle(color, BoardSide::King) { + if !position.player_has_right_to_castle(color, Castle::KingSide) { return None; } @@ -27,7 +27,7 @@ impl<'a> KingMoveGenerator<'a> { #[allow(unused_variables)] fn queen_side_castle(position: &Position, color: Color) -> Option { - if !position.player_has_right_to_castle(color, BoardSide::Queen) { + if !position.player_has_right_to_castle(color, Castle::QueenSide) { return None; } diff --git a/board/src/position/flags.rs b/board/src/position/flags.rs index f434f21..8bc0550 100644 --- a/board/src/position/flags.rs +++ b/board/src/position/flags.rs @@ -1,7 +1,7 @@ // Eryn Wells use super::position::BoardSide; -use crate::piece::Color; +use crate::{r#move::Castle, Color}; use std::fmt; #[derive(Clone, Copy, Eq, Hash, PartialEq)] @@ -9,20 +9,21 @@ pub(super) struct Flags(u8); impl Flags { #[inline] - pub(super) fn player_has_right_to_castle_flag_offset(color: Color, side: BoardSide) -> u8 { - ((color as u8) << 1) + side as u8 + pub(super) fn player_has_right_to_castle_flag_offset(color: Color, castle: Castle) -> u8 { + let board_side: BoardSide = castle.into(); + ((color as u8) << 1) + board_side as u8 } - pub(super) fn player_has_right_to_castle(&self, color: Color, side: BoardSide) -> bool { - (self.0 & (1 << Self::player_has_right_to_castle_flag_offset(color, side))) != 0 + pub(super) fn player_has_right_to_castle(&self, color: Color, castle: Castle) -> bool { + (self.0 & (1 << Self::player_has_right_to_castle_flag_offset(color, castle))) != 0 } - pub(super) fn set_player_has_right_to_castle_flag(&mut self, color: Color, side: BoardSide) { - self.0 |= 1 << Self::player_has_right_to_castle_flag_offset(color, side); + pub(super) fn set_player_has_right_to_castle_flag(&mut self, color: Color, castle: Castle) { + self.0 |= 1 << Self::player_has_right_to_castle_flag_offset(color, castle); } - pub(super) fn clear_player_has_right_to_castle_flag(&mut self, color: Color, side: BoardSide) { - self.0 &= !(1 << Self::player_has_right_to_castle_flag_offset(color, side)); + pub(super) fn clear_player_has_right_to_castle_flag(&mut self, color: Color, castle: Castle) { + self.0 &= !(1 << Self::player_has_right_to_castle_flag_offset(color, castle)); } } @@ -41,24 +42,24 @@ impl Default for Flags { #[cfg(test)] mod tests { use super::*; - use crate::piece::Color; + use crate::{r#move::Castle, Color}; #[test] fn castle_flags() { assert_eq!( - Flags::player_has_right_to_castle_flag_offset(Color::White, BoardSide::King), + Flags::player_has_right_to_castle_flag_offset(Color::White, Castle::KingSide), 0 ); assert_eq!( - Flags::player_has_right_to_castle_flag_offset(Color::White, BoardSide::Queen), + Flags::player_has_right_to_castle_flag_offset(Color::White, Castle::QueenSide), 1 ); assert_eq!( - Flags::player_has_right_to_castle_flag_offset(Color::Black, BoardSide::King), + Flags::player_has_right_to_castle_flag_offset(Color::Black, Castle::KingSide), 2 ); assert_eq!( - Flags::player_has_right_to_castle_flag_offset(Color::Black, BoardSide::Queen), + Flags::player_has_right_to_castle_flag_offset(Color::Black, Castle::QueenSide), 3 ); } @@ -66,21 +67,21 @@ mod tests { #[test] fn defaults() { let mut flags: Flags = Default::default(); - assert!(flags.player_has_right_to_castle(Color::White, BoardSide::King)); - assert!(flags.player_has_right_to_castle(Color::White, BoardSide::Queen)); - assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::King)); - assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::Queen)); + assert!(flags.player_has_right_to_castle(Color::White, Castle::KingSide)); + assert!(flags.player_has_right_to_castle(Color::White, Castle::QueenSide)); + assert!(flags.player_has_right_to_castle(Color::Black, Castle::KingSide)); + assert!(flags.player_has_right_to_castle(Color::Black, Castle::QueenSide)); - flags.clear_player_has_right_to_castle_flag(Color::White, BoardSide::Queen); - assert!(flags.player_has_right_to_castle(Color::White, BoardSide::King)); - assert!(!flags.player_has_right_to_castle(Color::White, BoardSide::Queen)); - assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::King)); - assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::Queen)); + flags.clear_player_has_right_to_castle_flag(Color::White, Castle::QueenSide); + assert!(flags.player_has_right_to_castle(Color::White, Castle::KingSide)); + assert!(!flags.player_has_right_to_castle(Color::White, Castle::QueenSide)); + assert!(flags.player_has_right_to_castle(Color::Black, Castle::KingSide)); + assert!(flags.player_has_right_to_castle(Color::Black, Castle::QueenSide)); - flags.set_player_has_right_to_castle_flag(Color::White, BoardSide::Queen); - assert!(flags.player_has_right_to_castle(Color::White, BoardSide::King)); - assert!(flags.player_has_right_to_castle(Color::White, BoardSide::Queen)); - assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::King)); - assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::Queen)); + flags.set_player_has_right_to_castle_flag(Color::White, Castle::QueenSide); + assert!(flags.player_has_right_to_castle(Color::White, Castle::KingSide)); + assert!(flags.player_has_right_to_castle(Color::White, Castle::QueenSide)); + assert!(flags.player_has_right_to_castle(Color::Black, Castle::KingSide)); + assert!(flags.player_has_right_to_castle(Color::Black, Castle::QueenSide)); } } diff --git a/board/src/position/position.rs b/board/src/position/position.rs index c2cb5dc..2ee5564 100644 --- a/board/src/position/position.rs +++ b/board/src/position/position.rs @@ -5,6 +5,7 @@ use crate::{ move_generator::Moves, piece::{Color, Piece, PlacedPiece, Shape}, position::DiagramFormatter, + r#move::Castle, sight::Sight, BitBoard, Move, Square, }; @@ -14,8 +15,17 @@ use std::{cell::OnceCell, fmt}; /// player's king starts on. Queenside is the side of the board the player's /// queen starts on. pub(crate) enum BoardSide { - King, - Queen, + King = 0, + Queen = 1, +} + +impl From for BoardSide { + fn from(value: Castle) -> Self { + match value { + Castle::KingSide => BoardSide::King, + Castle::QueenSide => BoardSide::Queen, + } + } } #[derive(Clone, Debug, Eq, PartialEq)] @@ -77,15 +87,26 @@ impl Position { /// 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. + pub(crate) fn player_has_right_to_castle(&self, color: Color, castle: Castle) -> bool { + self.flags.player_has_right_to_castle(color, castle) + } + + /// Returns `true` if the player is able to castle on the given side of the board. /// - /// The following requirements must also be met: + /// The following requirements must be met: /// + /// 1. The player must still have the right to castle on that side of the + /// board. The king and rook involved in the castle must not have moved. /// 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.player_has_right_to_castle(color, side) + pub(crate) fn player_can_castle(&self, player: Color, castle: Castle) -> bool { + if !self.player_has_right_to_castle(player, castle.into()) { + return false; + } + + true } pub fn moves(&self) -> Moves { diff --git a/board/src/square.rs b/board/src/square.rs index 0ad9d09..b04aede 100644 --- a/board/src/square.rs +++ b/board/src/square.rs @@ -1,5 +1,6 @@ // Eryn Wells +use crate::{position::BoardSide, r#move::Castle, Color}; use std::{fmt, str::FromStr}; pub enum Direction { @@ -157,12 +158,23 @@ impl Square { impl Square { pub(crate) const KING_STARTING_SQUARES: [Square; 2] = [Square::E1, Square::E8]; pub(crate) const KING_CASTLE_TARGET_SQUARES: [[Square; 2]; 2] = - [[Square::C1, Square::G1], [Square::C8, Square::G8]]; + [[Square::G1, Square::C1], [Square::G8, Square::C8]]; + pub(crate) const ROOK_CASTLE_TARGET_SQUARES: [[Square; 2]; 2] = + [[Square::F1, Square::D1], [Square::F8, Square::D8]]; pub fn from_algebraic_str(s: &str) -> Result { s.parse() } + pub fn king_castle_target(player: Color, castle: Castle) -> Square { + let board_side: BoardSide = castle.into(); + Self::KING_CASTLE_TARGET_SQUARES[player as usize][board_side as usize] + } + + pub fn rook_castle_target(player: Color, castle: Castle) -> Square { + let board_side: BoardSide = castle.into(); + Self::ROOK_CASTLE_TARGET_SQUARES[player as usize][board_side as usize] + } pub fn neighbor(self, direction: Direction) -> Option { match direction { Direction::North => Square::try_index(self as usize + 8),