use u64 as Bitboard; use crate::attack::{ fetch_bishop_attacks, fetch_king_attacks, fetch_knight_attacks, fetch_pawn_attacks, fetch_queen_attacks, fetch_rook_attacks, }; use crate::bitboard::have_common_bit; use crate::movegen::{ bishop_pseudo_moves, king_pseudo_moves, knight_pseudo_moves, pawn_pseudo_moves, queen_pseudo_moves, rook_pseudo_moves, }; use crate::r#move::Move; use crate::state::State; #[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, 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 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), }; have_common_bit( opponent[Kind::Pawn].bitboard, fetch_pawn_attacks(square, own_color), ) || have_common_bit( opponent[Kind::Knight].bitboard, fetch_knight_attacks(square), ) || have_common_bit( opponent[Kind::Bishop].bitboard, fetch_bishop_attacks(all_occupancies, square), ) || have_common_bit( opponent[Kind::Rook].bitboard, fetch_rook_attacks(all_occupancies, square), ) || have_common_bit( opponent[Kind::Queen].bitboard, fetch_queen_attacks(all_occupancies, square), ) || have_common_bit(opponent[Kind::King].bitboard, fetch_king_attacks(square)) } pub fn is_move_legit(&self, square: usize, opponent_color: Color) -> bool { !self.is_attacked(square, opponent_color) } pub fn pseudo_moves_all(&self, color: Color) -> Vec { let mut moves = vec![]; moves.extend(self.pseudo_moves(color, Kind::Pawn)); moves.extend(self.pseudo_moves(color, Kind::Knight)); moves.extend(self.pseudo_moves(color, Kind::Bishop)); moves.extend(self.pseudo_moves(color, Kind::Rook)); moves.extend(self.pseudo_moves(color, Kind::Queen)); moves.extend(self.pseudo_moves(color, Kind::King)); moves } pub fn pseudo_moves(&self, color: Color, kind: Kind) -> Vec { let all_occupancies = self.all_occupancies(); let (pieces, opponent_occupancies, own_occupancies) = match color { Color::White => ( self.white_pieces[kind].bitboard, self.black_occupancies(), self.white_occupancies(), ), Color::Black => ( self.black_pieces[kind].bitboard, self.white_occupancies(), self.black_occupancies(), ), }; match kind { Kind::Pawn => pawn_pseudo_moves( pieces, all_occupancies, opponent_occupancies, self.state.en_passant_target_square(), color, ), Kind::Knight => knight_pseudo_moves(pieces, all_occupancies, own_occupancies), Kind::Bishop => bishop_pseudo_moves(pieces, all_occupancies, own_occupancies), Kind::Rook => rook_pseudo_moves(pieces, all_occupancies, own_occupancies), Kind::Queen => queen_pseudo_moves(pieces, all_occupancies, own_occupancies), Kind::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.kind].bitboard |= piece.bitboard, Color::White => self.white_pieces[piece.kind].bitboard |= piece.bitboard, }; } pub fn set_state(&mut self, state: State) { self.state = state; } } impl Default for Board { fn default() -> Self { Self::new() } } #[derive(Debug, PartialEq, Eq, Clone)] 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, } } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Kind { Pawn, Knight, Bishop, Rook, Queen, King, } impl Kind { fn idx(&self) -> usize { match self { Kind::Pawn => 0, Kind::Knight => 1, Kind::Bishop => 2, Kind::Rook => 3, Kind::Queen => 4, Kind::King => 5, } } } use std::ops::{Index, IndexMut}; impl Index for [Piece] { type Output = Piece; fn index(&self, kind: Kind) -> &Self::Output { &self[kind.idx()] } } impl IndexMut for [Piece] { fn index_mut(&mut self, kind: Kind) -> &mut Self::Output { &mut self[kind.idx()] } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Color { White, Black, } impl Color { pub const fn opponent_color(color: Self) -> Self { match color { Self::White => Self::Black, Self::Black => Self::White, } } } #[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_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(()) } #[test] fn test_fifty_move_draw() -> Result<(), String> { //TODO: make a MoveHistory/BoardHistory/GameHistory struct Ok(()) } #[test] fn test_threefold_repetition() -> Result<(), String> { //TODO: make a MoveHistory/BoardHistory/GameHistory struct Ok(()) } }