use std::hint::unreachable_unchecked;
use crate::bitboard::{BitBoard, EMPTY};
use crate::color::Color;
use crate::file::File;
use crate::square::Square;
use crate::magic::{KINGSIDE_CASTLE_SQUARES, QUEENSIDE_CASTLE_SQUARES};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug, Hash)]
pub enum CastleRights {
NoRights,
KingSide,
QueenSide,
Both,
}
pub const NUM_CASTLE_RIGHTS: usize = 4;
pub const ALL_CASTLE_RIGHTS: [CastleRights; NUM_CASTLE_RIGHTS] = [
CastleRights::NoRights,
CastleRights::KingSide,
CastleRights::QueenSide,
CastleRights::Both,
];
const CASTLES_PER_SQUARE: [[u8; 64]; 2] = [
[
2, 0, 0, 0, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 1,
],
];
impl CastleRights {
pub fn has_kingside(&self) -> bool {
self.to_index() & 1 == 1
}
pub fn has_queenside(&self) -> bool {
self.to_index() & 2 == 2
}
pub fn square_to_castle_rights(color: Color, sq: Square) -> CastleRights {
CastleRights::from_index(unsafe {
*CASTLES_PER_SQUARE
.get_unchecked(color.to_index())
.get_unchecked(sq.to_index())
} as usize)
}
pub fn kingside_squares(&self, color: Color) -> BitBoard {
unsafe { *KINGSIDE_CASTLE_SQUARES.get_unchecked(color.to_index()) }
}
pub fn queenside_squares(&self, color: Color) -> BitBoard {
unsafe { *QUEENSIDE_CASTLE_SQUARES.get_unchecked(color.to_index()) }
}
pub fn remove(&self, remove: CastleRights) -> CastleRights {
CastleRights::from_index(self.to_index() & !remove.to_index())
}
pub fn add(&self, add: CastleRights) -> CastleRights {
CastleRights::from_index(self.to_index() | add.to_index())
}
pub fn to_index(&self) -> usize {
*self as usize
}
pub fn from_index(i: usize) -> CastleRights {
match i {
0 => CastleRights::NoRights,
1 => CastleRights::KingSide,
2 => CastleRights::QueenSide,
3 => CastleRights::Both,
_ => unsafe { unreachable_unchecked() },
}
}
pub fn unmoved_rooks(&self, color: Color) -> BitBoard {
match *self {
CastleRights::NoRights => EMPTY,
CastleRights::KingSide => BitBoard::set(color.to_my_backrank(), File::H),
CastleRights::QueenSide => BitBoard::set(color.to_my_backrank(), File::A),
CastleRights::Both => {
BitBoard::set(color.to_my_backrank(), File::A)
^ BitBoard::set(color.to_my_backrank(), File::H)
}
}
}
pub fn to_string(&self, color: Color) -> String {
let result = match *self {
CastleRights::NoRights => "",
CastleRights::KingSide => "k",
CastleRights::QueenSide => "q",
CastleRights::Both => "kq",
};
if color == Color::White {
result.to_uppercase()
} else {
result.to_string()
}
}
pub fn rook_square_to_castle_rights(square: Square) -> CastleRights {
match square.get_file() {
File::A => CastleRights::QueenSide,
File::H => CastleRights::KingSide,
_ => unsafe { unreachable_unchecked() },
}
}
}