[board] Use Castle as the interface type for methods related to castling
Use BoardSide as an internal type for looking up generated bitboards, target squares, etc.
This commit is contained in:
parent
7071f6a742
commit
918b68f300
4 changed files with 71 additions and 37 deletions
|
@ -6,7 +6,7 @@
|
||||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
position::BoardSide,
|
r#move::Castle,
|
||||||
BitBoard, Move, MoveBuilder, Position,
|
BitBoard, Move, MoveBuilder, Position,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ 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, color: Color) -> Option<Move> {
|
fn king_side_castle(position: &Position, color: Color) -> Option<Move> {
|
||||||
if !position.player_has_right_to_castle(color, BoardSide::King) {
|
if !position.player_has_right_to_castle(color, Castle::KingSide) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ impl<'a> KingMoveGenerator<'a> {
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn queen_side_castle(position: &Position, color: Color) -> Option<Move> {
|
fn queen_side_castle(position: &Position, color: Color) -> Option<Move> {
|
||||||
if !position.player_has_right_to_castle(color, BoardSide::Queen) {
|
if !position.player_has_right_to_castle(color, Castle::QueenSide) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use super::position::BoardSide;
|
use super::position::BoardSide;
|
||||||
use crate::piece::Color;
|
use crate::{r#move::Castle, Color};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||||
|
@ -9,20 +9,21 @@ pub(super) struct Flags(u8);
|
||||||
|
|
||||||
impl Flags {
|
impl Flags {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn player_has_right_to_castle_flag_offset(color: Color, side: BoardSide) -> u8 {
|
pub(super) fn player_has_right_to_castle_flag_offset(color: Color, castle: Castle) -> u8 {
|
||||||
((color as u8) << 1) + side as 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 {
|
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, side))) != 0
|
(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) {
|
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, side);
|
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) {
|
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, side));
|
self.0 &= !(1 << Self::player_has_right_to_castle_flag_offset(color, castle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,24 +42,24 @@ impl Default for Flags {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::piece::Color;
|
use crate::{r#move::Castle, Color};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn castle_flags() {
|
fn castle_flags() {
|
||||||
assert_eq!(
|
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
|
0
|
||||||
);
|
);
|
||||||
assert_eq!(
|
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
|
1
|
||||||
);
|
);
|
||||||
assert_eq!(
|
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
|
2
|
||||||
);
|
);
|
||||||
assert_eq!(
|
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
|
3
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -66,21 +67,21 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn defaults() {
|
fn defaults() {
|
||||||
let mut flags: Flags = Default::default();
|
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, Castle::KingSide));
|
||||||
assert!(flags.player_has_right_to_castle(Color::White, BoardSide::Queen));
|
assert!(flags.player_has_right_to_castle(Color::White, Castle::QueenSide));
|
||||||
assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::King));
|
assert!(flags.player_has_right_to_castle(Color::Black, Castle::KingSide));
|
||||||
assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::Queen));
|
assert!(flags.player_has_right_to_castle(Color::Black, Castle::QueenSide));
|
||||||
|
|
||||||
flags.clear_player_has_right_to_castle_flag(Color::White, BoardSide::Queen);
|
flags.clear_player_has_right_to_castle_flag(Color::White, Castle::QueenSide);
|
||||||
assert!(flags.player_has_right_to_castle(Color::White, BoardSide::King));
|
assert!(flags.player_has_right_to_castle(Color::White, Castle::KingSide));
|
||||||
assert!(!flags.player_has_right_to_castle(Color::White, BoardSide::Queen));
|
assert!(!flags.player_has_right_to_castle(Color::White, Castle::QueenSide));
|
||||||
assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::King));
|
assert!(flags.player_has_right_to_castle(Color::Black, Castle::KingSide));
|
||||||
assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::Queen));
|
assert!(flags.player_has_right_to_castle(Color::Black, Castle::QueenSide));
|
||||||
|
|
||||||
flags.set_player_has_right_to_castle_flag(Color::White, BoardSide::Queen);
|
flags.set_player_has_right_to_castle_flag(Color::White, Castle::QueenSide);
|
||||||
assert!(flags.player_has_right_to_castle(Color::White, BoardSide::King));
|
assert!(flags.player_has_right_to_castle(Color::White, Castle::KingSide));
|
||||||
assert!(flags.player_has_right_to_castle(Color::White, BoardSide::Queen));
|
assert!(flags.player_has_right_to_castle(Color::White, Castle::QueenSide));
|
||||||
assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::King));
|
assert!(flags.player_has_right_to_castle(Color::Black, Castle::KingSide));
|
||||||
assert!(flags.player_has_right_to_castle(Color::Black, BoardSide::Queen));
|
assert!(flags.player_has_right_to_castle(Color::Black, Castle::QueenSide));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
||||||
move_generator::Moves,
|
move_generator::Moves,
|
||||||
piece::{Color, Piece, PlacedPiece, Shape},
|
piece::{Color, Piece, PlacedPiece, Shape},
|
||||||
position::DiagramFormatter,
|
position::DiagramFormatter,
|
||||||
|
r#move::Castle,
|
||||||
sight::Sight,
|
sight::Sight,
|
||||||
BitBoard, Move, Square,
|
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
|
/// player's king starts on. Queenside is the side of the board the player's
|
||||||
/// queen starts on.
|
/// queen starts on.
|
||||||
pub(crate) enum BoardSide {
|
pub(crate) enum BoardSide {
|
||||||
King,
|
King = 0,
|
||||||
Queen,
|
Queen = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Castle> for BoardSide {
|
||||||
|
fn from(value: Castle) -> Self {
|
||||||
|
match value {
|
||||||
|
Castle::KingSide => BoardSide::King,
|
||||||
|
Castle::QueenSide => BoardSide::Queen,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[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
|
/// 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
|
/// long as the player has not moved their king, or the rook on that side of
|
||||||
/// the board.
|
/// 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
|
/// 1. The spaces between the king and rook must be clear
|
||||||
/// 2. The king must not be in check
|
/// 2. The king must not be in check
|
||||||
/// 3. In the course of castling on that side, the king must not pass
|
/// 3. In the course of castling on that side, the king must not pass
|
||||||
/// through a square that an enemy piece can see
|
/// through a square that an enemy piece can see
|
||||||
pub(crate) fn player_has_right_to_castle(&self, color: Color, side: BoardSide) -> bool {
|
pub(crate) fn player_can_castle(&self, player: Color, castle: Castle) -> bool {
|
||||||
self.flags.player_has_right_to_castle(color, side)
|
if !self.player_has_right_to_castle(player, castle.into()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn moves(&self) -> Moves {
|
pub fn moves(&self) -> Moves {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
|
use crate::{position::BoardSide, r#move::Castle, Color};
|
||||||
use std::{fmt, str::FromStr};
|
use std::{fmt, str::FromStr};
|
||||||
|
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
|
@ -157,12 +158,23 @@ impl Square {
|
||||||
impl Square {
|
impl Square {
|
||||||
pub(crate) const KING_STARTING_SQUARES: [Square; 2] = [Square::E1, Square::E8];
|
pub(crate) const KING_STARTING_SQUARES: [Square; 2] = [Square::E1, Square::E8];
|
||||||
pub(crate) const KING_CASTLE_TARGET_SQUARES: [[Square; 2]; 2] =
|
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<Square, ParseSquareError> {
|
pub fn from_algebraic_str(s: &str) -> Result<Square, ParseSquareError> {
|
||||||
s.parse()
|
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<Square> {
|
pub fn neighbor(self, direction: Direction) -> Option<Square> {
|
||||||
match direction {
|
match direction {
|
||||||
Direction::North => Square::try_index(self as usize + 8),
|
Direction::North => Square::try_index(self as usize + 8),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue