use core::fmt;
use core::str::FromStr;
use crate::{BitBoard, Color, File, Square};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug, Hash)]
pub struct CastleRights(u8);
impl FromStr for CastleRights {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut rights: u8 = 0;
for ch in s.chars() {
match ch {
'K' => rights |= CASTLE_WK_MASK,
'Q' => rights |= CASTLE_WQ_MASK,
'k' => rights |= CASTLE_BK_MASK,
'q' => rights |= CASTLE_BQ_MASK,
'-' => {
if s.len() != 1 {
return Err("Invalid format for castling rights");
}
rights = 0;
}
_ => return Err("Invalid character in castling rights"),
}
}
Ok(CastleRights(rights))
}
}
impl fmt::Display for CastleRights {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut has_rights: bool = false;
if self.0 & CASTLE_WK_MASK != 0 {
write!(f, "K")?;
has_rights = true;
};
if self.0 & CASTLE_WQ_MASK != 0 {
write!(f, "Q")?;
has_rights = true;
};
if self.0 & CASTLE_BK_MASK != 0 {
write!(f, "k")?;
has_rights = true;
};
if self.0 & CASTLE_BQ_MASK != 0 {
write!(f, "q")?;
has_rights = true;
};
if !has_rights {
write!(f, "-")?;
};
Ok(())
}
}
const CASTLE_WK_MASK: u8 = 0b1000;
const CASTLE_WQ_MASK: u8 = 0b0100;
const CASTLE_BK_MASK: u8 = 0b0010;
const CASTLE_BQ_MASK: u8 = 0b0001;
const KINGSIDE_CASTLE: [u8; 2] = [CASTLE_WK_MASK, CASTLE_BK_MASK];
const QUEENSIDE_CASTLE: [u8; 2] = [CASTLE_WQ_MASK, CASTLE_BQ_MASK];
const ALL_CASTLE: u8 = 0b1111;
const NOT_WK_RIGHTS: u8 = ALL_CASTLE ^ CASTLE_WK_MASK;
const NOT_WQ_RIGHTS: u8 = ALL_CASTLE ^ CASTLE_WQ_MASK;
const NOT_BK_RIGHTS: u8 = ALL_CASTLE ^ CASTLE_BK_MASK;
const NOT_BQ_RIGHTS: u8 = ALL_CASTLE ^ CASTLE_BQ_MASK;
const NOT_WHITE_RIGHTS: u8 = NOT_WK_RIGHTS & NOT_WQ_RIGHTS;
const NOT_BLACK_RIGHTS: u8 = NOT_BK_RIGHTS & NOT_BQ_RIGHTS;
pub(crate) const KING_SIDE: usize = 0;
pub(crate) const QUEEN_SIDE: usize = 1;
pub(crate) const SOURCE: [Square; 2] = [Square::E1, Square::E8];
pub(crate) const MEDIUM: [[Square; 2]; 2] = [[Square::F1, Square::F8], [Square::D1, Square::D8]];
pub(crate) const DESTINATION: [[Square; 2]; 2] =
[[Square::G1, Square::G8], [Square::C1, Square::C8]];
pub(crate) const PRESENCE: [[BitBoard; 2]; 2] = [
[BitBoard(0x0000000000000060), BitBoard(0x6000000000000000)],
[BitBoard(0x000000000000000E), BitBoard(0x0E00000000000000)],
];
const CASTLE_RIGHTS_MASK: [u8; Square::NUM_SQUARES] = [
NOT_WQ_RIGHTS, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, NOT_WHITE_RIGHTS, ALL_CASTLE, ALL_CASTLE, NOT_WK_RIGHTS, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, NOT_BQ_RIGHTS, ALL_CASTLE, ALL_CASTLE, ALL_CASTLE, NOT_BLACK_RIGHTS, ALL_CASTLE, ALL_CASTLE, NOT_BK_RIGHTS, ];
#[inline(always)]
pub(crate) const fn get_rook_castling(dest: Square) -> (Square, Square) {
match dest.file() {
File::C => (dest.left().left(), dest.right()),
File::G => (dest.right(), dest.left()),
_ => unreachable!(),
}
}
impl CastleRights {
pub const NUM_CASTLING_RIGHTS: usize = 16;
#[inline(always)]
pub const fn null() -> Self {
Self(0)
}
#[inline(always)]
pub const fn to_index(self) -> usize {
self.0 as usize
}
#[inline(always)]
pub const fn has_kingside(self, color: Color) -> bool {
self.0 & KINGSIDE_CASTLE[color as usize] != 0
}
#[inline(always)]
pub const fn has_queenside(self, color: Color) -> bool {
self.0 & QUEENSIDE_CASTLE[color as usize] != 0
}
#[inline(always)]
pub const fn update(self, src: Square, dest: Square) -> CastleRights {
CastleRights(
self.0 & CASTLE_RIGHTS_MASK[src.to_index()] & CASTLE_RIGHTS_MASK[dest.to_index()],
)
}
}