[board] Remove Flags struct, replace it with Castle and supporting structs
Encapsulate castling rights within a small module. Castle provides the API to the rest of the board package. Rights encodes the castling rights for each player. Parameters defines castling parameters for each player.
This commit is contained in:
parent
9f2bfc0457
commit
0b100d5f14
5 changed files with 210 additions and 203 deletions
|
@ -1,7 +1,12 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use chessfriend_bitboard::BitBoard;
|
mod parameters;
|
||||||
use chessfriend_core::{Color, Square};
|
mod rights;
|
||||||
|
|
||||||
|
pub use rights::Rights;
|
||||||
|
|
||||||
|
use chessfriend_core::Color;
|
||||||
|
use parameters::Parameters;
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -10,118 +15,10 @@ pub enum Castle {
|
||||||
QueenSide = 1,
|
QueenSide = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Parameters {
|
|
||||||
/// Origin squares of the king and rook.
|
|
||||||
origin: Squares,
|
|
||||||
|
|
||||||
/// Target or destination squares for the king and rook.
|
|
||||||
target: Squares,
|
|
||||||
|
|
||||||
/// The set of squares that must be clear of any pieces in order to perform
|
|
||||||
/// this castle.
|
|
||||||
clear: BitBoard,
|
|
||||||
|
|
||||||
/// The set of squares that must not be attacked (i.e. visible to opposing
|
|
||||||
/// pieces) in order to perform this castle.
|
|
||||||
check: BitBoard,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parameters {
|
|
||||||
pub fn king_origin_square(&self) -> Square {
|
|
||||||
self.origin.king
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rook_origin_square(&self) -> Square {
|
|
||||||
self.origin.rook
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn king_target_square(&self) -> Square {
|
|
||||||
self.target.king
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rook_target_square(&self) -> Square {
|
|
||||||
self.target.rook
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [`BitBoard`] of the squares that must be clear of any piece in order
|
|
||||||
/// to perform this castle move.
|
|
||||||
pub fn clear_squares(&self) -> &BitBoard {
|
|
||||||
&self.clear
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [`BitBoard`] of the squares that must not be visible to opposing
|
|
||||||
/// pieces in order to perform this castle move.
|
|
||||||
pub fn check_squares(&self) -> &BitBoard {
|
|
||||||
&self.check
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Squares {
|
|
||||||
king: Square,
|
|
||||||
rook: Square,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Castle {
|
impl Castle {
|
||||||
pub const ALL: [Castle; 2] = [Castle::KingSide, Castle::QueenSide];
|
pub const ALL: [Castle; 2] = [Castle::KingSide, Castle::QueenSide];
|
||||||
|
|
||||||
/// Parameters for each castling move, organized by color and board-side.
|
|
||||||
const PARAMETERS: [[Parameters; 2]; Color::NUM] = [
|
|
||||||
[
|
|
||||||
Parameters {
|
|
||||||
origin: Squares {
|
|
||||||
king: Square::E1,
|
|
||||||
rook: Square::H1,
|
|
||||||
},
|
|
||||||
target: Squares {
|
|
||||||
king: Square::G1,
|
|
||||||
rook: Square::F1,
|
|
||||||
},
|
|
||||||
clear: BitBoard::new(0b0110_0000),
|
|
||||||
check: BitBoard::new(0b0111_0000),
|
|
||||||
},
|
|
||||||
Parameters {
|
|
||||||
origin: Squares {
|
|
||||||
king: Square::E1,
|
|
||||||
rook: Square::A1,
|
|
||||||
},
|
|
||||||
target: Squares {
|
|
||||||
king: Square::C1,
|
|
||||||
rook: Square::D1,
|
|
||||||
},
|
|
||||||
clear: BitBoard::new(0b0000_1110),
|
|
||||||
check: BitBoard::new(0b0001_1100),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Parameters {
|
|
||||||
origin: Squares {
|
|
||||||
king: Square::E8,
|
|
||||||
rook: Square::H8,
|
|
||||||
},
|
|
||||||
target: Squares {
|
|
||||||
king: Square::G8,
|
|
||||||
rook: Square::F8,
|
|
||||||
},
|
|
||||||
clear: BitBoard::new(0b0110_0000 << (8 * 7)),
|
|
||||||
check: BitBoard::new(0b0111_0000 << (8 * 7)),
|
|
||||||
},
|
|
||||||
Parameters {
|
|
||||||
origin: Squares {
|
|
||||||
king: Square::E8,
|
|
||||||
rook: Square::A8,
|
|
||||||
},
|
|
||||||
target: Squares {
|
|
||||||
king: Square::C8,
|
|
||||||
rook: Square::D8,
|
|
||||||
},
|
|
||||||
clear: BitBoard::new(0b0000_1110 << (8 * 7)),
|
|
||||||
check: BitBoard::new(0b0001_1100 << (8 * 7)),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
pub fn parameters(self, color: Color) -> &'static Parameters {
|
pub fn parameters(self, color: Color) -> &'static Parameters {
|
||||||
&Castle::PARAMETERS[color as usize][self as usize]
|
&Parameters::BY_COLOR[color as usize][self as usize]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
110
board/src/castle/parameters.rs
Normal file
110
board/src/castle/parameters.rs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
use chessfriend_core::{Color, Square};
|
||||||
|
|
||||||
|
pub struct Parameters {
|
||||||
|
/// Origin squares of the king and rook.
|
||||||
|
origin: Squares,
|
||||||
|
|
||||||
|
/// Target or destination squares for the king and rook.
|
||||||
|
target: Squares,
|
||||||
|
|
||||||
|
/// The set of squares that must be clear of any pieces in order to perform
|
||||||
|
/// this castle.
|
||||||
|
clear: BitBoard,
|
||||||
|
|
||||||
|
/// The set of squares that must not be attacked (i.e. visible to opposing
|
||||||
|
/// pieces) in order to perform this castle.
|
||||||
|
check: BitBoard,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct Squares {
|
||||||
|
pub king: Square,
|
||||||
|
pub rook: Square,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parameters {
|
||||||
|
/// Parameters for each castling move, organized by color and board-side.
|
||||||
|
pub(super) const BY_COLOR: [[Self; 2]; Color::NUM] = [
|
||||||
|
[
|
||||||
|
Parameters {
|
||||||
|
origin: Squares {
|
||||||
|
king: Square::E1,
|
||||||
|
rook: Square::H1,
|
||||||
|
},
|
||||||
|
target: Squares {
|
||||||
|
king: Square::G1,
|
||||||
|
rook: Square::F1,
|
||||||
|
},
|
||||||
|
clear: BitBoard::new(0b0110_0000),
|
||||||
|
check: BitBoard::new(0b0111_0000),
|
||||||
|
},
|
||||||
|
Parameters {
|
||||||
|
origin: Squares {
|
||||||
|
king: Square::E1,
|
||||||
|
rook: Square::A1,
|
||||||
|
},
|
||||||
|
target: Squares {
|
||||||
|
king: Square::C1,
|
||||||
|
rook: Square::D1,
|
||||||
|
},
|
||||||
|
clear: BitBoard::new(0b0000_1110),
|
||||||
|
check: BitBoard::new(0b0001_1100),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Parameters {
|
||||||
|
origin: Squares {
|
||||||
|
king: Square::E8,
|
||||||
|
rook: Square::H8,
|
||||||
|
},
|
||||||
|
target: Squares {
|
||||||
|
king: Square::G8,
|
||||||
|
rook: Square::F8,
|
||||||
|
},
|
||||||
|
clear: BitBoard::new(0b0110_0000 << (8 * 7)),
|
||||||
|
check: BitBoard::new(0b0111_0000 << (8 * 7)),
|
||||||
|
},
|
||||||
|
Parameters {
|
||||||
|
origin: Squares {
|
||||||
|
king: Square::E8,
|
||||||
|
rook: Square::A8,
|
||||||
|
},
|
||||||
|
target: Squares {
|
||||||
|
king: Square::C8,
|
||||||
|
rook: Square::D8,
|
||||||
|
},
|
||||||
|
clear: BitBoard::new(0b0000_1110 << (8 * 7)),
|
||||||
|
check: BitBoard::new(0b0001_1100 << (8 * 7)),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn king_origin_square(&self) -> Square {
|
||||||
|
self.origin.king
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rook_origin_square(&self) -> Square {
|
||||||
|
self.origin.rook
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn king_target_square(&self) -> Square {
|
||||||
|
self.target.king
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rook_target_square(&self) -> Square {
|
||||||
|
self.target.rook
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [`BitBoard`] of the squares that must be clear of any piece in order
|
||||||
|
/// to perform this castle move.
|
||||||
|
pub fn clear_squares(&self) -> &BitBoard {
|
||||||
|
&self.clear
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [`BitBoard`] of the squares that must not be visible to opposing
|
||||||
|
/// pieces in order to perform this castle move.
|
||||||
|
pub fn check_squares(&self) -> &BitBoard {
|
||||||
|
&self.check
|
||||||
|
}
|
||||||
|
}
|
92
board/src/castle/rights.rs
Normal file
92
board/src/castle/rights.rs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
use super::Castle;
|
||||||
|
use chessfriend_core::Color;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||||
|
pub struct Rights(u8);
|
||||||
|
|
||||||
|
impl Rights {
|
||||||
|
/// Returns `true` if the player has the right to castle on the given side
|
||||||
|
/// of the board.
|
||||||
|
///
|
||||||
|
/// A player retains the right to castle on a particular side of the board
|
||||||
|
/// as long as they have not moved their king, or the rook on that side of
|
||||||
|
/// the board.
|
||||||
|
pub 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 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 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_all(&mut self) {
|
||||||
|
self.0 &= 0b1111_1100;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _player_has_right_to_castle_flag_offset(color: Color, castle: Castle) -> usize {
|
||||||
|
((color as usize) << 1) & castle as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Rights {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "Flags({:08b})", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Rights {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0b0000_1111)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn castling_rights() {
|
||||||
|
assert_eq!(
|
||||||
|
Rights::_player_has_right_to_castle_flag_offset(Color::White, Castle::KingSide),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Rights::_player_has_right_to_castle_flag_offset(Color::White, Castle::QueenSide),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Rights::_player_has_right_to_castle_flag_offset(Color::Black, Castle::KingSide),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Rights::_player_has_right_to_castle_flag_offset(Color::Black, Castle::QueenSide),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_rights() {
|
||||||
|
let mut rights = Rights::default();
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::White, Castle::KingSide));
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::White, Castle::QueenSide));
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::Black, Castle::KingSide));
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::Black, Castle::QueenSide));
|
||||||
|
|
||||||
|
rights.clear_player_has_right_to_castle_flag(Color::White, Castle::QueenSide);
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::White, Castle::KingSide));
|
||||||
|
assert!(!rights.player_has_right_to_castle(Color::White, Castle::QueenSide));
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::Black, Castle::KingSide));
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::Black, Castle::QueenSide));
|
||||||
|
|
||||||
|
rights.set_player_has_right_to_castle_flag(Color::White, Castle::QueenSide);
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::White, Castle::KingSide));
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::White, Castle::QueenSide));
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::Black, Castle::KingSide));
|
||||||
|
assert!(rights.player_has_right_to_castle(Color::Black, Castle::QueenSide));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,90 +0,0 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
|
||||||
|
|
||||||
use crate::Castle;
|
|
||||||
use chessfriend_core::Color;
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
|
||||||
pub struct Flags(u8);
|
|
||||||
|
|
||||||
impl Flags {
|
|
||||||
#[inline]
|
|
||||||
fn player_has_right_to_castle_flag_offset(color: Color, castle: Castle) -> usize {
|
|
||||||
((color as usize) << 1) + castle as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
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, 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, castle: Castle) {
|
|
||||||
self.0 &= !(1 << Self::player_has_right_to_castle_flag_offset(color, castle));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn clear_all_castling_rights(&mut self) {
|
|
||||||
self.0 &= 0b1111_1100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Flags {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "Flags({:08b})", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Flags {
|
|
||||||
fn default() -> Self {
|
|
||||||
Flags(0b0000_1111)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn castle_flags() {
|
|
||||||
assert_eq!(
|
|
||||||
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, Castle::QueenSide),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
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, Castle::QueenSide),
|
|
||||||
3
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn defaults() {
|
|
||||||
let mut flags: Flags = Default::default();
|
|
||||||
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, 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, 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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ pub mod castle;
|
||||||
pub mod display;
|
pub mod display;
|
||||||
pub mod en_passant;
|
pub mod en_passant;
|
||||||
pub mod fen;
|
pub mod fen;
|
||||||
pub mod flags;
|
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
pub mod move_counter;
|
pub mod move_counter;
|
||||||
|
|
||||||
|
@ -17,6 +16,5 @@ pub use builder::Builder;
|
||||||
|
|
||||||
use castle::Castle;
|
use castle::Castle;
|
||||||
use en_passant::EnPassant;
|
use en_passant::EnPassant;
|
||||||
use flags::Flags;
|
|
||||||
use move_counter::MoveCounter;
|
use move_counter::MoveCounter;
|
||||||
use piece_sets::PieceSet;
|
use piece_sets::PieceSet;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue