use crate::othello::{Position, constants::POSITIONS};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Bitboard(pub(crate) u64);
impl Bitboard {
pub const FILLED: Self = Bitboard(u64::MAX);
pub const EMPTY: Self = Bitboard(0);
#[must_use]
pub fn raw(self) -> u64 {
self.0
}
#[must_use]
pub fn is_empty(self) -> bool {
self.0 == 0
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn count_set(self) -> u8 {
self.0.count_ones() as u8
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn count_empty(self) -> u8 {
self.0.count_zeros() as u8
}
#[must_use]
pub fn bits(self) -> impl ExactSizeIterator<Item = Bitboard> {
POSITIONS.iter().map(move |m| self & *m)
}
#[must_use]
pub fn hot_bits(self) -> impl ExactSizeIterator<Item = Position> {
let positions = HotBits {
remaining: self.count_set(),
bitboard: self,
};
positions.into_iter()
}
}
#[derive(Clone, Debug)]
struct HotBits {
remaining: u8,
bitboard: Bitboard,
}
#[derive(Clone, Debug)]
struct HotBitsIntoIterator {
remaining: u8,
bitboard: Bitboard,
}
impl IntoIterator for HotBits {
type Item = Position;
type IntoIter = HotBitsIntoIterator;
fn into_iter(self) -> Self::IntoIter {
HotBitsIntoIterator {
remaining: self.remaining,
bitboard: self.bitboard,
}
}
}
impl Iterator for HotBitsIntoIterator {
type Item = Position;
fn next(&mut self) -> Option<Self::Item> {
if self.bitboard.is_empty() {
None
} else {
self.remaining -= 1;
let position = 1 << (63 - self.bitboard.raw().leading_zeros());
self.bitboard ^= position;
Some(Position::new_unchecked(position))
}
}
}
impl ExactSizeIterator for HotBitsIntoIterator {
fn len(&self) -> usize {
self.remaining.into()
}
}
impl From<u64> for Bitboard {
fn from(bitboard: u64) -> Self {
Bitboard(bitboard)
}
}
impl From<Bitboard> for u64 {
fn from(bitboard: Bitboard) -> Self {
bitboard.0
}
}