[board] A ton of API refinements
This commit is contained in:
parent
99dd2d1be2
commit
867deafd13
7 changed files with 208 additions and 244 deletions
|
@ -1,19 +1,16 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::{
|
||||
castle, display::DiagramFormatter, piece_sets::PlacePieceError, EnPassant, MoveCounter,
|
||||
PieceSet,
|
||||
};
|
||||
use crate::{castle, display::DiagramFormatter, Castle, Clock, PieceSet};
|
||||
use chessfriend_bitboard::BitBoard;
|
||||
use chessfriend_core::{Color, Piece, PlacedPiece, Shape, Square};
|
||||
use std::iter::Iterator;
|
||||
|
||||
#[derive(Clone, Debug, Eq)]
|
||||
#[derive(Clone, Debug, Default, Eq)]
|
||||
pub struct Board {
|
||||
pieces: PieceSet,
|
||||
en_passant: Option<EnPassant>,
|
||||
pub move_counter: MoveCounter,
|
||||
pub clock: Clock,
|
||||
pub pieces: PieceSet,
|
||||
pub castling_rights: castle::Rights,
|
||||
pub en_passant_target: Option<Square>,
|
||||
}
|
||||
|
||||
impl Board {
|
||||
|
@ -52,18 +49,7 @@ impl Board {
|
|||
|
||||
#[must_use]
|
||||
pub fn player_to_move(&self) -> Color {
|
||||
self.move_counter.active_color
|
||||
}
|
||||
|
||||
/// Returns `true` if the player has the right to castle on the given side
|
||||
/// of the board.
|
||||
///
|
||||
/// A player retains the right to castle on a particular side of the board
|
||||
/// as long as they have not moved their king, or the rook on that side of
|
||||
/// the board.
|
||||
#[must_use]
|
||||
pub fn player_has_right_to_castle(&self, color: Color, castle: Castle) -> bool {
|
||||
self.flags.player_has_right_to_castle(color, castle)
|
||||
self.clock.active_color()
|
||||
}
|
||||
|
||||
/// The rook to use for a castling move.
|
||||
|
@ -83,11 +69,9 @@ impl Board {
|
|||
/// 2. The king must not be in check
|
||||
/// 3. In the course of castling on that side, the king must not pass
|
||||
/// 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
|
||||
.player_has_right_to_castle(player, castle.into())
|
||||
{
|
||||
if !self.castling_rights.is_set(player, castle.into()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -115,12 +99,13 @@ impl Board {
|
|||
|
||||
#[must_use]
|
||||
pub fn friendly_pieces_bitboard(&self) -> BitBoard {
|
||||
self.pieces.all_pieces_of_color(self.player_to_move)
|
||||
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.player_to_move.other())
|
||||
self.pieces
|
||||
.all_pieces_of_color(self.clock.active_color().other())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
@ -131,7 +116,15 @@ impl Board {
|
|||
)
|
||||
}
|
||||
|
||||
/// A [BitBoard] representing the set of squares containing a piece. This
|
||||
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 {
|
||||
|
@ -145,12 +138,10 @@ impl Board {
|
|||
.map(|piece| PlacedPiece::new(piece, square))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn iter_all_pieces(&self) -> impl Iterator<Item = PlacedPiece> + '_ {
|
||||
self.pieces.iter()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn iter_pieces_of_color(&self, color: Color) -> impl Iterator<Item = PlacedPiece> + '_ {
|
||||
self.pieces
|
||||
.iter()
|
||||
|
@ -158,13 +149,8 @@ impl Board {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn has_en_passant_square(&self) -> bool {
|
||||
self.en_passant.is_some()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn en_passant(&self) -> Option<EnPassant> {
|
||||
self.en_passant
|
||||
pub fn en_passant_target(&self) -> Option<Square> {
|
||||
self.en_passant_target
|
||||
}
|
||||
|
||||
fn king_bitboard(&self, player: Color) -> BitBoard {
|
||||
|
@ -172,10 +158,7 @@ impl Board {
|
|||
}
|
||||
|
||||
pub(crate) fn king_square(&self, player: Color) -> Square {
|
||||
self.king_bitboard(player)
|
||||
.occupied_squares()
|
||||
.next()
|
||||
.unwrap()
|
||||
self.king_bitboard(player).try_into().unwrap()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
@ -192,16 +175,19 @@ impl Board {
|
|||
pub fn bitboard_for_piece(&self, piece: Piece) -> BitBoard {
|
||||
self.pieces.bitboard_for_piece(piece)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Board {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
castling_rights: castle::Rights::default(),
|
||||
pieces: PieceSet::default(),
|
||||
en_passant: None,
|
||||
move_counter: MoveCounter::default(),
|
||||
}
|
||||
/// 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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,8 +195,8 @@ impl PartialEq for Board {
|
|||
fn eq(&self, other: &Self) -> bool {
|
||||
self.pieces == other.pieces
|
||||
&& self.castling_rights == other.castling_rights
|
||||
&& self.en_passant == other.en_passant
|
||||
&& self.move_counter == other.move_counter
|
||||
&& self.en_passant_target == other.en_passant_target
|
||||
&& self.clock == other.clock
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,49 +229,4 @@ mod tests {
|
|||
Some(piece!(Black Rook on A8))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn king_not_on_starting_square_cannot_castle() {
|
||||
let board = test_board!(White King on E4);
|
||||
assert!(!board
|
||||
.castling_rights
|
||||
.player_has_right_to_castle(Color::White, Castle::KingSide));
|
||||
assert!(!board
|
||||
.castling_rights
|
||||
.player_has_right_to_castle(Color::White, Castle::QueenSide));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn king_on_starting_square_can_castle() {
|
||||
let board = test_board!(
|
||||
White King on E1,
|
||||
White Rook on A1,
|
||||
White Rook on H1
|
||||
);
|
||||
|
||||
assert!(board
|
||||
.castling_rights
|
||||
.player_has_right_to_castle(Color::White, Castle::KingSide));
|
||||
assert!(board
|
||||
.castling_rights
|
||||
.player_has_right_to_castle(Color::White, Castle::QueenSide));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rook_for_castle() {
|
||||
let board = test_board![
|
||||
White King on E1,
|
||||
White Rook on H1,
|
||||
White Rook on A1,
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
board.rook_for_castle(Color::White, Castle::KingSide),
|
||||
Some(piece!(White Rook on H1))
|
||||
);
|
||||
assert_eq!(
|
||||
board.rook_for_castle(Color::White, Castle::QueenSide),
|
||||
Some(piece!(White Rook on A1))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue