141 lines
3.7 KiB
Rust
141 lines
3.7 KiB
Rust
// Eryn Wells <eryn@erynwells.me>
|
|
|
|
use crate::{
|
|
bitboard::BitBoardBuilder,
|
|
piece::{PlacedPiece, Shape},
|
|
position::{flags::Flags, piece_sets::PieceBitBoards},
|
|
r#move::Castle,
|
|
BitBoard, Color, MakeMoveError, Move, Piece, Position,
|
|
};
|
|
use chess_core::{Rank, Square};
|
|
use std::collections::BTreeMap;
|
|
|
|
#[derive(Clone)]
|
|
pub struct Builder {
|
|
player_to_move: Color,
|
|
flags: Flags,
|
|
pieces: BTreeMap<Square, Piece>,
|
|
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));
|
|
}
|
|
}
|