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>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use chessfriend_bitboard::BitBoard;
|
mod bitboards;
|
||||||
use chessfriend_core::{Color, Piece, PlacedPiece, Square};
|
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 {
|
pub enum PlacePieceStrategy {
|
||||||
Replace,
|
Replace,
|
||||||
PreserveExisting,
|
PreserveExisting,
|
||||||
|
@ -11,7 +16,7 @@ pub enum PlacePieceStrategy {
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum PlacePieceError {
|
pub enum PlacePieceError {
|
||||||
ExisitingPiece,
|
ExisitingPiece(PlacedPiece),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlacePieceStrategy {
|
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)]
|
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||||
pub(crate) struct PieceBitBoards {
|
pub(crate) struct PieceSet {
|
||||||
by_color: ByColor,
|
by_color: ByColor,
|
||||||
by_color_and_shape: ByColorAndShape,
|
by_color_and_shape: ByColorAndShape,
|
||||||
|
mailbox: Mailbox,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
impl PieceSet {
|
||||||
struct ByColor(BitBoard, [BitBoard; 2]);
|
pub(crate) fn new(pieces: [[BitBoard; Shape::NUM]; Color::NUM]) -> Self {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
|
||||||
struct ByColorAndShape([[BitBoard; 6]; 2]);
|
|
||||||
|
|
||||||
impl PieceBitBoards {
|
|
||||||
pub(super) fn new(pieces: [[BitBoard; 6]; 2]) -> Self {
|
|
||||||
use std::ops::BitOr;
|
use std::ops::BitOr;
|
||||||
|
|
||||||
let white_pieces = pieces[Color::White as usize]
|
let white_pieces = pieces[Color::White as usize]
|
||||||
|
@ -45,130 +47,99 @@ impl PieceBitBoards {
|
||||||
|
|
||||||
let all_pieces = white_pieces | black_pieces;
|
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 {
|
Self {
|
||||||
by_color: ByColor(all_pieces, [white_pieces, black_pieces]),
|
by_color: ByColor::new(all_pieces, [white_pieces, black_pieces]),
|
||||||
by_color_and_shape: ByColorAndShape(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'.
|
/// 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()
|
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)
|
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)
|
self.by_color.bitboard(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn bitboard_for_color_mut(&mut self, color: Color) -> &mut BitBoard {
|
pub(crate) fn bitboard_for_piece(&self, piece: Piece) -> BitBoard {
|
||||||
self.by_color.bitboard_mut(color)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn bitboard_for_piece(&self, piece: &Piece) -> &BitBoard {
|
|
||||||
self.by_color_and_shape.bitboard_for_piece(piece)
|
self.by_color_and_shape.bitboard_for_piece(piece)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn bitboard_for_piece_mut(&mut self, piece: &Piece) -> &mut BitBoard {
|
pub(crate) fn get(&self, square: Square) -> Option<Piece> {
|
||||||
self.by_color_and_shape.bitboard_for_piece_mut(piece)
|
self.mailbox.get(square)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn place_piece(&mut self, piece: &PlacedPiece) -> Result<(), PlacePieceError> {
|
pub(crate) fn place_piece_on_square(
|
||||||
self.place_piece_with_strategy(piece, PlacePieceStrategy::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn place_piece_with_strategy(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
piece: &PlacedPiece,
|
piece: Piece,
|
||||||
strategy: PlacePieceStrategy,
|
square: Square,
|
||||||
) -> Result<(), PlacePieceError> {
|
) -> Result<PlacedPiece, PlacePieceError> {
|
||||||
let color = piece.color();
|
self.place_piece_on_square_with_strategy(piece, square, PlacePieceStrategy::default())
|
||||||
let square = piece.square();
|
}
|
||||||
|
|
||||||
if strategy == PlacePieceStrategy::PreserveExisting
|
pub(crate) fn place_piece_on_square_with_strategy(
|
||||||
&& self.by_color.bitboard(color).is_set(piece.square())
|
&mut self,
|
||||||
{
|
piece: Piece,
|
||||||
return Err(PlacePieceError::ExisitingPiece);
|
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.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) {
|
pub(crate) fn remove_piece_from_square(&mut self, square: Square) -> Option<PlacedPiece> {
|
||||||
let color = piece.color();
|
if let Some(piece) = self.mailbox.get(square) {
|
||||||
let square = piece.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());
|
Some(PlacedPiece::new(piece, square))
|
||||||
self.by_color.clear_square(square, color);
|
} else {
|
||||||
}
|
None
|
||||||
|
}
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<PlacedPiece> for PieceBitBoards {
|
impl FromIterator<PlacedPiece> for PieceSet {
|
||||||
fn from_iter<T: IntoIterator<Item = PlacedPiece>>(iter: T) -> Self {
|
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 {
|
for piece in iter {
|
||||||
let _ = pieces.place_piece(&piece);
|
let _ = pieces.place_piece_on_square(piece.piece(), piece.square());
|
||||||
}
|
}
|
||||||
|
|
||||||
pieces
|
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