Ver código fonte

reworking zobrist

Nicolas Winkler 2 anos atrás
pai
commit
9fa930dc05
7 arquivos alterados com 128 adições e 132 exclusões
  1. 84 103
      src/board.rs
  2. 6 6
      src/engine.rs
  3. 4 0
      src/main.rs
  4. 11 2
      src/movegen.rs
  5. 4 12
      src/search.rs
  6. 2 9
      src/ttable.rs
  7. 17 0
      src/zobrist.rs

+ 84 - 103
src/board.rs

@@ -3,7 +3,7 @@ use movegen::*;
 use log::info;
 use std::sync::Arc;
 use zobrist::{ZobristTable, Hash};
-use crate::movegen;
+use crate::{movegen, zobrist::{self, get_zobrist}};
 
 #[derive(Clone)]
 pub struct Board
@@ -26,12 +26,12 @@ pub struct Board
     // vvv
     pub turn_number: i32,
     pub halfmoves_since_last_event: i8,
-    pub zobrist: Option<(Arc<ZobristTable>, Hash)>
+    pub zobrist_hash: Hash
 }
 
 impl Default for Board {
     fn default () -> Board {
-        Board {
+        let mut b = Board {
             pieces: [
                 ROW_2,
                 0x42,
@@ -51,17 +51,18 @@ impl Default for Board {
             castling_rights: [true; 4],
             halfmoves_since_last_event: 0,
             turn_number: 0,
-            zobrist: None
-        }
+            zobrist_hash: 0
+        };
+        let z = b.calculate_zobrist(zobrist::get_zobrist());
+        b.zobrist_hash = z;
+        b
     }
 }
 
 
 impl std::hash::Hash for Board {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
-        if let Some((ref _zt, ref zb)) = &self.zobrist {
-            zb.hash(state);
-        }
+        self.zobrist_hash.hash(state);
     }
 }
 
@@ -80,15 +81,18 @@ impl Eq for Board {
 
 impl Board {
     pub fn empty() -> Board {
-        Board {
+        let mut b = Board {
             pieces: [0; 12],
             turn: WHITE,
             en_passant: None,
             castling_rights: [true; 4],
             halfmoves_since_last_event: 0,
             turn_number: 0,
-            zobrist: None
-        }
+            zobrist_hash: 0 
+        };
+        let z = b.calculate_zobrist(zobrist::get_zobrist());
+        b.zobrist_hash = z;
+        b
     }
 
     pub fn from_fen(fen: &[&str]) -> Option<Board> {
@@ -159,6 +163,8 @@ impl Board {
 
         game.halfmoves_since_last_event = halfmoves_since_last_event.parse::<i8>().unwrap_or(0);
         game.turn_number = turn_number.parse::<i32>().unwrap_or(0);
+
+        game.zobrist_hash = game.calculate_zobrist(zobrist::get_zobrist());
         
         Some(game)
     }
@@ -519,12 +525,15 @@ impl Board {
         return board;
     }
 
-    pub fn update_zobrist(&mut self, h: Hash) {
-        if let Some((ref _zt, ref mut zh)) = self.zobrist {
-            *zh ^= h;
-        }
+    fn update_zobrist(&mut self, h: Hash) {
+        self.zobrist_hash ^= h;
     }
 
+    ///
+    /// calculates the zobrist hash independently from the field zobrist_hash
+    /// 
+    /// doesn't set anything
+    /// 
     pub fn calculate_zobrist(&self, zt: &ZobristTable) -> Hash {
         let mut hash: Hash = 0;
         for pt in 0..6 {
@@ -556,12 +565,7 @@ impl Board {
     }
 
     pub fn is_zobrist_correct(&self) -> bool {
-        if let Some((ref zt, zv)) = self.zobrist {
-            self.calculate_zobrist(zt) == zv
-        }
-        else {
-            false
-        }
+        self.zobrist_hash == self.calculate_zobrist(zobrist::get_zobrist())
     }
 
     ///
@@ -591,14 +595,10 @@ impl Board {
             println!("incorrect zobrist before apply {} {:?}", mov.to_string(), mov);
             info!("incorrect zobrist before apply");
             panic!("zobrist");
-            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;
-            }
         }*/
 
+        let zobrist_table = get_zobrist();
+
         // save irrecoverable values
         let castling_rights_before = self.castling_rights.clone();
         let halfmoves_since_last_event_before = self.halfmoves_since_last_event.clone();
@@ -636,10 +636,9 @@ impl Board {
                     if from_square(mov.to) & others != 0 {
                         if let Some((other_piece, other_side)) = self.get_square(mov.to) {
                             // update zobrist
-                            if let Some((ref zt, ref mut zv)) = self.zobrist {
-                                let hup = zt.piece_hash(other_piece, other_side, mov.to);
-                                *zv ^= hup;
-                            }
+                            let hup = zobrist_table.piece_hash(other_piece, other_side, mov.to);
+                            self.update_zobrist(hup);
+
                             *self.get_piece_mut(other_piece, other_side) &= !from_square(mov.to);
                         }
                     }
@@ -662,10 +661,10 @@ impl Board {
 
                     let moved_piece = mov.apply_to(self.get_piece(pt, side));
                     self.set_piece(pt, side, moved_piece);
-                    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);
-                        *zv ^= hup;
-                    }
+
+                    let hup = zobrist_table.piece_hash(pt, side, mov.from)
+                                 ^ zobrist_table.piece_hash(pt, side, mov.to);
+                    self.update_zobrist(hup);
                 },
                 Move::Castling { mov:_, side, left } => {
                     // invalidate future castling rights
@@ -686,11 +685,14 @@ impl Board {
                     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;
-                    }
+
+
+                    let hupk = zobrist_table.piece_hash(KING, side, square(king))
+                                  ^ zobrist_table.piece_hash(KING, side, square(new_king));
+                    let hup = zobrist_table.piece_hash(ROOK, side, square(rook))
+                                  ^ zobrist_table.piece_hash(ROOK, side, square(new_rook));
+
+                    self.update_zobrist(hupk ^ hup);
 
                     self.en_passant = None;
                 },
@@ -700,11 +702,10 @@ impl Board {
                         *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;
-                        }
+                        let hup = zobrist_table.piece_hash(PAWN, side, mov.from)
+                                     ^ zobrist_table.piece_hash(PAWN, side, mov.to);
+                        let hupo = zobrist_table.piece_hash(PAWN, !side, beaten);
+                        self.update_zobrist(hup ^ hupo);
 
                         self.en_passant = None;
                     }
@@ -720,16 +721,13 @@ impl Board {
                     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;
-                        }
+                        let hup = zobrist_table.piece_hash(pt, !side, mov.to);
+                        self.update_zobrist(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;
-                    }
+
+                    let hup = zobrist_table.piece_hash(PAWN, side, mov.from);
+                    self.update_zobrist(hup);
 
                     match promote_to {
                         QUEEN => { *self.queens_mut(side) |= from_square(mov.to); }
@@ -740,10 +738,8 @@ impl Board {
                             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;
-                    }
+                    let hup = zobrist_table.piece_hash(promote_to, side, mov.to);
+                    self.update_zobrist(hup);
                     self.en_passant = None;
                 },
             }
@@ -755,24 +751,16 @@ impl Board {
         }
 
         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;
-        }
+        let hup = zobrist_table.turn_hash();
+        let castling_hup = zobrist_table.all_castling_rights_hash(castling_rights_before) ^ zobrist_table.all_castling_rights_hash(self.castling_rights);
+        let enpass_hup = en_passant_before.map(|f| zobrist_table.en_passant_hash(f)).unwrap_or(0) ^ self.en_passant.map(|f| zobrist_table.en_passant_hash(f)).unwrap_or(0);
+        self.update_zobrist(hup ^ castling_hup ^ enpass_hup);
 
         /*if !self.is_zobrist_correct() {
             println!("{}", self.beautiful_print());
             println!("incorrect zobrist after apply {} {:?}", mov.to_string(), mov);
             info!("incorrect zobrist after apply");
             panic!("zobrist");
-            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 {
@@ -793,11 +781,13 @@ impl Board {
             panic!("zobrist");
         }*/
 
-        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;
-        }
+        let zobrist_table = get_zobrist();
+
+        let crhup = zobrist_table.all_castling_rights_hash(self.castling_rights)
+                  ^ zobrist_table.all_castling_rights_hash(umov.castling_rights_before);
+        let enpass_hup = self.en_passant.map(|f| zobrist_table.en_passant_hash(f)).unwrap_or(0)
+                            ^ umov.en_passant_before.map(|f| zobrist_table.en_passant_hash(f)).unwrap_or(0);
+        self.update_zobrist(crhup ^ enpass_hup);
 
         self.castling_rights = umov.castling_rights_before;
         self.halfmoves_since_last_event = umov.halfmoves_since_last_event_before;
@@ -818,18 +808,15 @@ impl Board {
                     *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;
-                    }
+                    let hup = zobrist_table.piece_hash(piece_type, side, mov.from)
+                                 ^ zobrist_table.piece_hash(piece_type, side, mov.to);
+                    self.update_zobrist(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;
-                        }
+                        let hup = zobrist_table.piece_hash(pt, !side, mov.to);
+                        self.update_zobrist(hup);
                     }
                 },
                 Move::Castling { mov: _, side, left } => {
@@ -849,22 +836,21 @@ impl Board {
                     *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;
-                    }
+                    let khup = zobrist_table.piece_hash(KING, side, square(old_king))
+                                  ^ zobrist_table.piece_hash(KING, side, square(king));
+                    let rhup = zobrist_table.piece_hash(ROOK, side, square(rook))
+                                  ^ zobrist_table.piece_hash(ROOK, side, square(old_rook));
+                    self.update_zobrist(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;
-                    }
+                    let phup = zobrist_table.piece_hash(PAWN, side, mov.from)
+                                  ^ zobrist_table.piece_hash(PAWN, side, mov.to);
+                    let chup = zobrist_table.piece_hash(PAWN, !side, beaten);
+                    self.update_zobrist(phup ^ chup);
 
                     // should already be reverted
                     //self.en_passant = Some(indices_from_square(beaten).0);
@@ -884,18 +870,15 @@ impl Board {
                     }
                     *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;
-                    }
+                    let hup = zobrist_table.piece_hash(PAWN, side, mov.from)
+                                 ^ zobrist_table.piece_hash(promote_to, side, mov.to);
+                    self.update_zobrist(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;
-                        }
+                        let hup = zobrist_table.piece_hash(pt, !side, mov.to);
+                        self.update_zobrist(hup);
                     }
                 },
             }
@@ -906,9 +889,7 @@ impl Board {
             self.turn_number -= 1;
         }
 
-        if let Some((ref zt, ref mut zv)) = self.zobrist {
-            *zv ^= zt.turn_hash();
-        }
+        self.update_zobrist(zobrist_table.turn_hash());
 
         /*if !self.is_zobrist_correct() {
             println!("{}", self.beautiful_print());

+ 6 - 6
src/engine.rs

@@ -11,7 +11,7 @@ use std::thread;
 
 use std::sync::{Arc, RwLock};
 use crate::ttable::{RepetitionTable, Cache};
-use crate::uci;
+use crate::{uci, zobrist};
 
 ///
 /// Message types that are sent from the uci interface to the engine thread.
@@ -91,15 +91,13 @@ impl SearchInfo {
 
 impl Engine {
     pub fn new() -> Self {
-        let mut eng = Engine {
+        Engine {
             board: Board::default(),
             move_history: Arc::new(RwLock::new(RepetitionTable::new())),
             hash: Arc::new(RwLock::new(Cache::new_in_megabytes(4))),
             zobrist_table: Arc::new(ZobristTable::new()),
             search_thread: None,
-        };
-        eng.board.zobrist = Some((eng.zobrist_table.clone(), eng.board.calculate_zobrist(&eng.zobrist_table)));
-        eng
+        }
     }
 
     pub fn run(&mut self) {
@@ -158,7 +156,9 @@ impl Engine {
     fn set_position(&mut self, pos: Board, moves: &Vec<String>) {
         self.board = pos;
 
-        self.board.zobrist = Some((self.zobrist_table.clone(), self.board.calculate_zobrist(&self.zobrist_table)));
+        // ensure correct zobrist hash
+        self.board.zobrist_hash = self.board.calculate_zobrist(zobrist::get_zobrist());
+
         let mut move_history = self.move_history.write().unwrap();
         move_history.increment(self.board.calculate_zobrist(&self.zobrist_table));
 

+ 4 - 0
src/main.rs

@@ -1,3 +1,5 @@
+#![feature(const_for)]
+#![feature(const_mut_refs)]
 pub mod uci;
 pub mod bitboard;
 pub mod movegen;
@@ -24,6 +26,8 @@ fn main() {
     let see = movegen::calculate_see(board.clone(), movegen::Move::Default { mov: SimpleMove{ from: 20, to: 35 }, pc: PieceCaptureType::new(KNIGHT, Some(PAWN)) }, false);
     println!("see: {}", see);*/
 
+    zobrist::initialize_zobrist();
+
     let mut engine = Engine::new();
     engine.run();
 }

+ 11 - 2
src/movegen.rs

@@ -283,6 +283,8 @@ pub struct MoveGenerator {
     killers: Vec<Move>,
     last_move: Option<Move>,
     counters_table: Arc<Mutex<CountermoveTable>>,
+
+    is_late: bool,
 }
 
 impl MoveGenerator {
@@ -298,7 +300,8 @@ impl MoveGenerator {
             pv_move: ce.map(|e| e.mov),
             killers: killers.to_vec(),
             last_move,
-            counters_table
+            counters_table,
+            is_late: false,
         }
     }
 
@@ -307,7 +310,8 @@ impl MoveGenerator {
     }
 
     pub fn is_late(&self) -> bool {
-        return self.state == SortingState::Quiets;
+        //self.is_late
+        self.state == SortingState::Quiets
     }
 }
 
@@ -397,6 +401,11 @@ impl Iterator for MoveGenerator {
                             }
                         }
                         self.counters.retain(|c| *c != best);
+
+                        if best.1 <= 0 {
+                            self.is_late = true;
+                        }
+
                         return Some(best.0);
                     }
 

+ 4 - 12
src/search.rs

@@ -323,7 +323,7 @@ pub fn search(mut board: Board, sc: &mut SearchControl, hashs: Arc<RwLock<Cache>
             -negamax(&mut board, sc, &mut hash, decrease_mate_in(-beta), decrease_mate_in(-alpha), depth - 1)
         );
 
-        if sc.move_history.read().unwrap().lookup(board.zobrist.as_ref().unwrap().1) >= 2 {
+        if sc.move_history.read().unwrap().lookup(board.zobrist_hash) >= 2 {
             val = 0;
         }
 
@@ -428,7 +428,7 @@ pub fn negamax(game: &mut Board, sc: &mut SearchControl, hash: &mut Cache, mut a
         game,
         cache_entry.as_ref(),
         &sc.killer_moves[ply_depth],
-        if depth >= 3 { last_move } else { None },
+        last_move,
         sc.countermoves.clone(),
         game.turn
     );
@@ -485,7 +485,7 @@ pub fn negamax(game: &mut Board, sc: &mut SearchControl, hash: &mut Cache, mut a
         let reductions_allowed_before = sc.reductions_allowed;
         if depth > 4 && moves.is_late() && !mov.is_promotion() && reductions_allowed_before {
             reduce = 1;
-            if depth >= 8 {
+            if depth >= 7 {
                 reduce = 2;
             }
             sc.reductions_allowed = false;
@@ -499,7 +499,7 @@ pub fn negamax(game: &mut Board, sc: &mut SearchControl, hash: &mut Cache, mut a
             -negamax(game, sc, hash, -decrease_mate_in(beta), -decrease_mate_in(alpha), depth - 1 - reduce)
         );
 
-        if depth > 3 && sc.move_history.read().unwrap().lookup(game.zobrist.as_ref().unwrap().1) >= 1 {
+        if depth > 3 && sc.move_history.read().unwrap().lookup(game.zobrist_hash) >= 1 {
             val = 0;
         }
 
@@ -537,14 +537,6 @@ pub fn negamax(game: &mut Board, sc: &mut SearchControl, hash: &mut Cache, mut a
         if val > alpha {
             alpha = val;
             best_move = Some(mov);
-            if sc.initial_depth >= 10 && cache_entry.is_some() && cache_entry.as_ref().unwrap().entry_type == EntryType::Value {
-                //println!("mov: {}", mov.to_string());
-            }
-            if depth >= 2 {
-                if let Some(_lm) = last_move {
-                    //sc.countermoves.as_ref().lock().unwrap().update_score(lm, mov, (depth * depth) as i16);
-                }
-            }
             if alpha >= mate_in_plies(1) {
                 break;
             }

+ 2 - 9
src/ttable.rs

@@ -104,10 +104,7 @@ impl Cache {
     }
 
     pub fn lookup<'a>(&'a self, board: &Board) -> Option<&'a CacheEntry> {
-        if board.zobrist.is_none() {
-            info!("invalid zobrist");
-        }
-        let hash = board.zobrist.as_ref().unwrap().1;
+        let hash = board.zobrist_hash;
         let index = self.get_index(hash);
 
         let bucket = &self.table[index];
@@ -145,11 +142,7 @@ impl Cache {
     }
     
     pub fn cache(&mut self, game_pos: &Board, ce: CacheEntry) {
-        if game_pos.zobrist.is_none() {
-            info!("invalid zobrist");
-        }
-
-        let hash = game_pos.zobrist.as_ref().unwrap().1;
+        let hash = game_pos.zobrist_hash;
         let index = self.get_index(hash);
 
         let bucket = &mut self.table[index];

+ 17 - 0
src/zobrist.rs

@@ -1,3 +1,5 @@
+use std::{cell::UnsafeCell, mem::MaybeUninit};
+
 use rand::prelude::*;
 
 use movegen::{PieceType};
@@ -5,6 +7,21 @@ use bitboard::Square;
 
 pub type Hash = u64;
 
+
+
+static mut ZOBRIST: MaybeUninit<ZobristTable> = MaybeUninit::uninit();
+
+pub fn initialize_zobrist() {
+    unsafe {
+        ZOBRIST = MaybeUninit::new(ZobristTable::new());
+    }
+}
+
+pub fn get_zobrist() -> &'static ZobristTable {
+    unsafe { ZOBRIST.assume_init_ref() }
+}
+
+
 pub struct ZobristTable {
     board: [[Hash; 12]; 64],
     en_passant: [Hash; 8],