chessfriend/board/src/board.rs

173 lines
4.4 KiB
Rust
Raw Normal View History

// Eryn Wells <eryn@erynwells.me>
2025-05-08 17:37:51 -07:00
use crate::{
castle,
display::DiagramFormatter,
piece_sets::{PlacePieceError, PlacePieceStrategy},
PieceSet,
};
use chessfriend_bitboard::BitBoard;
use chessfriend_core::{Color, Piece, Shape, Square};
pub type HalfMoveClock = u32;
pub type FullMoveClock = u32;
2025-05-08 17:37:51 -07:00
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Board {
2025-05-08 17:37:51 -07:00
pub active_color: Color,
2025-05-03 16:02:56 -07:00
pub pieces: PieceSet,
pub castling_rights: castle::Rights,
2025-05-03 16:02:56 -07:00
pub en_passant_target: Option<Square>,
pub half_move_clock: HalfMoveClock,
pub full_move_number: FullMoveClock,
}
impl Board {
/// An empty board
#[must_use]
pub fn empty() -> Self {
Board::default()
}
/// The starting position
#[must_use]
pub fn starting() -> Self {
const BLACK_PIECES: [BitBoard; Shape::NUM] = [
BitBoard::new(0b0000_0000_1111_1111 << 48),
BitBoard::new(0b0100_0010_0000_0000 << 48),
BitBoard::new(0b0010_0100_0000_0000 << 48),
BitBoard::new(0b1000_0001_0000_0000 << 48),
BitBoard::new(0b0000_1000_0000_0000 << 48),
BitBoard::new(0b0001_0000_0000_0000 << 48),
];
const WHITE_PIECES: [BitBoard; Shape::NUM] = [
BitBoard::new(0b1111_1111_0000_0000),
BitBoard::new(0b0000_0000_0100_0010),
BitBoard::new(0b0000_0000_0010_0100),
BitBoard::new(0b0000_0000_1000_0001),
BitBoard::new(0b0000_0000_0000_1000),
BitBoard::new(0b0000_0000_0001_0000),
];
Self {
pieces: PieceSet::new([WHITE_PIECES, BLACK_PIECES]),
..Default::default()
}
}
2025-05-08 17:37:51 -07:00
}
impl Board {
#[must_use]
pub fn get_piece(&self, square: Square) -> Option<Piece> {
self.pieces.get(square)
}
pub fn find_pieces(&self, piece: Piece) -> BitBoard {
self.pieces.find_pieces(piece)
}
2025-05-08 17:37:51 -07:00
/// 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.
2025-05-08 17:37:51 -07:00
///
pub fn place_piece(
&mut self,
piece: Piece,
square: Square,
strategy: PlacePieceStrategy,
) -> Result<(), PlacePieceError> {
self.pieces.place(piece, square, strategy)
}
2025-05-08 17:37:51 -07:00
pub fn remove_piece(&mut self, square: Square) -> Option<Piece> {
self.pieces.remove(square)
}
}
impl Board {
pub fn iter(&self) -> impl Iterator<Item = (Square, Piece)> {
self.pieces.iter()
}
/// A [`BitBoard`] of squares occupied by pieces of all colors.
pub fn occupancy(&self) -> BitBoard {
self.pieces.occpuancy()
}
/// A [`BitBoard`] of squares that are vacant.
pub fn vacancy(&self) -> BitBoard {
!self.occupancy()
}
pub fn friendly_occupancy(&self, color: Color) -> BitBoard {
self.pieces.friendly_occupancy(color)
}
pub fn opposing_occupancy(&self, color: Color) -> BitBoard {
self.pieces.opposing_occupancy(color)
}
pub fn enemies(&self, color: Color) -> BitBoard {
self.pieces.opposing_occupancy(color)
}
/// Return a [`BitBoard`] of all pawns of a given color.
pub fn pawns(&self, color: Color) -> BitBoard {
self.pieces.find_pieces(Piece::pawn(color))
}
pub fn knights(&self, color: Color) -> BitBoard {
self.find_pieces(Piece::knight(color))
}
pub fn bishops(&self, color: Color) -> BitBoard {
self.find_pieces(Piece::bishop(color))
}
pub fn rooks(&self, color: Color) -> BitBoard {
self.find_pieces(Piece::rook(color))
}
pub fn queens(&self, color: Color) -> BitBoard {
self.find_pieces(Piece::queen(color))
}
pub fn kings(&self, color: Color) -> BitBoard {
self.find_pieces(Piece::king(color))
}
}
impl Board {
2025-05-08 17:37:51 -07:00
pub fn display(&self) -> DiagramFormatter<'_> {
DiagramFormatter::new(self)
}
2025-05-08 17:37:51 -07:00
}
impl Board {
#[must_use]
pub fn unwrap_color(&self, color: Option<Color>) -> Color {
color.unwrap_or(self.active_color)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_board;
use chessfriend_core::piece;
#[test]
2025-05-08 17:37:51 -07:00
fn get_piece_on_square() {
let board = test_board![
Black Bishop on F7,
];
2025-05-08 17:37:51 -07:00
assert_eq!(board.get_piece(Square::F7), Some(piece!(Black Bishop)));
}
}