From fac98735e3735ef9ae0909d4b431c85423ac0b36 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Tue, 26 Dec 2023 09:19:38 -0700 Subject: [PATCH] [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. --- board/src/piece.rs | 12 +++ board/src/position.rs | 10 ++- board/src/position/pieces.rs | 150 +++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 board/src/position/pieces.rs diff --git a/board/src/piece.rs b/board/src/piece.rs index e048075..693e190 100644 --- a/board/src/piece.rs +++ b/board/src/piece.rs @@ -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 } + } +} diff --git a/board/src/position.rs b/board/src/position.rs index e6645be..a532d53 100644 --- a/board/src/position.rs +++ b/board/src/position.rs @@ -1,5 +1,8 @@ // Eryn Wells +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(); diff --git a/board/src/position/pieces.rs b/board/src/position/pieces.rs new file mode 100644 index 0000000..bfad6e1 --- /dev/null +++ b/board/src/position/pieces.rs @@ -0,0 +1,150 @@ +// Eryn Wells + +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_iterator: Box>, + square_iterator: Option>>, +} + +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 { + 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 = 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 = 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); + } +}