Reduce bitboards from 12 to 8, add color info in mailbox representation
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
use strum_macros::EnumIter;
|
||||
use u64 as Bitboard;
|
||||
|
||||
use crate::board::bitboard::{have_common_bit, lsb, square_to_bitboard};
|
||||
@@ -14,62 +15,42 @@ use crate::movegen::r#move::{Move, MoveType, Promote};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Board {
|
||||
pub white_pieces: [Piece; 6],
|
||||
pub black_pieces: [Piece; 6],
|
||||
pub pieces: [Bitboard; 6],
|
||||
pub color: [Bitboard; 2],
|
||||
|
||||
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),
|
||||
pieces: [
|
||||
0xff00000000ff00,
|
||||
0x4200000000000042,
|
||||
0x2400000000000024,
|
||||
0x8100000000000081,
|
||||
0x800000000000008,
|
||||
0x1000000000000010,
|
||||
],
|
||||
color: [0xffff, 0xffff000000000000],
|
||||
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),
|
||||
],
|
||||
pieces: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
|
||||
color: [0x0, 0x0],
|
||||
state: State::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn white_occupancies(&self) -> Bitboard {
|
||||
self.white_pieces.iter().fold(0, |acc, p| p.bitboard | acc)
|
||||
fn white_occupancies(&self) -> Bitboard {
|
||||
self.color[Color::White]
|
||||
}
|
||||
|
||||
pub fn black_occupancies(&self) -> Bitboard {
|
||||
self.black_pieces.iter().fold(0, |acc, p| p.bitboard | acc)
|
||||
fn black_occupancies(&self) -> Bitboard {
|
||||
self.color[Color::Black]
|
||||
}
|
||||
|
||||
pub fn all_occupancies(&self) -> Bitboard {
|
||||
@@ -78,17 +59,15 @@ impl Board {
|
||||
|
||||
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 own_color = opponent_color.opponent();
|
||||
let opponent_color_bb = &self.color[opponent_color];
|
||||
|
||||
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;
|
||||
let pawns = self.pieces[PieceType::Pawn] & opponent_color_bb;
|
||||
let knights = self.pieces[PieceType::Knight] & opponent_color_bb;
|
||||
let bishops = self.pieces[PieceType::Bishop] & opponent_color_bb;
|
||||
let rooks = self.pieces[PieceType::Rook] & opponent_color_bb;
|
||||
let queens = self.pieces[PieceType::Queen] & opponent_color_bb;
|
||||
let king = self.pieces[PieceType::King] & opponent_color_bb;
|
||||
|
||||
have_common_bit(pawns, fetch_pawn_attacks(square, own_color))
|
||||
|| have_common_bit(knights, fetch_knight_attacks(square))
|
||||
@@ -99,11 +78,7 @@ impl Board {
|
||||
}
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
let own_king_square = lsb(self.pieces[PieceType::King] & self.color[color]);
|
||||
self.is_attacked(own_king_square, color.opponent())
|
||||
}
|
||||
|
||||
@@ -134,18 +109,9 @@ impl Board {
|
||||
|
||||
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(),
|
||||
),
|
||||
};
|
||||
let pieces = self.pieces[piece_type] & self.color[color];
|
||||
let own_occupancies = self.color[color];
|
||||
let opponent_occupancies = self.color[color.opponent()];
|
||||
|
||||
match piece_type {
|
||||
PieceType::Pawn => pawn_pseudo_moves(
|
||||
@@ -165,70 +131,56 @@ impl Board {
|
||||
}
|
||||
}
|
||||
|
||||
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_piece(&mut self, bb: Bitboard, piece_type: PieceType, color: Color) {
|
||||
self.pieces[piece_type] |= bb;
|
||||
self.color[color] |= bb;
|
||||
}
|
||||
|
||||
pub fn set_state(&mut self, state: State) {
|
||||
self.state = state;
|
||||
}
|
||||
|
||||
pub fn is_pawn_move(&mut self, square: usize) -> bool {
|
||||
let pieces = self.own_pieces();
|
||||
have_common_bit(square_to_bitboard(square), pieces[PieceType::Pawn].bitboard)
|
||||
}
|
||||
|
||||
pub fn own_pieces(&mut self) -> &mut [Piece; 6] {
|
||||
match self.state.current_player() {
|
||||
Color::White => &mut self.white_pieces,
|
||||
Color::Black => &mut self.black_pieces,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opponent_pieces(&mut self) -> &mut [Piece; 6] {
|
||||
match self.state.current_player() {
|
||||
Color::White => &mut self.black_pieces,
|
||||
Color::Black => &mut self.white_pieces,
|
||||
}
|
||||
pub fn is_pawn_move(&self, square: usize) -> bool {
|
||||
let side = self.state.current_player();
|
||||
let own_pawns = self.pieces[PieceType::Pawn] & self.color[side];
|
||||
have_common_bit(square_to_bitboard(square), own_pawns)
|
||||
}
|
||||
|
||||
pub fn move_piece(&mut self, src: usize, dst: usize, piece_type: PieceType) {
|
||||
let pieces = self.own_pieces();
|
||||
pieces[piece_type].bitboard &= !square_to_bitboard(src);
|
||||
pieces[piece_type].bitboard |= square_to_bitboard(dst);
|
||||
self.pieces[piece_type] &= !square_to_bitboard(src);
|
||||
self.pieces[piece_type] |= square_to_bitboard(dst);
|
||||
self.color[self.state.current_player()] &= !square_to_bitboard(src);
|
||||
self.color[self.state.current_player()] |= square_to_bitboard(dst);
|
||||
}
|
||||
|
||||
pub fn insert_own_piece(&mut self, square: usize, piece_type: PieceType) {
|
||||
let pieces = self.own_pieces();
|
||||
pieces[piece_type].bitboard |= square_to_bitboard(square);
|
||||
self.pieces[piece_type] |= square_to_bitboard(square);
|
||||
self.color[self.state.current_player()] |= square_to_bitboard(square);
|
||||
}
|
||||
|
||||
pub fn insert_opponent_piece(&mut self, square: usize, piece_type: PieceType) {
|
||||
let pieces = self.opponent_pieces();
|
||||
pieces[piece_type].bitboard |= square_to_bitboard(square);
|
||||
self.pieces[piece_type] |= square_to_bitboard(square);
|
||||
self.color[self.state.next_player()] |= square_to_bitboard(square);
|
||||
}
|
||||
|
||||
pub fn remove_own_piece(&mut self, square: usize, piece_type: PieceType) {
|
||||
let pieces = self.own_pieces();
|
||||
pieces[piece_type].bitboard &= !square_to_bitboard(square);
|
||||
self.pieces[piece_type] &= !square_to_bitboard(square);
|
||||
self.color[self.state.current_player()] &= !square_to_bitboard(square);
|
||||
}
|
||||
|
||||
pub fn remove_opponent_piece(&mut self, square: usize, piece_type: PieceType) {
|
||||
let pieces = self.opponent_pieces();
|
||||
pieces[piece_type].bitboard &= !square_to_bitboard(square);
|
||||
self.pieces[piece_type] &= !square_to_bitboard(square);
|
||||
self.color[self.state.next_player()] &= !square_to_bitboard(square);
|
||||
}
|
||||
|
||||
pub fn promote_piece(&mut self, square: usize, promote: &Promote) {
|
||||
let pieces = self.own_pieces();
|
||||
match promote {
|
||||
Promote::Knight => pieces[PieceType::Knight].bitboard |= square_to_bitboard(square),
|
||||
Promote::Bishop => pieces[PieceType::Bishop].bitboard |= square_to_bitboard(square),
|
||||
Promote::Rook => pieces[PieceType::Rook].bitboard |= square_to_bitboard(square),
|
||||
Promote::Queen => pieces[PieceType::Queen].bitboard |= square_to_bitboard(square),
|
||||
Promote::Knight => self.pieces[PieceType::Knight] |= square_to_bitboard(square),
|
||||
Promote::Bishop => self.pieces[PieceType::Bishop] |= square_to_bitboard(square),
|
||||
Promote::Rook => self.pieces[PieceType::Rook] |= square_to_bitboard(square),
|
||||
Promote::Queen => self.pieces[PieceType::Queen] |= square_to_bitboard(square),
|
||||
};
|
||||
self.color[self.state.current_player()] |= square_to_bitboard(square);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,24 +190,7 @@ impl Default for Board {
|
||||
}
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, EnumIter)]
|
||||
pub enum PieceType {
|
||||
Pawn,
|
||||
Knight,
|
||||
@@ -286,7 +221,7 @@ impl<T> IndexMut<PieceType> for [T] {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, EnumIter)]
|
||||
pub enum Color {
|
||||
White,
|
||||
Black,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::board::board::{Board, Color, Piece, PieceType};
|
||||
use crate::board::board::{Board, Color, PieceType};
|
||||
use crate::board::game::Game;
|
||||
use crate::board::state::{Castle, State};
|
||||
use String as FenError;
|
||||
@@ -71,7 +71,7 @@ pub fn piece_placement(pieces: &str) -> Result<Board, FenError> {
|
||||
))
|
||||
}
|
||||
} {
|
||||
board.set_piece(&Piece::new(1 << square, piece_type, color));
|
||||
board.set_piece(square_to_bitboard(square as usize), piece_type, color);
|
||||
file += 1;
|
||||
};
|
||||
}
|
||||
@@ -132,6 +132,7 @@ fn castling_ability(castling: &str) -> Result<[Castle; 2], FenError> {
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::bitboard::square_to_bitboard;
|
||||
use super::history::History;
|
||||
use super::mailbox::Mailbox;
|
||||
use super::zobrist::zobrist_keys;
|
||||
|
||||
@@ -15,8 +15,8 @@ use super::{
|
||||
|
||||
impl PartialEq for Game {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.board.white_pieces == other.board.white_pieces
|
||||
&& self.board.black_pieces == other.board.black_pieces
|
||||
self.board.pieces == other.board.pieces
|
||||
&& self.board.color == other.board.color
|
||||
&& self.board.state == other.board.state
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,10 @@ impl Game {
|
||||
self.board.state.current_player()
|
||||
}
|
||||
|
||||
pub const fn next_player(&self) -> Color {
|
||||
self.board.state.next_player()
|
||||
}
|
||||
|
||||
pub fn make_move(&mut self, mv: &Move) {
|
||||
self.history
|
||||
.push_move_parameters(MoveParameters::build(self, mv));
|
||||
@@ -66,20 +70,20 @@ impl Game {
|
||||
|
||||
let piece_at_src = mailbox
|
||||
.piece_at(mv.src)
|
||||
.expect("Expected piece at: {mv.src}");
|
||||
.unwrap_or_else(|| panic!("Expected piece at: {}", mv.src));
|
||||
let piece_at_dst = mailbox.piece_at(mv.dst);
|
||||
match &mv.move_type {
|
||||
MoveType::Quiet => {
|
||||
board.move_piece(mv.src, mv.dst, piece_at_src);
|
||||
hash.update_quiet(mv.src, mv.dst, piece_at_src, color);
|
||||
board.move_piece(mv.src, mv.dst, piece_at_src.0);
|
||||
hash.update_quiet(mv.src, mv.dst, piece_at_src.0, color);
|
||||
hash.drop_en_passant_hash(board.state.en_passant_square());
|
||||
mailbox.set_piece_at(mv.dst, Some(piece_at_src));
|
||||
}
|
||||
MoveType::Capture => {
|
||||
let piece_at_dst = piece_at_dst.expect("Expected piece at: {mv.dst}");
|
||||
board.move_piece(mv.src, mv.dst, piece_at_src);
|
||||
board.remove_opponent_piece(mv.dst, piece_at_dst);
|
||||
hash.update_capture(mv.src, mv.dst, piece_at_src, piece_at_dst, color);
|
||||
board.remove_opponent_piece(mv.dst, piece_at_dst.0);
|
||||
hash.update_capture(mv.src, mv.dst, piece_at_src.0, piece_at_dst.0, color);
|
||||
board.move_piece(mv.src, mv.dst, piece_at_src.0);
|
||||
hash.drop_en_passant_hash(board.state.en_passant_square());
|
||||
mailbox.set_piece_at(mv.dst, Some(piece_at_src));
|
||||
}
|
||||
@@ -88,11 +92,11 @@ impl Game {
|
||||
board.remove_opponent_piece(ep_capture, PieceType::Pawn);
|
||||
hash.update_en_passant(mv.src, mv.dst, ep_capture, color);
|
||||
hash.drop_en_passant_hash(board.state.en_passant_square());
|
||||
mailbox.set_piece_at(mv.dst, Some(PieceType::Pawn));
|
||||
mailbox.set_piece_at(mv.dst, Some((PieceType::Pawn, color)));
|
||||
mailbox.set_piece_at(ep_capture, None);
|
||||
}
|
||||
MoveType::DoublePush => {
|
||||
board.move_piece(mv.src, mv.dst, piece_at_src);
|
||||
board.move_piece(mv.src, mv.dst, piece_at_src.0);
|
||||
en_passant_square = match color {
|
||||
Color::White => Some(mv.src + 8),
|
||||
Color::Black => Some(mv.src.saturating_sub(8)),
|
||||
@@ -102,23 +106,23 @@ impl Game {
|
||||
mailbox.set_piece_at(mv.dst, Some(piece_at_src));
|
||||
}
|
||||
MoveType::Promotion(promote) => {
|
||||
board.remove_own_piece(mv.src, piece_at_src);
|
||||
board.remove_own_piece(mv.src, piece_at_src.0);
|
||||
board.promote_piece(mv.dst, promote);
|
||||
hash.update_promotion(mv.src, mv.dst, promote, color);
|
||||
hash.drop_en_passant_hash(board.state.en_passant_square());
|
||||
mailbox.set_piece_at(mv.dst, Some(promote.into_piece_type()));
|
||||
mailbox.set_piece_at(mv.dst, Some((promote.into_piece_type(), color)));
|
||||
}
|
||||
MoveType::PromotionCapture(promote) => {
|
||||
let piece_at_dst = piece_at_dst.expect("Expected piece at dst: {mv.dst}");
|
||||
board.remove_own_piece(mv.src, piece_at_src);
|
||||
board.remove_opponent_piece(mv.dst, piece_at_dst);
|
||||
board.remove_own_piece(mv.src, piece_at_src.0);
|
||||
board.remove_opponent_piece(mv.dst, piece_at_dst.0);
|
||||
board.promote_piece(mv.dst, promote);
|
||||
hash.update_promotion_capture(mv.src, mv.dst, piece_at_dst, promote, color);
|
||||
hash.update_promotion_capture(mv.src, mv.dst, piece_at_dst.0, promote, color);
|
||||
hash.drop_en_passant_hash(board.state.en_passant_square());
|
||||
mailbox.set_piece_at(mv.dst, Some(promote.into_piece_type()));
|
||||
mailbox.set_piece_at(mv.dst, Some((promote.into_piece_type(), color)));
|
||||
}
|
||||
MoveType::Castle => {
|
||||
board.move_piece(mv.src, mv.dst, piece_at_src);
|
||||
board.move_piece(mv.src, mv.dst, piece_at_src.0);
|
||||
let (rook_src, rook_dst) = match mv.dst {
|
||||
Square::C1 | Square::C8 => (mv.dst - 2, mv.dst + 1),
|
||||
Square::G1 | Square::G8 => (mv.dst + 1, mv.dst - 1),
|
||||
@@ -126,11 +130,11 @@ impl Game {
|
||||
};
|
||||
board.move_piece(rook_src, rook_dst, PieceType::Rook);
|
||||
board.state.set_castling_ability(color, Castle::None);
|
||||
hash.update_castle(mv.src, mv.dst, piece_at_src, rook_src, rook_dst, color);
|
||||
hash.update_castle(mv.src, mv.dst, piece_at_src.0, rook_src, rook_dst, color);
|
||||
hash.drop_en_passant_hash(board.state.en_passant_square());
|
||||
mailbox.set_piece_at(mv.dst, Some(piece_at_src));
|
||||
mailbox.set_piece_at(rook_src, None);
|
||||
mailbox.set_piece_at(rook_dst, Some(PieceType::Rook));
|
||||
mailbox.set_piece_at(rook_dst, Some((PieceType::Rook, color)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +176,7 @@ impl Game {
|
||||
let piece_at_dst = mailbox.piece_at(mv.dst).expect("Expected set piece");
|
||||
match &mv.move_type {
|
||||
MoveType::Quiet | MoveType::DoublePush => {
|
||||
board.move_piece(mv.dst, mv.src, piece_at_dst);
|
||||
board.move_piece(mv.dst, mv.src, piece_at_dst.0);
|
||||
mailbox.set_piece_at(mv.src, mailbox.piece_at(mv.dst));
|
||||
mailbox.set_piece_at(mv.dst, None);
|
||||
}
|
||||
@@ -180,19 +184,19 @@ impl Game {
|
||||
let captured_piece = move_parameters
|
||||
.captured_piece
|
||||
.expect("Expected captured piece to unmake Capture");
|
||||
board.move_piece(mv.dst, mv.src, piece_at_dst);
|
||||
board.insert_opponent_piece(mv.dst, captured_piece);
|
||||
mailbox.set_piece_at(mv.src, move_parameters.moved_piece);
|
||||
board.move_piece(mv.dst, mv.src, piece_at_dst.0);
|
||||
board.insert_opponent_piece(mv.dst, captured_piece.0);
|
||||
mailbox.set_piece_at(mv.src, move_parameters.moving_piece);
|
||||
mailbox.set_piece_at(mv.dst, Some(captured_piece));
|
||||
}
|
||||
MoveType::Promotion(_) => {
|
||||
let promoted_piece = move_parameters
|
||||
.promoted_piece
|
||||
.expect("Expected promoted piece to unmake Promotion");
|
||||
board.remove_own_piece(mv.dst, promoted_piece);
|
||||
board.remove_own_piece(mv.dst, promoted_piece.0);
|
||||
board.insert_own_piece(mv.src, PieceType::Pawn);
|
||||
|
||||
mailbox.set_piece_at(mv.src, Some(PieceType::Pawn));
|
||||
mailbox.set_piece_at(mv.src, Some((PieceType::Pawn, color_before_move)));
|
||||
mailbox.set_piece_at(mv.dst, None);
|
||||
}
|
||||
MoveType::PromotionCapture(_) => {
|
||||
@@ -202,10 +206,10 @@ impl Game {
|
||||
let captured_piece = move_parameters
|
||||
.captured_piece
|
||||
.expect("Expected captured piece to unmake PromotionCapture");
|
||||
board.remove_own_piece(mv.dst, promoted_piece);
|
||||
board.insert_opponent_piece(mv.dst, captured_piece);
|
||||
board.remove_own_piece(mv.dst, promoted_piece.0);
|
||||
board.insert_opponent_piece(mv.dst, captured_piece.0);
|
||||
board.insert_own_piece(mv.src, PieceType::Pawn);
|
||||
mailbox.set_piece_at(mv.src, Some(PieceType::Pawn));
|
||||
mailbox.set_piece_at(mv.src, Some((PieceType::Pawn, color_before_move)));
|
||||
mailbox.set_piece_at(mv.dst, Some(captured_piece));
|
||||
}
|
||||
MoveType::EnPassant => {
|
||||
@@ -213,10 +217,13 @@ impl Game {
|
||||
Color::White => mv.dst - 8,
|
||||
Color::Black => mv.dst + 8,
|
||||
};
|
||||
board.move_piece(mv.dst, mv.src, piece_at_dst);
|
||||
board.move_piece(mv.dst, mv.src, piece_at_dst.0);
|
||||
board.insert_opponent_piece(enemy_pawn_square, PieceType::Pawn);
|
||||
mailbox.set_piece_at(mv.src, Some(PieceType::Pawn));
|
||||
mailbox.set_piece_at(enemy_pawn_square, Some(PieceType::Pawn));
|
||||
mailbox.set_piece_at(mv.src, Some((PieceType::Pawn, color_before_move)));
|
||||
mailbox.set_piece_at(
|
||||
enemy_pawn_square,
|
||||
Some((PieceType::Pawn, color_before_move.opponent())),
|
||||
);
|
||||
}
|
||||
MoveType::Castle => {
|
||||
let (rook_src, rook_dst) = match mv.dst {
|
||||
@@ -224,12 +231,12 @@ impl Game {
|
||||
Square::G1 | Square::G8 => (mv.dst + 1, mv.dst - 1),
|
||||
_ => return,
|
||||
};
|
||||
board.move_piece(mv.dst, mv.src, piece_at_dst);
|
||||
board.move_piece(mv.dst, mv.src, piece_at_dst.0);
|
||||
board.remove_own_piece(rook_dst, PieceType::Rook);
|
||||
board.insert_own_piece(rook_src, PieceType::Rook);
|
||||
mailbox.set_piece_at(mv.src, mailbox.piece_at(mv.dst));
|
||||
mailbox.set_piece_at(mv.dst, None);
|
||||
mailbox.set_piece_at(rook_src, Some(PieceType::Rook));
|
||||
mailbox.set_piece_at(rook_src, Some((PieceType::Rook, color_before_move)));
|
||||
mailbox.set_piece_at(rook_dst, None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::movegen::r#move::{Move, MoveType};
|
||||
|
||||
use super::{
|
||||
board::PieceType,
|
||||
board::{Color, PieceType},
|
||||
game::Game,
|
||||
mailbox::Mailbox,
|
||||
state::{Castle, State},
|
||||
@@ -32,9 +32,9 @@ impl History {
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MoveParameters {
|
||||
pub mv: Option<Move>,
|
||||
pub moved_piece: Option<PieceType>,
|
||||
pub captured_piece: Option<PieceType>,
|
||||
pub promoted_piece: Option<PieceType>,
|
||||
pub moving_piece: Option<(PieceType, Color)>,
|
||||
pub captured_piece: Option<(PieceType, Color)>,
|
||||
pub promoted_piece: Option<(PieceType, Color)>,
|
||||
pub castling_ability: Option<[Castle; 2]>,
|
||||
pub en_passant_square: Option<usize>,
|
||||
pub halfmove_clock: Option<u8>,
|
||||
@@ -45,7 +45,7 @@ impl MoveParameters {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
mv: None,
|
||||
moved_piece: None,
|
||||
moving_piece: None,
|
||||
captured_piece: None,
|
||||
promoted_piece: None,
|
||||
castling_ability: None,
|
||||
@@ -59,9 +59,9 @@ impl MoveParameters {
|
||||
let mut move_parameters = Self::new();
|
||||
move_parameters.add_move(*mv);
|
||||
move_parameters.add_irreversible_parameters(&game.board.state);
|
||||
move_parameters.add_moved_piece(&game.mailbox, mv);
|
||||
move_parameters.add_moving_piece(&game.mailbox, mv);
|
||||
move_parameters.add_captured_piece(&game.mailbox, mv);
|
||||
move_parameters.add_promoted_piece(mv);
|
||||
move_parameters.add_promoted_piece(mv, game.current_player());
|
||||
move_parameters.add_zobrist_hash(&game.hash);
|
||||
|
||||
move_parameters
|
||||
@@ -77,8 +77,8 @@ impl MoveParameters {
|
||||
self.halfmove_clock = Some(state.halfmove_clock);
|
||||
}
|
||||
|
||||
fn add_moved_piece(&mut self, mailbox: &Mailbox, mv: &Move) {
|
||||
self.moved_piece = mailbox.piece_at(mv.src);
|
||||
fn add_moving_piece(&mut self, mailbox: &Mailbox, mv: &Move) {
|
||||
self.moving_piece = mailbox.piece_at(mv.src);
|
||||
}
|
||||
|
||||
fn add_captured_piece(&mut self, mailbox: &Mailbox, mv: &Move) {
|
||||
@@ -87,9 +87,9 @@ impl MoveParameters {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_promoted_piece(&mut self, mv: &Move) {
|
||||
fn add_promoted_piece(&mut self, mv: &Move, color: Color) {
|
||||
if let MoveType::Promotion(promote) | MoveType::PromotionCapture(promote) = mv.move_type {
|
||||
self.promoted_piece = Some(promote.into_piece_type())
|
||||
self.promoted_piece = Some((promote.into_piece_type(), color));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +1,46 @@
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use super::{
|
||||
bitboard::{have_common_bit, square_to_bitboard},
|
||||
board::{Board, PieceType},
|
||||
board::{Board, Color, PieceType},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Mailbox {
|
||||
pub mailbox: [Option<PieceType>; 64],
|
||||
pub mailbox: [Option<(PieceType, Color)>; 64],
|
||||
}
|
||||
|
||||
impl Mailbox {
|
||||
pub fn from_board(board: &Board) -> Self {
|
||||
let mut mailbox: [Option<PieceType>; 64] = [None; 64];
|
||||
let mut mailbox: [Option<(PieceType, Color)>; 64] = [None; 64];
|
||||
|
||||
for (square, mailbox_square) in mailbox.iter_mut().enumerate() {
|
||||
*mailbox_square = board
|
||||
.white_pieces
|
||||
.iter()
|
||||
.chain(board.black_pieces.iter())
|
||||
.find(|p| have_common_bit(p.bitboard, square_to_bitboard(square)))
|
||||
.map(|p| p.piece_type);
|
||||
for (square, m) in mailbox.iter_mut().enumerate() {
|
||||
*m = PieceType::iter()
|
||||
.flat_map(|p| Color::iter().map(move |c| (p, c)))
|
||||
.find(|&(p, c)| {
|
||||
have_common_bit(board.pieces[p] & board.color[c], square_to_bitboard(square))
|
||||
});
|
||||
}
|
||||
|
||||
Self { mailbox }
|
||||
}
|
||||
|
||||
pub fn set_piece_at(&mut self, square: usize, piece_type: Option<PieceType>) {
|
||||
self.mailbox[square] = piece_type;
|
||||
pub fn set_piece_at(&mut self, square: usize, piece: Option<(PieceType, Color)>) {
|
||||
self.mailbox[square] = piece;
|
||||
}
|
||||
|
||||
pub const fn piece_at(&self, square: usize) -> Option<PieceType> {
|
||||
pub const fn piece_at(&self, square: usize) -> Option<(PieceType, Color)> {
|
||||
self.mailbox[square]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::board::{board::PieceType, fen::from_fen, square::Square};
|
||||
use crate::board::{
|
||||
board::{Color, PieceType},
|
||||
fen::from_fen,
|
||||
square::Square,
|
||||
};
|
||||
|
||||
use super::Mailbox;
|
||||
|
||||
@@ -44,38 +49,23 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_from_board() -> Result<(), String> {
|
||||
let game = from_fen(FEN_MATE_IN_1)?;
|
||||
let mailbox = Mailbox::from_board(&game.board);
|
||||
#[rustfmt::skip]
|
||||
let expected: [Option<PieceType>; 64] = [
|
||||
None, None, None, None, None, Some(PieceType::King), None, None,
|
||||
None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, Some(PieceType::Queen), None, Some(PieceType::King), None,
|
||||
None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None,
|
||||
];
|
||||
|
||||
assert_eq!(expected, mailbox.mailbox);
|
||||
|
||||
let game = from_fen(FEN_STARTPOS)?;
|
||||
let mailbox = Mailbox::from_board(&game.board);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let expected: [Option<PieceType>; 64] = [
|
||||
Some(PieceType::Rook), Some(PieceType::Knight), Some(PieceType::Bishop), Some(PieceType::Queen),
|
||||
Some(PieceType::King), Some(PieceType::Bishop), Some(PieceType::Knight), Some(PieceType::Rook),
|
||||
Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn),
|
||||
Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn),
|
||||
let expected: [Option<(PieceType, Color)>; 64] = [
|
||||
Some((PieceType::Rook, Color::White)), Some((PieceType::Knight, Color::White)), Some((PieceType::Bishop, Color::White)), Some((PieceType::Queen, Color::White)),
|
||||
Some((PieceType::King, Color::White)), Some((PieceType::Bishop, Color::White)), Some((PieceType::Knight, Color::White)), Some((PieceType::Rook, Color::White)),
|
||||
Some((PieceType::Pawn, Color::White)), Some((PieceType::Pawn, Color::White)), Some((PieceType::Pawn, Color::White)), Some((PieceType::Pawn, Color::White)),
|
||||
Some((PieceType::Pawn, Color::White)), Some((PieceType::Pawn, Color::White)), Some((PieceType::Pawn, Color::White)), Some((PieceType::Pawn, Color::White)),
|
||||
None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None,
|
||||
Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn),
|
||||
Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn), Some(PieceType::Pawn),
|
||||
Some(PieceType::Rook), Some(PieceType::Knight), Some(PieceType::Bishop), Some(PieceType::Queen),
|
||||
Some(PieceType::King), Some(PieceType::Bishop), Some(PieceType::Knight), Some(PieceType::Rook),
|
||||
Some((PieceType::Pawn, Color::Black)), Some((PieceType::Pawn, Color::Black)), Some((PieceType::Pawn, Color::Black)), Some((PieceType::Pawn, Color::Black)),
|
||||
Some((PieceType::Pawn, Color::Black)), Some((PieceType::Pawn, Color::Black)), Some((PieceType::Pawn, Color::Black)), Some((PieceType::Pawn, Color::Black)),
|
||||
Some((PieceType::Rook, Color::Black)), Some((PieceType::Knight, Color::Black)), Some((PieceType::Bishop, Color::Black)), Some((PieceType::Queen, Color::Black)),
|
||||
Some((PieceType::King, Color::Black)), Some((PieceType::Bishop, Color::Black)), Some((PieceType::Knight, Color::Black)), Some((PieceType::Rook, Color::Black)),
|
||||
];
|
||||
|
||||
assert_eq!(expected, mailbox.mailbox);
|
||||
@@ -88,7 +78,10 @@ mod tests {
|
||||
let game = from_fen(FEN_MATE_IN_1)?;
|
||||
let mailbox = Mailbox::from_board(&game.board);
|
||||
|
||||
assert_eq!(PieceType::King, mailbox.piece_at(Square::F1).unwrap());
|
||||
assert_eq!(
|
||||
(PieceType::King, Color::White),
|
||||
mailbox.piece_at(Square::F1).unwrap()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -143,6 +143,13 @@ impl State {
|
||||
pub const fn current_player(&self) -> Color {
|
||||
self.side_to_move
|
||||
}
|
||||
|
||||
pub const fn next_player(&self) -> Color {
|
||||
match self.side_to_move {
|
||||
Color::White => Color::Black,
|
||||
Color::Black => Color::White,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
|
||||
@@ -8,6 +8,7 @@ use super::{
|
||||
};
|
||||
use rand::{rngs::SmallRng, RngCore, SeedableRng};
|
||||
use std::sync::LazyLock;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
static ZOBRIST_KEYS: LazyLock<ZobristKeys> = LazyLock::new(ZobristKeys::new);
|
||||
|
||||
@@ -44,39 +45,29 @@ impl ZobristKeys {
|
||||
}
|
||||
|
||||
keys.side_to_move = state.next_u64();
|
||||
|
||||
Self {
|
||||
piece_square_color: keys.piece_square_color,
|
||||
en_passant: keys.en_passant,
|
||||
castling_ability: keys.castling_ability,
|
||||
side_to_move: keys.side_to_move,
|
||||
}
|
||||
keys
|
||||
}
|
||||
|
||||
pub fn calculate_hash(&self, board: &Board) -> ZobristHash {
|
||||
let mut hash = 0;
|
||||
let white_pieces = &board.white_pieces;
|
||||
let black_pieces = &board.black_pieces;
|
||||
|
||||
for piece in white_pieces.iter() {
|
||||
let mut bb = piece.bitboard;
|
||||
PieceType::iter().for_each(|piece_type| {
|
||||
let mut bitboard = board.pieces[piece_type] & board.color[Color::White];
|
||||
|
||||
while bb != 0 {
|
||||
let square = lsb(bb);
|
||||
hash ^= self.piece_square_color[square][piece.piece_type][piece.color];
|
||||
bb &= bb - 1;
|
||||
while bitboard != 0 {
|
||||
let square = lsb(bitboard);
|
||||
hash ^= self.piece_square_color[square][piece_type][Color::White];
|
||||
bitboard &= bitboard - 1;
|
||||
}
|
||||
}
|
||||
|
||||
for piece in black_pieces.iter() {
|
||||
let mut bb = piece.bitboard;
|
||||
let mut bitboard = board.pieces[piece_type] & board.color[Color::Black];
|
||||
|
||||
while bb != 0 {
|
||||
let square = lsb(bb);
|
||||
hash ^= self.piece_square_color[square][piece.piece_type][piece.color];
|
||||
bb &= bb - 1;
|
||||
while bitboard != 0 {
|
||||
let square = lsb(bitboard);
|
||||
hash ^= self.piece_square_color[square][piece_type][Color::Black];
|
||||
bitboard &= bitboard - 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if board.state.current_player().eq(&Color::Black) {
|
||||
hash ^= self.side_to_move
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use u64 as Bitboard;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::{
|
||||
board::{
|
||||
@@ -22,45 +22,34 @@ pub const fn material_score(piece_type: PieceType) -> i32 {
|
||||
}
|
||||
|
||||
fn is_end_game(board: &Board) -> bool {
|
||||
let white_pieces = board.white_pieces.iter().fold(0, |acc, p| {
|
||||
acc + bitboard::bit_count(p.bitboard) * material_score(p.piece_type) as usize
|
||||
});
|
||||
|
||||
let black_pieces = board.black_pieces.iter().fold(0, |acc, p| {
|
||||
acc + bitboard::bit_count(p.bitboard) * material_score(p.piece_type) as usize
|
||||
});
|
||||
|
||||
(white_pieces + black_pieces) < 2000
|
||||
PieceType::iter().fold(0, |acc, p| {
|
||||
acc + bitboard::bit_count(board.pieces[p]) * material_score(p) as usize
|
||||
}) < 2000
|
||||
}
|
||||
|
||||
fn evaluate_side_for(board: &Board, color: Color) -> i32 {
|
||||
let mut total_score = 0;
|
||||
let pieces = match color {
|
||||
Color::White => &board.white_pieces,
|
||||
Color::Black => &board.black_pieces,
|
||||
};
|
||||
|
||||
let psqt = if is_end_game(board) {
|
||||
piece_square_score_endgame
|
||||
} else {
|
||||
piece_square_score
|
||||
};
|
||||
|
||||
for piece in pieces {
|
||||
let (piece_type, mut bitboard): (PieceType, Bitboard) = (piece.piece_type, piece.bitboard);
|
||||
let mut score = 0;
|
||||
let mut total_score = 0;
|
||||
|
||||
PieceType::iter().for_each(|piece_type| {
|
||||
let mut bitboard = board.pieces[piece_type] & board.color[color];
|
||||
while bitboard != 0 {
|
||||
let psqt_index = match color {
|
||||
Color::White => lsb(bitboard),
|
||||
Color::Black => mirror_index(lsb(bitboard)),
|
||||
};
|
||||
|
||||
score += material_score(piece_type);
|
||||
score += psqt(piece_type, psqt_index);
|
||||
total_score += material_score(piece_type);
|
||||
total_score += psqt(piece_type, psqt_index);
|
||||
bitboard &= bitboard - 1;
|
||||
}
|
||||
total_score += score;
|
||||
}
|
||||
});
|
||||
|
||||
total_score
|
||||
}
|
||||
|
||||
|
||||
@@ -325,118 +325,100 @@ pub fn init_attacks() {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::board::board::{Color, Piece, PieceType};
|
||||
use crate::board::{board::Color, square::Square};
|
||||
|
||||
#[test]
|
||||
fn test_pawn_attacks() -> Result<(), String> {
|
||||
let white_pawn_a_file = Piece::new(0x100, PieceType::Pawn, Color::White);
|
||||
let attacks = pawn_attacks(white_pawn_a_file.bitboard, white_pawn_a_file.color);
|
||||
assert_eq!(attacks, 0x20000);
|
||||
|
||||
let white_pawn_b_file = Piece::new(0x200, PieceType::Pawn, Color::White);
|
||||
let attacks = pawn_attacks(white_pawn_b_file.bitboard, white_pawn_b_file.color);
|
||||
assert_eq!(attacks, 0x50000);
|
||||
|
||||
let white_pawn_h_file = Piece::new(0x8000, PieceType::Pawn, Color::White);
|
||||
let attacks = pawn_attacks(white_pawn_h_file.bitboard, white_pawn_h_file.color);
|
||||
assert_eq!(attacks, 0x400000);
|
||||
|
||||
let black_pawn_a_file = Piece::new(0x1000000000000, PieceType::Pawn, Color::Black);
|
||||
let attacks = pawn_attacks(black_pawn_a_file.bitboard, black_pawn_a_file.color);
|
||||
assert_eq!(attacks, 0x20000000000);
|
||||
|
||||
let black_pawn_b_file = Piece::new(0x2000000000000, PieceType::Pawn, Color::Black);
|
||||
let attacks = pawn_attacks(black_pawn_b_file.bitboard, black_pawn_b_file.color);
|
||||
assert_eq!(attacks, 0x50000000000);
|
||||
|
||||
let black_pawn_h_file = Piece::new(0x80000000000000, PieceType::Pawn, Color::Black);
|
||||
let attacks = pawn_attacks(black_pawn_h_file.bitboard, black_pawn_h_file.color);
|
||||
assert_eq!(attacks, 0x400000000000);
|
||||
assert_eq!(
|
||||
0x20000,
|
||||
pawn_attacks(square_to_bitboard(Square::A2), Color::White)
|
||||
);
|
||||
assert_eq!(
|
||||
0x50000,
|
||||
pawn_attacks(square_to_bitboard(Square::B2), Color::White)
|
||||
);
|
||||
assert_eq!(
|
||||
0x400000,
|
||||
pawn_attacks(square_to_bitboard(Square::H2), Color::White)
|
||||
);
|
||||
assert_eq!(
|
||||
0x20000000000,
|
||||
pawn_attacks(square_to_bitboard(Square::A7), Color::Black)
|
||||
);
|
||||
assert_eq!(
|
||||
0x50000000000,
|
||||
pawn_attacks(square_to_bitboard(Square::B7), Color::Black)
|
||||
);
|
||||
assert_eq!(
|
||||
0x400000000000,
|
||||
pawn_attacks(square_to_bitboard(Square::H7), Color::Black)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_knight_attacks() -> Result<(), String> {
|
||||
let knight_two_attacks = Piece::new(0x1, PieceType::Knight, Color::White);
|
||||
let attacks = knight_attacks(knight_two_attacks.bitboard);
|
||||
assert_eq!(attacks, 0x20400);
|
||||
|
||||
let knight_three_attacks = Piece::new(0x2, PieceType::Knight, Color::White);
|
||||
let attacks = knight_attacks(knight_three_attacks.bitboard);
|
||||
assert_eq!(attacks, 0x50800);
|
||||
|
||||
let knight_three_attacks = Piece::new(0x4, PieceType::Knight, Color::White);
|
||||
let attacks = knight_attacks(knight_three_attacks.bitboard);
|
||||
assert_eq!(attacks, 0xa1100);
|
||||
|
||||
let knight_six_attacks = Piece::new(0x400, PieceType::Knight, Color::White);
|
||||
let attacks = knight_attacks(knight_six_attacks.bitboard);
|
||||
assert_eq!(attacks, 0xa110011);
|
||||
|
||||
let knight_eight_attacks = Piece::new(0x40000, PieceType::Knight, Color::White);
|
||||
let attacks = knight_attacks(knight_eight_attacks.bitboard);
|
||||
assert_eq!(attacks, 0xa1100110a);
|
||||
assert_eq!(0x20400, knight_attacks(square_to_bitboard(Square::A1)));
|
||||
assert_eq!(0x50800, knight_attacks(square_to_bitboard(Square::B1)));
|
||||
assert_eq!(0xa1100, knight_attacks(square_to_bitboard(Square::C1)));
|
||||
assert_eq!(0xa110011, knight_attacks(square_to_bitboard(Square::C2)));
|
||||
assert_eq!(0xa1100110a, knight_attacks(square_to_bitboard(Square::C3)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_attacks() -> Result<(), String> {
|
||||
let king_three_attacks = Piece::new(0x1, PieceType::King, Color::White);
|
||||
let attacks = king_attacks(king_three_attacks.bitboard);
|
||||
assert_eq!(attacks, 0x302);
|
||||
|
||||
let king_five_attacks = Piece::new(0x2, PieceType::King, Color::White);
|
||||
let attacks = king_attacks(king_five_attacks.bitboard);
|
||||
assert_eq!(attacks, 0x705);
|
||||
|
||||
let king_eight_attacks = Piece::new(0x200, PieceType::King, Color::White);
|
||||
let attacks = king_attacks(king_eight_attacks.bitboard);
|
||||
assert_eq!(attacks, 0x70507);
|
||||
assert_eq!(0x302, king_attacks(square_to_bitboard(Square::A1)));
|
||||
assert_eq!(0x705, king_attacks(square_to_bitboard(Square::B1)));
|
||||
assert_eq!(0x70507, king_attacks(square_to_bitboard(Square::B2)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mask_bishop_attacks() -> Result<(), String> {
|
||||
let bishop_d4 = Piece::new(0x8000000, PieceType::Bishop, Color::White);
|
||||
let all_directions_mask = mask_bishop_attacks(bishop_d4.bitboard);
|
||||
assert_eq!(all_directions_mask, 0x40221400142200);
|
||||
assert_eq!(
|
||||
0x40221400142200,
|
||||
mask_bishop_attacks(square_to_bitboard(Square::D4))
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bishop_attacks_on_the_fly() -> Result<(), String> {
|
||||
let bishop_d4 = Piece::new(0x8000000, PieceType::Bishop, Color::White);
|
||||
let blocker_c5 = 0x400000000_u64;
|
||||
let attacks = bishop_attacks_on_the_fly(bishop_d4.bitboard, blocker_c5);
|
||||
assert_eq!(attacks, 0x8040201400142241);
|
||||
|
||||
let bishop_a1 = Piece::new(0x0, PieceType::Bishop, Color::White);
|
||||
let blocker_none = 0x0_u64;
|
||||
let attacks = bishop_attacks_on_the_fly(bishop_a1.bitboard, blocker_none);
|
||||
assert_eq!(attacks, 0x8040201008040200);
|
||||
assert_eq!(
|
||||
0x8040201400142241,
|
||||
bishop_attacks_on_the_fly(
|
||||
square_to_bitboard(Square::D4),
|
||||
square_to_bitboard(Square::C5)
|
||||
)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mask_rook_attacks() -> Result<(), String> {
|
||||
let rook_d4 = Piece::new(0x8000000, PieceType::Rook, Color::White);
|
||||
let all_directions_mask = mask_rook_attacks(rook_d4.bitboard);
|
||||
assert_eq!(all_directions_mask, 0x8080876080800);
|
||||
assert_eq!(
|
||||
0x8080876080800,
|
||||
mask_rook_attacks(square_to_bitboard(Square::D4))
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rook_attacks_on_the_fly() -> Result<(), String> {
|
||||
let rook_d4 = Piece::new(0x8000000, PieceType::Rook, Color::White);
|
||||
let blocker_c4 = 0x4000000_u64;
|
||||
let attacks = rook_attacks_on_the_fly(rook_d4.bitboard, blocker_c4);
|
||||
assert_eq!(attacks, 0x8080808f4080808);
|
||||
assert_eq!(
|
||||
0x8080808f4080808,
|
||||
rook_attacks_on_the_fly(
|
||||
square_to_bitboard(Square::D4),
|
||||
square_to_bitboard(Square::C4)
|
||||
)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ impl Move {
|
||||
Ok(Self::build_with_type(&game.mailbox, src, dst, promote_into))
|
||||
}
|
||||
|
||||
fn build_with_type(
|
||||
const fn build_with_type(
|
||||
mailbox: &Mailbox,
|
||||
src: usize,
|
||||
dst: usize,
|
||||
@@ -136,7 +136,7 @@ impl Move {
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if moving == Some(PieceType::Pawn) {
|
||||
if let Some((PieceType::Pawn, _)) = moving {
|
||||
if src.abs_diff(dst) == 16 {
|
||||
return Self::with_type(src, dst, MoveType::DoublePush);
|
||||
}
|
||||
@@ -146,8 +146,10 @@ impl Move {
|
||||
}
|
||||
}
|
||||
|
||||
if moving == Some(PieceType::King) && src.abs_diff(dst) == 2 {
|
||||
return Self::with_type(src, dst, MoveType::Castle);
|
||||
if let Some((PieceType::King, _)) = moving {
|
||||
if src.abs_diff(dst) == 2 {
|
||||
return Self::with_type(src, dst, MoveType::Castle);
|
||||
}
|
||||
}
|
||||
|
||||
Self::new(src, dst)
|
||||
|
||||
@@ -17,7 +17,7 @@ pub fn sort_moves(mut moves: Vec<Move>, mailbox: &Mailbox, tt_move: Option<Move>
|
||||
|
||||
const fn mvv_lva(mailbox: &Mailbox, mv: Move) -> i32 {
|
||||
match (mailbox.piece_at(mv.src), mailbox.piece_at(mv.dst)) {
|
||||
(Some(aggressor), Some(victim)) => material_score(victim) - material_score(aggressor),
|
||||
(Some(aggressor), Some(victim)) => material_score(victim.0) - material_score(aggressor.0),
|
||||
_ => -1000,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user