Replace loops with mailbox lookups and move make/unmake tests to game.rs
This commit is contained in:
@@ -164,66 +164,6 @@ impl Board {
|
|||||||
self.state = state;
|
self.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_game_state(
|
|
||||||
state: &mut State,
|
|
||||||
mv: &Move,
|
|
||||||
color: Color,
|
|
||||||
pawn_move: bool,
|
|
||||||
en_passant_square: Option<usize>,
|
|
||||||
) {
|
|
||||||
state.set_en_passant_square(en_passant_square);
|
|
||||||
state.update_castling_state_quiet(mv.src, color);
|
|
||||||
state.update_castling_state_capture(mv.dst, color.opponent());
|
|
||||||
state.update_half_move(mv.move_type, pawn_move);
|
|
||||||
state.update_full_move(color);
|
|
||||||
state.change_side();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn move_piece(&mut self, src: usize, dst: usize) {
|
|
||||||
let pieces = self.own_pieces();
|
|
||||||
pieces
|
|
||||||
.iter_mut()
|
|
||||||
.filter(|p| have_common_bit(p.bitboard, square_to_bitboard(src)))
|
|
||||||
.for_each(|p| {
|
|
||||||
p.bitboard &= !square_to_bitboard(src);
|
|
||||||
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) {
|
|
||||||
let pieces = self.own_pieces();
|
|
||||||
pieces
|
|
||||||
.iter_mut()
|
|
||||||
.filter(|p| have_common_bit(p.bitboard, square_to_bitboard(square)))
|
|
||||||
.for_each(|p| {
|
|
||||||
p.bitboard &= !square_to_bitboard(square);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_opponent_piece(&mut self, square: usize) {
|
|
||||||
let pieces = self.opponent_pieces();
|
|
||||||
pieces
|
|
||||||
.iter_mut()
|
|
||||||
.filter(|p| have_common_bit(p.bitboard, square_to_bitboard(square)))
|
|
||||||
.for_each(|p| {
|
|
||||||
p.bitboard &= !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),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
@@ -249,6 +189,42 @@ impl Board {
|
|||||||
Color::Black => (&mut self.black_pieces, &mut self.white_pieces),
|
Color::Black => (&mut self.black_pieces, &mut self.white_pieces),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Board {
|
impl Default for Board {
|
||||||
@@ -324,10 +300,7 @@ impl Color {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{board::fen::from_fen, movegen::attack_generator::init_attacks};
|
||||||
board::{fen::from_fen, square::Square},
|
|
||||||
movegen::{attack_generator::init_attacks, r#move::MoveType},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -353,98 +326,4 @@ mod tests {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const FEN: &str = "1r2k2r/2P1pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R w KQk g6 0 1";
|
|
||||||
const FEN_QUIET: &str = "1r2k2r/2P1pq1p/2npb3/1p3ppP/p3P3/P2BQ3/1P1PNPP1/R3K2R b KQk - 1 1";
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_make_move_quiet() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN)?;
|
|
||||||
let b1c3 = Move::new(Square::F3, Square::E3);
|
|
||||||
game.make_move(&b1c3);
|
|
||||||
|
|
||||||
assert_eq!(game, from_fen(FEN_QUIET)?);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
const FEN_CAPTURE: &str = "1r2k2r/2P1pq1p/2npb3/1p3QpP/p3P3/P2B4/1P1PNPP1/R3K2R b KQk - 0 1";
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_make_move_capture() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN)?;
|
|
||||||
let f3f5 = Move::new_with_type(Square::F3, Square::F5, MoveType::Capture);
|
|
||||||
game.make_move(&f3f5);
|
|
||||||
|
|
||||||
assert_eq!(game, from_fen(FEN_CAPTURE)?);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
const FEN_EN_PASSANT: &str =
|
|
||||||
"1r2k2r/2P1pq1p/2npb1P1/1p3p2/p3P3/P2B1Q2/1P1PNPP1/R3K2R b KQk - 0 1";
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_make_move_en_passant() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN)?;
|
|
||||||
let h5g6 = Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant);
|
|
||||||
game.make_move(&h5g6);
|
|
||||||
|
|
||||||
assert_eq!(game, from_fen(FEN_EN_PASSANT)?);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
const FEN_DOUBLE_PUSH: &str =
|
|
||||||
"1r2k2r/2P1pq1p/2npb3/1p3ppP/pP2P3/P2B1Q2/3PNPP1/R3K2R b KQk b3 0 1";
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_make_move_double_push() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN)?;
|
|
||||||
let b2b4 = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush);
|
|
||||||
game.make_move(&b2b4);
|
|
||||||
assert_eq!(game, from_fen(FEN_DOUBLE_PUSH)?);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
const FEN_PROMOTION: &str = "1rQ1k2r/4pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R b KQk - 0 1";
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_make_move_promotion() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN)?;
|
|
||||||
let c7c8 = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen));
|
|
||||||
game.make_move(&c7c8);
|
|
||||||
assert_eq!(game, from_fen(FEN_PROMOTION)?);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
const FEN_PROMOTION_CAPTURE: &str =
|
|
||||||
"1Q2k2r/4pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R b KQk - 0 1";
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_make_move_promotion_capture() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN)?;
|
|
||||||
let c7b8 = Move::new_with_type(
|
|
||||||
Square::C7,
|
|
||||||
Square::B8,
|
|
||||||
MoveType::PromotionCapture(Promote::Queen),
|
|
||||||
);
|
|
||||||
game.make_move(&c7b8);
|
|
||||||
assert_eq!(game, from_fen(FEN_PROMOTION_CAPTURE)?);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
const FEN_CASTLE: &str = "1r2k2r/2P1pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R4RK1 b k - 1 1";
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_make_move_castle() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN)?;
|
|
||||||
let e1g1 = Move::new_with_type(Square::E1, Square::G1, MoveType::Castle);
|
|
||||||
game.make_move(&e1g1);
|
|
||||||
assert_eq!(game, from_fen(FEN_CASTLE)?);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use crate::{
|
|||||||
use String as FenError;
|
use String as FenError;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
bitboard::square_to_bitboard,
|
|
||||||
board::{Board, Color, PieceType},
|
board::{Board, Color, PieceType},
|
||||||
history::{History, MoveParameters},
|
history::{History, MoveParameters},
|
||||||
mailbox::Mailbox,
|
mailbox::Mailbox,
|
||||||
@@ -55,28 +54,30 @@ impl Game {
|
|||||||
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;
|
||||||
|
|
||||||
|
let piece_at_src = mailbox.find_piece_at(mv.src).expect("Expected set piece");
|
||||||
|
let piece_at_dst = mailbox.find_piece_at(mv.dst);
|
||||||
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, piece_at_src);
|
||||||
mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src));
|
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, piece_at_src);
|
||||||
board.remove_opponent_piece(mv.dst);
|
board.remove_opponent_piece(mv.dst, piece_at_dst.expect("Expected set piece"));
|
||||||
mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src));
|
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, piece_at_src);
|
||||||
let piece_to_remove = match color {
|
let piece_to_remove_sq = match color {
|
||||||
Color::White => mv.dst - 8,
|
Color::White => mv.dst - 8,
|
||||||
Color::Black => mv.dst + 8,
|
Color::Black => mv.dst + 8,
|
||||||
};
|
};
|
||||||
board.remove_opponent_piece(piece_to_remove);
|
board.remove_opponent_piece(piece_to_remove_sq, PieceType::Pawn);
|
||||||
mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src));
|
mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src));
|
||||||
mailbox.set_piece_at(piece_to_remove, None);
|
mailbox.set_piece_at(piece_to_remove_sq, None);
|
||||||
}
|
}
|
||||||
MoveType::DoublePush => {
|
MoveType::DoublePush => {
|
||||||
board.move_piece(mv.src, mv.dst);
|
board.move_piece(mv.src, mv.dst, piece_at_src);
|
||||||
en_passant_square = match color {
|
en_passant_square = match color {
|
||||||
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)),
|
||||||
@@ -84,24 +85,24 @@ impl Game {
|
|||||||
mailbox.set_piece_at(mv.dst, mailbox.find_piece_at(mv.src));
|
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, piece_at_src);
|
||||||
board.promote_piece(mv.dst, promote);
|
board.promote_piece(mv.dst, promote);
|
||||||
mailbox.set_piece_at(mv.dst, Some(promote.into_piece_type()));
|
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, piece_at_src);
|
||||||
board.remove_opponent_piece(mv.dst);
|
board.remove_opponent_piece(mv.dst, piece_at_dst.expect("Expected set piece"));
|
||||||
board.promote_piece(mv.dst, promote);
|
board.promote_piece(mv.dst, promote);
|
||||||
mailbox.set_piece_at(mv.dst, Some(promote.into_piece_type()));
|
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, piece_at_src);
|
||||||
let (rook_src, rook_dst) = match mv.dst {
|
let (rook_src, rook_dst) = match mv.dst {
|
||||||
Square::C1 | Square::C8 => (mv.dst - 2, mv.dst + 1),
|
Square::C1 | Square::C8 => (mv.dst - 2, mv.dst + 1),
|
||||||
Square::G1 | Square::G8 => (mv.dst + 1, mv.dst - 1),
|
Square::G1 | Square::G8 => (mv.dst + 1, mv.dst - 1),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
board.move_piece(rook_src, rook_dst);
|
board.move_piece(rook_src, rook_dst, PieceType::Rook);
|
||||||
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(mv.dst, mailbox.find_piece_at(mv.src));
|
||||||
mailbox.set_piece_at(rook_src, None);
|
mailbox.set_piece_at(rook_src, None);
|
||||||
@@ -110,7 +111,9 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mailbox.set_piece_at(mv.src, None);
|
mailbox.set_piece_at(mv.src, None);
|
||||||
Board::update_game_state(&mut board.state, mv, color, pawn_move, en_passant_square);
|
board
|
||||||
|
.state
|
||||||
|
.update_game_state(mv, color, pawn_move, en_passant_square);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmake_move(&mut self) {
|
pub fn unmake_move(&mut self) {
|
||||||
@@ -133,10 +136,10 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mv = move_parameters.mv.unwrap();
|
let mv = move_parameters.mv.unwrap();
|
||||||
|
let piece_at_dst = mailbox.find_piece_at(mv.dst).expect("Expected set piece");
|
||||||
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, piece_at_dst);
|
||||||
mailbox.set_piece_at(mv.src, mailbox.find_piece_at(mv.dst));
|
mailbox.set_piece_at(mv.src, mailbox.find_piece_at(mv.dst));
|
||||||
mailbox.set_piece_at(mv.dst, None);
|
mailbox.set_piece_at(mv.dst, None);
|
||||||
}
|
}
|
||||||
@@ -144,9 +147,8 @@ impl Game {
|
|||||||
let captured_piece = move_parameters
|
let captured_piece = move_parameters
|
||||||
.captured_piece
|
.captured_piece
|
||||||
.expect("Expected captured piece to unmake Capture");
|
.expect("Expected captured piece to unmake Capture");
|
||||||
board.move_piece(mv.dst, mv.src);
|
board.move_piece(mv.dst, mv.src, piece_at_dst);
|
||||||
let opponent_pieces = board.opponent_pieces();
|
board.insert_opponent_piece(mv.dst, captured_piece);
|
||||||
opponent_pieces[captured_piece].bitboard |= square_to_bitboard(mv.dst);
|
|
||||||
mailbox.set_piece_at(mv.src, move_parameters.moved_piece);
|
mailbox.set_piece_at(mv.src, move_parameters.moved_piece);
|
||||||
mailbox.set_piece_at(mv.dst, Some(captured_piece));
|
mailbox.set_piece_at(mv.dst, Some(captured_piece));
|
||||||
}
|
}
|
||||||
@@ -154,9 +156,9 @@ impl Game {
|
|||||||
let promoted_piece = move_parameters
|
let promoted_piece = move_parameters
|
||||||
.promoted_piece
|
.promoted_piece
|
||||||
.expect("Expected promoted piece to unmake Promotion");
|
.expect("Expected promoted piece to unmake Promotion");
|
||||||
let own_pieces = board.own_pieces();
|
board.remove_own_piece(mv.dst, promoted_piece);
|
||||||
own_pieces[promoted_piece].bitboard &= !square_to_bitboard(mv.dst);
|
board.insert_own_piece(mv.src, PieceType::Pawn);
|
||||||
own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src);
|
|
||||||
mailbox.set_piece_at(mv.src, Some(PieceType::Pawn));
|
mailbox.set_piece_at(mv.src, Some(PieceType::Pawn));
|
||||||
mailbox.set_piece_at(mv.dst, None);
|
mailbox.set_piece_at(mv.dst, None);
|
||||||
}
|
}
|
||||||
@@ -167,34 +169,31 @@ impl Game {
|
|||||||
let captured_piece = move_parameters
|
let captured_piece = move_parameters
|
||||||
.captured_piece
|
.captured_piece
|
||||||
.expect("Expected captured piece to unmake PromotionCapture");
|
.expect("Expected captured piece to unmake PromotionCapture");
|
||||||
let (own_pieces, opponent_pieces) = board.all_pieces();
|
board.remove_own_piece(mv.dst, promoted_piece);
|
||||||
opponent_pieces[captured_piece].bitboard |= square_to_bitboard(mv.dst);
|
board.insert_opponent_piece(mv.dst, captured_piece);
|
||||||
own_pieces[promoted_piece].bitboard &= !square_to_bitboard(mv.dst);
|
board.insert_own_piece(mv.src, PieceType::Pawn);
|
||||||
own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src);
|
|
||||||
mailbox.set_piece_at(mv.src, Some(PieceType::Pawn));
|
mailbox.set_piece_at(mv.src, Some(PieceType::Pawn));
|
||||||
mailbox.set_piece_at(mv.dst, Some(captured_piece));
|
mailbox.set_piece_at(mv.dst, Some(captured_piece));
|
||||||
}
|
}
|
||||||
MoveType::EnPassant => {
|
MoveType::EnPassant => {
|
||||||
board.move_piece(mv.dst, mv.src);
|
|
||||||
let enemy_pawn_square = match color_before_move {
|
let enemy_pawn_square = match color_before_move {
|
||||||
Color::White => mv.dst - 8,
|
Color::White => mv.dst - 8,
|
||||||
Color::Black => mv.dst + 8,
|
Color::Black => mv.dst + 8,
|
||||||
};
|
};
|
||||||
let opponent_pieces = board.opponent_pieces();
|
board.move_piece(mv.dst, mv.src, piece_at_dst);
|
||||||
opponent_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(enemy_pawn_square);
|
board.insert_opponent_piece(enemy_pawn_square, PieceType::Pawn);
|
||||||
mailbox.set_piece_at(mv.src, Some(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(enemy_pawn_square, Some(PieceType::Pawn));
|
||||||
}
|
}
|
||||||
MoveType::Castle => {
|
MoveType::Castle => {
|
||||||
board.move_piece(mv.dst, mv.src);
|
|
||||||
let (rook_src, rook_dst) = match mv.dst {
|
let (rook_src, rook_dst) = match mv.dst {
|
||||||
Square::C1 | Square::C8 => (mv.dst - 2, mv.dst + 1),
|
Square::C1 | Square::C8 => (mv.dst - 2, mv.dst + 1),
|
||||||
Square::G1 | Square::G8 => (mv.dst + 1, mv.dst - 1),
|
Square::G1 | Square::G8 => (mv.dst + 1, mv.dst - 1),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
let own_pieces = board.own_pieces();
|
board.move_piece(mv.dst, mv.src, piece_at_dst);
|
||||||
own_pieces[PieceType::Rook].bitboard &= !square_to_bitboard(rook_dst);
|
board.remove_own_piece(rook_dst, PieceType::Rook);
|
||||||
own_pieces[PieceType::Rook].bitboard |= square_to_bitboard(rook_src);
|
board.insert_own_piece(rook_src, PieceType::Rook);
|
||||||
mailbox.set_piece_at(mv.src, mailbox.find_piece_at(mv.dst));
|
mailbox.set_piece_at(mv.src, mailbox.find_piece_at(mv.dst));
|
||||||
mailbox.set_piece_at(mv.dst, None);
|
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));
|
||||||
@@ -209,3 +208,184 @@ impl Default for Game {
|
|||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
board::{fen::from_fen, square::Square},
|
||||||
|
movegen::r#move::{MoveType, Promote},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const FEN: &str = "1r2k2r/2P1pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R w KQk g6 0 1";
|
||||||
|
const FEN_QUIET: &str = "1r2k2r/2P1pq1p/2npb3/1p3ppP/p3P3/P2BQ3/1P1PNPP1/R3K2R b KQk - 1 1";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_make_move_quiet() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN)?;
|
||||||
|
let b1c3 = Move::new(Square::F3, Square::E3);
|
||||||
|
game.make_move(&b1c3);
|
||||||
|
|
||||||
|
assert_eq!(game, from_fen(FEN_QUIET)?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const FEN_CAPTURE: &str = "1r2k2r/2P1pq1p/2npb3/1p3QpP/p3P3/P2B4/1P1PNPP1/R3K2R b KQk - 0 1";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_make_move_capture() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN)?;
|
||||||
|
let f3f5 = Move::new_with_type(Square::F3, Square::F5, MoveType::Capture);
|
||||||
|
game.make_move(&f3f5);
|
||||||
|
|
||||||
|
assert_eq!(game, from_fen(FEN_CAPTURE)?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const FEN_EN_PASSANT: &str =
|
||||||
|
"1r2k2r/2P1pq1p/2npb1P1/1p3p2/p3P3/P2B1Q2/1P1PNPP1/R3K2R b KQk - 0 1";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_make_move_en_passant() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN)?;
|
||||||
|
let h5g6 = Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant);
|
||||||
|
game.make_move(&h5g6);
|
||||||
|
|
||||||
|
assert_eq!(game, from_fen(FEN_EN_PASSANT)?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const FEN_DOUBLE_PUSH: &str =
|
||||||
|
"1r2k2r/2P1pq1p/2npb3/1p3ppP/pP2P3/P2B1Q2/3PNPP1/R3K2R b KQk b3 0 1";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_make_move_double_push() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN)?;
|
||||||
|
let b2b4 = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush);
|
||||||
|
game.make_move(&b2b4);
|
||||||
|
assert_eq!(game, from_fen(FEN_DOUBLE_PUSH)?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const FEN_PROMOTION: &str = "1rQ1k2r/4pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R b KQk - 0 1";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_make_move_promotion() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN)?;
|
||||||
|
let c7c8 = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen));
|
||||||
|
game.make_move(&c7c8);
|
||||||
|
assert_eq!(game, from_fen(FEN_PROMOTION)?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const FEN_PROMOTION_CAPTURE: &str =
|
||||||
|
"1Q2k2r/4pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R b KQk - 0 1";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_make_move_promotion_capture() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN)?;
|
||||||
|
let c7b8 = Move::new_with_type(
|
||||||
|
Square::C7,
|
||||||
|
Square::B8,
|
||||||
|
MoveType::PromotionCapture(Promote::Queen),
|
||||||
|
);
|
||||||
|
game.make_move(&c7b8);
|
||||||
|
assert_eq!(game, from_fen(FEN_PROMOTION_CAPTURE)?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const FEN_CASTLE: &str = "1r2k2r/2P1pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R4RK1 b k - 1 1";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_make_move_castle() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN)?;
|
||||||
|
let e1g1 = Move::new_with_type(Square::E1, Square::G1, MoveType::Castle);
|
||||||
|
game.make_move(&e1g1);
|
||||||
|
assert_eq!(game, from_fen(FEN_CASTLE)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const FEN_1: &str = "1r2k2r/2P1p1qp/2npb3/1p3p2/p3P1pP/P2B1Q2/1P1PNPP1/R3K2R w KQk - 0 1";
|
||||||
|
const FEN_2: &str = "1r2k2r/2P1p1qp/2npb3/1p3p2/pP2P1pP/P2B1Q2/3PNPP1/R3K2R b KQk b3 0 1";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unmake_quiet_and_double_push() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN_1)?;
|
||||||
|
let game_before_make = game.clone();
|
||||||
|
let mv = Move::new_with_type(Square::B2, Square::B3, MoveType::Quiet);
|
||||||
|
game.make_move(&mv);
|
||||||
|
game.unmake_move();
|
||||||
|
|
||||||
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
|
let mv = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush);
|
||||||
|
game.make_move(&mv);
|
||||||
|
game.unmake_move();
|
||||||
|
|
||||||
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unmake_capture_and_promotion() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN_1)?;
|
||||||
|
let game_before_make = game.clone();
|
||||||
|
let mv = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture);
|
||||||
|
game.make_move(&mv);
|
||||||
|
game.unmake_move();
|
||||||
|
|
||||||
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
|
let mv = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen));
|
||||||
|
game.make_move(&mv);
|
||||||
|
game.unmake_move();
|
||||||
|
|
||||||
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
|
let mv = Move::new_with_type(
|
||||||
|
Square::C7,
|
||||||
|
Square::B8,
|
||||||
|
MoveType::PromotionCapture(Promote::Queen),
|
||||||
|
);
|
||||||
|
game.make_move(&mv);
|
||||||
|
game.unmake_move();
|
||||||
|
|
||||||
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unmake_en_passant() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN_2)?;
|
||||||
|
let game_before_make = game.clone();
|
||||||
|
let mv = Move::new_with_type(Square::A4, Square::B3, MoveType::EnPassant);
|
||||||
|
game.make_move(&mv);
|
||||||
|
game.unmake_move();
|
||||||
|
|
||||||
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unmake_castle() -> Result<(), String> {
|
||||||
|
let mut game = from_fen(FEN_1)?;
|
||||||
|
let game_before_make = game.clone();
|
||||||
|
let mv = Move::new_with_type(Square::E1, Square::C1, MoveType::Castle);
|
||||||
|
game.make_move(&mv);
|
||||||
|
game.unmake_move();
|
||||||
|
|
||||||
|
assert_eq!(game_before_make, game);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -95,88 +95,3 @@ impl Default for MoveParameters {
|
|||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::{
|
|
||||||
board::{fen::from_fen, square::Square},
|
|
||||||
movegen::r#move::{Move, MoveType, Promote},
|
|
||||||
};
|
|
||||||
|
|
||||||
const FEN: &str = "1r2k2r/2P1p1qp/2npb3/1p3p2/p3P1pP/P2B1Q2/1P1PNPP1/R3K2R w KQk - 0 1";
|
|
||||||
const FEN_2: &str = "1r2k2r/2P1p1qp/2npb3/1p3p2/pP2P1pP/P2B1Q2/3PNPP1/R3K2R b KQk b3 0 1";
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_unmake_quiet_and_double_push() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN)?;
|
|
||||||
let game_before_make = game.clone();
|
|
||||||
let mv = Move::new_with_type(Square::B2, Square::B3, MoveType::Quiet);
|
|
||||||
game.make_move(&mv);
|
|
||||||
game.unmake_move();
|
|
||||||
|
|
||||||
assert_eq!(game_before_make, game);
|
|
||||||
|
|
||||||
let mv = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush);
|
|
||||||
game.make_move(&mv);
|
|
||||||
game.unmake_move();
|
|
||||||
|
|
||||||
assert_eq!(game_before_make, game);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_unmake_capture_and_promotion() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN)?;
|
|
||||||
let game_before_make = game.clone();
|
|
||||||
let mv = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture);
|
|
||||||
game.make_move(&mv);
|
|
||||||
game.unmake_move();
|
|
||||||
|
|
||||||
assert_eq!(game_before_make, game);
|
|
||||||
|
|
||||||
let mv = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen));
|
|
||||||
game.make_move(&mv);
|
|
||||||
game.unmake_move();
|
|
||||||
|
|
||||||
assert_eq!(game_before_make, game);
|
|
||||||
|
|
||||||
let mv = Move::new_with_type(
|
|
||||||
Square::C7,
|
|
||||||
Square::B8,
|
|
||||||
MoveType::PromotionCapture(Promote::Queen),
|
|
||||||
);
|
|
||||||
game.make_move(&mv);
|
|
||||||
game.unmake_move();
|
|
||||||
|
|
||||||
assert_eq!(game_before_make, game);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_unmake_en_passant() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN_2)?;
|
|
||||||
let game_before_make = game.clone();
|
|
||||||
let mv = Move::new_with_type(Square::A4, Square::B3, MoveType::EnPassant);
|
|
||||||
game.make_move(&mv);
|
|
||||||
game.unmake_move();
|
|
||||||
|
|
||||||
assert_eq!(game_before_make, game);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_unmake_castle() -> Result<(), String> {
|
|
||||||
let mut game = from_fen(FEN)?;
|
|
||||||
let game_before_make = game.clone();
|
|
||||||
let mv = Move::new_with_type(Square::E1, Square::C1, MoveType::Castle);
|
|
||||||
game.make_move(&mv);
|
|
||||||
game.unmake_move();
|
|
||||||
|
|
||||||
assert_eq!(game_before_make, game);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::{board::board::Color, movegen::r#move::MoveType};
|
use crate::{
|
||||||
|
board::board::Color,
|
||||||
|
movegen::r#move::{Move, MoveType},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
@@ -36,6 +39,21 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_game_state(
|
||||||
|
&mut self,
|
||||||
|
mv: &Move,
|
||||||
|
color: Color,
|
||||||
|
pawn_move: bool,
|
||||||
|
en_passant_square: Option<usize>,
|
||||||
|
) {
|
||||||
|
self.set_en_passant_square(en_passant_square);
|
||||||
|
self.update_castling_state_quiet(mv.src, color);
|
||||||
|
self.update_castling_state_capture(mv.dst, color.opponent());
|
||||||
|
self.update_half_move(mv.move_type, pawn_move);
|
||||||
|
self.update_full_move(color);
|
||||||
|
self.change_side();
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn en_passant_square(&self) -> Option<usize> {
|
pub const fn en_passant_square(&self) -> Option<usize> {
|
||||||
self.en_passant_square
|
self.en_passant_square
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user