aboutsummaryrefslogtreecommitdiff
path: root/src/board/mod.rs
diff options
context:
space:
mode:
authoreug-vs <eugene@eug-vs.xyz>2023-01-25 03:12:20 +0300
committereug-vs <eugene@eug-vs.xyz>2023-01-25 03:12:20 +0300
commit46b862a25203cb492dd45ba1696a28338a42065b (patch)
tree3a68d3e5e99e514a303a2842653cbbfa3dc5bf3b /src/board/mod.rs
parent05e6d002225f561c9725b25ef7960bc10421f723 (diff)
downloadchessnost-46b862a25203cb492dd45ba1696a28338a42065b.tar.gz
feat: incrementally update zobrist hash
Diffstat (limited to 'src/board/mod.rs')
-rw-r--r--src/board/mod.rs47
1 files changed, 38 insertions, 9 deletions
diff --git a/src/board/mod.rs b/src/board/mod.rs
index 18e5e7f..a8166a1 100644
--- a/src/board/mod.rs
+++ b/src/board/mod.rs
@@ -483,6 +483,7 @@ impl Board {
{
Some((target_piece, _)) => {
self.pieces[target_piece] ^= move_target_bb;
+ self.hash ^= self.zobrist_seed[target_piece * 12 + mov.target as usize];
Some(PieceType::from(target_piece))
},
None => None,
@@ -491,7 +492,8 @@ impl Board {
// En Passant captures diffirently
if mov.kind == MoveKind::EnPassant {
debug_assert!(captured_piece.is_none(), "No capture should be found at this point");
- let captured_bb = Square::from_coords(mov.source.rank(), mov.target.file()).to_bitboard();
+ let captured_square = Square::from_coords(mov.source.rank(), mov.target.file());
+ let captured_bb = captured_square.to_bitboard();
captured_piece = match self.pieces
.iter()
.enumerate()
@@ -499,6 +501,7 @@ impl Board {
{
Some((pawn_type, _)) => {
self.pieces[pawn_type] ^= captured_bb;
+ self.hash ^= self.zobrist_seed[pawn_type * 12 + captured_square as usize];
Some(PieceType::from(pawn_type))
}
None => panic!("Pawn captured by En Passant was not found"),
@@ -514,9 +517,11 @@ impl Board {
Some((source_piece, _)) => {
self.pieces[source_piece] ^= move_source_bb;
self.occupancy ^= move_source_bb;
+ self.hash ^= self.zobrist_seed[source_piece * 12 + mov.source as usize];
self.pieces[source_piece] |= move_target_bb;
self.occupancy |= move_target_bb;
+ self.hash ^= self.zobrist_seed[source_piece * 12 + mov.target as usize];
PieceType::from(source_piece)
},
None => panic!("Move is malformed: source piece not found"),
@@ -530,8 +535,11 @@ impl Board {
6 => (7, 5),
_ => panic!("Malformed castle, target square invalid: {:?}", mov),
};
- let rook_source_bb = Square::from_coords(mov.target.rank(), rook_source_file).to_bitboard();
- let rook_target_bb = Square::from_coords(mov.target.rank(), rook_target_file).to_bitboard();
+ let rook_source_square = Square::from_coords(mov.target.rank(), rook_source_file);
+ let rook_source_bb = rook_source_square.to_bitboard();
+
+ let rook_target_square = Square::from_coords(mov.target.rank(), rook_target_file);
+ let rook_target_bb = rook_target_square.to_bitboard();
match self.pieces
.iter()
@@ -541,9 +549,11 @@ impl Board {
Some((rook_type, _)) => {
self.pieces[rook_type] ^= rook_source_bb;
self.occupancy ^= rook_source_bb;
+ self.hash ^= self.zobrist_seed[rook_type * 12 + rook_source_square as usize];
self.pieces[rook_type] |= rook_target_bb;
self.occupancy |= rook_target_bb;
+ self.hash ^= self.zobrist_seed[rook_type * 12 + rook_target_square as usize];
},
None => panic!("Rook was not found when castling"),
}
@@ -551,6 +561,7 @@ impl Board {
// Double push should set En Passant target square
self.ep_target = if mov.kind == MoveKind::DoublePush {
+ self.hash ^= self.zobrist_seed[64 * 12 + 4 + mov.source.file() as usize];
match mov.source.rank() {
1 => Some(mov.source.nort_one()),
6 => Some(mov.source.sout_one()),
@@ -559,15 +570,24 @@ impl Board {
} else { None };
// Withdraw castling rights when moving rooks or king
+ let source_color = Color::from_piece(source_piece) as usize;
match source_piece {
PieceType::King => {
- self.castling_rights[Color::from_piece(source_piece) as usize][CastlingSide::King as usize] = false;
- self.castling_rights[Color::from_piece(source_piece) as usize][CastlingSide::Queen as usize] = false;
+ self.castling_rights[source_color][CastlingSide::King as usize] = false;
+ self.castling_rights[source_color][CastlingSide::Queen as usize] = false;
+ self.hash ^= self.zobrist_seed[64 * 12 + source_color * 2 + 0];
+ self.hash ^= self.zobrist_seed[64 * 12 + source_color * 2 + 1];
},
PieceType::Rook => {
match mov.source.file() {
- 0 => self.castling_rights[Color::from_piece(source_piece) as usize][CastlingSide::Queen as usize] = false,
- 7 => self.castling_rights[Color::from_piece(source_piece) as usize][CastlingSide::King as usize] = false,
+ 0 => {
+ self.castling_rights[Color::from_piece(source_piece) as usize][CastlingSide::Queen as usize] = false;
+ self.hash ^= self.zobrist_seed[64 * 12 + source_color * 2 + CastlingSide::Queen as usize];
+ }
+ 7 => {
+ self.castling_rights[Color::from_piece(source_piece) as usize][CastlingSide::King as usize] = false;
+ self.hash ^= self.zobrist_seed[64 * 12 + source_color * 2 + CastlingSide::King as usize];
+ }
_ => {},
}
},
@@ -575,12 +595,20 @@ impl Board {
}
self.ply += 1;
+ self.hash ^= self.zobrist_seed[780];
captured_piece
}
/// Completely reverse make_move as if it never happened
- pub fn unmake_move(&mut self, mov: Move, captured_piece: Option<PieceType>, previous_ep_target: Option<Square>, previous_castling_rights: [[bool; 2]; 2]) {
+ pub fn unmake_move(
+ &mut self,
+ mov: Move,
+ captured_piece: Option<PieceType>,
+ previous_ep_target: Option<Square>,
+ previous_castling_rights: [[bool; 2]; 2],
+ previous_hash: u64,
+ ) {
let move_source_bb = mov.source.to_bitboard();
let move_target_bb = mov.target.to_bitboard();
@@ -648,6 +676,7 @@ impl Board {
self.ep_target = previous_ep_target;
self.castling_rights = previous_castling_rights;
+ self.hash = previous_hash;
self.ply -= 1;
}
@@ -838,7 +867,7 @@ mod tests {
let captured_piece = board.make_move(mov);
board.print();
- board.unmake_move(mov, captured_piece, None, board.castling_rights);
+ board.unmake_move(mov, captured_piece, None, board.castling_rights, initial_board.hash);
board.print();
assert_eq!(board, initial_board, "Board state after unmake_move should be the same as before make_move");