[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