use crate::{bit_twiddles, FILE_COUNT, RANK_COUNT, Square};
use core::fmt;
use std::{mem::{self, transmute}, ops::*};
#[derive(Clone, Copy, PartialEq)]
pub struct Bitboard(pub u64);
impl Bitboard {
#[inline(always)]
pub fn set_sq(&mut self, sq: Square) {
self.0 |= 1 << sq as u8;
}
#[inline(always)]
pub fn pop_sq(&mut self, sq: Square) {
self.0 &= !(1 << sq as u8);
}
#[inline(always)]
pub fn is_set_sq(&self, sq: Square) -> bool {
self.0 & (1 << sq as u8) != 0
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.0 == 0
}
#[inline(always)]
pub fn is_not_empty(&self) -> bool {
self.0 != 0
}
#[inline(always)]
pub fn shift_upwards(&self, amount: u8) -> Bitboard {
Bitboard(self.0 >> amount)
}
#[inline(always)]
pub fn shift_downwards(&self, amount: u8) -> Bitboard {
Bitboard(self.0 << amount)
}
#[inline(always)]
pub fn count_bits(self) -> u8 {
bit_twiddles::count_bits(self.0)
}
#[inline(always)]
pub fn get_lsb(self) -> Square {
debug_assert_ne!(self.count_bits(), 0);
Square::from(bit_twiddles::get_lsb(self.0))
}
#[inline(always)]
pub fn pop_lsb(&mut self) -> Square {
let lsb = self.get_lsb();
self.pop_sq(lsb);
lsb
}
}
impl Bitboard {
pub const FILE_A: Bitboard = Bitboard(0x0101010101010101);
pub const FILE_B: Bitboard = Bitboard(0x0202020202020202);
pub const FILE_C: Bitboard = Bitboard(0x0404040404040404);
pub const FILE_D: Bitboard = Bitboard(0x0808080808080808);
pub const FILE_E: Bitboard = Bitboard(0x1010101010101010);
pub const FILE_F: Bitboard = Bitboard(0x2020202020202020);
pub const FILE_G: Bitboard = Bitboard(0x4040404040404040);
pub const FILE_H: Bitboard = Bitboard(0x8080808080808080);
pub const ALL_FILES: [Bitboard; 8] = [
Self::FILE_A, Self::FILE_B, Self::FILE_C, Self::FILE_D, Self::FILE_E, Self::FILE_F, Self::FILE_G, Self::FILE_H,
];
pub const RANK_1: Bitboard = Bitboard(0xFF00000000000000);
pub const RANK_2: Bitboard = Bitboard(0x00FF000000000000);
pub const RANK_3: Bitboard = Bitboard(0x0000FF0000000000);
pub const RANK_4: Bitboard = Bitboard(0x000000FF00000000);
pub const RANK_5: Bitboard = Bitboard(0x00000000FF000000);
pub const RANK_6: Bitboard = Bitboard(0x0000000000FF0000);
pub const RANK_7: Bitboard = Bitboard(0x000000000000FF00);
pub const RANK_8: Bitboard = Bitboard(0x00000000000000FF);
pub const ALL_RANKS: [Bitboard; 8] = [
Self::RANK_8, Self::RANK_7, Self::RANK_6, Self::RANK_5, Self::RANK_4, Self::RANK_3, Self::RANK_2, Self::RANK_1,
];
pub(crate) const NOT_A: Bitboard = Bitboard(0xFEFEFEFEFEFEFEFE);
pub(crate) const NOT_AB: Bitboard = Bitboard(0xFCFCFCFCFCFCFCFC);
pub(crate) const NOT_H: Bitboard = Bitboard(0x7F7F7F7F7F7F7F7F);
pub(crate) const NOT_GH: Bitboard = Bitboard(0x3F3F3F3F3F3F3F3F);
pub(crate) const WHITE_SQUARES: Bitboard = Bitboard(0xAA55AA55AA55AA55);
pub(crate) const BLACK_SQUARES: Bitboard = Bitboard(0x55AA55AA55AA55AA);
pub(crate) const WHITE_STARTING_PIECES: Bitboard = Bitboard(0xFFFF000000000000);
pub(crate) const BLACK_STARTING_PIECES: Bitboard = Bitboard(0x000000000000FFFF);
pub(crate) const ALL_STARTING_PIECES: Bitboard = Bitboard(0xFFFF00000000FFFF);
pub(crate) const EDGES: Bitboard = Bitboard(0xFF818181818181FF);
pub(crate) const EMPTY: Bitboard = unsafe { mem::zeroed() };
pub(crate) const W_KING_SIDE_MASK: Bitboard = Bitboard(0x6000000000000000);
pub(crate) const W_QUEEN_SIDE_MASK: Bitboard = Bitboard(0x0E00000000000000);
pub(crate) const B_KING_SIDE_MASK: Bitboard = Bitboard(0x0000000000000060);
pub(crate) const B_QUEEN_SIDE_MASK: Bitboard = Bitboard(0x000000000000000E);
pub(crate) const BP: Bitboard = Bitboard::RANK_7;
pub(crate) const BN: Bitboard = Bitboard(0x0000000000000042);
pub(crate) const BB: Bitboard = Bitboard(0x0000000000000024);
pub(crate) const BR: Bitboard = Bitboard(0x0000000000000081);
pub(crate) const BQ: Bitboard = Bitboard(0x0000000000000008);
pub(crate) const BK: Bitboard = Bitboard(0x0000000000000010);
pub(crate) const WP: Bitboard = Bitboard::RANK_2;
pub(crate) const WN: Bitboard = Bitboard(0x4200000000000000);
pub(crate) const WB: Bitboard = Bitboard(0x2400000000000000);
pub(crate) const WR: Bitboard = Bitboard(0x8100000000000000);
pub(crate) const WQ: Bitboard = Bitboard(0x0800000000000000);
pub(crate) const WK: Bitboard = Bitboard(0x1000000000000000);
}
macro_rules! impl_bb_op {
($trait:ident, $method:ident, $op:tt) => {
impl $trait<Bitboard> for Bitboard {
type Output = Bitboard;
#[inline(always)]
fn $method(self, rhs: Bitboard) -> Bitboard {
Bitboard(self.0 $op rhs.0 as u64)
}
}
};
}
macro_rules! impl_bb_assign {
($trait:ident, $method:ident, $op:tt) => {
impl $trait<Bitboard> for Bitboard {
#[inline(always)]
fn $method(&mut self, rhs: Self) {
self.0 $op rhs.0
}
}
};
}
impl_bb_op!(BitAnd, bitand, &);
impl_bb_op!(BitOr, bitor, |);
impl_bb_op!(BitXor, bitxor, ^);
impl_bb_assign!(BitAndAssign, bitand_assign, &=);
impl_bb_assign!(BitOrAssign, bitor_assign, |=);
impl_bb_assign!(BitXorAssign, bitxor_assign, ^=);
impl Not for Bitboard {
type Output = Bitboard;
fn not(self) -> Self::Output {
Bitboard(!self.0)
}
}
impl From<u64> for Bitboard {
#[inline(always)]
fn from(number: u64) -> Self {
unsafe { transmute::<u64, Self>(number) }
}
}
impl fmt::Display for Bitboard {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s = String::from("\n");
for i in 0..FILE_COUNT {
s += &format!(" {} ", FILE_COUNT - i);
for j in 0..RANK_COUNT {
let square = (self.0 >> (i * RANK_COUNT + j)) & 1;
s += if square != 0 { "O " } else { ". " };
}
s += "\n";
}
s += "\n a b c d e f g h\n";
s += &format!("\nBitboard: {}\n", self.0);
f.pad(&s)
}
}