2024-01-19 18:08:41 -08:00
|
|
|
// Eryn Wells <eryn@erynwells.me>
|
|
|
|
|
|
|
|
use crate::{
|
2024-01-21 09:20:03 -08:00
|
|
|
bitboard::BitBoardBuilder,
|
2024-01-19 18:08:41 -08:00
|
|
|
piece::{PlacedPiece, Shape},
|
2024-01-21 09:20:03 -08:00
|
|
|
position::{flags::Flags, piece_sets::PieceBitBoards, BoardSide},
|
|
|
|
r#move::Castle,
|
|
|
|
square::{Direction, Rank},
|
2024-01-19 18:08:41 -08:00
|
|
|
BitBoard, Color, MakeMoveError, Move, Piece, Position, Square,
|
|
|
|
};
|
|
|
|
use std::collections::BTreeMap;
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Builder {
|
|
|
|
player_to_move: Color,
|
|
|
|
flags: Flags,
|
|
|
|
pieces: BTreeMap<Square, Piece>,
|
|
|
|
kings: [Square; 2],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Builder {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-01-21 09:20:03 -08:00
|
|
|
self.pieces.insert(square, *piece.piece());
|
2024-01-19 18:08:41 -08:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 pieces = BTreeMap::from_iter([
|
|
|
|
(
|
|
|
|
Square::KING_STARTING_SQUARES[Color::White as usize],
|
|
|
|
piece!(White King),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
Square::KING_STARTING_SQUARES[Color::Black as usize],
|
|
|
|
piece!(Black King),
|
|
|
|
),
|
|
|
|
]);
|
|
|
|
|
|
|
|
Self {
|
|
|
|
player_to_move: Color::White,
|
|
|
|
flags: Flags::default(),
|
|
|
|
pieces: pieces,
|
|
|
|
kings: Square::KING_STARTING_SQUARES,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-01-21 09:20:03 -08:00
|
|
|
|
|
|
|
#[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));
|
|
|
|
}
|
|
|
|
}
|