[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>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
|
use crate::bit_scanner::{LeadingBitScanner, TrailingBitScanner};
|
||||||
|
use crate::direction::IterationDirection;
|
||||||
use crate::library;
|
use crate::library;
|
||||||
use crate::{LeadingBitScanner, TrailingBitScanner};
|
|
||||||
use chessfriend_core::{Color, Direction, File, Rank, Square};
|
use chessfriend_core::{Color, Direction, File, Rank, Square};
|
||||||
use forward_ref::{forward_ref_binop, forward_ref_op_assign, forward_ref_unop};
|
use forward_ref::{forward_ref_binop, forward_ref_op_assign, forward_ref_unop};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -223,27 +224,39 @@ impl BitBoard {
|
||||||
self.0.is_power_of_two()
|
self.0.is_power_of_two()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an Iterator over the occupied squares. The Iterator yields
|
/// Return an Iterator over the occupied squares.
|
||||||
/// squares starting from the leading (most-significant bit) end of the
|
|
||||||
/// board.
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn occupied_squares(&self) -> impl Iterator<Item = Square> {
|
pub fn occupied_squares(
|
||||||
LeadingBitScanner::new(self.0).map(|idx| unsafe { Square::from_index_unchecked(idx as u8) })
|
&self,
|
||||||
|
direction: IterationDirection,
|
||||||
|
) -> Box<dyn Iterator<Item = Square>> {
|
||||||
|
fn index_to_square(index: usize) -> Square {
|
||||||
|
unsafe { Square::from_index_unchecked(index as u8) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an Iterator over the occupied squares. The Iterator yields
|
match direction {
|
||||||
/// squares starting from the trailing (least-significant bit) end of the
|
IterationDirection::Leading => {
|
||||||
/// board.
|
Box::new(LeadingBitScanner::new(self.0).map(index_to_square))
|
||||||
pub fn occupied_squares_trailing(&self) -> impl Iterator<Item = Square> {
|
}
|
||||||
TrailingBitScanner::new(self.0)
|
IterationDirection::Trailing => {
|
||||||
.map(|idx| unsafe { Square::from_index_unchecked(idx as u8) })
|
Box::new(TrailingBitScanner::new(self.0).map(index_to_square))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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
|
/// 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
|
/// board, starting at the leading (most-significant) end of the board. If
|
||||||
/// the board is empty, returns `None`.
|
/// the board is empty, returns `None`.
|
||||||
#[must_use]
|
#[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;
|
let leading_zeros = self.0.leading_zeros() as u8;
|
||||||
if leading_zeros < Square::NUM as u8 {
|
if leading_zeros < Square::NUM as u8 {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -260,7 +273,7 @@ impl BitBoard {
|
||||||
/// board, starting at the trailing (least-significant) end of the board.
|
/// board, starting at the trailing (least-significant) end of the board.
|
||||||
/// If the board is empty, returns `None`.
|
/// If the board is empty, returns `None`.
|
||||||
#[must_use]
|
#[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;
|
let trailing_zeros = self.0.trailing_zeros() as u8;
|
||||||
if trailing_zeros < Square::NUM as u8 {
|
if trailing_zeros < Square::NUM as u8 {
|
||||||
unsafe { Some(Square::from_index_unchecked(trailing_zeros)) }
|
unsafe { Some(Square::from_index_unchecked(trailing_zeros)) }
|
||||||
|
@ -458,7 +471,10 @@ mod tests {
|
||||||
fn single_rank_occupancy() {
|
fn single_rank_occupancy() {
|
||||||
let bb = BitBoard(0b01010100);
|
let bb = BitBoard(0b01010100);
|
||||||
let expected_squares = [Square::G1, Square::E1, Square::C1];
|
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);
|
assert_eq!(a, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,7 +486,10 @@ mod tests {
|
||||||
|
|
||||||
let expected_squares = [Square::H8, Square::F6, Square::C5, Square::E2, Square::D1];
|
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);
|
assert_eq!(a, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,7 +533,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn first_occupied_squares() {
|
fn first_occupied_squares() {
|
||||||
let bb = bitboard![A8 E1];
|
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));
|
assert_eq!(bb.first_occupied_square_trailing(), Some(Square::E1));
|
||||||
|
|
||||||
let bb = bitboard![D6 E7 F8];
|
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 bit_scanner;
|
||||||
mod bitboard;
|
mod bitboard;
|
||||||
|
mod direction;
|
||||||
mod library;
|
mod library;
|
||||||
mod shifts;
|
mod shifts;
|
||||||
|
|
||||||
pub use bitboard::BitBoard;
|
pub use bitboard::BitBoard;
|
||||||
|
pub use direction::IterationDirection;
|
||||||
pub(crate) use bit_scanner::{LeadingBitScanner, TrailingBitScanner};
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! bitboard {
|
macro_rules! bitboard {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue