Refactor project structure to use submodules
This commit is contained in:
285
src/board/board.rs
Normal file
285
src/board/board.rs
Normal file
@@ -0,0 +1,285 @@
|
||||
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),
|
||||
};
|
||||
|
||||
have_common_bit(
|
||||
opponent[PieceType::Pawn].bitboard,
|
||||
fetch_pawn_attacks(square, own_color),
|
||||
) || have_common_bit(
|
||||
opponent[PieceType::Knight].bitboard,
|
||||
fetch_knight_attacks(square),
|
||||
) || have_common_bit(
|
||||
opponent[PieceType::Bishop].bitboard,
|
||||
fetch_bishop_attacks(all_occupancies, square),
|
||||
) || have_common_bit(
|
||||
opponent[PieceType::Rook].bitboard,
|
||||
fetch_rook_attacks(all_occupancies, square),
|
||||
) || have_common_bit(
|
||||
opponent[PieceType::Queen].bitboard,
|
||||
fetch_queen_attacks(all_occupancies, square),
|
||||
) || have_common_bit(
|
||||
opponent[PieceType::King].bitboard,
|
||||
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_color(color))
|
||||
}
|
||||
|
||||
pub fn pseudo_moves_all(&self, color: Color) -> Vec<Move> {
|
||||
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<Move> {
|
||||
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_target_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;
|
||||
}
|
||||
}
|
||||
|
||||
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};
|
||||
|
||||
impl Index<PieceType> for [Piece] {
|
||||
type Output = Piece;
|
||||
|
||||
fn index(&self, piece_type: PieceType) -> &Self::Output {
|
||||
&self[piece_type.idx()]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<PieceType> 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_color(color: Self) -> Self {
|
||||
match color {
|
||||
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(())
|
||||
}
|
||||
|
||||
#[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(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user