use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
#[derive(Clone, Copy, Debug)]
pub struct BitBoard {
data: u64,
}
impl BitBoard {
pub fn new(data: u64) -> Self {
Self { data }
}
#[inline]
pub fn raw(&self) -> u64 {
self.data
}
#[inline(always)]
pub fn set_bit(&mut self, index: u8) -> Option<u64> {
if index < 64 {
self.set_bit_unchecked(index);
Some(self.data)
} else {
None
}
}
#[inline(always)]
pub fn set_bit_unchecked(&mut self, index: u8) -> u64 {
debug_assert!(index < 64, "Index out of bounds: {index}");
self.data |= 1 << index;
self.data
}
#[inline(always)]
pub fn unset_bit(&mut self, index: u8) -> Option<u64> {
if index < 64 {
self.unset_bit_unchecked(index);
Some(self.data)
} else {
None
}
}
#[inline(always)]
pub fn unset_bit_unchecked(&mut self, index: u8) -> u64 {
debug_assert!(index < 64, "Index out of bounds: {index}");
self.data &= !(1 << index);
self.data
}
#[inline]
pub fn update_bit(&mut self, index: u8, value: bool) -> Option<u64> {
if value {
self.set_bit(index)
} else {
self.unset_bit(index)
}
}
#[inline(always)]
pub fn get_bit(&self, index: u8) -> Option<bool> {
if index < 64 {
Some(self.get_bit_unchecked(index))
} else {
None
}
}
#[inline(always)]
pub fn get_bit_unchecked(&self, index: u8) -> bool {
debug_assert!(index < 64, "Index out of bounds: {index}");
(self.data & (1 << index)) != 0
}
pub const EMPTY: Self = Self { data: 0 };
pub const ALL_SQUARES: Self = Self { data: u64::MAX };
}
impl BitOr for BitBoard {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self::new(self.data | rhs.data)
}
}
impl BitAnd for BitBoard {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self::new(self.data & rhs.data)
}
}
impl BitAnd<u64> for BitBoard {
type Output = Self;
fn bitand(self, rhs: u64) -> Self::Output {
Self::new(self.data & rhs)
}
}
impl BitXor<bool> for BitBoard {
type Output = Self;
fn bitxor(self, rhs: bool) -> Self::Output {
if rhs {
Self::new(self.data ^ u64::MAX)
} else {
self
}
}
}
impl Not for BitBoard {
type Output = Self;
fn not(self) -> Self::Output {
let inverted = !self.data;
Self::new(inverted)
}
}
impl Shl<u8> for BitBoard {
type Output = Self;
fn shl(self, rhs: u8) -> Self::Output {
Self::new(self.data << rhs)
}
}
impl Shr<u8> for BitBoard {
type Output = Self;
fn shr(self, rhs: u8) -> Self::Output {
Self::new(self.data >> rhs)
}
}
impl From<BitBoard> for u64 {
fn from(val: BitBoard) -> Self {
val.data
}
}
pub struct BitBoardIter {
data: u64,
}
impl Iterator for BitBoardIter {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
if self.data == 0 {
None
} else {
let square = self.data.trailing_zeros() as u8;
self.data &= self.data - 1; Some(square)
}
}
}
impl IntoIterator for BitBoard {
type Item = u8;
type IntoIter = BitBoardIter;
fn into_iter(self) -> Self::IntoIter {
BitBoardIter { data: self.data }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
Up = -8,
Down = 8,
Left = -1,
Right = 1,
UpLeft = -9,
UpRight = -7,
DownLeft = 7,
DownRight = 9,
}
impl From<Direction> for i8 {
fn from(val: Direction) -> Self {
match val {
Direction::Up => -8,
Direction::Down => 8,
Direction::Left => -1,
Direction::Right => 1,
Direction::UpLeft => -9,
Direction::UpRight => -7,
Direction::DownLeft => 7,
Direction::DownRight => 9,
}
}
}