[board] Implement a BitScanner on u64
This struct implements an Iterator that returns the positions of the 1 bits in the u64.
BitBoard takes this iterator and maps it into Squares in the pieces() method.
This is laying the groundwork for an iterator over the pieces in a Position. 👀
This commit is contained in:
parent
a2f88f0fde
commit
1da827a3bb
3 changed files with 91 additions and 23 deletions
|
@ -1,11 +1,14 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
|
mod bit_scanner;
|
||||||
|
|
||||||
|
use self::bit_scanner::BitScanner;
|
||||||
use crate::square::Square;
|
use crate::square::Square;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{BitAnd, BitOr, Not};
|
use std::ops::{BitAnd, BitOr, Not};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
pub struct BitBoard(u64);
|
pub(crate) struct BitBoard(u64);
|
||||||
|
|
||||||
impl BitBoard {
|
impl BitBoard {
|
||||||
pub fn empty() -> BitBoard {
|
pub fn empty() -> BitBoard {
|
||||||
|
@ -16,7 +19,7 @@ impl BitBoard {
|
||||||
BitBoard(bits)
|
BitBoard(bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.0 == 0
|
self.0 == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,20 +34,6 @@ impl BitBoard {
|
||||||
fn remove_piece_at(&mut self, sq: &Square) {
|
fn remove_piece_at(&mut self, sq: &Square) {
|
||||||
self.0 &= !(1 << sq.index)
|
self.0 &= !(1 << sq.index)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "arm")]
|
|
||||||
fn _arm_count_leading_zeros(&self) -> u8 {
|
|
||||||
let mut number_of_leading_zeros: u8 = 0;
|
|
||||||
unsafe {
|
|
||||||
asm!(
|
|
||||||
"clz {count}, {bitfield}",
|
|
||||||
count = out(reg) number_of_leading_zeros,
|
|
||||||
bitfield = in(reg) self.0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
number_of_leading_zeros
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitBoard {
|
impl BitBoard {
|
||||||
|
@ -92,6 +81,15 @@ impl BitBoard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BitBoard {
|
||||||
|
fn pieces(&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_unsafe(x.unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for BitBoard {
|
impl fmt::Debug for BitBoard {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
let bits = self.0;
|
let bits = self.0;
|
||||||
|
@ -229,12 +227,15 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "arm")]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn arm_count_leading_zeros() {
|
fn pieces() {
|
||||||
assert_eq!(BitBoard(0)._arm_count_leading_zeros(), 0);
|
let bb = BitBoard(0x1001_1010); // e4
|
||||||
assert_eq!(BitBoard(0b10)._arm_count_leading_zeros(), 62);
|
|
||||||
assert_eq!(BitBoard(0b1010)._arm_count_leading_zeros(), 60);
|
let mut pieces = bb.pieces();
|
||||||
assert_eq!(BitBoard(0x80000000)._arm_count_leading_zeros(), 0);
|
assert_eq!(pieces.next(), Some(Square::from_index_unsafe(28)));
|
||||||
|
assert_eq!(pieces.next(), Some(Square::from_index_unsafe(16)));
|
||||||
|
assert_eq!(pieces.next(), Some(Square::from_index_unsafe(12)));
|
||||||
|
assert_eq!(pieces.next(), Some(Square::from_index_unsafe(4)));
|
||||||
|
assert_eq!(pieces.next(), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
67
board/src/bitboard/bit_scanner.rs
Normal file
67
board/src/bitboard/bit_scanner.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
|
use super::BitBoard;
|
||||||
|
use crate::square::Square;
|
||||||
|
|
||||||
|
pub(crate) struct BitScanner {
|
||||||
|
bits: u64,
|
||||||
|
shift: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitScanner {
|
||||||
|
pub(crate) fn new(bits: u64) -> BitScanner {
|
||||||
|
BitScanner { bits, shift: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for BitScanner {
|
||||||
|
type Item = u32;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.shift == u64::BITS {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let shifted_bits = self.bits << self.shift;
|
||||||
|
let leading_zeros = shifted_bits.leading_zeros();
|
||||||
|
|
||||||
|
if leading_zeros == u64::BITS {
|
||||||
|
self.shift = leading_zeros;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let position = u64::BITS - (self.shift + leading_zeros + 1);
|
||||||
|
// Shift 1 additional place to account for the 1 that `leading_zeros` found.
|
||||||
|
self.shift += leading_zeros + 1;
|
||||||
|
|
||||||
|
Some(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn zero() {
|
||||||
|
let mut scanner = BitScanner::new(0);
|
||||||
|
assert_eq!(scanner.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one() {
|
||||||
|
let mut scanner = BitScanner::new(1);
|
||||||
|
assert_eq!(scanner.next(), Some(0));
|
||||||
|
assert_eq!(scanner.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn complex() {
|
||||||
|
let mut scanner = BitScanner::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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ impl Square {
|
||||||
Ok(Square::from_index_unsafe(index))
|
Ok(Square::from_index_unsafe(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_index_unsafe(index: u8) -> Square {
|
pub(crate) fn from_index_unsafe(index: u8) -> Square {
|
||||||
Square {
|
Square {
|
||||||
rank: index / 8,
|
rank: index / 8,
|
||||||
file: index % 8,
|
file: index % 8,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue