Files
zeal/src/board.rs

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(())
}
}