eschac
This commit is contained in:
commit
faccfbc1c5
16 changed files with 5154 additions and 0 deletions
676
src/board.rs
Normal file
676
src/board.rs
Normal file
|
|
@ -0,0 +1,676 @@
|
|||
//! Chessboard vocabulary.
|
||||
|
||||
use crate::bitboard::*;
|
||||
|
||||
macro_rules! container {
|
||||
($a:ident, $b:ident, $n:literal) => {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub(crate) struct $b<T>(pub(crate) [T; $n]);
|
||||
#[allow(unused)]
|
||||
impl<T> $b<T> {
|
||||
#[inline]
|
||||
pub fn new<F>(f: F) -> Self
|
||||
where
|
||||
F: FnMut($a) -> T,
|
||||
{
|
||||
Self($a::all().map(f))
|
||||
}
|
||||
#[inline]
|
||||
pub fn get(&self, k: $a) -> &T {
|
||||
unsafe { self.0.get_unchecked(k as usize) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_mut(&mut self, k: $a) -> &mut T {
|
||||
unsafe { self.0.get_unchecked_mut(k as usize) }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// The players.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum Color {
|
||||
White,
|
||||
Black,
|
||||
}
|
||||
|
||||
container!(Color, ByColor, 2);
|
||||
|
||||
impl Color {
|
||||
#[inline]
|
||||
pub fn all() -> [Self; 2] {
|
||||
[Self::White, Self::Black]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn home_rank(self) -> Rank {
|
||||
match self {
|
||||
Self::White => Rank::First,
|
||||
Self::Black => Rank::Eighth,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn promotion_rank(self) -> Rank {
|
||||
match self {
|
||||
Self::White => Rank::Eighth,
|
||||
Self::Black => Rank::First,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn forward(self) -> Direction {
|
||||
match self {
|
||||
Self::White => Direction::North,
|
||||
Self::Black => Direction::South,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Not for Color {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn not(self) -> Self::Output {
|
||||
match self {
|
||||
Self::Black => Self::White,
|
||||
Self::White => Self::Black,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A column of the board.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum File {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E,
|
||||
F,
|
||||
G,
|
||||
H,
|
||||
}
|
||||
|
||||
container!(File, ByFile, 8);
|
||||
|
||||
impl File {
|
||||
#[inline]
|
||||
pub fn all() -> [Self; 8] {
|
||||
[
|
||||
Self::A,
|
||||
Self::B,
|
||||
Self::C,
|
||||
Self::D,
|
||||
Self::E,
|
||||
Self::F,
|
||||
Self::G,
|
||||
Self::H,
|
||||
]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_char(self) -> char {
|
||||
self.to_ascii() as char
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_char(c: char) -> Option<Self> {
|
||||
Self::from_ascii(c as u8)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_ascii(self) -> u8 {
|
||||
self as u8 + b'a'
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_ascii(c: u8) -> Option<Self> {
|
||||
(c <= b'h')
|
||||
.then(|| c.checked_sub(b'a').map(|i| unsafe { Self::transmute(i) }))
|
||||
.flatten()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn bitboard(self) -> Bitboard {
|
||||
Bitboard(0x0101010101010101 << (self as u8))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn transmute(value: u8) -> Self {
|
||||
debug_assert!(value < 8);
|
||||
std::mem::transmute(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for File {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_char())
|
||||
}
|
||||
}
|
||||
|
||||
/// A row of the board.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum Rank {
|
||||
First,
|
||||
Second,
|
||||
Third,
|
||||
Fourth,
|
||||
Fifth,
|
||||
Sixth,
|
||||
Seventh,
|
||||
Eighth,
|
||||
}
|
||||
|
||||
container!(Rank, ByRank, 8);
|
||||
|
||||
impl Rank {
|
||||
#[inline]
|
||||
pub fn all() -> [Self; 8] {
|
||||
[
|
||||
Self::First,
|
||||
Self::Second,
|
||||
Self::Third,
|
||||
Self::Fourth,
|
||||
Self::Fifth,
|
||||
Self::Sixth,
|
||||
Self::Seventh,
|
||||
Self::Eighth,
|
||||
]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_char(self) -> char {
|
||||
self.to_ascii() as char
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_char(c: char) -> Option<Self> {
|
||||
Self::from_ascii(c as u8)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mirror(self) -> Self {
|
||||
unsafe { Self::transmute(7_u8.unchecked_sub(self as u8)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_ascii(self) -> u8 {
|
||||
self as u8 + b'1'
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_ascii(c: u8) -> Option<Self> {
|
||||
(c <= b'8')
|
||||
.then(|| c.checked_sub(b'1').map(|i| unsafe { Self::transmute(i) }))
|
||||
.flatten()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn bitboard(self) -> Bitboard {
|
||||
Bitboard(0xFF << ((self as u64) << 3))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn transmute(value: u8) -> Self {
|
||||
debug_assert!(value < 8);
|
||||
std::mem::transmute(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Rank {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_char())
|
||||
}
|
||||
}
|
||||
|
||||
/// A square of the board.
|
||||
#[rustfmt::skip]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum Square{
|
||||
A1, B1, C1, D1, E1, F1, G1, H1,
|
||||
A2, B2, C2, D2, E2, F2, G2, H2,
|
||||
A3, B3, C3, D3, E3, F3, G3, H3,
|
||||
A4, B4, C4, D4, E4, F4, G4, H4,
|
||||
A5, B5, C5, D5, E5, F5, G5, H5,
|
||||
A6, B6, C6, D6, E6, F6, G6, H6,
|
||||
A7, B7, C7, D7, E7, F7, G7, H7,
|
||||
A8, B8, C8, D8, E8, F8, G8, H8,
|
||||
}
|
||||
|
||||
container!(Square, BySquare, 64);
|
||||
|
||||
impl Square {
|
||||
#[inline]
|
||||
#[rustfmt::skip]
|
||||
pub fn all() -> [Self; 64] {
|
||||
[
|
||||
Self::A1, Self::B1, Self::C1, Self::D1, Self::E1, Self::F1, Self::G1, Self::H1,
|
||||
Self::A2, Self::B2, Self::C2, Self::D2, Self::E2, Self::F2, Self::G2, Self::H2,
|
||||
Self::A3, Self::B3, Self::C3, Self::D3, Self::E3, Self::F3, Self::G3, Self::H3,
|
||||
Self::A4, Self::B4, Self::C4, Self::D4, Self::E4, Self::F4, Self::G4, Self::H4,
|
||||
Self::A5, Self::B5, Self::C5, Self::D5, Self::E5, Self::F5, Self::G5, Self::H5,
|
||||
Self::A6, Self::B6, Self::C6, Self::D6, Self::E6, Self::F6, Self::G6, Self::H6,
|
||||
Self::A7, Self::B7, Self::C7, Self::D7, Self::E7, Self::F7, Self::G7, Self::H7,
|
||||
Self::A8, Self::B8, Self::C8, Self::D8, Self::E8, Self::F8, Self::G8, Self::H8,
|
||||
]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new(file: File, rank: Rank) -> Self {
|
||||
unsafe { Self::transmute(((rank as u8) << 3) + file as u8) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn file(self) -> File {
|
||||
unsafe { File::transmute((self as u8) & 7) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn rank(self) -> Rank {
|
||||
unsafe { Rank::transmute((self as u8) >> 3) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mirror(self) -> Self {
|
||||
Self::new(self.file(), self.rank().mirror())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn bitboard(self) -> Bitboard {
|
||||
Bitboard(1 << self as u8)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[rustfmt::skip]
|
||||
pub(crate) fn to_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::A1 => "a1", Self::B1 => "b1", Self::C1 => "c1", Self::D1 => "d1", Self::E1 => "e1", Self::F1 => "f1", Self::G1 => "g1", Self::H1 => "h1",
|
||||
Self::A2 => "a2", Self::B2 => "b2", Self::C2 => "c2", Self::D2 => "d2", Self::E2 => "e2", Self::F2 => "f2", Self::G2 => "g2", Self::H2 => "h2",
|
||||
Self::A3 => "a3", Self::B3 => "b3", Self::C3 => "c3", Self::D3 => "d3", Self::E3 => "e3", Self::F3 => "f3", Self::G3 => "g3", Self::H3 => "h3",
|
||||
Self::A4 => "a4", Self::B4 => "b4", Self::C4 => "c4", Self::D4 => "d4", Self::E4 => "e4", Self::F4 => "f4", Self::G4 => "g4", Self::H4 => "h4",
|
||||
Self::A5 => "a5", Self::B5 => "b5", Self::C5 => "c5", Self::D5 => "d5", Self::E5 => "e5", Self::F5 => "f5", Self::G5 => "g5", Self::H5 => "h5",
|
||||
Self::A6 => "a6", Self::B6 => "b6", Self::C6 => "c6", Self::D6 => "d6", Self::E6 => "e6", Self::F6 => "f6", Self::G6 => "g6", Self::H6 => "h6",
|
||||
Self::A7 => "a7", Self::B7 => "b7", Self::C7 => "c7", Self::D7 => "d7", Self::E7 => "e7", Self::F7 => "f7", Self::G7 => "g7", Self::H7 => "h7",
|
||||
Self::A8 => "a8", Self::B8 => "b8", Self::C8 => "c8", Self::D8 => "d8", Self::E8 => "e8", Self::F8 => "f8", Self::G8 => "g8", Self::H8 => "h8",
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_str(s: &str) -> Option<Self> {
|
||||
match s.as_bytes() {
|
||||
[f, r] => Self::from_ascii(&[*f, *r]),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_ascii(s: &[u8; 2]) -> Option<Self> {
|
||||
let [f, r] = *s;
|
||||
Some(Self::new(File::from_ascii(f)?, Rank::from_ascii(r)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn trans(self, direction: Direction) -> Option<Self> {
|
||||
self.check_trans(direction).then(|| unsafe {
|
||||
// SAFETY: condition is checked before doing the translation
|
||||
self.trans_unchecked(direction)
|
||||
})
|
||||
}
|
||||
|
||||
/// SAFETY: the translation must not move the square outside the board
|
||||
#[inline]
|
||||
pub(crate) unsafe fn trans_unchecked(self, direction: Direction) -> Self {
|
||||
debug_assert!(self.check_trans(direction));
|
||||
let i = self as u8;
|
||||
unsafe {
|
||||
Self::transmute(match direction {
|
||||
Direction::East => i.unchecked_add(1),
|
||||
Direction::NorthEast => i.unchecked_add(9),
|
||||
Direction::North => i.unchecked_add(8),
|
||||
Direction::NorthWest => i.unchecked_add(7),
|
||||
Direction::SouthEast => i.unchecked_sub(7),
|
||||
Direction::South => i.unchecked_sub(8),
|
||||
Direction::SouthWest => i.unchecked_sub(9),
|
||||
Direction::West => i.unchecked_sub(1),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `false` if the translation would move the square outside the board
|
||||
#[inline]
|
||||
fn check_trans(self, direction: Direction) -> bool {
|
||||
match direction {
|
||||
Direction::East => self.file() < File::H,
|
||||
Direction::NorthEast => self.file() < File::H && self.rank() < Rank::Eighth,
|
||||
Direction::North => self.rank() < Rank::Eighth,
|
||||
Direction::NorthWest => self.file() > File::A && self.rank() < Rank::Eighth,
|
||||
Direction::SouthEast => self.file() < File::H && self.rank() > Rank::First,
|
||||
Direction::South => self.rank() > Rank::First,
|
||||
Direction::SouthWest => self.file() > File::A && self.rank() > Rank::First,
|
||||
Direction::West => self.file() > File::A,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn transmute(value: u8) -> Self {
|
||||
debug_assert!(value < 64);
|
||||
std::mem::transmute(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Square {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
f.write_str(self.to_str())
|
||||
}
|
||||
}
|
||||
|
||||
/// An error while parsing a [`Square`].
|
||||
#[derive(Debug)]
|
||||
pub struct ParseSquareError;
|
||||
impl std::fmt::Display for ParseSquareError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("invalid square syntax")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for ParseSquareError {}
|
||||
|
||||
impl std::str::FromStr for Square {
|
||||
type Err = ParseSquareError;
|
||||
#[inline]
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::from_str(s).ok_or(ParseSquareError)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
#[rustfmt::skip]
|
||||
pub(crate) enum OptionSquare {
|
||||
_A1, _B1, _C1, _D1, _E1, _F1, _G1, _H1,
|
||||
_A2, _B2, _C2, _D2, _E2, _F2, _G2, _H2,
|
||||
_A3, _B3, _C3, _D3, _E3, _F3, _G3, _H3,
|
||||
_A4, _B4, _C4, _D4, _E4, _F4, _G4, _H4,
|
||||
_A5, _B5, _C5, _D5, _E5, _F5, _G5, _H5,
|
||||
_A6, _B6, _C6, _D6, _E6, _F6, _G6, _H6,
|
||||
_A7, _B7, _C7, _D7, _E7, _F7, _G7, _H7,
|
||||
_A8, _B8, _C8, _D8, _E8, _F8, _G8, _H8,
|
||||
None,
|
||||
}
|
||||
|
||||
impl OptionSquare {
|
||||
#[inline]
|
||||
pub(crate) fn new(square: Option<Square>) -> OptionSquare {
|
||||
match square {
|
||||
Some(square) => Self::from_square(square),
|
||||
None => Self::None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn try_into_square(self) -> Option<Square> {
|
||||
unsafe {
|
||||
match self {
|
||||
Self::None => None,
|
||||
_ => Some(Square::transmute(self as u8)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_square(square: Square) -> Self {
|
||||
unsafe { std::mem::transmute(square) }
|
||||
}
|
||||
}
|
||||
|
||||
/// A type of piece.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum Role {
|
||||
Pawn = 1,
|
||||
Knight,
|
||||
Bishop,
|
||||
Rook,
|
||||
Queen,
|
||||
King,
|
||||
}
|
||||
|
||||
impl Role {
|
||||
#[inline]
|
||||
pub fn all() -> [Self; 6] {
|
||||
[
|
||||
Self::Pawn,
|
||||
Self::Knight,
|
||||
Self::Bishop,
|
||||
Self::Rook,
|
||||
Self::Queen,
|
||||
Self::King,
|
||||
]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_char_uppercase(self) -> char {
|
||||
match self {
|
||||
Self::Pawn => 'P',
|
||||
Self::Knight => 'N',
|
||||
Self::Bishop => 'B',
|
||||
Self::Rook => 'R',
|
||||
Self::Queen => 'Q',
|
||||
Self::King => 'K',
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_char_lowercase(self) -> char {
|
||||
match self {
|
||||
Self::Pawn => 'p',
|
||||
Self::Knight => 'n',
|
||||
Self::Bishop => 'b',
|
||||
Self::Rook => 'r',
|
||||
Self::Queen => 'q',
|
||||
Self::King => 'k',
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_ascii(x: u8) -> Option<Self> {
|
||||
Some(match x {
|
||||
b'p' | b'P' => Self::Pawn,
|
||||
b'n' | b'N' => Self::Knight,
|
||||
b'b' | b'B' => Self::Bishop,
|
||||
b'r' | b'R' => Self::Rook,
|
||||
b'q' | b'Q' => Self::Queen,
|
||||
b'k' | b'K' => Self::King,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn transmute(i: u8) -> Self {
|
||||
debug_assert!(i > 0 && i <= 6, "got {i}");
|
||||
unsafe { std::mem::transmute(i) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct ByRole<T>(pub(crate) [T; 6]);
|
||||
#[allow(unused)]
|
||||
impl<T> ByRole<T> {
|
||||
#[inline]
|
||||
pub fn new<F>(f: F) -> Self
|
||||
where
|
||||
F: FnMut(Role) -> T,
|
||||
{
|
||||
Self(Role::all().map(f))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, kind: Role) -> &T {
|
||||
unsafe { self.0.get_unchecked((kind as usize).unchecked_sub(1)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_mut(&mut self, kind: Role) -> &mut T {
|
||||
unsafe { self.0.get_unchecked_mut((kind as usize).unchecked_sub(1)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByRole<T>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
#[inline]
|
||||
pub(crate) fn pawn(&self) -> T {
|
||||
*self.get(Role::Pawn)
|
||||
}
|
||||
#[inline]
|
||||
pub(crate) fn knight(&self) -> T {
|
||||
*self.get(Role::Knight)
|
||||
}
|
||||
#[inline]
|
||||
pub(crate) fn bishop(&self) -> T {
|
||||
*self.get(Role::Bishop)
|
||||
}
|
||||
#[inline]
|
||||
pub(crate) fn rook(&self) -> T {
|
||||
*self.get(Role::Rook)
|
||||
}
|
||||
#[inline]
|
||||
pub(crate) fn queen(&self) -> T {
|
||||
*self.get(Role::Queen)
|
||||
}
|
||||
#[inline]
|
||||
pub(crate) fn king(&self) -> T {
|
||||
*self.get(Role::King)
|
||||
}
|
||||
}
|
||||
|
||||
/// A chess piece (i.e. its [`Role`] and [`Color`]).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Piece {
|
||||
pub role: Role,
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
pub(crate) enum Direction {
|
||||
East,
|
||||
NorthEast,
|
||||
North,
|
||||
NorthWest,
|
||||
SouthEast,
|
||||
South,
|
||||
SouthWest,
|
||||
West,
|
||||
}
|
||||
|
||||
container!(Direction, ByDirection, 8);
|
||||
|
||||
impl Direction {
|
||||
#[inline]
|
||||
pub fn all() -> [Self; 8] {
|
||||
[
|
||||
Self::East,
|
||||
Self::NorthEast,
|
||||
Self::North,
|
||||
Self::NorthWest,
|
||||
Self::SouthEast,
|
||||
Self::South,
|
||||
Self::SouthWest,
|
||||
Self::West,
|
||||
]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn transmute(value: u8) -> Self {
|
||||
debug_assert!(value < 8);
|
||||
std::mem::transmute(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Not for Direction {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn not(self) -> Self::Output {
|
||||
unsafe { Self::transmute(self as u8 ^ 0b111) }
|
||||
}
|
||||
}
|
||||
|
||||
/// A side of the board.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum CastlingSide {
|
||||
/// King's side
|
||||
Short,
|
||||
/// Queen's side
|
||||
Long,
|
||||
}
|
||||
|
||||
container!(CastlingSide, ByCastlingSide, 2);
|
||||
|
||||
impl CastlingSide {
|
||||
#[inline]
|
||||
pub fn all() -> [Self; 2] {
|
||||
[Self::Short, Self::Long]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn rook_origin_file(self) -> File {
|
||||
match self {
|
||||
Self::Short => File::H,
|
||||
Self::Long => File::A,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub(crate) struct CastlingRights(u8);
|
||||
|
||||
impl CastlingRights {
|
||||
#[inline]
|
||||
pub(crate) fn new() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) const fn full() -> Self {
|
||||
Self(15)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn get(&self, color: Color, side: CastlingSide) -> bool {
|
||||
(self.0 & Self::mask(color, side)) != 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set(&mut self, color: Color, side: CastlingSide) {
|
||||
self.0 |= Self::mask(color, side);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn unset(&mut self, color: Color, side: CastlingSide) {
|
||||
self.0 &= !Self::mask(color, side);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn mirror(&self) -> Self {
|
||||
Self(((self.0 & 3) << 2) | (self.0 >> 2))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
const fn mask(color: Color, side: CastlingSide) -> u8 {
|
||||
match (color, side) {
|
||||
(Color::White, CastlingSide::Short) => 1,
|
||||
(Color::White, CastlingSide::Long) => 2,
|
||||
(Color::Black, CastlingSide::Short) => 4,
|
||||
(Color::Black, CastlingSide::Long) => 8,
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue