|
@@ -527,6 +527,15 @@ impl Game {
|
|
|
return hash;
|
|
|
}
|
|
|
|
|
|
+ pub fn is_zobrist_correct(&self) -> bool {
|
|
|
+ if let Some((ref zt, zv)) = self.zobrist {
|
|
|
+ self.calculate_zobrist(zt) == zv
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
pub fn apply(&mut self, mov: Move) -> MoveUndo {
|
|
|
|
|
|
// save irrecoverable values
|
|
@@ -538,6 +547,8 @@ impl Game {
|
|
|
let friends = self.get_all_side(side);
|
|
|
let others = self.get_all_side(!side);
|
|
|
|
|
|
+ let with_zobrist = self.zobrist.is_some();
|
|
|
+
|
|
|
match mov {
|
|
|
Move::Default{ mov, piece_type: pt, captured: _ } => {
|
|
|
|
|
@@ -564,19 +575,20 @@ impl Game {
|
|
|
// if it is a capture
|
|
|
if from_square(mov.to) & others != 0 {
|
|
|
let (other_piece, other_side) = self.get_square(mov.to);
|
|
|
- if let Some((ref zt, ref _zv)) = self.zobrist {
|
|
|
+
|
|
|
+ // update zobrist
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
let hup = zt.piece_hash(other_piece, other_side, mov.to);
|
|
|
- self.update_zobrist(hup);
|
|
|
+ *zv ^= hup;
|
|
|
}
|
|
|
*self.get_piece_mut(other_piece, other_side) &= !from_square(mov.to);
|
|
|
}
|
|
|
|
|
|
let moved_piece = mov.apply_to(self.get_piece(pt, side));
|
|
|
self.set_piece(pt, side, moved_piece);
|
|
|
-
|
|
|
- if let Some((ref zt, ref _zv)) = self.zobrist {
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
let hup = zt.piece_hash(pt, side, mov.from) ^ zt.piece_hash(pt, side, mov.to);
|
|
|
- self.update_zobrist(hup);
|
|
|
+ *zv ^= hup;
|
|
|
}
|
|
|
},
|
|
|
Move::Castling { side, left } => {
|
|
@@ -598,20 +610,43 @@ impl Game {
|
|
|
self.set_piece(KING, side, new_king);
|
|
|
*self.get_piece_mut(ROOK, side) &= !rook;
|
|
|
*self.get_piece_mut(ROOK, side) |= new_rook;
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let hupk = zt.piece_hash(KING, side, square(king)) ^ zt.piece_hash(KING, side, square(new_king));
|
|
|
+ let hup = zt.piece_hash(ROOK, side, square(rook)) ^ zt.piece_hash(ROOK, side, square(new_rook));
|
|
|
+ *zv ^= hup ^ hupk;
|
|
|
+ }
|
|
|
},
|
|
|
Move::EnPassant { mov, beaten } => {
|
|
|
if let Some(_ep) = self.en_passant {
|
|
|
*self.get_piece_mut(PAWN, side) &= !from_square(mov.from);
|
|
|
*self.get_piece_mut(PAWN, side) |= from_square(mov.to);
|
|
|
*self.get_piece_mut(PAWN, !side) &= !from_square(beaten);
|
|
|
+
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let hup = zt.piece_hash(PAWN, side, mov.from) ^ zt.piece_hash(PAWN, side, mov.to);
|
|
|
+ let hupo = zt.piece_hash(PAWN, !side, beaten);
|
|
|
+ *zv ^= hup ^ hupo;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ panic!("internal en passant error");
|
|
|
}
|
|
|
},
|
|
|
Move::Promotion { mov, promote_to, captured } => {
|
|
|
//if from_square(mov.to) & others != 0 {
|
|
|
if let Some(pt) = captured {
|
|
|
*self.get_piece_mut(pt, !side) &= !from_square(mov.to);
|
|
|
+
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let hup = zt.piece_hash(pt, !side, mov.to);
|
|
|
+ *zv ^= hup;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ *self.get_piece_mut(PAWN, side) &= !from_square(mov.from);
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let hup = zt.piece_hash(PAWN, side, mov.from);
|
|
|
+ *zv ^= hup;
|
|
|
}
|
|
|
- self.apply_mask(!from_square(mov.from));
|
|
|
|
|
|
match promote_to {
|
|
|
QUEEN => { *self.queens_mut(side) |= from_square(mov.to); }
|
|
@@ -622,13 +657,34 @@ impl Game {
|
|
|
info!("internal error");
|
|
|
}
|
|
|
}
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let hup = zt.piece_hash(promote_to, side, mov.to);
|
|
|
+ *zv ^= hup;
|
|
|
+ }
|
|
|
},
|
|
|
}
|
|
|
|
|
|
if self.turn == BLACK {
|
|
|
self.turn_number += 1;
|
|
|
}
|
|
|
+
|
|
|
self.turn = !self.turn;
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let hup = zt.turn_hash();
|
|
|
+ let castling_hup = zt.all_castling_rights_hash(castling_rights_before) ^ zt.all_castling_rights_hash(self.castling_rights);
|
|
|
+ let enpass_hup = en_passant_before.map(|f| zt.en_passant_hash(f)).unwrap_or(0) ^ self.en_passant.map(|f| zt.en_passant_hash(f)).unwrap_or(0);
|
|
|
+ *zv ^= hup ^ castling_hup ^ enpass_hup;
|
|
|
+ }
|
|
|
+
|
|
|
+ if !self.is_zobrist_correct() {
|
|
|
+ println!("incorrect zobrist after apply");
|
|
|
+ let val = if let Some((ref zt, _zv)) = self.zobrist {
|
|
|
+ self.calculate_zobrist(zt)
|
|
|
+ } else { 0 };
|
|
|
+ if let Some((ref _zt, ref mut zv)) = self.zobrist {
|
|
|
+ *zv = val;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
MoveUndo {
|
|
|
castling_rights_before,
|
|
@@ -639,6 +695,13 @@ impl Game {
|
|
|
}
|
|
|
|
|
|
pub fn undo_move(&mut self, umov: MoveUndo) {
|
|
|
+
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let crhup = zt.all_castling_rights_hash(self.castling_rights) ^ zt.all_castling_rights_hash(umov.castling_rights_before);
|
|
|
+ let enpass_hup = self.en_passant.map(|f| zt.en_passant_hash(f)).unwrap_or(0) ^ umov.en_passant_before.map(|f| zt.en_passant_hash(f)).unwrap_or(0);
|
|
|
+ *zv ^= crhup ^ enpass_hup;
|
|
|
+ }
|
|
|
+
|
|
|
self.castling_rights = umov.castling_rights_before;
|
|
|
self.halfmoves_since_last_event = umov.halfmoves_since_last_event_before;
|
|
|
self.en_passant = umov.en_passant_before;
|
|
@@ -653,8 +716,18 @@ impl Game {
|
|
|
*moved_piece_bb &= !from_square(mov.to);
|
|
|
*moved_piece_bb |= from_square(mov.from);
|
|
|
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let hup = zt.piece_hash(piece_type, side, mov.from) ^ zt.piece_hash(piece_type, side, mov.to);
|
|
|
+ *zv ^= hup;
|
|
|
+ }
|
|
|
+
|
|
|
if let Some(pt) = captured {
|
|
|
*self.get_piece_mut(pt, !side) |= from_square(mov.to);
|
|
|
+
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let hup = zt.piece_hash(pt, !side, mov.to);
|
|
|
+ *zv ^= hup;
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
Move::Castling { side, left } => {
|
|
@@ -673,12 +746,24 @@ impl Game {
|
|
|
self.set_piece(KING, side, old_king);
|
|
|
*self.get_piece_mut(ROOK, side) &= !rook;
|
|
|
*self.get_piece_mut(ROOK, side) |= old_rook;
|
|
|
+
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let khup = zt.piece_hash(KING, side, square(old_king)) ^ zt.piece_hash(KING, side, square(king));
|
|
|
+ let rhup = zt.piece_hash(ROOK, side, square(rook)) ^ zt.piece_hash(ROOK, side, square(old_rook));
|
|
|
+ *zv ^= khup ^ rhup;
|
|
|
+ }
|
|
|
},
|
|
|
Move::EnPassant { mov, beaten } => {
|
|
|
*self.get_piece_mut(PAWN, side) |= from_square(mov.from);
|
|
|
*self.get_piece_mut(PAWN, side) &= !from_square(mov.to);
|
|
|
*self.get_piece_mut(PAWN, !side) |= from_square(beaten);
|
|
|
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let phup = zt.piece_hash(PAWN, side, mov.from) ^ zt.piece_hash(PAWN, side, mov.to);
|
|
|
+ let chup = zt.piece_hash(PAWN, !side, beaten);
|
|
|
+ *zv ^= phup ^ chup;
|
|
|
+ }
|
|
|
+
|
|
|
// should already be reverted
|
|
|
//self.en_passant = Some(indices_from_square(beaten).0);
|
|
|
},
|
|
@@ -694,8 +779,18 @@ impl Game {
|
|
|
}
|
|
|
*self.pawns_mut(side) |= from_square(mov.from);
|
|
|
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let hup = zt.piece_hash(PAWN, side, mov.from) ^ zt.piece_hash(promote_to, side, mov.to);
|
|
|
+ *zv ^= hup;
|
|
|
+ }
|
|
|
+
|
|
|
if let Some(pt) = captured {
|
|
|
*self.get_piece_mut(pt, !side) |= from_square(mov.to);
|
|
|
+
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ let hup = zt.piece_hash(pt, !side, mov.to);
|
|
|
+ *zv ^= hup;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -704,5 +799,26 @@ impl Game {
|
|
|
if side == BLACK {
|
|
|
self.turn_number -= 1;
|
|
|
}
|
|
|
+
|
|
|
+ if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
|
+ *zv ^= zt.turn_hash();
|
|
|
+ }
|
|
|
+
|
|
|
+ /*let val = if let Some((ref zt, _zv)) = self.zobrist {
|
|
|
+ self.calculate_zobrist(zt)
|
|
|
+ } else { 0 };
|
|
|
+ if let Some((ref _zt, ref mut zv)) = self.zobrist {
|
|
|
+ *zv = val;
|
|
|
+ }*/
|
|
|
+
|
|
|
+ if !self.is_zobrist_correct() {
|
|
|
+ println!("incorrect zobrist after undo {}!", umov.mov.to_string());
|
|
|
+ let val = if let Some((ref zt, _zv)) = self.zobrist {
|
|
|
+ self.calculate_zobrist(zt)
|
|
|
+ } else { 0 };
|
|
|
+ if let Some((ref _zt, ref mut zv)) = self.zobrist {
|
|
|
+ *zv = val;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|