// Eryn Wells use crate::{ bitboard::BitBoardBuilder, piece::{PlacedPiece, Shape}, position::{flags::Flags, piece_sets::PieceBitBoards}, r#move::Castle, square::{Direction, Rank}, BitBoard, Color, MakeMoveError, Move, Piece, Position, Square, }; use std::collections::BTreeMap; #[derive(Clone)] pub struct Builder { player_to_move: Color, flags: Flags, pieces: BTreeMap, kings: [Square; 2], ply_counter: u16, move_number: u16, } impl Builder { pub fn new() -> Self { Self::default() } pub fn from_position(position: &Position) -> Self { let pieces = BTreeMap::from_iter( position .pieces(Color::White) .chain(position.pieces(Color::Black)) .map(|placed_piece| (placed_piece.square(), *placed_piece.piece())), ); let white_king = position.king_square(Color::White); let black_king = position.king_square(Color::Black); Self { player_to_move: position.player_to_move(), flags: position.flags(), pieces, kings: [white_king, black_king], ply_counter: position.ply_counter(), move_number: position.move_number(), } } pub fn to_move(&mut self, player: Color) -> &mut Self { self.player_to_move = player; self } pub fn ply_counter(&mut self, num: u16) -> &mut Self { self.ply_counter = num; self } pub fn move_number(&mut self, num: u16) -> &mut Self { self.move_number = num; self } pub fn place_piece(&mut self, piece: PlacedPiece) -> &mut Self { let square = piece.square(); if piece.shape() == Shape::King { let color_index: usize = piece.color() as usize; self.pieces.remove(&self.kings[color_index]); self.kings[color_index] = square; } self.pieces.insert(square, *piece.piece()); self } pub fn build(&self) -> Position { let pieces = PieceBitBoards::from_iter( self.pieces .iter() .map(PlacedPiece::from) .filter(Self::is_piece_placement_valid), ); Position::new( self.player_to_move, self.flags, pieces, None, self.ply_counter, self.move_number, ) } } impl Builder { fn is_piece_placement_valid(piece: &PlacedPiece) -> bool { if piece.shape() == Shape::Pawn { // Pawns cannot be placed on the first (back) rank of their side, // and cannot be placed on the final rank without a promotion. let rank = piece.square().rank(); return rank != Rank::One && rank != Rank::Eight; } true } } impl Default for Builder { fn default() -> Self { let white_king_square = Square::king_starting_square(Color::White); let black_king_square = Square::king_starting_square(Color::Black); let pieces = BTreeMap::from_iter([ (white_king_square, piece!(White King)), (black_king_square, piece!(Black King)), ]); Self { player_to_move: Color::White, flags: Flags::default(), pieces: pieces, kings: [white_king_square, black_king_square], ply_counter: 0, move_number: 1, } } } #[cfg(test)] mod tests { use crate::PositionBuilder; #[test] fn place_piece() { let piece = piece!(White Queen on E4); let builder = PositionBuilder::new().place_piece(piece).build(); assert_eq!(builder.piece_on_square(piece.square()), Some(piece)); } }