WIP
This commit is contained in:
parent
d5cdf273c8
commit
091cc99cb3
42 changed files with 805 additions and 1662 deletions
|
@ -1,16 +1,22 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::{castle, display::DiagramFormatter, Castle, Clock, PieceSet};
|
||||
use crate::{
|
||||
castle,
|
||||
display::DiagramFormatter,
|
||||
piece_sets::{PlacePieceError, PlacePieceStrategy},
|
||||
PieceSet,
|
||||
};
|
||||
use chessfriend_bitboard::BitBoard;
|
||||
use chessfriend_core::{Color, Piece, PlacedPiece, Shape, Square};
|
||||
use std::iter::Iterator;
|
||||
use chessfriend_core::{Color, Piece, Shape, Square};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct Board {
|
||||
pub clock: Clock,
|
||||
pub active_color: Color,
|
||||
pub pieces: PieceSet,
|
||||
pub castling_rights: castle::Rights,
|
||||
pub en_passant_target: Option<Square>,
|
||||
pub half_move_clock: u32,
|
||||
pub full_move_number: u32,
|
||||
}
|
||||
|
||||
impl Board {
|
||||
|
@ -46,12 +52,44 @@ impl Board {
|
|||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Board {
|
||||
#[must_use]
|
||||
pub fn player_to_move(&self) -> Color {
|
||||
self.clock.active_color()
|
||||
pub fn get_piece(&self, square: Square) -> Option<Piece> {
|
||||
self.pieces.get(square)
|
||||
}
|
||||
|
||||
/// Place a piece on the board.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// When is called with [`PlacePieceStrategy::PreserveExisting`], and a piece already exists on
|
||||
/// `square`, this method returns a [`PlacePieceError::ExistingPiece`] error.
|
||||
///
|
||||
pub fn place_piece(
|
||||
&mut self,
|
||||
piece: Piece,
|
||||
square: Square,
|
||||
strategy: PlacePieceStrategy,
|
||||
) -> Result<(), PlacePieceError> {
|
||||
self.pieces.place(piece, square, strategy)
|
||||
}
|
||||
|
||||
pub fn remove_piece(&mut self, square: Square) -> Option<Piece> {
|
||||
self.pieces.remove(square)
|
||||
}
|
||||
}
|
||||
|
||||
impl Board {
|
||||
#[must_use]
|
||||
pub fn display(&self) -> DiagramFormatter<'_> {
|
||||
DiagramFormatter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl Board {
|
||||
/// The rook to use for a castling move.
|
||||
#[must_use]
|
||||
pub fn rook_for_castle(&self, player: Color, castle: Castle) -> Option<PlacedPiece> {
|
||||
|
@ -71,73 +109,26 @@ impl Board {
|
|||
/// through a square that an enemy piece can see
|
||||
#[must_use]
|
||||
pub fn player_can_castle(&self, player: Color, castle: Castle) -> bool {
|
||||
if !self.castling_rights.is_set(player, castle.into()) {
|
||||
if !self.castling_rights.is_set(player, castle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let castling_parameters = castle.parameters(player);
|
||||
|
||||
let all_pieces = self.all_pieces_bitboard();
|
||||
let all_pieces = self.pieces.all_pieces();
|
||||
if !(all_pieces & castling_parameters.clear_squares()).is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let danger_squares = self.king_danger(player);
|
||||
if !(danger_squares & castling_parameters.check_squares()).is_empty() {
|
||||
return false;
|
||||
}
|
||||
// TODO: Reimplement king_danger here or in Position.
|
||||
// let danger_squares = self.king_danger(player);
|
||||
// if !(danger_squares & castling_parameters.check_squares()).is_empty() {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// A [`BitBoard`] representing the set of squares containing a piece. This
|
||||
/// set is the inverse of [`Board::empty_squares`].
|
||||
#[must_use]
|
||||
pub fn occupied_squares(&self) -> BitBoard {
|
||||
self.pieces.all_pieces()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn friendly_pieces_bitboard(&self) -> BitBoard {
|
||||
self.pieces.all_pieces_of_color(self.clock.active_color())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn opposing_pieces_bitboard(&self) -> BitBoard {
|
||||
self.pieces
|
||||
.all_pieces_of_color(self.clock.active_color().other())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn all_pieces(&self) -> (BitBoard, BitBoard) {
|
||||
(
|
||||
self.friendly_pieces_bitboard(),
|
||||
self.opposing_pieces_bitboard(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn all_pieces_bitboard(&self) -> BitBoard {
|
||||
self.pieces.all_pieces()
|
||||
}
|
||||
|
||||
pub fn all_pieces_of_color_bitboard(&self, color: Color) -> BitBoard {
|
||||
self.pieces.all_pieces_of_color(color)
|
||||
}
|
||||
|
||||
/// A [`BitBoard`] representing the set of squares containing a piece. This
|
||||
/// set is the inverse of [`Board::occupied_squares`].
|
||||
#[must_use]
|
||||
pub fn empty_squares(&self) -> BitBoard {
|
||||
!self.occupied_squares()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn piece_on_square(&self, square: Square) -> Option<PlacedPiece> {
|
||||
self.pieces
|
||||
.get(square)
|
||||
.map(|piece| PlacedPiece::new(piece, square))
|
||||
}
|
||||
|
||||
pub fn iter_all_pieces(&self) -> impl Iterator<Item = PlacedPiece> + '_ {
|
||||
self.pieces.iter()
|
||||
}
|
||||
|
@ -147,58 +138,8 @@ impl Board {
|
|||
.iter()
|
||||
.filter(move |piece| piece.color() == color)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn en_passant_target(&self) -> Option<Square> {
|
||||
self.en_passant_target
|
||||
}
|
||||
|
||||
fn king_bitboard(&self, player: Color) -> BitBoard {
|
||||
self.pieces.bitboard_for_piece(Piece::king(player))
|
||||
}
|
||||
|
||||
pub(crate) fn king_square(&self, player: Color) -> Square {
|
||||
self.king_bitboard(player).try_into().unwrap()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn display(&self) -> DiagramFormatter<'_> {
|
||||
DiagramFormatter::new(self)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn bitboard_for_color(&self, color: Color) -> BitBoard {
|
||||
self.pieces.bitboard_for_color(color)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn bitboard_for_piece(&self, piece: Piece) -> BitBoard {
|
||||
self.pieces.bitboard_for_piece(piece)
|
||||
}
|
||||
|
||||
/// A [`BitBoard`] representing the squares where a king of the given color will
|
||||
/// be in danger of being captured by the opposing player. If the king is on
|
||||
/// one of these squares, it is in check. The king cannot move to these
|
||||
/// squares.
|
||||
pub(crate) fn king_danger(&self, color: Color) -> BitBoard {
|
||||
let board_without_king = {
|
||||
let mut cloned_board = self.clone();
|
||||
cloned_board.pieces.remove(self.king_square(color));
|
||||
cloned_board
|
||||
};
|
||||
|
||||
BitBoard::full()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Board {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.pieces == other.pieces
|
||||
&& self.castling_rights == other.castling_rights
|
||||
&& self.en_passant_target == other.en_passant_target
|
||||
&& self.clock == other.clock
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -207,26 +148,11 @@ mod tests {
|
|||
use chessfriend_core::piece;
|
||||
|
||||
#[test]
|
||||
fn piece_on_square() {
|
||||
let pos = test_board![
|
||||
fn get_piece_on_square() {
|
||||
let board = test_board![
|
||||
Black Bishop on F7,
|
||||
];
|
||||
|
||||
let piece = pos.piece_on_square(Square::F7);
|
||||
assert_eq!(piece, Some(piece!(Black Bishop on F7)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn piece_in_starting_position() {
|
||||
let board = test_board!(starting);
|
||||
|
||||
assert_eq!(
|
||||
board.piece_on_square(Square::H1),
|
||||
Some(piece!(White Rook on H1))
|
||||
);
|
||||
assert_eq!(
|
||||
board.piece_on_square(Square::A8),
|
||||
Some(piece!(Black Rook on A8))
|
||||
);
|
||||
assert_eq!(board.get_piece(Square::F7), Some(piece!(Black Bishop)));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue