//! Sets of squares. use crate::board::*; /// A set of squares. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Bitboard(pub u64); impl Bitboard { /// Makes a new, empty `Bitboard`. #[inline] pub const fn new() -> Self { Self(0) } /// Returns `true` if the bitboard contains the given square. #[inline] pub const fn contains(&self, square: Square) -> bool { self.0 & (1 << square as u8) != 0 } /// Returns the first square in the bitboard, if any. #[inline] pub const fn first(&self) -> Option { let mask = self.0; match mask { 0 => None, _ => Some(unsafe { Square::new_unchecked(mask.trailing_zeros() as u8) }), } } /// Returns the last square in the bitboard, if any. #[inline] pub const fn last(&self) -> Option { let mask = self.0; match mask { 0 => None, _ => Some(unsafe { Square::new_unchecked(63 ^ mask.leading_zeros() as u8) }), } } /// Removes the first square from the bitboard and returns it, if any. #[inline] pub const fn pop_first(&mut self) -> Option { let mask = &mut self.0; let square = match mask { 0 => None, _ => Some(unsafe { Square::new_unchecked(mask.trailing_zeros() as u8) }), }; *mask &= mask.wrapping_sub(1); square } /// Adds a square to the bitboard. #[inline] pub const fn insert(&mut self, square: Square) { self.0 |= 1 << square as u8; } /// Removes a square from the bitboard. #[inline] pub const fn remove(&mut self, square: Square) { self.0 &= !(1 << square as u8); } /// Returns the number of squares in the bitboard. #[inline] pub const fn len(&self) -> usize { self.0.count_ones() as usize } /// Returns `true` if the bitboard contains no squares. #[inline] pub const fn is_empty(&self) -> bool { self.0 == 0 } /// Returns the mirror image of the bitboard. This is the set of the mirror images of all the /// squares in the bitboard. #[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 { 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(), } } } impl core::ops::BitOr for Bitboard { type Output = Self; #[inline] fn bitor(self, rhs: Self) -> Self::Output { Self(self.0 | rhs.0) } } impl core::ops::BitAnd for Bitboard { type Output = Self; #[inline] fn bitand(self, rhs: Self) -> Self::Output { Self(self.0 & rhs.0) } } impl core::ops::BitXor for Bitboard { type Output = Self; #[inline] fn bitxor(self, rhs: Self) -> Self::Output { Self(self.0 ^ rhs.0) } } impl core::ops::BitOrAssign for Bitboard { #[inline] fn bitor_assign(&mut self, rhs: Self) { self.0 |= rhs.0; } } impl core::ops::BitAndAssign for Bitboard { #[inline] fn bitand_assign(&mut self, rhs: Self) { self.0 &= rhs.0; } } impl core::ops::BitXorAssign for Bitboard { #[inline] fn bitxor_assign(&mut self, rhs: Self) { self.0 ^= rhs.0; } } impl core::ops::Not for Bitboard { 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.pop_first() } #[inline] fn size_hint(&self) -> (usize, Option) { let len = self.len(); (len, Some(len)) } #[inline] fn for_each(self, mut f: F) where Self: Sized, F: FnMut(Self::Item), { let mut mask = self.0; while mask != 0 { f(unsafe { Square::new_unchecked(mask.trailing_zeros() as u8) }); mask &= mask.wrapping_sub(1); } } #[inline] fn fold(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 { Square::new_unchecked(mask.trailing_zeros() as u8) }); mask &= mask.wrapping_sub(1); } acc } } impl core::iter::FusedIterator for Bitboard {} impl core::iter::ExactSizeIterator for Bitboard { #[inline] fn len(&self) -> usize { self.len() } } impl core::fmt::Debug for Bitboard { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Bitboard(0x{:016X})", self.0) } } pub(crate) trait BitboardIterExt { fn reduce_or(self) -> Bitboard; } impl BitboardIterExt for T where T: Iterator, { #[inline] fn reduce_or(self) -> Bitboard { self.fold(Bitboard(0), |a, b| a | b) } }