[board] Implement a TrailingBitScanner
This bit scanner iterates populated bits in a BitBoard from the trailing (least-significant) end. Rename BitScanner → LeadingBitScanner. Factor implementation of these two into a macro. Clean up iterator returned by BitBoard::occupied_squares Implement BitBoard::occupied_squares_trailing
This commit is contained in:
parent
35756e28cf
commit
2394afc210
3 changed files with 83 additions and 22 deletions
|
@ -1,17 +1,24 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
pub(crate) struct BitScanner {
|
||||
bits: u64,
|
||||
shift: usize,
|
||||
macro_rules! bit_scanner {
|
||||
($name:ident) => {
|
||||
pub(crate) struct $name {
|
||||
bits: u64,
|
||||
shift: usize,
|
||||
}
|
||||
|
||||
impl $name {
|
||||
pub(crate) fn new(bits: u64) -> Self {
|
||||
Self { bits, shift: 0 }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl BitScanner {
|
||||
pub(crate) fn new(bits: u64) -> BitScanner {
|
||||
BitScanner { bits, shift: 0 }
|
||||
}
|
||||
}
|
||||
bit_scanner!(LeadingBitScanner);
|
||||
bit_scanner!(TrailingBitScanner);
|
||||
|
||||
impl Iterator for BitScanner {
|
||||
impl Iterator for LeadingBitScanner {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
|
@ -37,30 +44,79 @@ impl Iterator for BitScanner {
|
|||
}
|
||||
}
|
||||
|
||||
impl Iterator for TrailingBitScanner {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let u64bits = u64::BITS as usize;
|
||||
|
||||
if self.shift == u64bits {
|
||||
return None;
|
||||
}
|
||||
|
||||
let shifted_bits = self.bits >> self.shift;
|
||||
let trailing_zeros = shifted_bits.trailing_zeros() as usize;
|
||||
|
||||
if trailing_zeros == u64bits {
|
||||
self.shift = trailing_zeros;
|
||||
return None;
|
||||
}
|
||||
|
||||
let position = self.shift + trailing_zeros;
|
||||
// Shift 1 additional place to account for the 1 that `leading_zeros` found.
|
||||
self.shift += trailing_zeros + 1;
|
||||
|
||||
Some(position)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn zero() {
|
||||
let mut scanner = BitScanner::new(0);
|
||||
fn leading_zero() {
|
||||
let mut scanner = LeadingBitScanner::new(0);
|
||||
assert_eq!(scanner.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one() {
|
||||
let mut scanner = BitScanner::new(1);
|
||||
fn leading_one() {
|
||||
let mut scanner = LeadingBitScanner::new(1);
|
||||
assert_eq!(scanner.next(), Some(0));
|
||||
assert_eq!(scanner.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex() {
|
||||
let mut scanner = BitScanner::new(0b11000101);
|
||||
fn leading_complex() {
|
||||
let mut scanner = LeadingBitScanner::new(0b11000101);
|
||||
assert_eq!(scanner.next(), Some(7));
|
||||
assert_eq!(scanner.next(), Some(6));
|
||||
assert_eq!(scanner.next(), Some(2));
|
||||
assert_eq!(scanner.next(), Some(0));
|
||||
assert_eq!(scanner.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_zero() {
|
||||
let mut scanner = TrailingBitScanner::new(0);
|
||||
assert_eq!(scanner.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_one() {
|
||||
let mut scanner = TrailingBitScanner::new(1);
|
||||
assert_eq!(scanner.next(), Some(0));
|
||||
assert_eq!(scanner.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_complex() {
|
||||
let mut scanner = TrailingBitScanner::new(0b11000101);
|
||||
assert_eq!(scanner.next(), Some(0));
|
||||
assert_eq!(scanner.next(), Some(2));
|
||||
assert_eq!(scanner.next(), Some(6));
|
||||
assert_eq!(scanner.next(), Some(7));
|
||||
assert_eq!(scanner.next(), None);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use super::library::{library, FILES, RANKS};
|
||||
use super::BitScanner;
|
||||
use crate::Square;
|
||||
use super::{LeadingBitScanner, TrailingBitScanner};
|
||||
use crate::{square::Direction, Square};
|
||||
use std::fmt;
|
||||
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
|
||||
|
||||
|
@ -62,11 +62,16 @@ impl BitBoard {
|
|||
}
|
||||
|
||||
impl BitBoard {
|
||||
/// Return an Iterator over the occupied squares, starting from the leading
|
||||
/// (most-significant bit) end of the field.
|
||||
pub(crate) fn occupied_squares(&self) -> impl Iterator<Item = Square> {
|
||||
BitScanner::new(self.0)
|
||||
.map(|x| u8::try_from(x))
|
||||
.take_while(|x| x.is_ok())
|
||||
.map(|x| Square::from_index(x.unwrap() as usize))
|
||||
LeadingBitScanner::new(self.0).map(Square::from_index)
|
||||
}
|
||||
|
||||
/// Return an Iterator over the occupied squares, starting from the trailing
|
||||
/// (least-significant bit) end of the field.
|
||||
pub(crate) fn occupied_squares_trailing(&self) -> impl Iterator<Item = Square> {
|
||||
LeadingBitScanner::new(self.0).map(Square::from_index)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,5 +3,5 @@ mod bitboard;
|
|||
mod library;
|
||||
mod shifts;
|
||||
|
||||
pub(crate) use self::bit_scanner::BitScanner;
|
||||
pub(crate) use self::bit_scanner::{LeadingBitScanner, TrailingBitScanner};
|
||||
pub(crate) use self::bitboard::BitBoard;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue