From 46b862a25203cb492dd45ba1696a28338a42065b Mon Sep 17 00:00:00 2001 From: eug-vs Date: Wed, 25 Jan 2023 03:12:20 +0300 Subject: feat: incrementally update zobrist hash --- src/board/mod.rs | 47 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) (limited to 'src/board/mod.rs') 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, previous_ep_target: Option, previous_castling_rights: [[bool; 2]; 2]) { + pub fn unmake_move( + &mut self, + mov: Move, + captured_piece: Option, + previous_ep_target: Option, + 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"); -- cgit v1.2.3