[bitboard] Replace separate methods for leading and trailing iteration
Add chessfriend_bitboard::IterationDirection Make BitBoard::occupied_squares() take an IterationDirection and return an iterator corresponding to the direction. Do the same for ::first_occupied_square().
This commit is contained in:
parent
9f62996175
commit
7b0469d689
3 changed files with 44 additions and 19 deletions
|
@ -1,7 +1,8 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::bit_scanner::{LeadingBitScanner, TrailingBitScanner};
|
||||
use crate::direction::IterationDirection;
|
||||
use crate::library;
|
||||
use crate::{LeadingBitScanner, TrailingBitScanner};
|
||||
use chessfriend_core::{Color, Direction, File, Rank, Square};
|
||||
use forward_ref::{forward_ref_binop, forward_ref_op_assign, forward_ref_unop};
|
||||
use std::fmt;
|
||||
|
@ -223,27 +224,39 @@ impl BitBoard {
|
|||
self.0.is_power_of_two()
|
||||
}
|
||||
|
||||
/// Return an Iterator over the occupied squares. The Iterator yields
|
||||
/// squares starting from the leading (most-significant bit) end of the
|
||||
/// board.
|
||||
/// Return an Iterator over the occupied squares.
|
||||
#[must_use]
|
||||
pub fn occupied_squares(&self) -> impl Iterator<Item = Square> {
|
||||
LeadingBitScanner::new(self.0).map(|idx| unsafe { Square::from_index_unchecked(idx as u8) })
|
||||
pub fn occupied_squares(
|
||||
&self,
|
||||
direction: IterationDirection,
|
||||
) -> Box<dyn Iterator<Item = Square>> {
|
||||
fn index_to_square(index: usize) -> Square {
|
||||
unsafe { Square::from_index_unchecked(index as u8) }
|
||||
}
|
||||
|
||||
match direction {
|
||||
IterationDirection::Leading => {
|
||||
Box::new(LeadingBitScanner::new(self.0).map(index_to_square))
|
||||
}
|
||||
IterationDirection::Trailing => {
|
||||
Box::new(TrailingBitScanner::new(self.0).map(index_to_square))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an Iterator over the occupied squares. The Iterator yields
|
||||
/// squares starting from the trailing (least-significant bit) end of the
|
||||
/// board.
|
||||
pub fn occupied_squares_trailing(&self) -> impl Iterator<Item = Square> {
|
||||
TrailingBitScanner::new(self.0)
|
||||
.map(|idx| unsafe { Square::from_index_unchecked(idx as u8) })
|
||||
#[must_use]
|
||||
pub fn first_occupied_square(&self, direction: IterationDirection) -> Option<Square> {
|
||||
match direction {
|
||||
IterationDirection::Leading => self.first_occupied_square_leading(),
|
||||
IterationDirection::Trailing => self.first_occupied_square_trailing(),
|
||||
}
|
||||
}
|
||||
|
||||
/// If the board is not empty, returns the first occupied square on the
|
||||
/// board, starting at the leading (most-significant) end of the board. If
|
||||
/// the board is empty, returns `None`.
|
||||
#[must_use]
|
||||
pub fn first_occupied_square(&self) -> Option<Square> {
|
||||
fn first_occupied_square_leading(&self) -> Option<Square> {
|
||||
let leading_zeros = self.0.leading_zeros() as u8;
|
||||
if leading_zeros < Square::NUM as u8 {
|
||||
unsafe {
|
||||
|
@ -260,7 +273,7 @@ impl BitBoard {
|
|||
/// board, starting at the trailing (least-significant) end of the board.
|
||||
/// If the board is empty, returns `None`.
|
||||
#[must_use]
|
||||
pub fn first_occupied_square_trailing(&self) -> Option<Square> {
|
||||
fn first_occupied_square_trailing(&self) -> Option<Square> {
|
||||
let trailing_zeros = self.0.trailing_zeros() as u8;
|
||||
if trailing_zeros < Square::NUM as u8 {
|
||||
unsafe { Some(Square::from_index_unchecked(trailing_zeros)) }
|
||||
|
@ -458,7 +471,10 @@ mod tests {
|
|||
fn single_rank_occupancy() {
|
||||
let bb = BitBoard(0b01010100);
|
||||
let expected_squares = [Square::G1, Square::E1, Square::C1];
|
||||
for (a, b) in bb.occupied_squares().zip(expected_squares.iter().cloned()) {
|
||||
for (a, b) in bb
|
||||
.occupied_squares(IterationDirection::Leading)
|
||||
.zip(expected_squares.iter().cloned())
|
||||
{
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
@ -470,7 +486,10 @@ mod tests {
|
|||
|
||||
let expected_squares = [Square::H8, Square::F6, Square::C5, Square::E2, Square::D1];
|
||||
|
||||
for (a, b) in bb.occupied_squares().zip(expected_squares.iter().cloned()) {
|
||||
for (a, b) in bb
|
||||
.occupied_squares(IterationDirection::Leading)
|
||||
.zip(expected_squares.iter().cloned())
|
||||
{
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
@ -514,7 +533,7 @@ mod tests {
|
|||
#[test]
|
||||
fn first_occupied_squares() {
|
||||
let bb = bitboard![A8 E1];
|
||||
assert_eq!(bb.first_occupied_square(), Some(Square::A8));
|
||||
assert_eq!(bb.first_occupied_square_leading(), Some(Square::A8));
|
||||
assert_eq!(bb.first_occupied_square_trailing(), Some(Square::E1));
|
||||
|
||||
let bb = bitboard![D6 E7 F8];
|
||||
|
|
6
bitboard/src/direction.rs
Normal file
6
bitboard/src/direction.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
#[derive(Default)]
|
||||
pub enum IterationDirection {
|
||||
#[default]
|
||||
Leading,
|
||||
Trailing,
|
||||
}
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
mod bit_scanner;
|
||||
mod bitboard;
|
||||
mod direction;
|
||||
mod library;
|
||||
mod shifts;
|
||||
|
||||
pub use bitboard::BitBoard;
|
||||
|
||||
pub(crate) use bit_scanner::{LeadingBitScanner, TrailingBitScanner};
|
||||
pub use direction::IterationDirection;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! bitboard {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue