[board] Implement a Pieces iterator
This type iterates the pieces in a Position using the BitScanner struct to iterate all the occupied squares of the position's bitboards.
This commit is contained in:
parent
18d9a845e6
commit
fac98735e3
3 changed files with 171 additions and 1 deletions
|
@ -54,3 +54,15 @@ impl Piece {
|
|||
Piece { color, shape }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct PlacedPiece {
|
||||
pub piece: Piece,
|
||||
pub square: Square,
|
||||
}
|
||||
|
||||
impl PlacedPiece {
|
||||
pub fn new(piece: Piece, square: Square) -> PlacedPiece {
|
||||
PlacedPiece { piece, square }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
mod pieces;
|
||||
|
||||
use self::pieces::Pieces;
|
||||
use crate::bitboard::BitBoard;
|
||||
use crate::piece::{Piece, PiecePlacementError};
|
||||
use crate::square::Square;
|
||||
|
@ -81,7 +84,7 @@ impl Position {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn bitboard_for_piece(&self, piece: &Piece) -> &BitBoard {
|
||||
pub(super) fn bitboard_for_piece(&self, piece: &Piece) -> &BitBoard {
|
||||
&self.pieces_per_type[piece.color as usize][piece.shape as usize]
|
||||
}
|
||||
|
||||
|
@ -89,6 +92,11 @@ impl Position {
|
|||
&mut self.pieces_per_type[piece.color as usize][piece.shape as usize]
|
||||
}
|
||||
|
||||
fn pieces(&self, color: Color) -> Pieces {
|
||||
Pieces::new(&self, color)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Position {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut output = String::new();
|
||||
|
|
150
board/src/position/pieces.rs
Normal file
150
board/src/position/pieces.rs
Normal file
|
@ -0,0 +1,150 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::bitboard::BitBoard;
|
||||
use crate::piece::{Color, Piece, PlacedPiece, Shape};
|
||||
use crate::position::Position;
|
||||
use crate::square::Square;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub struct Pieces<'a> {
|
||||
color: Color,
|
||||
position: &'a Position,
|
||||
|
||||
current_shape: Option<Shape>,
|
||||
|
||||
shape_iterator: Box<dyn Iterator<Item = Shape>>,
|
||||
square_iterator: Option<Box<dyn Iterator<Item = Square>>>,
|
||||
}
|
||||
|
||||
impl<'a> Pieces<'a> {
|
||||
pub(crate) fn new(position: &Position, color: Color) -> Pieces {
|
||||
Pieces {
|
||||
color,
|
||||
position,
|
||||
current_shape: None,
|
||||
shape_iterator: Box::new(Shape::iter()),
|
||||
square_iterator: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Pieces<'a> {
|
||||
type Item = PlacedPiece;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(square_iterator) = &mut self.square_iterator {
|
||||
println!("1 Got square iterator");
|
||||
if let (Some(square), Some(shape)) = (square_iterator.next(), self.current_shape) {
|
||||
println!("1 Got square {:?} and shape {:?}", &square, &shape);
|
||||
return Some(PlacedPiece::new(Piece::new(self.color, shape), square));
|
||||
}
|
||||
}
|
||||
|
||||
let mut current_shape: Option<Shape> = None;
|
||||
let mut next_nonempty_bitboard: Option<&BitBoard> = None;
|
||||
|
||||
while let Some(shape) = self.shape_iterator.next() {
|
||||
let piece = Piece::new(self.color, shape);
|
||||
|
||||
let bitboard = self.position.bitboard_for_piece(&piece);
|
||||
if bitboard.is_empty() {
|
||||
println!("No {:?} pieces; looping", &piece);
|
||||
continue;
|
||||
}
|
||||
|
||||
println!("Found some {:?} pieces", &piece);
|
||||
|
||||
next_nonempty_bitboard = Some(bitboard);
|
||||
current_shape = Some(shape);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if let (Some(bitboard), Some(shape)) = (next_nonempty_bitboard, current_shape) {
|
||||
println!("Got bitboard and shape {:?}", &shape);
|
||||
|
||||
let piece = Piece::new(self.color, shape);
|
||||
|
||||
let mut square_iterator = bitboard.occupied_squares();
|
||||
println!("Created occupied_squares iterator for {:?}", &piece);
|
||||
|
||||
let mut next_placed_piece: Option<PlacedPiece> = None;
|
||||
if let Some(square) = square_iterator.next() {
|
||||
println!("2 Got {:?} and shape {:?}", &square, &shape);
|
||||
next_placed_piece = Some(PlacedPiece::new(Piece::new(self.color, shape), square));
|
||||
}
|
||||
|
||||
self.square_iterator = Some(Box::new(square_iterator));
|
||||
self.current_shape = Some(shape);
|
||||
|
||||
println!("Next placed piece {:?}", &next_placed_piece);
|
||||
return next_placed_piece;
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::piece::{Color, Piece, Shape};
|
||||
use crate::position::Position;
|
||||
use crate::square::Square;
|
||||
|
||||
fn square_at(sq: &str) -> Square {
|
||||
Square::from_algebraic_string(sq).expect(sq)
|
||||
}
|
||||
|
||||
fn place_piece_in_position(pos: &mut Position, sq: &str, piece: Piece) {
|
||||
pos.place_piece(&piece, &square_at(sq))
|
||||
.expect("Unable to place {piece:?} queen on {sq}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let pos = Position::empty();
|
||||
let mut pieces = pos.pieces(Color::White);
|
||||
assert_eq!(pieces.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one() {
|
||||
let sq = Square::from_algebraic_string("e4").expect("e4");
|
||||
|
||||
let mut pos = Position::empty();
|
||||
pos.place_piece(&Piece::new(Color::White, Shape::Queen), &sq)
|
||||
.expect("Unable to place white queen on e4");
|
||||
println!("{:?}", &pos);
|
||||
|
||||
let mut pieces = pos.pieces(Color::White);
|
||||
assert_eq!(
|
||||
pieces.next(),
|
||||
Some(PlacedPiece::new(Piece::new(Color::White, Shape::Queen), sq))
|
||||
);
|
||||
assert_eq!(pieces.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_pieces() {
|
||||
let mut pos = Position::empty();
|
||||
|
||||
place_piece_in_position(&mut pos, "e4", Piece::new(Color::White, Shape::Queen));
|
||||
place_piece_in_position(&mut pos, "e1", Piece::new(Color::White, Shape::King));
|
||||
place_piece_in_position(&mut pos, "b2", Piece::new(Color::White, Shape::Pawn));
|
||||
place_piece_in_position(&mut pos, "c2", Piece::new(Color::White, Shape::Pawn));
|
||||
|
||||
println!("{:?}", &pos);
|
||||
|
||||
let expected_placed_pieces = HashSet::from([
|
||||
PlacedPiece::new(Piece::new(Color::White, Shape::Queen), square_at("e4")),
|
||||
PlacedPiece::new(Piece::new(Color::White, Shape::King), square_at("e1")),
|
||||
PlacedPiece::new(Piece::new(Color::White, Shape::Pawn), square_at("b2")),
|
||||
PlacedPiece::new(Piece::new(Color::White, Shape::Pawn), square_at("c2")),
|
||||
]);
|
||||
|
||||
let placed_pieces = HashSet::from_iter(pos.pieces(Color::White));
|
||||
|
||||
assert_eq!(placed_pieces, expected_placed_pieces);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue