// Eryn Wells use crate::{ castle, display::DiagramFormatter, piece_sets::{PlacePieceError, PlacePieceStrategy}, PieceSet, }; use chessfriend_bitboard::BitBoard; use chessfriend_core::{Color, Piece, Shape, Square, Wing}; pub type HalfMoveClock = u32; pub type FullMoveClock = u32; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Board { pub active_color: Color, pub pieces: PieceSet, pub castling_rights: castle::Rights, pub en_passant_target: Option, 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() } } } impl Board { #[must_use] pub fn get_piece(&self, square: Square) -> Option { 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 { self.pieces.remove(square) } } impl Board { /// 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) } } impl Board { #[must_use] pub fn castling_parameters(&self, wing: Wing) -> &'static castle::Parameters { &castle::Parameters::BY_COLOR[self.active_color as usize][wing as usize] } } impl Board { pub fn display(&self) -> DiagramFormatter<'_> { DiagramFormatter::new(self) } } impl Board { #[must_use] pub fn unwrap_color(&self, color: Option) -> Color { color.unwrap_or(self.active_color) } } #[cfg(test)] mod tests { use super::*; use crate::test_board; use chessfriend_core::piece; #[test] fn get_piece_on_square() { let board = test_board![ Black Bishop on F7, ]; assert_eq!(board.get_piece(Square::F7), Some(piece!(Black Bishop))); } }