use std::fmt; use u64 as Bitboard; use crate::attack::{ get_bishop_attacks, get_king_attacks, get_knight_attacks, get_pawn_attacks, get_queen_attacks, get_rook_attacks, }; use crate::game::State; #[derive(Debug, PartialEq, Eq)] pub struct Board { pub white_pieces: [Piece; 6], pub black_pieces: [Piece; 6], pub state: State, } impl Board { pub const fn new() -> Self { Self { white_pieces: [ Piece::new(0xff00, Kind::Pawn, Color::White), Piece::new(0x42, Kind::Knight, Color::White), Piece::new(0x24, Kind::Bishop, Color::White), Piece::new(0x81, Kind::Rook, Color::White), Piece::new(0x8, Kind::Queen, Color::White), Piece::new(0x10, Kind::King, Color::White), ], black_pieces: [ Piece::new(0xff000000000000, Kind::Pawn, Color::Black), Piece::new(0x4200000000000000, Kind::Knight, Color::Black), Piece::new(0x2400000000000000, Kind::Bishop, Color::Black), Piece::new(0x8100000000000000, Kind::Rook, Color::Black), Piece::new(0x800000000000000, Kind::Queen, Color::Black), Piece::new(0x1000000000000000, Kind::King, Color::Black), ], state: State::new(), } } pub const fn empty_board() -> Self { Self { white_pieces: [ Piece::new(0x0, Kind::Pawn, Color::White), Piece::new(0x0, Kind::Knight, Color::White), Piece::new(0x0, Kind::Bishop, Color::White), Piece::new(0x0, Kind::Rook, Color::White), Piece::new(0x0, Kind::Queen, Color::White), Piece::new(0x0, Kind::King, Color::White), ], black_pieces: [ Piece::new(0x0, Kind::Pawn, Color::Black), Piece::new(0x0, Kind::Knight, Color::Black), Piece::new(0x0, Kind::Bishop, Color::Black), Piece::new(0x0, Kind::Rook, Color::Black), Piece::new(0x0, Kind::Queen, Color::Black), Piece::new(0x0, Kind::King, Color::Black), ], state: State::new(), } } pub fn set_piece(&mut self, piece: Piece) { match piece.color { Color::Black => self.black_pieces[piece.kind.idx()].bitboard |= piece.bitboard, Color::White => self.white_pieces[piece.kind.idx()].bitboard |= piece.bitboard, }; } pub fn set_state(&mut self, state: State) { self.state = state; } pub fn get_white_occupancies(&self) -> Bitboard { self.white_pieces.iter().fold(0, |acc, p| p.bitboard | acc) } pub fn get_black_occupancies(&self) -> Bitboard { self.black_pieces.iter().fold(0, |acc, p| p.bitboard | acc) } pub fn get_all_occupancies(&self) -> Bitboard { self.get_white_occupancies() | self.get_black_occupancies() } pub fn is_attacked(&self, sq: usize, opponent_color: Color) -> bool { let all_occupancies = self.get_all_occupancies(); let enemy = match opponent_color { Color::Black => &self.black_pieces, Color::White => &self.white_pieces, }; enemy[Kind::Pawn.idx()].bitboard & get_pawn_attacks(sq, opponent_color) != 0 || enemy[Kind::Knight.idx()].bitboard & get_knight_attacks(sq) != 0 || enemy[Kind::Bishop.idx()].bitboard & get_bishop_attacks(all_occupancies, sq) != 0 || enemy[Kind::Rook.idx()].bitboard & get_rook_attacks(all_occupancies, sq) != 0 || enemy[Kind::Queen.idx()].bitboard & get_queen_attacks(all_occupancies, sq) != 0 || enemy[Kind::King.idx()].bitboard & get_king_attacks(sq) != 0 } } impl Default for Board { fn default() -> Self { Self::new() } } impl fmt::Display for Board { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for piece in &self.white_pieces { writeln!( f, "Color: {:?}\nKind: {:?}\n{piece}", piece.color, piece.kind )?; } writeln!(f)?; for piece in &self.black_pieces { writeln!( f, "Color: {:?}\nKind: {:?}\n{piece}", piece.color, piece.kind )?; } writeln!(f) } } #[derive(Debug, PartialEq, Eq)] pub struct Piece { pub bitboard: Bitboard, pub kind: Kind, pub color: Color, } impl Piece { pub const fn new(bitboard: Bitboard, kind: Kind, color: Color) -> Self { Self { bitboard, kind, color, } } } impl fmt::Display for Piece { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for rank in (0..8).rev() { for file in 0..8 { let square = 1 << (rank * 8 + file); let position = if square & self.bitboard != 0x0 { 1 } else { 0 }; write!(f, "{} ", position)?; } writeln!(f)?; } writeln!(f) } } #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum Kind { Pawn, Knight, Bishop, Rook, Queen, King, } impl Kind { fn idx(&self) -> usize { *self as usize } } #[derive(Debug, PartialEq, Eq)] pub enum Color { White, Black, } #[cfg(test)] mod tests { use crate::{attack::init_attacks, fen::from_fen}; use super::*; const FEN_EXAMPLE: [&str; 1] = [ "8/6P1/4n2b/1p6/1Kp5/6n1/4b3/1k6 w - - 0 1", ]; #[test] fn test_get_all_occupancies() -> Result<(), String> { let new_game = from_fen(FEN_EXAMPLE[0])?; assert_eq!(new_game.board.get_all_occupancies(), 0x40900206401002); Ok(()) } #[test] fn test_is_attacked() -> Result<(), String> { let new_game = from_fen(FEN_EXAMPLE[0])?; init_attacks(); assert!(new_game.board.is_attacked(54, Color::Black)); Ok(()) } }