Solidify PieceSet and supporting types
This commit is contained in:
parent
b3c472fbce
commit
19feff9591
3 changed files with 187 additions and 101 deletions
|
@ -1,9 +1,14 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use chessfriend_bitboard::BitBoard;
|
||||
use chessfriend_core::{Color, Piece, PlacedPiece, Square};
|
||||
mod bitboards;
|
||||
mod mailbox;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
use bitboards::{ByColor, ByColorAndShape};
|
||||
use chessfriend_bitboard::BitBoard;
|
||||
use chessfriend_core::{Color, Piece, PlacedPiece, Shape, Square};
|
||||
use mailbox::Mailbox;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum PlacePieceStrategy {
|
||||
Replace,
|
||||
PreserveExisting,
|
||||
|
@ -11,7 +16,7 @@ pub enum PlacePieceStrategy {
|
|||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum PlacePieceError {
|
||||
ExisitingPiece,
|
||||
ExisitingPiece(PlacedPiece),
|
||||
}
|
||||
|
||||
impl Default for PlacePieceStrategy {
|
||||
|
@ -20,20 +25,17 @@ impl Default for PlacePieceStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
/// The internal data structure of a [Board] that efficiently manages the
|
||||
/// placement of pieces on the board.
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub(crate) struct PieceBitBoards {
|
||||
pub(crate) struct PieceSet {
|
||||
by_color: ByColor,
|
||||
by_color_and_shape: ByColorAndShape,
|
||||
mailbox: Mailbox,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||
struct ByColor(BitBoard, [BitBoard; 2]);
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||
struct ByColorAndShape([[BitBoard; 6]; 2]);
|
||||
|
||||
impl PieceBitBoards {
|
||||
pub(super) fn new(pieces: [[BitBoard; 6]; 2]) -> Self {
|
||||
impl PieceSet {
|
||||
pub(crate) fn new(pieces: [[BitBoard; Shape::NUM]; Color::NUM]) -> Self {
|
||||
use std::ops::BitOr;
|
||||
|
||||
let white_pieces = pieces[Color::White as usize]
|
||||
|
@ -45,130 +47,99 @@ impl PieceBitBoards {
|
|||
|
||||
let all_pieces = white_pieces | black_pieces;
|
||||
|
||||
let mut mailbox = Mailbox::default();
|
||||
for c in Color::into_iter() {
|
||||
for s in Shape::into_iter() {
|
||||
let bitboard = pieces[c as usize][s as usize];
|
||||
for square in bitboard.occupied_squares() {
|
||||
mailbox.set(square, Piece::new(c, s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
by_color: ByColor(all_pieces, [white_pieces, black_pieces]),
|
||||
by_color_and_shape: ByColorAndShape(pieces),
|
||||
by_color: ByColor::new(all_pieces, [white_pieces, black_pieces]),
|
||||
by_color_and_shape: ByColorAndShape::new(pieces),
|
||||
mailbox,
|
||||
}
|
||||
}
|
||||
|
||||
/// A BitBoard representing all the pieces currently on the board. Other
|
||||
/// A [`BitBoard`] representing all the pieces currently on the board. Other
|
||||
/// engines might refer to this concept as 'occupancy'.
|
||||
pub(crate) fn all_pieces(&self) -> &BitBoard {
|
||||
pub(crate) fn all_pieces(&self) -> BitBoard {
|
||||
self.by_color.all()
|
||||
}
|
||||
|
||||
pub(crate) fn all_pieces_of_color(&self, color: Color) -> &BitBoard {
|
||||
pub(crate) fn all_pieces_of_color(&self, color: Color) -> BitBoard {
|
||||
self.by_color.bitboard(color)
|
||||
}
|
||||
|
||||
pub(super) fn bitboard_for_color(&self, color: Color) -> &BitBoard {
|
||||
pub(super) fn bitboard_for_color(&self, color: Color) -> BitBoard {
|
||||
self.by_color.bitboard(color)
|
||||
}
|
||||
|
||||
pub(super) fn bitboard_for_color_mut(&mut self, color: Color) -> &mut BitBoard {
|
||||
self.by_color.bitboard_mut(color)
|
||||
}
|
||||
|
||||
pub(super) fn bitboard_for_piece(&self, piece: &Piece) -> &BitBoard {
|
||||
pub(crate) fn bitboard_for_piece(&self, piece: Piece) -> BitBoard {
|
||||
self.by_color_and_shape.bitboard_for_piece(piece)
|
||||
}
|
||||
|
||||
pub(super) fn bitboard_for_piece_mut(&mut self, piece: &Piece) -> &mut BitBoard {
|
||||
self.by_color_and_shape.bitboard_for_piece_mut(piece)
|
||||
pub(crate) fn get(&self, square: Square) -> Option<Piece> {
|
||||
self.mailbox.get(square)
|
||||
}
|
||||
|
||||
pub(super) fn place_piece(&mut self, piece: &PlacedPiece) -> Result<(), PlacePieceError> {
|
||||
self.place_piece_with_strategy(piece, PlacePieceStrategy::default())
|
||||
}
|
||||
|
||||
pub(super) fn place_piece_with_strategy(
|
||||
pub(crate) fn place_piece_on_square(
|
||||
&mut self,
|
||||
piece: &PlacedPiece,
|
||||
strategy: PlacePieceStrategy,
|
||||
) -> Result<(), PlacePieceError> {
|
||||
let color = piece.color();
|
||||
let square = piece.square();
|
||||
piece: Piece,
|
||||
square: Square,
|
||||
) -> Result<PlacedPiece, PlacePieceError> {
|
||||
self.place_piece_on_square_with_strategy(piece, square, PlacePieceStrategy::default())
|
||||
}
|
||||
|
||||
if strategy == PlacePieceStrategy::PreserveExisting
|
||||
&& self.by_color.bitboard(color).is_set(piece.square())
|
||||
{
|
||||
return Err(PlacePieceError::ExisitingPiece);
|
||||
pub(crate) fn place_piece_on_square_with_strategy(
|
||||
&mut self,
|
||||
piece: Piece,
|
||||
square: Square,
|
||||
strategy: PlacePieceStrategy,
|
||||
) -> Result<PlacedPiece, PlacePieceError> {
|
||||
let color = piece.color();
|
||||
|
||||
if strategy == PlacePieceStrategy::PreserveExisting {
|
||||
if let Some(existing_piece) = self.mailbox.get(square) {
|
||||
return Err(PlacePieceError::ExisitingPiece(PlacedPiece::new(
|
||||
existing_piece,
|
||||
square,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
self.by_color_and_shape.set_square(square, piece.piece());
|
||||
let piece: Piece = piece.into();
|
||||
self.by_color_and_shape.set_square(square, piece);
|
||||
self.by_color.set_square(square, color);
|
||||
self.mailbox.set(square, piece);
|
||||
|
||||
Ok(())
|
||||
Ok(PlacedPiece::new(piece, square))
|
||||
}
|
||||
|
||||
pub(super) fn remove_piece(&mut self, piece: &PlacedPiece) {
|
||||
let color = piece.color();
|
||||
let square = piece.square();
|
||||
pub(crate) fn remove_piece_from_square(&mut self, square: Square) -> Option<PlacedPiece> {
|
||||
if let Some(piece) = self.mailbox.get(square) {
|
||||
self.by_color_and_shape.clear_square(square, piece.into());
|
||||
self.by_color.clear_square(square, piece.color());
|
||||
self.mailbox.clear(square);
|
||||
|
||||
self.by_color_and_shape.clear_square(square, piece.piece());
|
||||
self.by_color.clear_square(square, color);
|
||||
}
|
||||
|
||||
pub(super) fn move_piece(&mut self, piece: &Piece, from_square: Square, to_square: Square) {
|
||||
let color = piece.color();
|
||||
|
||||
self.by_color_and_shape.clear_square(from_square, piece);
|
||||
self.by_color.clear_square(from_square, color);
|
||||
self.by_color_and_shape.set_square(to_square, piece);
|
||||
self.by_color.set_square(to_square, color);
|
||||
Some(PlacedPiece::new(piece, square))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<PlacedPiece> for PieceBitBoards {
|
||||
impl FromIterator<PlacedPiece> for PieceSet {
|
||||
fn from_iter<T: IntoIterator<Item = PlacedPiece>>(iter: T) -> Self {
|
||||
let mut pieces: Self = Default::default();
|
||||
let mut pieces: Self = Self::default();
|
||||
|
||||
for piece in iter {
|
||||
let _ = pieces.place_piece(&piece);
|
||||
let _ = pieces.place_piece_on_square(piece.piece(), piece.square());
|
||||
}
|
||||
|
||||
pieces
|
||||
}
|
||||
}
|
||||
|
||||
impl ByColor {
|
||||
fn all(&self) -> &BitBoard {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub(super) fn bitboard(&self, color: Color) -> &BitBoard {
|
||||
&self.1[color as usize]
|
||||
}
|
||||
|
||||
pub(super) fn bitboard_mut(&mut self, color: Color) -> &mut BitBoard {
|
||||
&mut self.1[color as usize]
|
||||
}
|
||||
|
||||
fn set_square(&mut self, square: Square, color: Color) {
|
||||
self.0.set_square(square);
|
||||
self.1[color as usize].set_square(square)
|
||||
}
|
||||
|
||||
fn clear_square(&mut self, square: Square, color: Color) {
|
||||
self.0.clear_square(square);
|
||||
self.1[color as usize].clear_square(square);
|
||||
}
|
||||
}
|
||||
|
||||
impl ByColorAndShape {
|
||||
fn bitboard_for_piece(&self, piece: &Piece) -> &BitBoard {
|
||||
&self.0[piece.color() as usize][piece.shape() as usize]
|
||||
}
|
||||
|
||||
fn bitboard_for_piece_mut(&mut self, piece: &Piece) -> &mut BitBoard {
|
||||
&mut self.0[piece.color() as usize][piece.shape() as usize]
|
||||
}
|
||||
|
||||
fn set_square(&mut self, square: Square, piece: &Piece) {
|
||||
self.bitboard_for_piece_mut(piece).set_square(square);
|
||||
}
|
||||
|
||||
fn clear_square(&mut self, square: Square, piece: &Piece) {
|
||||
self.bitboard_for_piece_mut(piece).clear_square(square);
|
||||
}
|
||||
}
|
||||
|
|
56
board/src/piece_sets/bitboards.rs
Normal file
56
board/src/piece_sets/bitboards.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use chessfriend_bitboard::BitBoard;
|
||||
use chessfriend_core::{Color, Piece, Shape, Square};
|
||||
|
||||
/// A collection of bitboards that organize pieces by color.
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub(super) struct ByColor(BitBoard, [BitBoard; Color::NUM]);
|
||||
|
||||
/// A collection of bitboards that organize pieces first by color and then by piece type.
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub(super) struct ByColorAndShape([[BitBoard; Shape::NUM]; Color::NUM]);
|
||||
|
||||
impl ByColor {
|
||||
pub(super) fn new(all_pieces: BitBoard, bitboards_by_color: [BitBoard; Color::NUM]) -> Self {
|
||||
ByColor(all_pieces, bitboards_by_color)
|
||||
}
|
||||
|
||||
pub(crate) fn all(&self) -> BitBoard {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub(crate) fn bitboard(&self, color: Color) -> BitBoard {
|
||||
self.1[color as usize]
|
||||
}
|
||||
|
||||
pub(super) fn set_square(&mut self, square: Square, color: Color) {
|
||||
self.0.set(square);
|
||||
self.1[color as usize].set(square);
|
||||
}
|
||||
|
||||
pub(super) fn clear_square(&mut self, square: Square, color: Color) {
|
||||
self.0.clear(square);
|
||||
self.1[color as usize].clear(square);
|
||||
}
|
||||
}
|
||||
|
||||
impl ByColorAndShape {
|
||||
pub(super) fn new(bitboards: [[BitBoard; Shape::NUM]; Color::NUM]) -> Self {
|
||||
Self(bitboards)
|
||||
}
|
||||
|
||||
pub(super) fn bitboard_for_piece(&self, piece: Piece) -> BitBoard {
|
||||
self.0[piece.color() as usize][piece.shape() as usize]
|
||||
}
|
||||
|
||||
pub(super) fn bitboard_for_piece_mut(&mut self, piece: Piece) -> &mut BitBoard {
|
||||
&mut self.0[piece.color() as usize][piece.shape() as usize]
|
||||
}
|
||||
|
||||
pub(super) fn set_square(&mut self, square: Square, piece: Piece) {
|
||||
self.bitboard_for_piece_mut(piece).set(square);
|
||||
}
|
||||
|
||||
pub(super) fn clear_square(&mut self, square: Square, piece: Piece) {
|
||||
self.bitboard_for_piece_mut(piece).clear(square);
|
||||
}
|
||||
}
|
59
board/src/piece_sets/mailbox.rs
Normal file
59
board/src/piece_sets/mailbox.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use chessfriend_core::{Piece, PlacedPiece, Square};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub(super) struct Mailbox([Option<Piece>; Square::NUM]);
|
||||
|
||||
impl Mailbox {
|
||||
pub(super) fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub(super) fn get(&self, square: Square) -> Option<Piece> {
|
||||
self.0[square as usize]
|
||||
}
|
||||
|
||||
pub(super) fn set(&mut self, square: Square, piece: Piece) {
|
||||
self.0[square as usize] = Some(piece);
|
||||
}
|
||||
|
||||
pub(super) fn clear(&mut self, square: Square) {
|
||||
self.0[square as usize] = None;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Mailbox {
|
||||
fn default() -> Self {
|
||||
Self([None; Square::NUM])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[Option<Piece>; Square::NUM]> for Mailbox {
|
||||
fn from(value: [Option<Piece>; Square::NUM]) -> Self {
|
||||
Mailbox(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<PlacedPiece> for Mailbox {
|
||||
fn from_iter<T: IntoIterator<Item = PlacedPiece>>(iter: T) -> Self {
|
||||
let mut mailbox = Self::new();
|
||||
for placed_piece in iter {
|
||||
mailbox.set(placed_piece.square(), placed_piece.piece());
|
||||
}
|
||||
|
||||
mailbox
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<(Square, Piece)> for Mailbox {
|
||||
fn from_iter<T: IntoIterator<Item = (Square, Piece)>>(iter: T) -> Self {
|
||||
let mut mailbox = Self::new();
|
||||
for (square, piece) in iter {
|
||||
mailbox.set(square, piece);
|
||||
}
|
||||
|
||||
mailbox
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue