|  | @@ -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;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |