Move make/unmake and History on Game
This commit is contained in:
@@ -10,14 +10,13 @@ use crate::movegen::move_generator::{
|
|||||||
bishop_pseudo_moves, king_pseudo_moves, knight_pseudo_moves, pawn_pseudo_moves,
|
bishop_pseudo_moves, king_pseudo_moves, knight_pseudo_moves, pawn_pseudo_moves,
|
||||||
queen_pseudo_moves, rook_pseudo_moves,
|
queen_pseudo_moves, rook_pseudo_moves,
|
||||||
};
|
};
|
||||||
use crate::movegen::r#move::{Move, MoveType, Promote};
|
use crate::movegen::r#move::{Move, Promote};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Board {
|
pub struct Board {
|
||||||
pub white_pieces: [Piece; 6],
|
pub white_pieces: [Piece; 6],
|
||||||
pub black_pieces: [Piece; 6],
|
pub black_pieces: [Piece; 6],
|
||||||
pub state: State,
|
pub state: State,
|
||||||
pub history: History,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Board {
|
impl Board {
|
||||||
@@ -40,7 +39,6 @@ impl Board {
|
|||||||
Piece::new(0x1000000000000000, PieceType::King, Color::Black),
|
Piece::new(0x1000000000000000, PieceType::King, Color::Black),
|
||||||
],
|
],
|
||||||
state: State::new(),
|
state: State::new(),
|
||||||
history: History::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +61,6 @@ impl Board {
|
|||||||
Piece::new(0x0, PieceType::King, Color::Black),
|
Piece::new(0x0, PieceType::King, Color::Black),
|
||||||
],
|
],
|
||||||
state: State::new(),
|
state: State::new(),
|
||||||
history: History::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,117 +188,7 @@ impl Board {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_move(&mut self, mv: &Move) {
|
pub fn update_game_state(
|
||||||
let color = self.state.current_player();
|
|
||||||
let pawn_move = self.is_pawn_move(mv.src);
|
|
||||||
let mut en_passant_square = None;
|
|
||||||
self.history
|
|
||||||
.push_move_parameters(MoveParameters::build(&self, mv));
|
|
||||||
|
|
||||||
match &mv.move_type {
|
|
||||||
MoveType::Quiet => {
|
|
||||||
self.move_piece(mv.src, mv.dst);
|
|
||||||
}
|
|
||||||
MoveType::Capture => {
|
|
||||||
self.move_piece(mv.src, mv.dst);
|
|
||||||
self.remove_opponent_piece(mv.dst);
|
|
||||||
}
|
|
||||||
MoveType::EnPassant => {
|
|
||||||
self.move_piece(mv.src, mv.dst);
|
|
||||||
self.remove_pawn_enpassant(mv.dst, color);
|
|
||||||
}
|
|
||||||
MoveType::DoublePush => {
|
|
||||||
self.move_piece(mv.src, mv.dst);
|
|
||||||
en_passant_square = match color {
|
|
||||||
Color::White => Some(mv.src + 8),
|
|
||||||
Color::Black => Some(mv.src.saturating_sub(8)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
MoveType::Promotion(promote) => {
|
|
||||||
self.remove_own_piece(mv.src);
|
|
||||||
self.promote_piece(mv.dst, promote);
|
|
||||||
}
|
|
||||||
MoveType::PromotionCapture(promote) => {
|
|
||||||
self.remove_own_piece(mv.src);
|
|
||||||
self.remove_opponent_piece(mv.dst);
|
|
||||||
self.promote_piece(mv.dst, promote);
|
|
||||||
}
|
|
||||||
MoveType::Castle => {
|
|
||||||
self.move_piece(mv.src, mv.dst);
|
|
||||||
self.move_rook_castle(mv.dst);
|
|
||||||
self.state.set_castling_ability(color, Castle::None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::update_game_state(&mut self.state, mv, color, pawn_move, en_passant_square);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unmake_move(&mut self) {
|
|
||||||
let move_parameters =
|
|
||||||
std::mem::take(&mut self.history.pop_move_parameters()).unwrap_or_default();
|
|
||||||
let color_before_move = self.state.change_side();
|
|
||||||
self.state.revert_full_move(color_before_move);
|
|
||||||
self.state.en_passant_square = move_parameters.en_passant_square;
|
|
||||||
|
|
||||||
if let Some(new_castling_ability) = move_parameters.castling_ability {
|
|
||||||
self.state.castling_ability = new_castling_ability;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(new_halfmove_clock) = move_parameters.halfmove_clock {
|
|
||||||
self.state.halfmove_clock = new_halfmove_clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mv = move_parameters.mv.unwrap();
|
|
||||||
|
|
||||||
match &mv.move_type {
|
|
||||||
MoveType::Quiet | MoveType::DoublePush => {
|
|
||||||
self.move_piece(mv.dst, mv.src);
|
|
||||||
}
|
|
||||||
MoveType::Capture | MoveType::Promotion(_) | MoveType::PromotionCapture(_) => {
|
|
||||||
if let (Some(captured_piece_type), Some(promoted_piece_type)) = (
|
|
||||||
move_parameters.captured_piece,
|
|
||||||
move_parameters.promoted_piece,
|
|
||||||
) {
|
|
||||||
let (own_pieces, opponent_pieces) = self.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 {
|
|
||||||
self.move_piece(mv.dst, mv.src);
|
|
||||||
let opponent_pieces = self.opponent_pieces();
|
|
||||||
opponent_pieces[captured_piece_type].bitboard |= square_to_bitboard(mv.dst);
|
|
||||||
} else if let Some(promoted_piece_type) = move_parameters.promoted_piece {
|
|
||||||
let own_pieces = self.own_pieces();
|
|
||||||
|
|
||||||
own_pieces[promoted_piece_type].bitboard &= !square_to_bitboard(mv.dst);
|
|
||||||
own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MoveType::EnPassant => {
|
|
||||||
self.move_piece(mv.dst, mv.src);
|
|
||||||
let enemy_pawn_square = match color_before_move {
|
|
||||||
Color::White => mv.dst - 8,
|
|
||||||
Color::Black => mv.dst + 8,
|
|
||||||
};
|
|
||||||
let opponent_pieces = self.opponent_pieces();
|
|
||||||
opponent_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(enemy_pawn_square);
|
|
||||||
}
|
|
||||||
MoveType::Castle => {
|
|
||||||
self.move_piece(mv.dst, mv.src);
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
let own_pieces = self.own_pieces();
|
|
||||||
own_pieces[PieceType::Rook].bitboard &= !square_to_bitboard(rook_dst);
|
|
||||||
own_pieces[PieceType::Rook].bitboard |= square_to_bitboard(rook_src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_game_state(
|
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
mv: &Move,
|
mv: &Move,
|
||||||
color: Color,
|
color: Color,
|
||||||
@@ -316,7 +203,7 @@ impl Board {
|
|||||||
state.change_side();
|
state.change_side();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_piece(&mut self, src: usize, dst: usize) {
|
pub fn move_piece(&mut self, src: usize, dst: usize) {
|
||||||
let pieces = self.own_pieces();
|
let pieces = self.own_pieces();
|
||||||
pieces
|
pieces
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@@ -327,7 +214,7 @@ impl Board {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_own_piece(&mut self, square: usize) {
|
pub fn remove_own_piece(&mut self, square: usize) {
|
||||||
let pieces = self.own_pieces();
|
let pieces = self.own_pieces();
|
||||||
pieces
|
pieces
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@@ -337,7 +224,7 @@ impl Board {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_opponent_piece(&mut self, square: usize) {
|
pub fn remove_opponent_piece(&mut self, square: usize) {
|
||||||
let pieces = self.opponent_pieces();
|
let pieces = self.opponent_pieces();
|
||||||
pieces
|
pieces
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@@ -347,7 +234,7 @@ impl Board {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_rook_castle(&mut self, king_dst: usize) {
|
pub fn move_rook_castle(&mut self, king_dst: usize) {
|
||||||
let (rook_src, rook_dst) = match king_dst {
|
let (rook_src, rook_dst) = match king_dst {
|
||||||
Square::C1 | Square::C8 => (king_dst - 2, king_dst + 1),
|
Square::C1 | Square::C8 => (king_dst - 2, king_dst + 1),
|
||||||
Square::G1 | Square::G8 => (king_dst + 1, king_dst - 1),
|
Square::G1 | Square::G8 => (king_dst + 1, king_dst - 1),
|
||||||
@@ -357,7 +244,7 @@ impl Board {
|
|||||||
self.move_piece(rook_src, rook_dst);
|
self.move_piece(rook_src, rook_dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
Promote::Knight => pieces[PieceType::Knight].bitboard |= square_to_bitboard(square),
|
Promote::Knight => pieces[PieceType::Knight].bitboard |= square_to_bitboard(square),
|
||||||
@@ -367,7 +254,7 @@ impl Board {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_pawn_enpassant(&mut self, square: usize, color: Color) {
|
pub fn remove_pawn_enpassant(&mut self, square: usize, color: Color) {
|
||||||
let piece_to_remove = match color {
|
let piece_to_remove = match color {
|
||||||
Color::White => square - 8,
|
Color::White => square - 8,
|
||||||
Color::Black => square + 8,
|
Color::Black => square + 8,
|
||||||
@@ -376,26 +263,26 @@ impl Board {
|
|||||||
self.remove_opponent_piece(piece_to_remove);
|
self.remove_opponent_piece(piece_to_remove);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn own_pieces(&mut self) -> &mut [Piece; 6] {
|
pub fn own_pieces(&mut self) -> &mut [Piece; 6] {
|
||||||
match self.state.current_player() {
|
match self.state.current_player() {
|
||||||
Color::White => &mut self.white_pieces,
|
Color::White => &mut self.white_pieces,
|
||||||
Color::Black => &mut self.black_pieces,
|
Color::Black => &mut self.black_pieces,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opponent_pieces(&mut self) -> &mut [Piece; 6] {
|
pub fn opponent_pieces(&mut self) -> &mut [Piece; 6] {
|
||||||
match self.state.current_player() {
|
match self.state.current_player() {
|
||||||
Color::White => &mut self.black_pieces,
|
Color::White => &mut self.black_pieces,
|
||||||
Color::Black => &mut self.white_pieces,
|
Color::Black => &mut self.white_pieces,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_pieces(&mut self) -> (&mut [Piece; 6], &mut [Piece; 6]) {
|
pub fn all_pieces(&mut self) -> (&mut [Piece; 6], &mut [Piece; 6]) {
|
||||||
match self.state.current_player() {
|
match self.state.current_player() {
|
||||||
Color::White => (&mut self.white_pieces, &mut self.black_pieces),
|
Color::White => (&mut self.white_pieces, &mut self.black_pieces),
|
||||||
Color::Black => (&mut self.black_pieces, &mut self.white_pieces),
|
Color::Black => (&mut self.black_pieces, &mut self.white_pieces),
|
||||||
@@ -444,9 +331,7 @@ 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::history::{History, MoveParameters};
|
|
||||||
use super::square::Square;
|
use super::square::Square;
|
||||||
use super::state::Castle;
|
|
||||||
|
|
||||||
impl Index<PieceType> for [Piece] {
|
impl Index<PieceType> for [Piece] {
|
||||||
type Output = Piece;
|
type Output = Piece;
|
||||||
@@ -516,7 +401,7 @@ mod tests {
|
|||||||
fn test_make_move_quiet() -> Result<(), String> {
|
fn test_make_move_quiet() -> Result<(), String> {
|
||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let b1c3 = Move::new(Square::F3, Square::E3);
|
let b1c3 = Move::new(Square::F3, Square::E3);
|
||||||
game.board.make_move(&b1c3);
|
game.make_move(&b1c3);
|
||||||
|
|
||||||
assert_eq!(game, from_fen(FEN_QUIET)?);
|
assert_eq!(game, from_fen(FEN_QUIET)?);
|
||||||
|
|
||||||
@@ -529,7 +414,7 @@ mod tests {
|
|||||||
fn test_make_move_capture() -> Result<(), String> {
|
fn test_make_move_capture() -> Result<(), String> {
|
||||||
let mut game = from_fen(FEN)?;
|
let mut 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);
|
||||||
game.board.make_move(&f3f5);
|
game.make_move(&f3f5);
|
||||||
|
|
||||||
assert_eq!(game, from_fen(FEN_CAPTURE)?);
|
assert_eq!(game, from_fen(FEN_CAPTURE)?);
|
||||||
|
|
||||||
@@ -543,7 +428,7 @@ mod tests {
|
|||||||
fn test_make_move_en_passant() -> Result<(), String> {
|
fn test_make_move_en_passant() -> Result<(), String> {
|
||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let h5g6 = Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant);
|
let h5g6 = Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant);
|
||||||
game.board.make_move(&h5g6);
|
game.make_move(&h5g6);
|
||||||
|
|
||||||
assert_eq!(game, from_fen(FEN_EN_PASSANT)?);
|
assert_eq!(game, from_fen(FEN_EN_PASSANT)?);
|
||||||
|
|
||||||
@@ -557,7 +442,7 @@ mod tests {
|
|||||||
fn test_make_move_double_push() -> Result<(), String> {
|
fn test_make_move_double_push() -> Result<(), String> {
|
||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let b2b4 = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush);
|
let b2b4 = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush);
|
||||||
game.board.make_move(&b2b4);
|
game.make_move(&b2b4);
|
||||||
assert_eq!(game, from_fen(FEN_DOUBLE_PUSH)?);
|
assert_eq!(game, from_fen(FEN_DOUBLE_PUSH)?);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -569,7 +454,7 @@ mod tests {
|
|||||||
fn test_make_move_promotion() -> Result<(), String> {
|
fn test_make_move_promotion() -> Result<(), String> {
|
||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let c7c8 = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen));
|
let c7c8 = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen));
|
||||||
game.board.make_move(&c7c8);
|
game.make_move(&c7c8);
|
||||||
assert_eq!(game, from_fen(FEN_PROMOTION)?);
|
assert_eq!(game, from_fen(FEN_PROMOTION)?);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -586,7 +471,7 @@ mod tests {
|
|||||||
Square::B8,
|
Square::B8,
|
||||||
MoveType::PromotionCapture(Promote::Queen),
|
MoveType::PromotionCapture(Promote::Queen),
|
||||||
);
|
);
|
||||||
game.board.make_move(&c7b8);
|
game.make_move(&c7b8);
|
||||||
assert_eq!(game, from_fen(FEN_PROMOTION_CAPTURE)?);
|
assert_eq!(game, from_fen(FEN_PROMOTION_CAPTURE)?);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -598,7 +483,7 @@ mod tests {
|
|||||||
fn test_make_move_castle() -> Result<(), String> {
|
fn test_make_move_castle() -> Result<(), String> {
|
||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let e1g1 = Move::new_with_type(Square::E1, Square::G1, MoveType::Castle);
|
let e1g1 = Move::new_with_type(Square::E1, Square::G1, MoveType::Castle);
|
||||||
game.board.make_move(&e1g1);
|
game.make_move(&e1g1);
|
||||||
assert_eq!(game, from_fen(FEN_CASTLE)?);
|
assert_eq!(game, from_fen(FEN_CASTLE)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ pub fn from_fen(fen: &str) -> Result<Game, FenError> {
|
|||||||
halfmove_clock,
|
halfmove_clock,
|
||||||
fullmove_counter,
|
fullmove_counter,
|
||||||
));
|
));
|
||||||
Ok(Game { board })
|
Ok(Game {
|
||||||
|
board,
|
||||||
|
history: History::new(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn piece_placement(pieces: &str) -> Result<Board, FenError> {
|
pub fn piece_placement(pieces: &str) -> Result<Board, FenError> {
|
||||||
@@ -123,6 +126,8 @@ fn castling_ability(castling: &str) -> Result<[Castle; 2], FenError> {
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::history::History;
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
use crate::board::fen::from_fen;
|
use crate::{
|
||||||
|
board::fen::from_fen,
|
||||||
|
movegen::r#move::{Move, MoveType},
|
||||||
|
};
|
||||||
use String as FenError;
|
use String as FenError;
|
||||||
|
|
||||||
use super::board::{Board, Color};
|
use super::{
|
||||||
|
bitboard::square_to_bitboard,
|
||||||
|
board::{Board, Color, PieceType},
|
||||||
|
history::{History, MoveParameters},
|
||||||
|
square::Square,
|
||||||
|
state::Castle,
|
||||||
|
};
|
||||||
|
|
||||||
impl PartialEq for Game {
|
impl PartialEq for Game {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
@@ -14,12 +23,14 @@ impl PartialEq for Game {
|
|||||||
#[derive(Debug, Eq)]
|
#[derive(Debug, Eq)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
pub board: Board,
|
pub board: Board,
|
||||||
|
pub history: History,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
board: Board::new(),
|
board: Board::new(),
|
||||||
|
history: History::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +41,118 @@ impl Game {
|
|||||||
pub const fn current_player(&self) -> Color {
|
pub const fn current_player(&self) -> Color {
|
||||||
self.board.state.current_player()
|
self.board.state.current_player()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn make_move(&mut self, mv: &Move) {
|
||||||
|
let board = &mut self.board;
|
||||||
|
let color = board.state.current_player();
|
||||||
|
let pawn_move = board.is_pawn_move(mv.src);
|
||||||
|
let mut en_passant_square = None;
|
||||||
|
self.history
|
||||||
|
.push_move_parameters(MoveParameters::build(board, mv));
|
||||||
|
|
||||||
|
match &mv.move_type {
|
||||||
|
MoveType::Quiet => {
|
||||||
|
board.move_piece(mv.src, mv.dst);
|
||||||
|
}
|
||||||
|
MoveType::Capture => {
|
||||||
|
board.move_piece(mv.src, mv.dst);
|
||||||
|
board.remove_opponent_piece(mv.dst);
|
||||||
|
}
|
||||||
|
MoveType::EnPassant => {
|
||||||
|
board.move_piece(mv.src, mv.dst);
|
||||||
|
board.remove_pawn_enpassant(mv.dst, color);
|
||||||
|
}
|
||||||
|
MoveType::DoublePush => {
|
||||||
|
board.move_piece(mv.src, mv.dst);
|
||||||
|
en_passant_square = match color {
|
||||||
|
Color::White => Some(mv.src + 8),
|
||||||
|
Color::Black => Some(mv.src.saturating_sub(8)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
MoveType::Promotion(promote) => {
|
||||||
|
board.remove_own_piece(mv.src);
|
||||||
|
board.promote_piece(mv.dst, promote);
|
||||||
|
}
|
||||||
|
MoveType::PromotionCapture(promote) => {
|
||||||
|
board.remove_own_piece(mv.src);
|
||||||
|
board.remove_opponent_piece(mv.dst);
|
||||||
|
board.promote_piece(mv.dst, promote);
|
||||||
|
}
|
||||||
|
MoveType::Castle => {
|
||||||
|
board.move_piece(mv.src, mv.dst);
|
||||||
|
board.move_rook_castle(mv.dst);
|
||||||
|
board.state.set_castling_ability(color, Castle::None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Board::update_game_state(&mut board.state, mv, color, pawn_move, en_passant_square);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmake_move(&mut self) {
|
||||||
|
let board = &mut self.board;
|
||||||
|
let move_parameters =
|
||||||
|
std::mem::take(&mut self.history.pop_move_parameters()).unwrap_or_default();
|
||||||
|
let color_before_move = board.state.change_side();
|
||||||
|
board.state.revert_full_move(color_before_move);
|
||||||
|
board.state.en_passant_square = move_parameters.en_passant_square;
|
||||||
|
|
||||||
|
if let Some(new_castling_ability) = move_parameters.castling_ability {
|
||||||
|
board.state.castling_ability = new_castling_ability;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(new_halfmove_clock) = move_parameters.halfmove_clock {
|
||||||
|
board.state.halfmove_clock = new_halfmove_clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mv = move_parameters.mv.unwrap();
|
||||||
|
|
||||||
|
match &mv.move_type {
|
||||||
|
MoveType::Quiet | MoveType::DoublePush => {
|
||||||
|
board.move_piece(mv.dst, mv.src);
|
||||||
|
}
|
||||||
|
MoveType::Capture | MoveType::Promotion(_) | MoveType::PromotionCapture(_) => {
|
||||||
|
if let (Some(captured_piece_type), Some(promoted_piece_type)) = (
|
||||||
|
move_parameters.captured_piece,
|
||||||
|
move_parameters.promoted_piece,
|
||||||
|
) {
|
||||||
|
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);
|
||||||
|
let opponent_pieces = board.opponent_pieces();
|
||||||
|
opponent_pieces[captured_piece_type].bitboard |= square_to_bitboard(mv.dst);
|
||||||
|
} else if let Some(promoted_piece_type) = move_parameters.promoted_piece {
|
||||||
|
let own_pieces = board.own_pieces();
|
||||||
|
|
||||||
|
own_pieces[promoted_piece_type].bitboard &= !square_to_bitboard(mv.dst);
|
||||||
|
own_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(mv.src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MoveType::EnPassant => {
|
||||||
|
board.move_piece(mv.dst, mv.src);
|
||||||
|
let enemy_pawn_square = match color_before_move {
|
||||||
|
Color::White => mv.dst - 8,
|
||||||
|
Color::Black => mv.dst + 8,
|
||||||
|
};
|
||||||
|
let opponent_pieces = board.opponent_pieces();
|
||||||
|
opponent_pieces[PieceType::Pawn].bitboard |= square_to_bitboard(enemy_pawn_square);
|
||||||
|
}
|
||||||
|
MoveType::Castle => {
|
||||||
|
board.move_piece(mv.dst, mv.src);
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
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_src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Game {
|
impl Default for Game {
|
||||||
|
|||||||
@@ -109,14 +109,14 @@ mod tests {
|
|||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let board_before_make = game.board.clone();
|
let board_before_make = game.board.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.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(board_before_make, game.board);
|
||||||
|
|
||||||
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.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(board_before_make, game.board);
|
||||||
|
|
||||||
@@ -128,14 +128,14 @@ mod tests {
|
|||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let board_before_make = game.board.clone();
|
let board_before_make = game.board.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.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(board_before_make, game.board);
|
||||||
|
|
||||||
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.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(board_before_make, game.board);
|
||||||
|
|
||||||
@@ -144,8 +144,8 @@ mod tests {
|
|||||||
Square::B8,
|
Square::B8,
|
||||||
MoveType::PromotionCapture(Promote::Queen),
|
MoveType::PromotionCapture(Promote::Queen),
|
||||||
);
|
);
|
||||||
game.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(board_before_make, game.board);
|
||||||
|
|
||||||
@@ -157,8 +157,8 @@ mod tests {
|
|||||||
let mut game = from_fen(FEN_2)?;
|
let mut game = from_fen(FEN_2)?;
|
||||||
let board_before_make = game.board.clone();
|
let board_before_make = game.board.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.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(board_before_make, game.board);
|
||||||
|
|
||||||
@@ -170,8 +170,8 @@ mod tests {
|
|||||||
let mut game = from_fen(FEN)?;
|
let mut game = from_fen(FEN)?;
|
||||||
let board_before_make = game.board.clone();
|
let board_before_make = game.board.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.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
assert_eq!(board_before_make, game.board);
|
assert_eq!(board_before_make, game.board);
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,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.board, mv_str)?;
|
||||||
game.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(game)
|
Ok(game)
|
||||||
|
|||||||
@@ -26,16 +26,16 @@ pub fn negamax(
|
|||||||
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.board, *mv));
|
||||||
|
|
||||||
for mv in pseudo_legal_moves {
|
for mv in pseudo_legal_moves {
|
||||||
game.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
|
|
||||||
if game.board.king_under_check(color) {
|
if game.board.king_under_check(color) {
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
legal_moves += 1;
|
legal_moves += 1;
|
||||||
let move_score = -negamax(game, -beta, -alpha, depth - 1, plies + 1).1;
|
let move_score = -negamax(game, -beta, -alpha, depth - 1, plies + 1).1;
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
if move_score > best_score {
|
if move_score > best_score {
|
||||||
best_score = move_score;
|
best_score = move_score;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ pub fn driver(game: &mut Game, nodes: &mut u64, depth: u8) {
|
|||||||
|
|
||||||
for mv in pseudo_moves {
|
for mv in pseudo_moves {
|
||||||
let original_board = game.board.clone();
|
let original_board = game.board.clone();
|
||||||
game.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
|
|
||||||
if game.board.king_under_check(color) {
|
if game.board.king_under_check(color) {
|
||||||
game.board = original_board;
|
game.board = original_board;
|
||||||
|
|||||||
@@ -33,15 +33,15 @@ pub fn quiescence(game: &mut Game, mut alpha: i32, beta: i32) -> (Option<Move>,
|
|||||||
captures.sort_unstable_by_key(|mv| score_by_mvv_lva(&game.board, *mv));
|
captures.sort_unstable_by_key(|mv| score_by_mvv_lva(&game.board, *mv));
|
||||||
|
|
||||||
for mv in captures {
|
for mv in captures {
|
||||||
game.board.make_move(&mv);
|
game.make_move(&mv);
|
||||||
|
|
||||||
if game.board.king_under_check(color) {
|
if game.board.king_under_check(color) {
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let move_score = -quiescence(game, -beta, -alpha).1;
|
let move_score = -quiescence(game, -beta, -alpha).1;
|
||||||
game.board.unmake_move();
|
game.unmake_move();
|
||||||
|
|
||||||
if move_score >= beta {
|
if move_score >= beta {
|
||||||
return (Some(mv), beta);
|
return (Some(mv), beta);
|
||||||
|
|||||||
Reference in New Issue
Block a user