use core::fmt;
use core::mem::transmute;
use core::ops::Not;
use crate::{BitBoardConsts, Color, Square};
#[derive(PartialEq, Eq, PartialOrd, Clone, Copy, Debug, Default, Hash)]
pub struct BitBoard(pub u64);
impl fmt::Display for BitBoard {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "\n Bitboard: {}\n", self.0)?;
for rank in (0..8).rev() {
write!(f, "\n{} ", rank + 1)?;
for file in 0..8 {
let square: usize = rank * 8 + file;
let symbol: &str = if self.get_square(Square::from_index(square)) {
"★ "
} else {
"· "
};
write!(f, "{}", symbol)?;
}
}
write!(f, "\n\n A B C D E F G H")?;
Ok(())
}
}
impl Not for BitBoard {
type Output = Self;
#[inline(always)]
fn not(self) -> Self::Output {
Self(!self.0)
}
}
impl Iterator for BitBoard {
type Item = Square;
#[inline(always)]
fn next(&mut self) -> Option<Square> {
if self.0 == 0 {
None
} else {
let square: Square = self.to_square();
self.0 &= self.0 - 1;
Some(square)
}
}
}
impl BitBoard {
BitBoardConsts! {
WHITE_SIDE = 0x0000_0000_FFFF_FFFF,
BLACK_SIDE = 0xFFFF_FFFF_0000_0000,
FILE_A = 0x0101_0101_0101_0101,
FILE_B = 0x0202_0202_0202_0202,
FILE_C = 0x0404_0404_0404_0404,
FILE_D = 0x0808_0808_0808_0808,
FILE_E = 0x1010_1010_1010_1010,
FILE_F = 0x2020_2020_2020_2020,
FILE_G = 0x4040_4040_4040_4040,
FILE_H = 0x8080_8080_8080_8080,
RANK_1 = 0x0000_0000_0000_00FF,
RANK_2 = 0x0000_0000_0000_FF00,
RANK_3 = 0x0000_0000_00FF_0000,
RANK_4 = 0x0000_0000_FF00_0000,
RANK_5 = 0x0000_00FF_0000_0000,
RANK_6 = 0x0000_FF00_0000_0000,
RANK_7 = 0x00FF_0000_0000_0000,
RANK_8 = 0xFF00_0000_0000_0000,
DARK_SQUARES = 0xAA55_AA55_AA55_AA55,
LIGHT_SQUARES = 0x55AA_55AA_55AA_55AA,
EMPTY = 0,
FULL = 0xFFFF_FFFF_FFFF_FFFF,
}
#[inline(always)]
pub const fn to_square(self) -> Square {
unsafe { transmute((self.0.trailing_zeros() as u8) & 63) }
}
#[inline(always)]
pub const fn set_square(self, square: Square) -> Self {
Self(self.0 | (1u64 << square.to_index()))
}
#[inline(always)]
pub const fn get_square(self, square: Square) -> bool {
self.0 & (1u64 << square.to_index()) != 0
}
#[inline(always)]
pub const fn pop_square(self, square: Square) -> Self {
Self(self.0 & !(1u64 << square.to_index()))
}
#[inline(always)]
pub const fn count_bits(self) -> u32 {
self.0.count_ones()
}
#[inline(always)]
pub const fn flip(self) -> Self {
Self(self.0.swap_bytes())
}
#[inline(always)]
pub const fn forward(self, side: Color) -> Self {
match side {
Color::White => Self(self.0 << 8),
Color::Black => Self(self.0 >> 8),
}
}
#[inline(always)]
pub const fn up_left(self, side: Color) -> Self {
match side {
Color::White => Self((self.0 & !BitBoard::FILE_A.0) << 7),
Color::Black => Self((self.0 & !BitBoard::FILE_H.0) >> 7),
}
}
#[inline(always)]
pub const fn up_right(self, side: Color) -> Self {
match side {
Color::White => Self((self.0 & !BitBoard::FILE_H.0) << 9),
Color::Black => Self((self.0 & !BitBoard::FILE_A.0) >> 9),
}
}
#[inline(always)]
pub const fn is_empty(self) -> bool {
self.0 == 0
}
}