208 lines
6.0 KiB
Rust
208 lines
6.0 KiB
Rust
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(())
|
|
}
|
|
}
|