Просмотр исходного кода

first try at 3-fold repetition detection

Nicolas Winkler 2 лет назад
Родитель
Сommit
51a754faf6
6 измененных файлов с 47 добавлено и 34 удалено
  1. 21 8
      src/engine.rs
  2. 0 17
      src/evaluate.rs
  3. 0 4
      src/main.rs
  4. 0 1
      src/movegen.rs
  5. 21 3
      src/search.rs
  6. 5 1
      src/ttable.rs

+ 21 - 8
src/engine.rs

@@ -61,7 +61,7 @@ pub enum SearchMessage {
 /// 
 pub struct Engine {
     board: Board,
-    move_history: RepetitionTable,
+    move_history: Arc<RwLock<RepetitionTable>>,
     hash: Arc<RwLock<Cache>>,
     zobrist_table: Arc<ZobristTable>,
 
@@ -93,7 +93,7 @@ impl Engine {
     pub fn new() -> Self {
         let mut eng = Engine {
             board: Board::default(),
-            move_history: RepetitionTable::new(),
+            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,
@@ -131,8 +131,6 @@ impl Engine {
                 println!("readyok");
             },
             Command::NewGame => {
-                self.set_position(Board::default(), &Vec::new());
-                self.hash.write().unwrap().clear();
             },
             Command::Position { pos, moves } => {
                 self.set_position(pos, &moves);
@@ -161,13 +159,22 @@ impl Engine {
         self.board = pos;
 
         self.board.zobrist = Some((self.zobrist_table.clone(), self.board.calculate_zobrist(&self.zobrist_table)));
-        self.move_history.clear();
-        self.move_history.increment(self.board.calculate_zobrist(&self.zobrist_table));
+        let mut move_history = self.move_history.write().unwrap();
+        move_history.increment(self.board.calculate_zobrist(&self.zobrist_table));
+
+        if !moves.is_empty() {
+            move_history.clear();
+        }
         for mov in moves {
             let m = self.board.parse_move(&mov);
             if let Ok(mm) = m {
                 self.board.apply(mm);
-                self.move_history.increment(self.board.calculate_zobrist(&self.zobrist_table));
+
+                if mm.is_capture() {
+                    move_history.clear();
+                }
+                
+                move_history.increment(self.board.calculate_zobrist(&self.zobrist_table));
             }
             else {
                 println!("{}", self.board.beautiful_print());
@@ -188,7 +195,7 @@ impl Engine {
                 thread::spawn(search_rtn)
             }
             else {
-                let mut sc = SearchControl::new(&self.board, rcv, self.hash.clone());
+                let mut sc = SearchControl::new(&self.board, rcv, self.hash.clone(), self.move_history.clone());
                 sc.hash = self.hash.clone();
                 sc.movetime = si.movetime.map(|ms| Duration::from_millis(ms as _));
                 if self.board.turn == WHITE {
@@ -216,6 +223,12 @@ impl Engine {
         }
     }
 
+    fn newgame(&mut self) {
+        self.set_position(Board::default(), &Vec::new());
+        self.hash.write().unwrap().clear();
+        self.move_history.write().unwrap().clear();
+    }
+
     fn set_option(&mut self, name: &str, val: &str) {
         match name {
             "Hash" => {

+ 0 - 17
src/evaluate.rs

@@ -67,23 +67,6 @@ pub fn increase_mate_in(mut val: PosValue) -> PosValue {
     else {
         val
     }
-    /*if let Some(plies) = is_mate_in_p1(val) {
-        if plies < 0 {
-            val = mate_in_p1(plies - 1);
-        }
-        if plies > 0 {
-            val = mate_in_p1(plies + 1);
-        }
-        if plies == 0 {
-            if val < 0 {
-                val = mate_in_p1(-1);
-            }
-            else {
-                val = mate_in_p1(1);
-            }
-        }
-    }
-    val*/
 }
 
 pub fn decrease_mate_in(mut val: PosValue) -> PosValue {

+ 0 - 4
src/main.rs

@@ -15,12 +15,8 @@ extern crate simplelog;
 extern crate rand;
 extern crate static_assertions;
 
-use board::Board;
 use engine::Engine;
 
-use crate::movegen::{PieceCaptureType, PAWN, KNIGHT, SimpleMove};
-
-
 fn main() {
 
     /*let board = Board::from_fen_str("1k1r3q/1ppn3p/p4b2/4p3/8/P2N2P1/1PP1R1BP/2K1Q3 w - - 0 0").unwrap();

+ 0 - 1
src/movegen.rs

@@ -2,7 +2,6 @@ use bitboard::Bitboard;
 use bitboard::Square;
 use bitboard::*;
 use board::Board;
-use static_assertions::const_assert_eq;
 use ttable::{Cache, EntryType};
 use std::cmp::max;
 use std::iter::Iterator;

+ 21 - 3
src/search.rs

@@ -24,6 +24,7 @@ pub struct SearchControl {
 
     pub board: Board,
     pub hash: Arc<RwLock<Cache>>,
+    pub move_history: Arc<RwLock<RepetitionTable>>,
 
     /// depth the current iteration was started at 
     initial_depth: i32,
@@ -64,11 +65,12 @@ pub enum SearchResult {
 }
 
 impl SearchControl {
-    pub fn new(board: &Board, stop_channel: mpsc::Receiver<SearchMessage>, hash: Arc<RwLock<Cache>>) -> Self {
+    pub fn new(board: &Board, stop_channel: mpsc::Receiver<SearchMessage>, hash: Arc<RwLock<Cache>>, move_history: Arc<RwLock<RepetitionTable>>) -> Self {
         SearchControl {
             nodes: 0,
             board: board.clone(),
             hash,
+            move_history,
             killer_moves: Vec::new(),
             last_move: None,
             countermoves: Arc::new(Mutex::new(CountermoveTable::new())),
@@ -316,10 +318,16 @@ pub fn search(mut board: Board, sc: &mut SearchControl, hashs: Arc<RwLock<Cache>
     for mov in moves {
         let undo = board.apply(mov);
 
-        let val = increase_mate_in(
+
+        let mut val = increase_mate_in(
             -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 {
+            println!("mov {} hit", mov.to_string());
+            val = 0;
+        }
+
         //info!("moveval {} -> {}\n", mov.to_string(), val);
 
         board.undo_move(undo);
@@ -372,7 +380,11 @@ pub fn negamax(game: &mut Board, sc: &mut SearchControl, hash: &mut Cache, mut a
         if e.depth() as i32 >= depth {
             //println!("TABLE HIT!");
             match e.entry_type {
-                EntryType::Value => { return e.value(); },
+                EntryType::Value => {
+                    if e.halfmove_age as u16 != sc.halfmove_age {
+                        return e.value();
+                    }
+                },
                 EntryType::LowerBound => {
                     if e.value() >= beta { return beta; }
                 },
@@ -487,6 +499,11 @@ pub fn negamax(game: &mut Board, sc: &mut SearchControl, hash: &mut Cache, mut a
         let mut val = increase_mate_in(
             -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 {
+            val = 0;
+        }
+
         game.undo_move(undo);
         sc.reductions_allowed = reductions_allowed_before;
 
@@ -644,6 +661,7 @@ impl SearchControl {
             nodes: 0,
             board: board.clone(),
             hash: Arc::new(RwLock::new(Cache::new(0))),
+            move_history: Arc::new(RwLock::new(RepetitionTable::new())),
             initial_depth: depth,
             killer_moves: Vec::new(),
             last_move: None,

+ 5 - 1
src/ttable.rs

@@ -192,7 +192,7 @@ impl Cache {
 impl RepetitionTable {
     pub fn new() -> Self {
         RepetitionTable {
-            hashmap: HashMap::with_capacity(1024)
+            hashmap: HashMap::with_capacity(64)
         }
     }
 
@@ -200,6 +200,10 @@ impl RepetitionTable {
         self.hashmap.clear();
     }
 
+    pub fn lookup(&self, hash: zobrist::Hash) -> i32 {
+        *self.hashmap.get(&hash).unwrap_or(&0)
+    }
+
     pub fn increment(&mut self, hash: zobrist::Hash) -> i32 {
         if let Some(entry) = self.hashmap.get_mut(&hash) {
             *entry += 1;