[board, core, moves, position] Implement castling
Implement a new method on Position that evaluates whether the active color can castle on a given wing of the board. Then, implement making a castling move in the position. Make a new Wing enum in the core crate to specify kingside or queenside. Replace the Castle enum from the board crate with this one. This caused a lot of churn... Along the way fix a bunch of tests. Note: there's still no way to actually make a castling move in explorer.
This commit is contained in:
parent
6816e350eb
commit
0c1863acb9
18 changed files with 499 additions and 258 deletions
|
@ -1,31 +1,32 @@
|
|||
use chessfriend_bitboard::BitBoard;
|
||||
use chessfriend_core::{Color, Square};
|
||||
use chessfriend_core::{Color, Square, Wing};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Parameters {
|
||||
/// Origin squares of the king and rook.
|
||||
origin: Squares,
|
||||
pub origin: Squares,
|
||||
|
||||
/// Target or destination squares for the king and rook.
|
||||
target: Squares,
|
||||
pub target: Squares,
|
||||
|
||||
/// The set of squares that must be clear of any pieces in order to perform
|
||||
/// this castle.
|
||||
clear: BitBoard,
|
||||
pub 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,
|
||||
pub check: BitBoard,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct Squares {
|
||||
pub 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] = [
|
||||
pub(crate) const BY_COLOR: [[Self; Wing::NUM]; Color::NUM] = [
|
||||
[
|
||||
Parameters {
|
||||
origin: Squares {
|
||||
|
@ -80,31 +81,8 @@ 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
|
||||
#[must_use]
|
||||
pub fn get(color: Color, wing: Wing) -> &'static Parameters {
|
||||
&Self::BY_COLOR[color as usize][wing as usize]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use super::Castle;
|
||||
use chessfriend_core::Color;
|
||||
use chessfriend_core::{Color, Wing};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
|
@ -13,16 +12,16 @@ impl Rights {
|
|||
/// as long as they have not moved their king, or the rook on that side of
|
||||
/// the board.
|
||||
#[must_use]
|
||||
pub fn color_has_right(self, color: Color, castle: Castle) -> bool {
|
||||
(self.0 & (1 << Self::flag_offset(color, castle))) != 0
|
||||
pub fn color_has_right(self, color: Color, wing: Wing) -> bool {
|
||||
(self.0 & (1 << Self::flag_offset(color, wing))) != 0
|
||||
}
|
||||
|
||||
pub fn grant(&mut self, color: Color, castle: Castle) {
|
||||
self.0 |= 1 << Self::flag_offset(color, castle);
|
||||
pub fn grant(&mut self, color: Color, wing: Wing) {
|
||||
self.0 |= 1 << Self::flag_offset(color, wing);
|
||||
}
|
||||
|
||||
pub fn revoke(&mut self, color: Color, castle: Castle) {
|
||||
self.0 &= !(1 << Self::flag_offset(color, castle));
|
||||
pub fn revoke(&mut self, color: Color, wing: Wing) {
|
||||
self.0 &= !(1 << Self::flag_offset(color, wing));
|
||||
}
|
||||
|
||||
/// Revoke castling rights for all colors and all sides of the board.
|
||||
|
@ -32,8 +31,8 @@ impl Rights {
|
|||
}
|
||||
|
||||
impl Rights {
|
||||
fn flag_offset(color: Color, castle: Castle) -> usize {
|
||||
((color as usize) << 1) + castle as usize
|
||||
fn flag_offset(color: Color, wing: Wing) -> usize {
|
||||
((color as usize) << 1) + wing as usize
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,30 +54,30 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn bitfield_offsets() {
|
||||
assert_eq!(Rights::flag_offset(Color::White, Castle::KingSide), 0);
|
||||
assert_eq!(Rights::flag_offset(Color::White, Castle::QueenSide), 1);
|
||||
assert_eq!(Rights::flag_offset(Color::Black, Castle::KingSide), 2);
|
||||
assert_eq!(Rights::flag_offset(Color::Black, Castle::QueenSide), 3);
|
||||
assert_eq!(Rights::flag_offset(Color::White, Wing::KingSide), 0);
|
||||
assert_eq!(Rights::flag_offset(Color::White, Wing::QueenSide), 1);
|
||||
assert_eq!(Rights::flag_offset(Color::Black, Wing::KingSide), 2);
|
||||
assert_eq!(Rights::flag_offset(Color::Black, Wing::QueenSide), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_rights() {
|
||||
let mut rights = Rights::default();
|
||||
assert!(rights.color_has_right(Color::White, Castle::KingSide));
|
||||
assert!(rights.color_has_right(Color::White, Castle::QueenSide));
|
||||
assert!(rights.color_has_right(Color::Black, Castle::KingSide));
|
||||
assert!(rights.color_has_right(Color::Black, Castle::QueenSide));
|
||||
assert!(rights.color_has_right(Color::White, Wing::KingSide));
|
||||
assert!(rights.color_has_right(Color::White, Wing::QueenSide));
|
||||
assert!(rights.color_has_right(Color::Black, Wing::KingSide));
|
||||
assert!(rights.color_has_right(Color::Black, Wing::QueenSide));
|
||||
|
||||
rights.revoke(Color::White, Castle::QueenSide);
|
||||
assert!(rights.color_has_right(Color::White, Castle::KingSide));
|
||||
assert!(!rights.color_has_right(Color::White, Castle::QueenSide));
|
||||
assert!(rights.color_has_right(Color::Black, Castle::KingSide));
|
||||
assert!(rights.color_has_right(Color::Black, Castle::QueenSide));
|
||||
rights.revoke(Color::White, Wing::QueenSide);
|
||||
assert!(rights.color_has_right(Color::White, Wing::KingSide));
|
||||
assert!(!rights.color_has_right(Color::White, Wing::QueenSide));
|
||||
assert!(rights.color_has_right(Color::Black, Wing::KingSide));
|
||||
assert!(rights.color_has_right(Color::Black, Wing::QueenSide));
|
||||
|
||||
rights.grant(Color::White, Castle::QueenSide);
|
||||
assert!(rights.color_has_right(Color::White, Castle::KingSide));
|
||||
assert!(rights.color_has_right(Color::White, Castle::QueenSide));
|
||||
assert!(rights.color_has_right(Color::Black, Castle::KingSide));
|
||||
assert!(rights.color_has_right(Color::Black, Castle::QueenSide));
|
||||
rights.grant(Color::White, Wing::QueenSide);
|
||||
assert!(rights.color_has_right(Color::White, Wing::KingSide));
|
||||
assert!(rights.color_has_right(Color::White, Wing::QueenSide));
|
||||
assert!(rights.color_has_right(Color::Black, Wing::KingSide));
|
||||
assert!(rights.color_has_right(Color::Black, Wing::QueenSide));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue