use u64 as Bitboard; use crate::board::bitboard::{have_common_bit, lsb}; use crate::board::state::State; use crate::movegen::attack::{ fetch_bishop_attacks, fetch_king_attacks, fetch_knight_attacks, fetch_pawn_attacks, fetch_queen_attacks, fetch_rook_attacks, }; use crate::movegen::movegen::{ bishop_pseudo_moves, king_pseudo_moves, knight_pseudo_moves, pawn_pseudo_moves, queen_pseudo_moves, rook_pseudo_moves, }; use crate::movegen::r#move::Move; #[derive(Debug, PartialEq, Eq, Clone)] 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, PieceType::Pawn, Color::White), Piece::new(0x42, PieceType::Knight, Color::White), Piece::new(0x24, PieceType::Bishop, Color::White), Piece::new(0x81, PieceType::Rook, Color::White), Piece::new(0x8, PieceType::Queen, Color::White), Piece::new(0x10, PieceType::King, Color::White), ], black_pieces: [ Piece::new(0xff000000000000, PieceType::Pawn, Color::Black), Piece::new(0x4200000000000000, PieceType::Knight, Color::Black), Piece::new(0x2400000000000000, PieceType::Bishop, Color::Black), Piece::new(0x8100000000000000, PieceType::Rook, Color::Black), Piece::new(0x800000000000000, PieceType::Queen, Color::Black), Piece::new(0x1000000000000000, PieceType::King, Color::Black), ], state: State::new(), } } pub const fn empty_board() -> Self { Self { white_pieces: [ Piece::new(0x0, PieceType::Pawn, Color::White), Piece::new(0x0, PieceType::Knight, Color::White), Piece::new(0x0, PieceType::Bishop, Color::White), Piece::new(0x0, PieceType::Rook, Color::White), Piece::new(0x0, PieceType::Queen, Color::White), Piece::new(0x0, PieceType::King, Color::White), ], black_pieces: [ Piece::new(0x0, PieceType::Pawn, Color::Black), Piece::new(0x0, PieceType::Knight, Color::Black), Piece::new(0x0, PieceType::Bishop, Color::Black), Piece::new(0x0, PieceType::Rook, Color::Black), Piece::new(0x0, PieceType::Queen, Color::Black), Piece::new(0x0, PieceType::King, Color::Black), ], state: State::new(), } } pub fn white_occupancies(&self) -> Bitboard { self.white_pieces.iter().fold(0, |acc, p| p.bitboard | acc) } pub fn black_occupancies(&self) -> Bitboard { self.black_pieces.iter().fold(0, |acc, p| p.bitboard | acc) } pub fn all_occupancies(&self) -> Bitboard { self.white_occupancies() | self.black_occupancies() } pub fn is_attacked(&self, square: usize, opponent_color: Color) -> bool { let all_occupancies = self.all_occupancies(); let (opponent, own_color) = match opponent_color { Color::Black => (&self.black_pieces, Color::White), Color::White => (&self.white_pieces, Color::Black), }; let pawns = opponent[PieceType::Pawn].bitboard; let knights = opponent[PieceType::Knight].bitboard; let bishops = opponent[PieceType::Bishop].bitboard; let rooks = opponent[PieceType::Rook].bitboard; let queens = opponent[PieceType::Queen].bitboard; let king = opponent[PieceType::King].bitboard; have_common_bit(pawns, fetch_pawn_attacks(square, own_color)) || have_common_bit(knights, fetch_knight_attacks(square)) || have_common_bit(bishops, fetch_bishop_attacks(all_occupancies, square)) || have_common_bit(rooks, fetch_rook_attacks(all_occupancies, square)) || have_common_bit(queens, fetch_queen_attacks(all_occupancies, square)) || have_common_bit(king, fetch_king_attacks(square)) } pub fn king_under_check(&self, color: Color) -> bool { let own_king_square = match color { Color::White => lsb(self.white_pieces[PieceType::King].bitboard), Color::Black => lsb(self.black_pieces[PieceType::King].bitboard), }; self.is_attacked(own_king_square, color.opponent()) } pub fn pseudo_moves_all(&self) -> Vec { let color = self.state.current_player(); let mut moves = vec![]; moves.extend(self.pseudo_moves(color, PieceType::Pawn)); moves.extend(self.pseudo_moves(color, PieceType::Knight)); moves.extend(self.pseudo_moves(color, PieceType::Bishop)); moves.extend(self.pseudo_moves(color, PieceType::Rook)); moves.extend(self.pseudo_moves(color, PieceType::Queen)); moves.extend(self.pseudo_moves(color, PieceType::King)); moves } pub fn pseudo_moves(&self, color: Color, piece_type: PieceType) -> Vec { let all_occupancies = self.all_occupancies(); let (pieces, opponent_occupancies, own_occupancies) = match color { Color::White => ( self.white_pieces[piece_type].bitboard, self.black_occupancies(), self.white_occupancies(), ), Color::Black => ( self.black_pieces[piece_type].bitboard, self.white_occupancies(), self.black_occupancies(), ), }; match piece_type { PieceType::Pawn => pawn_pseudo_moves( pieces, all_occupancies, opponent_occupancies, self.state.en_passant_square(), color, ), PieceType::Knight => knight_pseudo_moves(pieces, all_occupancies, own_occupancies), PieceType::Bishop => bishop_pseudo_moves(pieces, all_occupancies, own_occupancies), PieceType::Rook => rook_pseudo_moves(pieces, all_occupancies, own_occupancies), PieceType::Queen => queen_pseudo_moves(pieces, all_occupancies, own_occupancies), PieceType::King => { king_pseudo_moves(pieces, all_occupancies, own_occupancies, self, color) } } } pub fn set_piece(&mut self, piece: Piece) { match piece.color { Color::Black => self.black_pieces[piece.piece_type].bitboard |= piece.bitboard, Color::White => self.white_pieces[piece.piece_type].bitboard |= piece.bitboard, }; } pub fn set_state(&mut self, state: State) { self.state = state; } pub fn piece_type_at(&self, square: usize, color: Color) -> Option { let pieces = match color { Color::White => &self.white_pieces, Color::Black => &self.black_pieces, }; pieces .iter() .find(|p| have_common_bit(p.bitboard, square_to_bitboard(square))) .map(|p| p.piece_type) } } impl Default for Board { fn default() -> Self { Self::new() } } #[derive(Debug, PartialEq, Eq, Clone)] pub struct Piece { pub bitboard: Bitboard, pub piece_type: PieceType, pub color: Color, } impl Piece { pub const fn new(bitboard: Bitboard, piece_type: PieceType, color: Color) -> Self { Self { bitboard, piece_type, color, } } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum PieceType { Pawn, Knight, Bishop, Rook, Queen, King, } impl PieceType { const fn idx(&self) -> usize { match self { Self::Pawn => 0, Self::Knight => 1, Self::Bishop => 2, Self::Rook => 3, Self::Queen => 4, Self::King => 5, } } } use std::ops::{Index, IndexMut}; use super::bitboard::square_to_bitboard; impl Index for [Piece] { type Output = Piece; fn index(&self, piece_type: PieceType) -> &Self::Output { &self[piece_type.idx()] } } impl IndexMut for [Piece] { fn index_mut(&mut self, piece_type: PieceType) -> &mut Self::Output { &mut self[piece_type.idx()] } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Color { White, Black, } impl Color { pub const fn opponent(&self) -> Self { match self { Self::White => Self::Black, Self::Black => Self::White, } } } #[cfg(test)] mod tests { use crate::{board::fen::from_fen, movegen::attack::init_attacks}; use super::*; const FEN_EXAMPLE: [&str; 1] = ["8/6P1/4n2b/1p6/1Kp5/6n1/4b3/1k6 w - - 0 1"]; #[test] fn test_occupancies() -> Result<(), String> { let new_game = from_fen(FEN_EXAMPLE[0])?; assert_eq!(new_game.board.white_occupancies(), 0x40000002000000); assert_eq!(new_game.board.black_occupancies(), 0x900204401002); assert_eq!(new_game.board.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(()) } }