Implement redundant mailbox representation
This commit is contained in:
@@ -164,30 +164,6 @@ impl Board {
|
|||||||
self.state = state;
|
self.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn piece_type_at_color(&self, square: usize, color: Color) -> Option<PieceType> {
|
|
||||||
let pieces = match color {
|
|
||||||
Color::White => &self.white_pieces,
|
|
||||||
Color::Black => &self.black_pieces,
|
|
||||||
};
|
|
||||||
|
|
||||||
pieces
|
|
||||||
.iter()
|
|
||||||
.find(|p| have_common_bit(p.bitboard, square_to_bitboard(square)))
|
|
||||||
.map(|p| p.piece_type)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn piece_type_at(&self, square: usize) -> Option<PieceType> {
|
|
||||||
if let Some(at_white) = self.piece_type_at_color(square, Color::White) {
|
|
||||||
return Some(at_white);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(at_black) = self.piece_type_at_color(square, Color::Black) {
|
|
||||||
return Some(at_black);
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_game_state(
|
pub fn update_game_state(
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
mv: &Move,
|
mv: &Move,
|
||||||
@@ -212,6 +188,10 @@ impl Board {
|
|||||||
p.bitboard &= !square_to_bitboard(src);
|
p.bitboard &= !square_to_bitboard(src);
|
||||||
p.bitboard |= square_to_bitboard(dst);
|
p.bitboard |= square_to_bitboard(dst);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//TODO:
|
||||||
|
// pieces[piece_type].bitboard &= !square_to_bitboard(src);
|
||||||
|
// pieces[piece_type].bitboard |= square_to_bitboard(dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_own_piece(&mut self, square: usize) {
|
pub fn remove_own_piece(&mut self, square: usize) {
|
||||||
@@ -234,16 +214,6 @@ impl Board {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_rook_castle(&mut self, king_dst: usize) {
|
|
||||||
let (rook_src, rook_dst) = match king_dst {
|
|
||||||
Square::C1 | Square::C8 => (king_dst - 2, king_dst + 1),
|
|
||||||
Square::G1 | Square::G8 => (king_dst + 1, king_dst - 1),
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.move_piece(rook_src, rook_dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn promote_piece(&mut self, square: usize, promote: &Promote) {
|
pub fn promote_piece(&mut self, square: usize, promote: &Promote) {
|
||||||
let pieces = self.own_pieces();
|
let pieces = self.own_pieces();
|
||||||
match promote {
|
match promote {
|
||||||
@@ -254,15 +224,6 @@ impl Board {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_pawn_enpassant(&mut self, square: usize, color: Color) {
|
|
||||||
let piece_to_remove = match color {
|
|
||||||
Color::White => square - 8,
|
|
||||||
Color::Black => square + 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.remove_opponent_piece(piece_to_remove);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_pawn_move(&mut self, square: usize) -> bool {
|
pub fn is_pawn_move(&mut self, square: usize) -> bool {
|
||||||
let pieces = self.own_pieces();
|
let pieces = self.own_pieces();
|
||||||
have_common_bit(square_to_bitboard(square), pieces[PieceType::Pawn].bitboard)
|
have_common_bit(square_to_bitboard(square), pieces[PieceType::Pawn].bitboard)
|
||||||
@@ -331,7 +292,6 @@ impl PieceType {
|
|||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
use super::bitboard::square_to_bitboard;
|
use super::bitboard::square_to_bitboard;
|
||||||
use super::square::Square;
|
|
||||||
|
|
||||||
impl Index<PieceType> for [Piece] {
|
impl Index<PieceType> for [Piece] {
|
||||||
type Output = Piece;
|
type Output = Piece;
|
||||||
@@ -365,7 +325,7 @@ impl Color {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
board::fen::from_fen,
|
board::{fen::from_fen, square::Square},
|
||||||
movegen::{attack_generator::init_attacks, r#move::MoveType},
|
movegen::{attack_generator::init_attacks, r#move::MoveType},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,13 @@ pub fn from_fen(fen: &str) -> Result<Game, FenError> {
|
|||||||
halfmove_clock,
|
halfmove_clock,
|
||||||
fullmove_counter,
|
fullmove_counter,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let mailbox = Mailbox::new_from_board(&board);
|
||||||
|
|
||||||
Ok(Game {
|
Ok(Game {
|
||||||
board,
|
board,
|
||||||
history: History::new(),
|
history: History::new(),
|
||||||
|
mailbox,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +131,7 @@ fn castling_ability(castling: &str) -> Result<[Castle; 2], FenError> {
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use super::history::History;
|
use super::history::History;
|
||||||
|
use super::mailbox::Mailbox;
|
||||||
|
|
||||||
fn en_passant_square(square: &str) -> Result<Option<usize>, FenError> {
|
fn en_passant_square(square: &str) -> Result<Option<usize>, FenError> {
|
||||||
let mut sqr = square.chars();
|
let mut sqr = square.chars();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use super::{
|
|||||||
bitboard::square_to_bitboard,
|
bitboard::square_to_bitboard,
|
||||||
board::{Board, Color, PieceType},
|
board::{Board, Color, PieceType},
|
||||||
history::{History, MoveParameters},
|
history::{History, MoveParameters},
|
||||||
|
mailbox::Mailbox,
|
||||||
square::Square,
|
square::Square,
|
||||||
state::Castle,
|
state::Castle,
|
||||||
};
|
};
|
||||||
@@ -20,17 +21,19 @@ impl PartialEq for Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq)]
|
#[derive(Debug, Clone, Eq)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
pub board: Board,
|
pub board: Board,
|
||||||
pub history: History,
|
pub history: History,
|
||||||
|
pub mailbox: Mailbox,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub const fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
board: Board::new(),
|
board: Board::new(),
|
||||||
history: History::new(),
|
history: History::new(),
|
||||||
|
mailbox: Mailbox::new_from_board(&Board::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,24 +46,34 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_move(&mut self, mv: &Move) {
|
pub fn make_move(&mut self, mv: &Move) {
|
||||||
|
self.history
|
||||||
|
.push_move_parameters(MoveParameters::build(&self, mv));
|
||||||
|
|
||||||
let board = &mut self.board;
|
let board = &mut self.board;
|
||||||
|
let mailbox = &mut self.mailbox;
|
||||||
let color = board.state.current_player();
|
let color = board.state.current_player();
|
||||||
let pawn_move = board.is_pawn_move(mv.src);
|
let pawn_move = board.is_pawn_move(mv.src);
|
||||||
let mut en_passant_square = None;
|
let mut en_passant_square = None;
|
||||||
self.history
|
|
||||||
.push_move_parameters(MoveParameters::build(board, mv));
|
|
||||||
|
|
||||||
match &mv.move_type {
|
match &mv.move_type {
|
||||||
MoveType::Quiet => {
|
MoveType::Quiet => {
|
||||||
board.move_piece(mv.src, mv.dst);
|
board.move_piece(mv.src, mv.dst);
|
||||||
|
mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src));
|
||||||
}
|
}
|
||||||
MoveType::Capture => {
|
MoveType::Capture => {
|
||||||
board.move_piece(mv.src, mv.dst);
|
board.move_piece(mv.src, mv.dst);
|
||||||
board.remove_opponent_piece(mv.dst);
|
board.remove_opponent_piece(mv.dst);
|
||||||
|
mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src));
|
||||||
}
|
}
|
||||||
MoveType::EnPassant => {
|
MoveType::EnPassant => {
|
||||||
board.move_piece(mv.src, mv.dst);
|
board.move_piece(mv.src, mv.dst);
|
||||||
board.remove_pawn_enpassant(mv.dst, color);
|
let piece_to_remove = match color {
|
||||||
|
Color::White => mv.dst - 8,
|
||||||
|
Color::Black => mv.dst + 8,
|
||||||
|
};
|
||||||
|
board.remove_opponent_piece(piece_to_remove);
|
||||||
|
mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src));
|
||||||
|
mailbox.set_piece_at(piece_to_remove, None);
|
||||||
}
|
}
|
||||||
MoveType::DoublePush => {
|
MoveType::DoublePush => {
|
||||||
board.move_piece(mv.src, mv.dst);
|
board.move_piece(mv.src, mv.dst);
|
||||||
@@ -68,29 +81,45 @@ impl Game {
|
|||||||
Color::White => Some(mv.src + 8),
|
Color::White => Some(mv.src + 8),
|
||||||
Color::Black => Some(mv.src.saturating_sub(8)),
|
Color::Black => Some(mv.src.saturating_sub(8)),
|
||||||
};
|
};
|
||||||
|
mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src));
|
||||||
}
|
}
|
||||||
MoveType::Promotion(promote) => {
|
MoveType::Promotion(promote) => {
|
||||||
board.remove_own_piece(mv.src);
|
board.remove_own_piece(mv.src);
|
||||||
board.promote_piece(mv.dst, promote);
|
board.promote_piece(mv.dst, promote);
|
||||||
|
mailbox.set_piece_at(mv.dst, Some(promote.into_piece_type()));
|
||||||
}
|
}
|
||||||
MoveType::PromotionCapture(promote) => {
|
MoveType::PromotionCapture(promote) => {
|
||||||
board.remove_own_piece(mv.src);
|
board.remove_own_piece(mv.src);
|
||||||
board.remove_opponent_piece(mv.dst);
|
board.remove_opponent_piece(mv.dst);
|
||||||
board.promote_piece(mv.dst, promote);
|
board.promote_piece(mv.dst, promote);
|
||||||
|
mailbox.set_piece_at(mv.dst, Some(promote.into_piece_type()));
|
||||||
}
|
}
|
||||||
MoveType::Castle => {
|
MoveType::Castle => {
|
||||||
board.move_piece(mv.src, mv.dst);
|
board.move_piece(mv.src, mv.dst);
|
||||||
board.move_rook_castle(mv.dst);
|
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),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
board.move_piece(rook_src, rook_dst);
|
||||||
board.state.set_castling_ability(color, Castle::None);
|
board.state.set_castling_ability(color, Castle::None);
|
||||||
|
mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src));
|
||||||
|
mailbox.set_piece_at(rook_src, None);
|
||||||
|
mailbox.set_piece_at(rook_dst, Some(PieceType::Rook));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mailbox.set_piece_at(mv.src, None);
|
||||||
Board::update_game_state(&mut board.state, mv, color, pawn_move, en_passant_square);
|
Board::update_game_state(&mut board.state, mv, color, pawn_move, en_passant_square);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmake_move(&mut self) {
|
pub fn unmake_move(&mut self) {
|
||||||
let board = &mut self.board;
|
let board = &mut self.board;
|
||||||
let move_parameters = &mut self.history.pop_move_parameters().unwrap_or_default();
|
let mailbox = &mut self.mailbox;
|
||||||
|
let move_parameters = &mut self
|
||||||
|
.history
|
||||||
|
.pop_move_parameters()
|
||||||
|
.expect("History stack is empty");
|
||||||
let color_before_move = board.state.change_side();
|
let color_before_move = board.state.change_side();
|
||||||
board.state.revert_full_move(color_before_move);
|
board.state.revert_full_move(color_before_move);
|
||||||
board.state.en_passant_square = move_parameters.en_passant_square;
|
board.state.en_passant_square = move_parameters.en_passant_square;
|
||||||
@@ -108,27 +137,42 @@ impl Game {
|
|||||||
match &mv.move_type {
|
match &mv.move_type {
|
||||||
MoveType::Quiet | MoveType::DoublePush => {
|
MoveType::Quiet | MoveType::DoublePush => {
|
||||||
board.move_piece(mv.dst, mv.src);
|
board.move_piece(mv.dst, mv.src);
|
||||||
|
mailbox.set_piece_at(mv.src, mailbox.find_piece_at(mv.dst));
|
||||||
|
mailbox.set_piece_at(mv.dst, None);
|
||||||
}
|
}
|
||||||
MoveType::Capture | MoveType::Promotion(_) | MoveType::PromotionCapture(_) => {
|
MoveType::Capture => {
|
||||||
if let (Some(captured_piece_type), Some(promoted_piece_type)) = (
|
let captured_piece = move_parameters
|
||||||
move_parameters.captured_piece,
|
.captured_piece
|
||||||
move_parameters.promoted_piece,
|
.expect("Expected captured piece to unmake Capture");
|
||||||
) {
|
|
||||||
let (own_pieces, opponent_pieces) = board.all_pieces();
|
|
||||||
|
|
||||||
opponent_pieces[captured_piece_type].bitboard |= square_to_bitboard(mv.dst);
|
|
||||||
own_pieces[promoted_piece_type].bitboard &= !square_to_bitboard(mv.dst);
|
|
||||||
own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src);
|
|
||||||
} else if let Some(captured_piece_type) = move_parameters.captured_piece {
|
|
||||||
board.move_piece(mv.dst, mv.src);
|
board.move_piece(mv.dst, mv.src);
|
||||||
let opponent_pieces = board.opponent_pieces();
|
let opponent_pieces = board.opponent_pieces();
|
||||||
opponent_pieces[captured_piece_type].bitboard |= square_to_bitboard(mv.dst);
|
opponent_pieces[captured_piece].bitboard |= square_to_bitboard(mv.dst);
|
||||||
} else if let Some(promoted_piece_type) = move_parameters.promoted_piece {
|
mailbox.set_piece_at(mv.src, move_parameters.moved_piece);
|
||||||
let own_pieces = board.own_pieces();
|
mailbox.set_piece_at(mv.dst, Some(captured_piece));
|
||||||
|
|
||||||
own_pieces[promoted_piece_type].bitboard &= !square_to_bitboard(mv.dst);
|
|
||||||
own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src);
|
|
||||||
}
|
}
|
||||||
|
MoveType::Promotion(_) => {
|
||||||
|
let promoted_piece = move_parameters
|
||||||
|
.promoted_piece
|
||||||
|
.expect("Expected promoted piece to unmake Promotion");
|
||||||
|
let own_pieces = board.own_pieces();
|
||||||
|
own_pieces[promoted_piece].bitboard &= !square_to_bitboard(mv.dst);
|
||||||
|
own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src);
|
||||||
|
mailbox.set_piece_at(mv.src, Some(PieceType::Pawn));
|
||||||
|
mailbox.set_piece_at(mv.dst, None);
|
||||||
|
}
|
||||||
|
MoveType::PromotionCapture(_) => {
|
||||||
|
let promoted_piece = move_parameters
|
||||||
|
.promoted_piece
|
||||||
|
.expect("Expected promoted piece to unmake PromotionCapture");
|
||||||
|
let captured_piece = move_parameters
|
||||||
|
.captured_piece
|
||||||
|
.expect("Expected captured piece to unmake PromotionCapture");
|
||||||
|
let (own_pieces, opponent_pieces) = board.all_pieces();
|
||||||
|
opponent_pieces[captured_piece].bitboard |= square_to_bitboard(mv.dst);
|
||||||
|
own_pieces[promoted_piece].bitboard &= !square_to_bitboard(mv.dst);
|
||||||
|
own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src);
|
||||||
|
mailbox.set_piece_at(mv.src, Some(PieceType::Pawn));
|
||||||
|
mailbox.set_piece_at(mv.dst, Some(captured_piece));
|
||||||
}
|
}
|
||||||
MoveType::EnPassant => {
|
MoveType::EnPassant => {
|
||||||
board.move_piece(mv.dst, mv.src);
|
board.move_piece(mv.dst, mv.src);
|
||||||
@@ -138,6 +182,8 @@ impl Game {
|
|||||||
};
|
};
|
||||||
let opponent_pieces = board.opponent_pieces();
|
let opponent_pieces = board.opponent_pieces();
|
||||||
opponent_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(enemy_pawn_square);
|
opponent_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(enemy_pawn_square);
|
||||||
|
mailbox.set_piece_at(mv.src, Some(PieceType::Pawn));
|
||||||
|
mailbox.set_piece_at(enemy_pawn_square, Some(PieceType::Pawn));
|
||||||
}
|
}
|
||||||
MoveType::Castle => {
|
MoveType::Castle => {
|
||||||
board.move_piece(mv.dst, mv.src);
|
board.move_piece(mv.dst, mv.src);
|
||||||
@@ -149,6 +195,10 @@ impl Game {
|
|||||||
let own_pieces = board.own_pieces();
|
let own_pieces = board.own_pieces();
|
||||||
own_pieces[PieceType::Rook].bitboard &= !square_to_bitboard(rook_dst);
|
own_pieces[PieceType::Rook].bitboard &= !square_to_bitboard(rook_dst);
|
||||||
own_pieces[PieceType::Rook].bitboard |= square_to_bitboard(rook_src);
|
own_pieces[PieceType::Rook].bitboard |= square_to_bitboard(rook_src);
|
||||||
|
mailbox.set_piece_at(mv.src, mailbox.find_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_dst, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use crate::movegen::r#move::{Move, MoveType, Promote};
|
use crate::movegen::r#move::{Move, MoveType};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
board::{Board, Color, PieceType},
|
board::PieceType,
|
||||||
|
game::Game,
|
||||||
state::{Castle, State},
|
state::{Castle, State},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ impl History {
|
|||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct MoveParameters {
|
pub struct MoveParameters {
|
||||||
pub mv: Option<Move>,
|
pub mv: Option<Move>,
|
||||||
|
pub moved_piece: Option<PieceType>,
|
||||||
pub captured_piece: Option<PieceType>,
|
pub captured_piece: Option<PieceType>,
|
||||||
pub promoted_piece: Option<PieceType>,
|
pub promoted_piece: Option<PieceType>,
|
||||||
pub castling_ability: Option<[Castle; 2]>,
|
pub castling_ability: Option<[Castle; 2]>,
|
||||||
@@ -40,6 +42,7 @@ impl MoveParameters {
|
|||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mv: None,
|
mv: None,
|
||||||
|
moved_piece: None,
|
||||||
captured_piece: None,
|
captured_piece: None,
|
||||||
promoted_piece: None,
|
promoted_piece: None,
|
||||||
castling_ability: None,
|
castling_ability: None,
|
||||||
@@ -48,11 +51,13 @@ impl MoveParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(board: &Board, mv: &Move) -> Self {
|
pub fn build(game: &Game, mv: &Move) -> Self {
|
||||||
let mut move_parameters = Self::new();
|
let mut move_parameters = Self::new();
|
||||||
move_parameters.add_move(*mv);
|
move_parameters.add_move(*mv);
|
||||||
move_parameters.add_irreversible_parameters(board.state);
|
move_parameters.add_irreversible_parameters(game.board.state);
|
||||||
move_parameters.add_capture_and_promotion_piece(board, *mv, board.state.current_player());
|
move_parameters.add_moved_piece(game, mv);
|
||||||
|
move_parameters.add_captured_piece(game, mv);
|
||||||
|
move_parameters.add_promoted_piece(mv);
|
||||||
|
|
||||||
move_parameters
|
move_parameters
|
||||||
}
|
}
|
||||||
@@ -61,31 +66,27 @@ impl MoveParameters {
|
|||||||
self.mv = Some(mv);
|
self.mv = Some(mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_captured_piece(&mut self, board: &Board, dst: usize, color: Color) {
|
fn add_moved_piece(&mut self, game: &Game, mv: &Move) {
|
||||||
self.captured_piece = board.piece_type_at_color(dst, color);
|
self.moved_piece = game.mailbox.find_piece_at(mv.src);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_promoted_piece(&mut self, promote: Promote) {
|
fn add_captured_piece(&mut self, game: &Game, mv: &Move) {
|
||||||
self.promoted_piece = Some(promote.into_piece_type());
|
if let MoveType::Capture | MoveType::PromotionCapture(_) = mv.move_type {
|
||||||
|
self.captured_piece = game.mailbox.find_piece_at(mv.dst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_irreversible_parameters(&mut self, state: State) {
|
fn add_promoted_piece(&mut self, mv: &Move) {
|
||||||
|
if let MoveType::Promotion(promote) | MoveType::PromotionCapture(promote) = mv.move_type {
|
||||||
|
self.promoted_piece = Some(promote.into_piece_type())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_irreversible_parameters(&mut self, state: State) {
|
||||||
self.castling_ability = Some(state.castling_ability);
|
self.castling_ability = Some(state.castling_ability);
|
||||||
self.en_passant_square = state.en_passant_square;
|
self.en_passant_square = state.en_passant_square;
|
||||||
self.halfmove_clock = Some(state.halfmove_clock);
|
self.halfmove_clock = Some(state.halfmove_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_capture_and_promotion_piece(&mut self, board: &Board, mv: Move, color: Color) {
|
|
||||||
match mv.move_type {
|
|
||||||
MoveType::Capture => self.add_captured_piece(board, mv.dst, color.opponent()),
|
|
||||||
MoveType::Promotion(piece) => self.add_promoted_piece(piece),
|
|
||||||
MoveType::PromotionCapture(piece) => {
|
|
||||||
self.add_promoted_piece(piece);
|
|
||||||
self.add_captured_piece(board, mv.dst, color.opponent());
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MoveParameters {
|
impl Default for MoveParameters {
|
||||||
@@ -107,18 +108,18 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_unmake_quiet_and_double_push() -> Result<(), String> {
|
fn test_unmake_quiet_and_double_push() -> Result<(), String> {
|
||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let board_before_make = game.board.clone();
|
let game_before_make = game.clone();
|
||||||
let mv = Move::new_with_type(Square::B2, Square::B3, MoveType::Quiet);
|
let mv = Move::new_with_type(Square::B2, Square::B3, MoveType::Quiet);
|
||||||
game.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
let mv = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush);
|
let mv = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush);
|
||||||
game.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -126,18 +127,18 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_unmake_capture_and_promotion() -> Result<(), String> {
|
fn test_unmake_capture_and_promotion() -> Result<(), String> {
|
||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let board_before_make = game.board.clone();
|
let game_before_make = game.clone();
|
||||||
let mv = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture);
|
let mv = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture);
|
||||||
game.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
let mv = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen));
|
let mv = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen));
|
||||||
game.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
let mv = Move::new_with_type(
|
let mv = Move::new_with_type(
|
||||||
Square::C7,
|
Square::C7,
|
||||||
@@ -147,7 +148,7 @@ mod tests {
|
|||||||
game.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -155,12 +156,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_unmake_en_passant() -> Result<(), String> {
|
fn test_unmake_en_passant() -> Result<(), String> {
|
||||||
let mut game = from_fen(FEN_2)?;
|
let mut game = from_fen(FEN_2)?;
|
||||||
let board_before_make = game.board.clone();
|
let game_before_make = game.clone();
|
||||||
let mv = Move::new_with_type(Square::A4, Square::B3, MoveType::EnPassant);
|
let mv = Move::new_with_type(Square::A4, Square::B3, MoveType::EnPassant);
|
||||||
game.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -168,12 +169,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_unmake_castle() -> Result<(), String> {
|
fn test_unmake_castle() -> Result<(), String> {
|
||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let board_before_make = game.board.clone();
|
let game_before_make = game.clone();
|
||||||
let mv = Move::new_with_type(Square::E1, Square::C1, MoveType::Castle);
|
let mv = Move::new_with_type(Square::E1, Square::C1, MoveType::Castle);
|
||||||
game.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
101
src/board/mailbox.rs
Normal file
101
src/board/mailbox.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
use super::{
|
||||||
|
bitboard::{have_common_bit, square_to_bitboard},
|
||||||
|
board::{Board, PieceType},
|
||||||
|
square::Square,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Mailbox {
|
||||||
|
pub mailbox: [Option<PieceType>; 64],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mailbox {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
mailbox: [None; 64],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from_board(board: &Board) -> Self {
|
||||||
|
let mut mailbox: [Option<PieceType>; 64] = [None; 64];
|
||||||
|
for square in Square::A1..=Square::H8 {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { mailbox }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_piece_at(&mut self, square: usize, piece_type: Option<PieceType>) {
|
||||||
|
self.mailbox[square] = piece_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn find_piece_at(&self, square: usize) -> Option<PieceType> {
|
||||||
|
self.mailbox[square]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::board::{board::PieceType, fen::from_fen, square::Square};
|
||||||
|
|
||||||
|
use super::Mailbox;
|
||||||
|
|
||||||
|
const FEN_MATE_IN_1: &str = "8/8/8/8/8/4q1k1/8/5K2 b - - 0 1";
|
||||||
|
const FEN_STARTPOS: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new_from_board() -> Result<(), String> {
|
||||||
|
let game = from_fen(FEN_MATE_IN_1)?;
|
||||||
|
let mailbox = Mailbox::new_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::new_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),
|
||||||
|
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),
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(expected, mailbox.mailbox);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_find_piece_at() -> Result<(), String> {
|
||||||
|
let game = from_fen(FEN_MATE_IN_1)?;
|
||||||
|
let mailbox = Mailbox::new_from_board(&game.board);
|
||||||
|
|
||||||
|
assert_eq!(PieceType::King, mailbox.find_piece_at(Square::F1).unwrap());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,5 +3,6 @@ pub mod board;
|
|||||||
pub mod fen;
|
pub mod fen;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
pub mod history;
|
pub mod history;
|
||||||
|
pub mod mailbox;
|
||||||
pub mod square;
|
pub mod square;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ pub fn uci_position(position: &mut SplitWhitespace) -> Result<Game, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for mv_str in position {
|
for mv_str in position {
|
||||||
let mv = Move::parse_from_str(&game.board, mv_str)?;
|
let mv = Move::parse_from_str(&game, mv_str)?;
|
||||||
game.make_move(&mv);
|
game.make_move(&mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ mod tests {
|
|||||||
fn test_uci_go() -> Result<(), String> {
|
fn test_uci_go() -> Result<(), String> {
|
||||||
init_attacks();
|
init_attacks();
|
||||||
let mut game = from_fen(FEN_MATE_IN_1)?;
|
let mut game = from_fen(FEN_MATE_IN_1)?;
|
||||||
let command_go = "go depth 4";
|
let command_go = "go depth 2";
|
||||||
let mut parts = command_go.split_whitespace();
|
let mut parts = command_go.split_whitespace();
|
||||||
let response = uci_go(&mut parts, &mut game)?;
|
let response = uci_go(&mut parts, &mut game)?;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ use core::fmt;
|
|||||||
use std::str::Chars;
|
use std::str::Chars;
|
||||||
|
|
||||||
use crate::board::{
|
use crate::board::{
|
||||||
board::{Board, PieceType},
|
board::PieceType,
|
||||||
|
game::Game,
|
||||||
square::{coords_to_square, square_to_algebraic},
|
square::{coords_to_square, square_to_algebraic},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,6 +63,9 @@ impl fmt::Debug for Move {
|
|||||||
write!(f, "{promote_char}")?;
|
write!(f, "{promote_char}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
write!(f, ", debug_field: {:?}", self.move_type)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,7 +97,7 @@ impl Move {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_from_str(board: &Board, mv: &str) -> Result<Self, String> {
|
pub fn parse_from_str(game: &Game, mv: &str) -> Result<Self, String> {
|
||||||
if mv.len() != 4 && mv.len() != 5 {
|
if mv.len() != 4 && mv.len() != 5 {
|
||||||
return Err("Invalid move characters length".to_string());
|
return Err("Invalid move characters length".to_string());
|
||||||
}
|
}
|
||||||
@@ -113,17 +117,12 @@ impl Move {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self::build_with_type(board, src, dst, promote_into))
|
Ok(Self::build_with_type(game, src, dst, promote_into))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_with_type(
|
fn build_with_type(game: &Game, src: usize, dst: usize, promote_into: Option<Promote>) -> Self {
|
||||||
board: &Board,
|
let moving = game.mailbox.find_piece_at(src);
|
||||||
src: usize,
|
let captured = game.mailbox.find_piece_at(dst);
|
||||||
dst: usize,
|
|
||||||
promote_into: Option<Promote>,
|
|
||||||
) -> Self {
|
|
||||||
let moving = board.piece_type_at(src);
|
|
||||||
let captured = board.piece_type_at(dst);
|
|
||||||
|
|
||||||
match (captured, promote_into) {
|
match (captured, promote_into) {
|
||||||
(Some(_), None) => return Self::new_with_type(src, dst, MoveType::Capture),
|
(Some(_), None) => return Self::new_with_type(src, dst, MoveType::Capture),
|
||||||
@@ -170,7 +169,7 @@ mod tests {
|
|||||||
fn test_parse_from_str_quiet() -> Result<(), String> {
|
fn test_parse_from_str_quiet() -> Result<(), String> {
|
||||||
let game = from_fen(FEN)?;
|
let game = from_fen(FEN)?;
|
||||||
let mv_str = "b2b3";
|
let mv_str = "b2b3";
|
||||||
let actual = Move::parse_from_str(&game.board, &mv_str)?;
|
let actual = Move::parse_from_str(&game, &mv_str)?;
|
||||||
let expected = Move::new(Square::B2, Square::B3);
|
let expected = Move::new(Square::B2, Square::B3);
|
||||||
|
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
@@ -182,7 +181,7 @@ mod tests {
|
|||||||
fn test_parse_from_str_capture() -> Result<(), String> {
|
fn test_parse_from_str_capture() -> Result<(), String> {
|
||||||
let game = from_fen(FEN)?;
|
let game = from_fen(FEN)?;
|
||||||
let mv_str = "d3b5";
|
let mv_str = "d3b5";
|
||||||
let actual = Move::parse_from_str(&game.board, &mv_str)?;
|
let actual = Move::parse_from_str(&game, &mv_str)?;
|
||||||
let expected = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture);
|
let expected = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture);
|
||||||
|
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
@@ -194,7 +193,7 @@ mod tests {
|
|||||||
fn test_parse_from_str_en_passant() -> Result<(), String> {
|
fn test_parse_from_str_en_passant() -> Result<(), String> {
|
||||||
let game = from_fen(FEN)?;
|
let game = from_fen(FEN)?;
|
||||||
let mv_str = "h5g6";
|
let mv_str = "h5g6";
|
||||||
let actual = Move::parse_from_str(&game.board, &mv_str)?;
|
let actual = Move::parse_from_str(&game, &mv_str)?;
|
||||||
let expected = Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant);
|
let expected = Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant);
|
||||||
|
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
@@ -206,7 +205,7 @@ mod tests {
|
|||||||
fn test_parse_from_str_double_push() -> Result<(), String> {
|
fn test_parse_from_str_double_push() -> Result<(), String> {
|
||||||
let game = from_fen(FEN)?;
|
let game = from_fen(FEN)?;
|
||||||
let mv_str = "b2b4";
|
let mv_str = "b2b4";
|
||||||
let actual = Move::parse_from_str(&game.board, &mv_str)?;
|
let actual = Move::parse_from_str(&game, &mv_str)?;
|
||||||
let expected = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush);
|
let expected = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush);
|
||||||
|
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
@@ -218,7 +217,7 @@ mod tests {
|
|||||||
fn test_parse_from_str_promotion() -> Result<(), String> {
|
fn test_parse_from_str_promotion() -> Result<(), String> {
|
||||||
let game = from_fen(FEN)?;
|
let game = from_fen(FEN)?;
|
||||||
let mv_str = "c7c8q";
|
let mv_str = "c7c8q";
|
||||||
let actual = Move::parse_from_str(&game.board, &mv_str)?;
|
let actual = Move::parse_from_str(&game, &mv_str)?;
|
||||||
let expected =
|
let expected =
|
||||||
Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen));
|
Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen));
|
||||||
|
|
||||||
@@ -231,7 +230,7 @@ mod tests {
|
|||||||
fn test_parse_from_str_promotion_capture() -> Result<(), String> {
|
fn test_parse_from_str_promotion_capture() -> Result<(), String> {
|
||||||
let game = from_fen(FEN)?;
|
let game = from_fen(FEN)?;
|
||||||
let mv_str = "c7b8q";
|
let mv_str = "c7b8q";
|
||||||
let actual = Move::parse_from_str(&game.board, &mv_str)?;
|
let actual = Move::parse_from_str(&game, &mv_str)?;
|
||||||
let expected = Move::new_with_type(
|
let expected = Move::new_with_type(
|
||||||
Square::C7,
|
Square::C7,
|
||||||
Square::B8,
|
Square::B8,
|
||||||
@@ -248,7 +247,7 @@ mod tests {
|
|||||||
fn test_parse_from_str_panic_1() {
|
fn test_parse_from_str_panic_1() {
|
||||||
let game = from_fen(FEN);
|
let game = from_fen(FEN);
|
||||||
let mv_str = "c7c8qq";
|
let mv_str = "c7c8qq";
|
||||||
Move::parse_from_str(&game.unwrap().board, &mv_str).unwrap();
|
Move::parse_from_str(&game.unwrap(), &mv_str).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -256,6 +255,6 @@ mod tests {
|
|||||||
fn test_parse_from_str_panic_2() -> () {
|
fn test_parse_from_str_panic_2() -> () {
|
||||||
let game = from_fen(FEN);
|
let game = from_fen(FEN);
|
||||||
let mv_str = "c7c8w";
|
let mv_str = "c7c8w";
|
||||||
Move::parse_from_str(&game.unwrap().board, &mv_str).unwrap();
|
Move::parse_from_str(&game.unwrap(), &mv_str).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{board::board::Board, movegen::r#move::Move};
|
use crate::{board::game::Game, movegen::r#move::Move};
|
||||||
|
|
||||||
// Rows: Aggressors (P, N, B, R, Q, K)
|
// Rows: Aggressors (P, N, B, R, Q, K)
|
||||||
// Columns: Victims (K, Q, R, B, N, P)
|
// Columns: Victims (K, Q, R, B, N, P)
|
||||||
@@ -12,8 +12,11 @@ const MVV_LVA: [[usize; 6]; 6] = [
|
|||||||
[5, 4, 3, 2, 1, 0],
|
[5, 4, 3, 2, 1, 0],
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn score_by_mvv_lva(board: &Board, mv: Move) -> usize {
|
pub fn score_by_mvv_lva(game: &Game, mv: Move) -> usize {
|
||||||
match (board.piece_type_at(mv.src), board.piece_type_at(mv.dst)) {
|
match (
|
||||||
|
game.mailbox.find_piece_at(mv.src),
|
||||||
|
game.mailbox.find_piece_at(mv.dst),
|
||||||
|
) {
|
||||||
(Some(aggressor), Some(victim)) => MVV_LVA[aggressor.idx()][victim.idx()],
|
(Some(aggressor), Some(victim)) => MVV_LVA[aggressor.idx()][victim.idx()],
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
@@ -33,7 +36,7 @@ mod tests {
|
|||||||
fn test_score_by_mvv_lva() -> Result<(), String> {
|
fn test_score_by_mvv_lva() -> Result<(), String> {
|
||||||
let game = from_fen(FEN)?;
|
let game = from_fen(FEN)?;
|
||||||
let f3f5 = Move::new_with_type(Square::F3, Square::F5, MoveType::Capture);
|
let f3f5 = Move::new_with_type(Square::F3, Square::F5, MoveType::Capture);
|
||||||
let actual = score_by_mvv_lva(&game.board, f3f5);
|
let actual = score_by_mvv_lva(&game, f3f5);
|
||||||
let expected = MVV_LVA[PieceType::Queen.idx()][PieceType::Pawn.idx()];
|
let expected = MVV_LVA[PieceType::Queen.idx()][PieceType::Pawn.idx()];
|
||||||
|
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub fn negamax(
|
|||||||
let mut legal_moves = 0;
|
let mut legal_moves = 0;
|
||||||
|
|
||||||
let mut pseudo_legal_moves = game.board.pseudo_moves_all();
|
let mut pseudo_legal_moves = game.board.pseudo_moves_all();
|
||||||
pseudo_legal_moves.sort_unstable_by_key(|mv| score_by_mvv_lva(&game.board, *mv));
|
pseudo_legal_moves.sort_unstable_by_key(|mv| score_by_mvv_lva(&game, *mv));
|
||||||
|
|
||||||
for mv in pseudo_legal_moves {
|
for mv in pseudo_legal_moves {
|
||||||
game.make_move(&mv);
|
game.make_move(&mv);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ pub fn quiescence(game: &mut Game, mut alpha: i32, beta: i32) -> (Option<Move>,
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
captures.sort_unstable_by_key(|mv| score_by_mvv_lva(&game.board, *mv));
|
captures.sort_unstable_by_key(|mv| score_by_mvv_lva(&game, *mv));
|
||||||
|
|
||||||
for mv in captures {
|
for mv in captures {
|
||||||
game.make_move(&mv);
|
game.make_move(&mv);
|
||||||
|
|||||||
Reference in New Issue
Block a user