Solidify PieceSet and supporting types

This commit is contained in:
Eryn Wells 2024-07-12 15:52:41 -07:00
parent b3c472fbce
commit 19feff9591
3 changed files with 187 additions and 101 deletions

View file

@ -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);
}
}

View 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);
}
}

View 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
}
}