1
0
Fork 0
eschac/src/bitboard.rs

203 lines
4.9 KiB
Rust
Raw Normal View History

2025-11-05 23:37:02 +01:00
//! Sets of squares.
2024-04-29 02:00:26 +02:00
use crate::board::*;
2025-11-17 22:07:04 +01:00
use core::iter::ExactSizeIterator;
use core::iter::FusedIterator;
2024-04-29 02:00:26 +02:00
2025-11-05 23:37:02 +01:00
/// A set of squares.
2024-04-29 02:00:26 +02:00
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2025-11-05 23:37:02 +01:00
pub struct Bitboard(pub u64);
2024-04-29 02:00:26 +02:00
impl Bitboard {
#[inline]
2025-11-05 23:37:02 +01:00
pub const fn new() -> Self {
2024-04-29 02:00:26 +02:00
Self(0)
}
#[inline]
2025-11-05 23:37:02 +01:00
pub const fn is_empty(&self) -> bool {
2024-04-29 02:00:26 +02:00
self.0 == 0
}
#[inline]
2025-10-22 22:59:53 +02:00
pub const fn first(&self) -> Option<Square> {
2024-04-29 02:00:26 +02:00
let mask = self.0;
match mask {
0 => None,
2025-11-05 23:37:02 +01:00
_ => Some(unsafe { Square::new_unchecked(mask.trailing_zeros() as u8) }),
2024-04-29 02:00:26 +02:00
}
}
2025-10-22 22:59:53 +02:00
#[inline]
pub const fn last(&self) -> Option<Square> {
let mask = self.0;
match mask {
0 => None,
2025-11-05 23:37:02 +01:00
_ => Some(unsafe {
Square::new_unchecked(63_u8.unchecked_sub(mask.leading_zeros() as u8))
}),
2025-10-22 22:59:53 +02:00
}
}
2024-04-29 02:00:26 +02:00
#[inline]
2025-11-05 23:37:02 +01:00
pub const fn pop(&mut self) -> Option<Square> {
2025-11-17 22:07:04 +01:00
let mask = &mut self.0;
2024-04-29 02:00:26 +02:00
let square = match mask {
0 => None,
2025-11-05 23:37:02 +01:00
_ => Some(unsafe { Square::new_unchecked(mask.trailing_zeros() as u8) }),
2024-04-29 02:00:26 +02:00
};
*mask &= mask.wrapping_sub(1);
square
}
#[inline]
2025-10-22 22:59:53 +02:00
pub const fn insert(&mut self, square: Square) {
2024-04-29 02:00:26 +02:00
self.0 |= 1 << square as u8;
}
#[inline]
2025-11-05 23:37:02 +01:00
pub const fn contains(&self, square: Square) -> bool {
self.0 & (1 << square as u8) != 0
}
#[inline]
pub const fn remove(&mut self, square: Square) {
self.0 &= !(1 << square as u8);
}
#[inline]
pub const fn mirror(self) -> Bitboard {
let [a, b, c, d, e, f, g, h] = self.0.to_le_bytes();
Self(u64::from_le_bytes([h, g, f, e, d, c, b, a]))
}
#[inline]
pub(crate) fn trans(&self, direction: Direction) -> Self {
2024-04-29 02:00:26 +02:00
match direction {
Direction::North => Self(self.0 << 8),
Direction::NorthEast => Self(self.0 << 9) & !File::A.bitboard(),
Direction::East => Self(self.0 << 1) & !File::A.bitboard(),
Direction::SouthEast => Self(self.0 >> 7) & !File::A.bitboard(),
Direction::South => Self(self.0 >> 8),
Direction::SouthWest => Self(self.0 >> 9) & !File::H.bitboard(),
Direction::West => Self(self.0 >> 1) & !File::H.bitboard(),
Direction::NorthWest => Self(self.0 << 7) & !File::H.bitboard(),
}
}
}
2025-11-17 22:07:04 +01:00
impl core::ops::BitOr for Bitboard {
2024-04-29 02:00:26 +02:00
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
2025-11-17 22:07:04 +01:00
impl core::ops::BitAnd for Bitboard {
2024-04-29 02:00:26 +02:00
type Output = Self;
#[inline]
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
2025-11-17 22:07:04 +01:00
impl core::ops::BitXor for Bitboard {
2024-04-29 02:00:26 +02:00
type Output = Self;
#[inline]
fn bitxor(self, rhs: Self) -> Self::Output {
Self(self.0 ^ rhs.0)
}
}
2025-11-17 22:07:04 +01:00
impl core::ops::BitOrAssign for Bitboard {
2024-04-29 02:00:26 +02:00
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
2025-11-17 22:07:04 +01:00
impl core::ops::BitAndAssign for Bitboard {
2024-04-29 02:00:26 +02:00
#[inline]
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
2025-11-17 22:07:04 +01:00
impl core::ops::BitXorAssign for Bitboard {
2024-04-29 02:00:26 +02:00
#[inline]
fn bitxor_assign(&mut self, rhs: Self) {
self.0 ^= rhs.0;
}
}
2025-11-17 22:07:04 +01:00
impl core::ops::Not for Bitboard {
2024-04-29 02:00:26 +02:00
type Output = Self;
#[inline]
fn not(self) -> Self::Output {
Self(!self.0)
}
}
impl Iterator for Bitboard {
type Item = Square;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.pop()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
#[inline]
fn for_each<F>(self, mut f: F)
where
Self: Sized,
F: FnMut(Self::Item),
{
let mut mask = self.0;
while mask != 0 {
2025-11-05 23:37:02 +01:00
f(unsafe { Square::new_unchecked(mask.trailing_zeros() as u8) });
2024-04-29 02:00:26 +02:00
mask &= mask.wrapping_sub(1);
}
}
#[inline]
fn fold<B, F>(self, init: B, mut f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
let mut mask = self.0;
let mut acc = init;
while mask != 0 {
acc = f(acc, unsafe {
2025-11-05 23:37:02 +01:00
Square::new_unchecked(mask.trailing_zeros() as u8)
2024-04-29 02:00:26 +02:00
});
mask &= mask.wrapping_sub(1);
}
acc
}
}
impl FusedIterator for Bitboard {}
impl ExactSizeIterator for Bitboard {
#[inline]
fn len(&self) -> usize {
self.0.count_ones() as usize
}
}
2025-11-17 22:07:04 +01:00
impl core::fmt::Debug for Bitboard {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2025-11-13 23:10:22 +01:00
write!(f, "Bitboard(0x{:016X})", self.0)
}
}
2024-04-29 02:00:26 +02:00
pub(crate) trait BitboardIterExt {
fn reduce_or(self) -> Bitboard;
}
impl<T> BitboardIterExt for T
where
T: Iterator<Item = Bitboard>,
{
#[inline]
fn reduce_or(self) -> Bitboard {
self.fold(Bitboard(0), |a, b| a | b)
}
}