Simplify History struct into a Vec
This commit is contained in:
@@ -33,7 +33,7 @@ pub fn from_fen(fen: &str) -> Result<Game, FenError> {
|
|||||||
|
|
||||||
Ok(Game {
|
Ok(Game {
|
||||||
board,
|
board,
|
||||||
history: History::new(),
|
unmake_stack: Vec::new(),
|
||||||
mailbox,
|
mailbox,
|
||||||
hash,
|
hash,
|
||||||
tt: TranspositionTable::new(),
|
tt: TranspositionTable::new(),
|
||||||
@@ -138,7 +138,6 @@ fn castling_ability(castling: &str) -> Result<[Castle; 2], FenError> {
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use super::bitboard::square_to_bitboard;
|
use super::bitboard::square_to_bitboard;
|
||||||
use super::history::History;
|
|
||||||
use super::mailbox::Mailbox;
|
use super::mailbox::Mailbox;
|
||||||
use super::zobrist::zobrist_keys;
|
use super::zobrist::zobrist_keys;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use String as FenError;
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
board::{Board, Color, PieceType},
|
board::{Board, Color, PieceType},
|
||||||
history::{History, MoveInfo},
|
|
||||||
mailbox::Mailbox,
|
mailbox::Mailbox,
|
||||||
square::Square,
|
square::Square,
|
||||||
state::Castle,
|
state::Castle,
|
||||||
@@ -25,7 +24,7 @@ impl PartialEq for Game {
|
|||||||
#[derive(Debug, Clone, Eq)]
|
#[derive(Debug, Clone, Eq)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
pub board: Board,
|
pub board: Board,
|
||||||
pub history: History,
|
pub unmake_stack: Vec<UnmakeState>,
|
||||||
pub mailbox: Mailbox,
|
pub mailbox: Mailbox,
|
||||||
pub hash: ZobristHash,
|
pub hash: ZobristHash,
|
||||||
pub tt: TranspositionTable,
|
pub tt: TranspositionTable,
|
||||||
@@ -35,11 +34,13 @@ pub struct Game {
|
|||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
let board = Board::startpos();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
board: Board::startpos(),
|
board: Board::startpos(),
|
||||||
history: History::new(),
|
unmake_stack: Vec::new(),
|
||||||
mailbox: Mailbox::from_board(&Board::startpos()),
|
mailbox: Mailbox::from_board(&board),
|
||||||
hash: zobrist_keys().calculate_hash(&Board::startpos()),
|
hash: zobrist_keys().calculate_hash(&board),
|
||||||
tt: TranspositionTable::new(),
|
tt: TranspositionTable::new(),
|
||||||
killer: [None; MAX_DEPTH as usize],
|
killer: [None; MAX_DEPTH as usize],
|
||||||
history_heuristic: [[[0; 64]; 64]; 2],
|
history_heuristic: [[[0; 64]; 64]; 2],
|
||||||
@@ -59,7 +60,7 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_move(&mut self, mv: &Move) {
|
pub fn make_move(&mut self, mv: &Move) {
|
||||||
let move_info = MoveInfo::new()
|
let unmake_info = UnmakeState::new()
|
||||||
.with_move(*mv)
|
.with_move(*mv)
|
||||||
.with_castling_ability(self.board.state.castling_ability)
|
.with_castling_ability(self.board.state.castling_ability)
|
||||||
.with_en_passant_square(self.board.state.en_passant_square)
|
.with_en_passant_square(self.board.state.en_passant_square)
|
||||||
@@ -69,7 +70,7 @@ impl Game {
|
|||||||
.with_promoted_piece(mv, self.current_player())
|
.with_promoted_piece(mv, self.current_player())
|
||||||
.with_zobrist_hash(&self.hash);
|
.with_zobrist_hash(&self.hash);
|
||||||
|
|
||||||
self.history.push_move_info(move_info);
|
self.unmake_stack.push(unmake_info);
|
||||||
|
|
||||||
let board = &mut self.board;
|
let board = &mut self.board;
|
||||||
let hash = &mut self.hash;
|
let hash = &mut self.hash;
|
||||||
@@ -178,29 +179,24 @@ impl Game {
|
|||||||
pub fn unmake_move(&mut self) {
|
pub fn unmake_move(&mut self) {
|
||||||
let board = &mut self.board;
|
let board = &mut self.board;
|
||||||
let mailbox = &mut self.mailbox;
|
let mailbox = &mut self.mailbox;
|
||||||
let move_info = &mut self
|
let unmake_info = self.unmake_stack.pop().expect("Stack empty before pop.");
|
||||||
.history
|
|
||||||
.pop_move_info()
|
|
||||||
.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_info.en_passant_square;
|
board.state.en_passant_square = unmake_info.en_passant_square;
|
||||||
|
|
||||||
if let Some(hash) = move_info.zobrist_hash {
|
if let Some(hash) = unmake_info.zobrist_hash {
|
||||||
self.hash = hash;
|
self.hash = hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(new_castling_ability) = move_info.castling_ability {
|
if let Some(new_castling_ability) = unmake_info.castling_ability {
|
||||||
board.state.castling_ability = new_castling_ability;
|
board.state.castling_ability = new_castling_ability;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(new_halfmove_clock) = move_info.halfmove_clock {
|
if let Some(new_halfmove_clock) = unmake_info.halfmove_clock {
|
||||||
board.state.halfmove_clock = new_halfmove_clock;
|
board.state.halfmove_clock = new_halfmove_clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mv = move_info
|
let mv = unmake_info.mv.expect("Expected move info from stack.");
|
||||||
.mv
|
|
||||||
.expect("Expected move parameters from history stack");
|
|
||||||
let piece_at_dst = mailbox.piece_at(mv.dst()).expect("No piece at dst.");
|
let piece_at_dst = mailbox.piece_at(mv.dst()).expect("No piece at dst.");
|
||||||
match MoveType::from_move(&mv) {
|
match MoveType::from_move(&mv) {
|
||||||
MoveType::Quiet | MoveType::DoublePush => {
|
MoveType::Quiet | MoveType::DoublePush => {
|
||||||
@@ -209,19 +205,19 @@ impl Game {
|
|||||||
mailbox.set_piece_at(mv.dst(), None);
|
mailbox.set_piece_at(mv.dst(), None);
|
||||||
}
|
}
|
||||||
MoveType::Capture => {
|
MoveType::Capture => {
|
||||||
let captured_piece = move_info
|
let captured_piece = unmake_info
|
||||||
.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(), piece_at_dst.0);
|
board.move_piece(mv.dst(), mv.src(), piece_at_dst.0);
|
||||||
board.insert_opponent_piece(mv.dst(), captured_piece.0);
|
board.insert_opponent_piece(mv.dst(), captured_piece.0);
|
||||||
mailbox.set_piece_at(mv.src(), move_info.moving_piece);
|
mailbox.set_piece_at(mv.src(), unmake_info.moving_piece);
|
||||||
mailbox.set_piece_at(mv.dst(), Some(captured_piece));
|
mailbox.set_piece_at(mv.dst(), Some(captured_piece));
|
||||||
}
|
}
|
||||||
MoveType::PromotionKnight
|
MoveType::PromotionKnight
|
||||||
| MoveType::PromotionBishop
|
| MoveType::PromotionBishop
|
||||||
| MoveType::PromotionRook
|
| MoveType::PromotionRook
|
||||||
| MoveType::PromotionQueen => {
|
| MoveType::PromotionQueen => {
|
||||||
let promoted_piece = move_info
|
let promoted_piece = unmake_info
|
||||||
.promoted_piece
|
.promoted_piece
|
||||||
.expect("Expected promoted piece to unmake Promotion");
|
.expect("Expected promoted piece to unmake Promotion");
|
||||||
board.remove_own_piece(mv.dst(), promoted_piece.0);
|
board.remove_own_piece(mv.dst(), promoted_piece.0);
|
||||||
@@ -234,10 +230,10 @@ impl Game {
|
|||||||
| MoveType::PromotionCaptureBishop
|
| MoveType::PromotionCaptureBishop
|
||||||
| MoveType::PromotionCaptureRook
|
| MoveType::PromotionCaptureRook
|
||||||
| MoveType::PromotionCaptureQueen => {
|
| MoveType::PromotionCaptureQueen => {
|
||||||
let promoted_piece = move_info
|
let promoted_piece = unmake_info
|
||||||
.promoted_piece
|
.promoted_piece
|
||||||
.expect("Expected promoted piece to unmake PromotionCapture");
|
.expect("Expected promoted piece to unmake PromotionCapture");
|
||||||
let captured_piece = move_info
|
let captured_piece = unmake_info
|
||||||
.captured_piece
|
.captured_piece
|
||||||
.expect("Expected captured piece to unmake PromotionCapture");
|
.expect("Expected captured piece to unmake PromotionCapture");
|
||||||
board.remove_own_piece(mv.dst(), promoted_piece.0);
|
board.remove_own_piece(mv.dst(), promoted_piece.0);
|
||||||
@@ -277,13 +273,13 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_null_move(&mut self) {
|
pub fn make_null_move(&mut self) {
|
||||||
let move_info = MoveInfo::new()
|
let unmake_info = UnmakeState::new()
|
||||||
.with_castling_ability(self.board.state.castling_ability)
|
.with_castling_ability(self.board.state.castling_ability)
|
||||||
.with_en_passant_square(self.board.state.en_passant_square)
|
.with_en_passant_square(self.board.state.en_passant_square)
|
||||||
.with_halfmove_clock(self.board.state.halfmove_clock)
|
.with_halfmove_clock(self.board.state.halfmove_clock)
|
||||||
.with_zobrist_hash(&self.hash);
|
.with_zobrist_hash(&self.hash);
|
||||||
|
|
||||||
self.history.push_move_info(move_info);
|
self.unmake_stack.push(unmake_info);
|
||||||
self.hash.update_side_to_move_key();
|
self.hash.update_side_to_move_key();
|
||||||
self.board
|
self.board
|
||||||
.state
|
.state
|
||||||
@@ -292,25 +288,22 @@ impl Game {
|
|||||||
|
|
||||||
pub fn unmake_null_move(&mut self) {
|
pub fn unmake_null_move(&mut self) {
|
||||||
let board = &mut self.board;
|
let board = &mut self.board;
|
||||||
let move_info = &mut self
|
let unmake_info = self.unmake_stack.pop().expect("Stack empty before pop.");
|
||||||
.history
|
|
||||||
.pop_move_info()
|
|
||||||
.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_info.en_passant_square;
|
board.state.en_passant_square = unmake_info.en_passant_square;
|
||||||
|
|
||||||
if let Some(hash) = move_info.zobrist_hash {
|
if let Some(hash) = unmake_info.zobrist_hash {
|
||||||
self.hash = hash;
|
self.hash = hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(new_castling_ability) = move_info.castling_ability {
|
if let Some(new_castling_ability) = unmake_info.castling_ability {
|
||||||
board.state.castling_ability = new_castling_ability;
|
board.state.castling_ability = new_castling_ability;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(new_halfmove_clock) = move_info.halfmove_clock {
|
if let Some(new_halfmove_clock) = unmake_info.halfmove_clock {
|
||||||
board.state.halfmove_clock = new_halfmove_clock;
|
board.state.halfmove_clock = new_halfmove_clock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,7 +313,79 @@ impl Game {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.history.in_repetition(self.hash)
|
self.unmake_stack
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.skip(1)
|
||||||
|
.step_by(2)
|
||||||
|
.any(|mp| mp.zobrist_hash.expect("State without hash.") == self.hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct UnmakeState {
|
||||||
|
pub mv: Option<Move>,
|
||||||
|
pub moving_piece: Option<(PieceType, Color)>,
|
||||||
|
pub captured_piece: Option<(PieceType, Color)>,
|
||||||
|
pub promoted_piece: Option<(PieceType, Color)>,
|
||||||
|
pub castling_ability: Option<[Castle; 2]>,
|
||||||
|
pub en_passant_square: Option<usize>,
|
||||||
|
pub halfmove_clock: Option<u8>,
|
||||||
|
pub zobrist_hash: Option<ZobristHash>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnmakeState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn with_move(mut self, mv: Move) -> Self {
|
||||||
|
self.mv = Some(mv);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn with_castling_ability(mut self, castling_ability: [Castle; 2]) -> Self {
|
||||||
|
self.castling_ability = Some(castling_ability);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn with_en_passant_square(mut self, en_passant_square: Option<usize>) -> Self {
|
||||||
|
self.en_passant_square = en_passant_square;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn with_halfmove_clock(mut self, halfmove_clock: u8) -> Self {
|
||||||
|
self.halfmove_clock = Some(halfmove_clock);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn with_moving_piece(mut self, mailbox: &Mailbox, mv: &Move) -> Self {
|
||||||
|
self.moving_piece = mailbox.piece_at(mv.src());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_captured_piece(mut self, mailbox: &Mailbox, mv: &Move) -> Self {
|
||||||
|
if let MoveType::Capture
|
||||||
|
| MoveType::PromotionCaptureKnight
|
||||||
|
| MoveType::PromotionCaptureBishop
|
||||||
|
| MoveType::PromotionCaptureRook
|
||||||
|
| MoveType::PromotionCaptureQueen = MoveType::from_move(mv)
|
||||||
|
{
|
||||||
|
self.captured_piece = mailbox.piece_at(mv.dst())
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_promoted_piece(mut self, mv: &Move, color: Color) -> Self {
|
||||||
|
if mv.is_promotion() {
|
||||||
|
self.promoted_piece = Some((mv.promotion_type().into_piece_type(), color));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_zobrist_hash(mut self, zobrist_hash: &ZobristHash) -> Self {
|
||||||
|
self.zobrist_hash = Some(zobrist_hash.to_owned());
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
use crate::movegen::r#move::{Move, MoveType};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
board::{Color, PieceType},
|
|
||||||
mailbox::Mailbox,
|
|
||||||
state::Castle,
|
|
||||||
zobrist::ZobristHash,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct History(Vec<MoveInfo>);
|
|
||||||
|
|
||||||
impl History {
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_move_info(&mut self, move_info: MoveInfo) {
|
|
||||||
self.0.push(move_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_move_info(&mut self) -> Option<MoveInfo> {
|
|
||||||
self.0.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn in_repetition(&self, hash: ZobristHash) -> bool {
|
|
||||||
self.0
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.skip(1)
|
|
||||||
.step_by(2)
|
|
||||||
.any(|mp| mp.zobrist_hash.expect("State without hash") == hash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct MoveInfo {
|
|
||||||
pub mv: Option<Move>,
|
|
||||||
pub moving_piece: Option<(PieceType, Color)>,
|
|
||||||
pub captured_piece: Option<(PieceType, Color)>,
|
|
||||||
pub promoted_piece: Option<(PieceType, Color)>,
|
|
||||||
pub castling_ability: Option<[Castle; 2]>,
|
|
||||||
pub en_passant_square: Option<usize>,
|
|
||||||
pub halfmove_clock: Option<u8>,
|
|
||||||
pub zobrist_hash: Option<ZobristHash>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MoveInfo {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn with_move(mut self, mv: Move) -> Self {
|
|
||||||
self.mv = Some(mv);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn with_castling_ability(mut self, castling_ability: [Castle; 2]) -> Self {
|
|
||||||
self.castling_ability = Some(castling_ability);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn with_en_passant_square(mut self, en_passant_square: Option<usize>) -> Self {
|
|
||||||
self.en_passant_square = en_passant_square;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn with_halfmove_clock(mut self, halfmove_clock: u8) -> Self {
|
|
||||||
self.halfmove_clock = Some(halfmove_clock);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn with_moving_piece(mut self, mailbox: &Mailbox, mv: &Move) -> Self {
|
|
||||||
self.moving_piece = mailbox.piece_at(mv.src());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_captured_piece(mut self, mailbox: &Mailbox, mv: &Move) -> Self {
|
|
||||||
if let MoveType::Capture
|
|
||||||
| MoveType::PromotionCaptureKnight
|
|
||||||
| MoveType::PromotionCaptureBishop
|
|
||||||
| MoveType::PromotionCaptureRook
|
|
||||||
| MoveType::PromotionCaptureQueen = MoveType::from_move(mv)
|
|
||||||
{
|
|
||||||
self.captured_piece = mailbox.piece_at(mv.dst())
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_promoted_piece(mut self, mv: &Move, color: Color) -> Self {
|
|
||||||
if mv.is_promotion() {
|
|
||||||
self.promoted_piece = Some((mv.promotion_type().into_piece_type(), color));
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_zobrist_hash(mut self, zobrist_hash: &ZobristHash) -> Self {
|
|
||||||
self.zobrist_hash = Some(zobrist_hash.to_owned());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ pub mod bitboard;
|
|||||||
pub mod board;
|
pub mod board;
|
||||||
pub mod fen;
|
pub mod fen;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
pub mod history;
|
|
||||||
pub mod mailbox;
|
pub mod mailbox;
|
||||||
pub mod square;
|
pub mod square;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
|
|||||||
Reference in New Issue
Block a user