diff options
-rw-r--r-- | benches/negamax.rs | 2 | ||||
-rw-r--r-- | src/board/engine.rs | 13 | ||||
-rw-r--r-- | src/board/mod.rs | 47 |
3 files changed, 47 insertions, 15 deletions
diff --git a/benches/negamax.rs b/benches/negamax.rs index b9e38df..33c90ea 100644 --- a/benches/negamax.rs +++ b/benches/negamax.rs @@ -13,8 +13,8 @@ fn main() { board.print(); for mov in pv { println!("{:?}", mov); + println!("Eval for {:?}: {}", board.color(), board.evaluate(None)); board.make_move(mov); board.print(); - println!("Eval for {:?}: {}", board.color(), board.material_advantage()); } } diff --git a/src/board/engine.rs b/src/board/engine.rs index d00b89b..73c57af 100644 --- a/src/board/engine.rs +++ b/src/board/engine.rs @@ -29,6 +29,7 @@ impl Board { for mov in moves { let ep_target_before = self.ep_target.clone(); let castling_rights_before = self.castling_rights.clone(); + let hash_before = self.hash.clone(); let captured_piece = self.make_move(mov); // King can not be in check after our own move if !self.is_king_in_check(color) { @@ -64,7 +65,7 @@ impl Board { result.en_passants += subtree_result.en_passants; } - self.unmake_move(mov, captured_piece, ep_target_before, castling_rights_before); + self.unmake_move(mov, captured_piece, ep_target_before, castling_rights_before, hash_before); } if print { @@ -126,12 +127,13 @@ impl Board { for mov in moves { let ep_target_before = self.ep_target.clone(); let castling_rights_before = self.castling_rights.clone(); + let hash_before = self.hash.clone(); let captured_piece = self.make_move(mov); if !self.is_king_in_check(color) { let (mut evaluation, mut subtree_pv) = self.negamax_search(-beta, -alpha, depth_left - 1); evaluation *= -1.; - self.unmake_move(mov, captured_piece, ep_target_before, castling_rights_before); + self.unmake_move(mov, captured_piece, ep_target_before, castling_rights_before, hash_before); if evaluation >= beta { return (beta, principal_variation); // Fail-hard beta-cutoff @@ -143,7 +145,7 @@ impl Board { principal_variation.append(&mut subtree_pv); } } else { - self.unmake_move(mov, captured_piece, ep_target_before, castling_rights_before); + self.unmake_move(mov, captured_piece, ep_target_before, castling_rights_before, hash_before); } } (alpha, principal_variation) @@ -167,11 +169,12 @@ impl Board { for mov in tactical_moves { let ep_target_before = self.ep_target.clone(); let castling_rights_before = self.castling_rights.clone(); + let hash_before = self.hash.clone(); let captured_piece = self.make_move(*mov); if !self.is_king_in_check(color) { let evaluation = -self.quiscence(-beta, -alpha); - self.unmake_move(*mov, captured_piece, ep_target_before, castling_rights_before); + self.unmake_move(*mov, captured_piece, ep_target_before, castling_rights_before, hash_before); if evaluation >= beta { return beta; // Fail-hard beta-cutoff @@ -180,7 +183,7 @@ impl Board { alpha = evaluation; } } else { - self.unmake_move(*mov, captured_piece, ep_target_before, castling_rights_before); + self.unmake_move(*mov, captured_piece, ep_target_before, castling_rights_before, hash_before); } } 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"); |