瀏覽代碼

playing around with hash search stuff

Nicolas Winkler 3 年之前
父節點
當前提交
1d25d7a372
共有 6 個文件被更改,包括 145 次插入67 次删除
  1. 64 0
      src/bitboard.rs
  2. 8 2
      src/engine.rs
  3. 30 1
      src/evaluate.rs
  4. 5 0
      src/hash.rs
  5. 2 14
      src/main.rs
  6. 36 50
      src/search.rs

+ 64 - 0
src/bitboard.rs

@@ -87,6 +87,28 @@ pub fn square(b: Bitboard) -> Square {
     b.trailing_zeros() as Square
 }
 
+pub fn populate_files(b: Bitboard) -> Bitboard {
+    let two = b | b.rotate_left(8);
+    let four = two | two.rotate_left(16);
+    let eight = four | four.rotate_left(32);
+
+    eight
+}
+
+// TODO: improve
+pub fn populate_rows(b: Bitboard) -> Bitboard {
+    let twol = b | west_one(b);
+    let fourl = twol | west_one(west_one(twol));
+    let eightl = fourl | west_one(west_one(west_one(west_one(fourl))));
+
+    let twor = b | east_one(b);
+    let fourr = twor | east_one(east_one(twor));
+    let eightr = fourr | east_one(east_one(east_one(east_one(fourr))));
+
+    eightl | eightr
+}
+
+
 ///
 /// \brief calculates the square index of a square
 /// 
@@ -118,3 +140,45 @@ pub fn print_board(b: Bitboard) -> String {
 }
 
 
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    #[test]
+    fn test_populate_rows() {
+        let tests = [
+            (0x_0000_0000_0000_0020_u64, ROW_1),
+            (0x_0000_0001_0000_0020_u64, ROW_1 | ROW_5),
+            (0x_8000_0000_0000_0000_u64, ROW_8),
+            (0x_5001_0000_0000_0000_u64, ROW_8 | ROW_7),
+            (0x_2004_0420_8008_1040_u64, !(0_u64)),
+        ];
+
+        for (input, result) in tests {
+            assert_eq!(populate_rows(input), result);
+        }
+    }
+
+    #[test]
+    fn test_populate_files() {
+        let tests = [
+            (0x_0000_0000_0000_0080_u64, FILE_A),
+            (0x_0000_0000_0000_0040_u64, FILE_B),
+            (0x_0000_0000_0000_0020_u64, FILE_C),
+            (0x_0000_0000_0000_0010_u64, FILE_D),
+            (0x_0000_0000_0000_0008_u64, FILE_E),
+            (0x_0000_0000_0000_0004_u64, FILE_F),
+            (0x_0000_0000_0000_0002_u64, FILE_G),
+            (0x_0000_0000_0000_0001_u64, FILE_H),
+            (0x_0004_0030_0000_0001_u64, FILE_C | FILE_D | FILE_F | FILE_H),
+        ];
+
+        for (input, result) in tests {
+            assert_eq!(populate_files(input), result);
+        }
+    }
+}
+
+
+

+ 8 - 2
src/engine.rs

@@ -251,7 +251,13 @@ impl Engine {
                     let turns = plies / 2;
                     println!("info depth {} score mate {} time {} nodes {} nps {} pv {}", depth, turns, elapsed.as_millis(), nodes, nps, pv);
                     info!("info depth {} score mate {} time {} nodes {} nps {} pv {}", depth, turns, elapsed.as_millis(), nodes, nps, pv);
-                    break;
+                    
+                    /*if depth > 3 {
+                        break;
+                    }*/
+                    /*if plies.abs() * 3 < depth {
+                        break;
+                    }*/
                 }
                 else {
                     println!("info depth {} score cp {} time {} nodes {} nps {} pv {}", depth, cp, elapsed.as_millis(), nodes, nps, pv);
@@ -262,7 +268,7 @@ impl Engine {
             else if let SearchResult::Cancelled(Some((bm, bv))) = search_result {
                 if best_move == Move::Nullmove {
                     best_move = bm;
-                    best_val = bv;
+                    //best_val = bv;
                 }
                 break;
             }

+ 30 - 1
src/evaluate.rs

@@ -68,6 +68,18 @@ pub fn increase_mate_in(mut val: PosValue) -> PosValue {
     val
 }
 
+pub fn decrease_mate_in(mut val: PosValue) -> PosValue {
+    if let Some(turns) = is_mate_in_p1(val) {
+        if turns < 0 {
+            val = mate_in_p1(turns + 1);
+        }
+        if turns > 0 {
+            val = mate_in_p1(turns - 1);
+        }
+    }
+    val
+}
+
 
 fn side_value(game: &Game, side: Side) -> u32 {
     let adv_pawn_mask = match side { WHITE => ROW_7, BLACK => ROW_2 };
@@ -95,7 +107,7 @@ fn knight_value(game: &Game, side: Side) -> PosValue {
 
 fn material_value(game: &Game, side: Side) -> PosValue {
     (game.get_piece(PAWN, side).count_ones() * 100
-        + game.get_piece(KNIGHT, side).count_ones() * 300
+        + game.get_piece(KNIGHT, side).count_ones() * 280
         + game.get_piece(BISHOP, side).count_ones() * 320
         + game.get_piece(ROOK, side).count_ones() * 400
         + game.get_piece(QUEEN, side).count_ones() * 700) as PosValue
@@ -200,3 +212,20 @@ pub fn blocked_pawns(game: &Game, side: Side) -> PosValue {
 
     blocked_pawns.count_ones() as _
 }
+
+
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_mate_values() {
+        let mate_in_three = mate_in_p1(3);
+        let mate_in_four = mate_in_p1(4);
+
+        assert!(mate_in_three > mate_in_four);
+        assert!(mate_in_three > mate_in_four);
+    }
+}
+

+ 5 - 0
src/hash.rs

@@ -67,6 +67,11 @@ impl Cache {
     }
     
     pub fn cache(&mut self, game_pos: &Game, ce: CacheEntry) {
+        if let Some(c) = self.lookup(game_pos) {
+            if c.depth > ce.depth {
+                return;
+            }
+        }
         if self.hashmap.len() > self.max_capacity {
             //let first_key = self.hashmap.keys().next().unwrap().clone();
             //self.hashmap.remove(&first_key);

+ 2 - 14
src/main.rs

@@ -26,20 +26,8 @@ fn main() {
         //.target(Target::Stderr)
         .init();
         */
-    
-    //assert_eq!(std::mem::size_of::<crate::movegen::Move>(), 6);
-
-    /*let mit = mate_in_p1(4);
-    let mis = mate_in_p1(-7);
-    if mit < mis {
-        println!("ohno");
-    }
-    println!("mit: {}", mit);
-    if let Some(t) = is_mate_in_p1(-mit) {
-        println!("t: {}", t);
-    }*/
-
-    let logfile = File::create("/home/nicolas/debug.log").unwrap();
+
+    let logfile = File::create("C:\\Users\\Nicolas\\debug.log").unwrap();
     simplelog::WriteLogger::init(LevelFilter::Info, Config::default(), logfile).unwrap();
 
     let (esend, erecv) = mpsc::channel();

+ 36 - 50
src/search.rs

@@ -59,7 +59,7 @@ pub fn search(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut alp
 
     // use a slight offset for the alpha value in the root node in order to
     // determine possibly multiple good moves
-    const ALPHA_OFFSET: PosValue = 50 as _;
+    const ALPHA_OFFSET: PosValue = 50 as PosValue;
 
     let mut valued_moves: Vec<(Move, PosValue)> = Vec::with_capacity(moves.len());
     let mut cancelled = false;
@@ -69,55 +69,36 @@ pub fn search(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut alp
         //assert_eq!(new_game, *game, );
 
         //info!("searching {}", mov.to_string());
-        let (mut val, ret) = negamax(game, sc, hash, -beta, -alpha, depth - 1);
+        let (mut val, ret) = negamax(game, sc, hash, decrease_mate_in(-beta), decrease_mate_in(-alpha), depth - 1);
+        game.undo_move(undo);
         val = -val;
 
-        if let Some(turns) = is_mate_in_p1(val) {
-            if turns < 0 {
-                val = mate_in_p1(turns - 1);
-            }
-            if turns > 0 {
-                val = mate_in_p1(turns + 1);
-            }
-            if turns == 0 {
-                if val < 0 {
-                    val = mate_in_p1(-1);
-                }
-                else {
-                    val = mate_in_p1(1);
-                }
-            }
-        }
+        val = increase_mate_in(val);
 
         if ret {
             //return (Move::default(), 0);
             cancelled = true;
-            game.undo_move(undo);
             break;
         }
 
-        if val >= mate() {
+        /*if val >= mate_in_p1(1) {
             // mate in 1 --- can't get better than that
             info!("yay mate!");
-            game.undo_move(undo);
-            return SearchResult::Finished(mov, val);
-        }
+            return SearchResult::Finished(mov, increase_mate_in(val));
+        }*/
 
         //info!("searched {} -> {}", mov.to_string(), val);
 
         if val > alpha {
             alpha = val - ALPHA_OFFSET;
-            //info!("updated alpha to {}", alpha);
         }
 
         valued_moves.push((mov, -val));
-        
-        game.undo_move(undo);
     }
 
 
 
-    //info!("movvalues: {:?}", valued_moves.iter().map(|mv| mv.0.to_string() + " - " + &mv.1.to_string()).collect::<Vec<String>>());
+    info!("movvalues: {:?}", valued_moves.iter().map(|mv| mv.0.to_string() + " - " + &mv.1.to_string()).collect::<Vec<String>>());
 
     valued_moves.sort_by_key(|mv| mv.1);
 
@@ -150,10 +131,16 @@ fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut alpha:
             //println!("TABLE HIT!");
             match e.entry_type {
                 EntryType::Value => { return (e.value, false); },
+                //EntryType::Value => { if e.value >= alpha { return (e.value, false); } else { return (alpha, false); } },
                 //EntryType::LowerBound => { if e.value > alpha { return (e.value, false) } },
-                EntryType::LowerBound => { if e.value > alpha { alpha = e.value; } },
+                EntryType::LowerBound => {
+                    if e.value < alpha { return (alpha, false); }
+                    //if e.value >= beta { return (beta, false); }
+                },
                 //EntryType::UpperBound => { if e.value >= beta { return (beta, false); } },
-                EntryType::UpperBound => { if e.value >= beta { return (beta, false); } },
+                EntryType::UpperBound => {
+                    if e.value >= beta { return (beta, false); }
+                },
             }
         }
     }
@@ -171,6 +158,7 @@ fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut alpha:
 
 
     let mut moves = generate_legal_moves(game, game.turn);
+    //info!("nega moves: {:?}", moves.iter().map(|mv| mv.to_string()).collect::<Vec<String>>());
 
     let check = is_check(game, game.turn);
     if moves.len() == 0 {
@@ -185,25 +173,22 @@ fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut alpha:
     }
 
     // Nullmove
-    if !check && depth >= 4 && game_lateness(game) < 80 {
+    /*if !check && depth >= 4 && game_lateness(game) < 80 {
         let nmov = Move::Nullmove;
         let undo = game.apply(nmov);
 
         let (mut val, ret) = negamax(game, sc, hash, -beta, -alpha, depth / 2 - 1);
+        game.undo_move(undo);
         val = -val;
-        val = increase_mate_in(val);
         
         if ret {
-            game.undo_move(undo);
             return (alpha, ret);
         }
 
         if val >= beta {
-            game.undo_move(undo);
             return (beta, false);
         }
-        game.undo_move(undo);
-    }
+    }*/
 
 
     sort_moves(game, hash, &mut moves);
@@ -214,28 +199,29 @@ fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut alpha:
     for mov in moves {
         let undo = game.apply(mov);
 
-        let (mut val, ret) = negamax(game, sc, hash, -beta, -alpha, depth - 1);
+        let (mut val, ret) = negamax(game, sc, hash, decrease_mate_in(-beta), decrease_mate_in(-alpha), depth - 1);
+        game.undo_move(undo);
         val = -val;
-
         val = increase_mate_in(val);
 
         if ret {
-            game.undo_move(undo);
             return (alpha, ret)
         }
 
         if val >= beta {
-            game.undo_move(undo);
-            hash.cache(game, CacheEntry::new_upper(depth, val));
+            //hash.cache(game, CacheEntry::new_upper(depth, val));
             //println!("but ret {}: {}", depth, beta);
+            //info!("{} causes beta cutoff at {} ", mov.to_string(), val);
             return (beta, false);
         }
         if val > alpha {
             alpha = val;//(val as f64 * 0.95) as _;
+            if let Some(p) = is_mate_in_p1(val) {
+                //info!("{} is mate in {} plies: {}", mov.to_string(), p, val);
+            }
             alpha_is_exact = true;
             best_move = mov;
         }
-        game.undo_move(undo);
     }
 
 
@@ -247,7 +233,7 @@ fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut alpha:
     else {
         hash.cache(game, CacheEntry::new_lower(depth, alpha));
     }
-    //info!("best alpha {}", best);
+    //info!("best alpha {}", alpha);
     return (alpha, false);
 }
 
@@ -280,23 +266,21 @@ fn quiescence_search(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache,
 
     for mov in moves {
         let undo = game.apply(mov);
-
-        let (mut val, ret) = quiescence_search(game, sc, hash, -beta, -alpha, depth - 1);
+        let (mut val, ret) = quiescence_search(game, sc, hash, decrease_mate_in(-beta), decrease_mate_in(-alpha), depth - 1);
+        game.undo_move(undo);
         val = -val;
+        val = increase_mate_in(val);
 
         if ret {
-            game.undo_move(undo);
             return (alpha, ret)
         }
 
         if val >= beta {
-            game.undo_move(undo);
             return (beta, false);
         }
         if val > alpha {
             alpha = val;
         }
-        game.undo_move(undo);
     }
     return (alpha, false);
 }
@@ -319,11 +303,11 @@ pub fn perft(game: &mut Game, sc: &mut SearchControl, depth: i32) -> bool {
     for mov in moves {
         let undo = game.apply(mov);
         let do_return = perft(game, sc, depth - 1);
+        game.undo_move(undo);
+
         if do_return {
-            game.undo_move(undo);
             return true;
         }
-        game.undo_move(undo);
     }
 
     return false;
@@ -349,7 +333,9 @@ mod tests {
             let mut game = Game::from_fen_str(position).unwrap();
             for (j, &p_res) in perft_results[i].iter().enumerate() {
                 let depth = j + 1;
-                let mut sc = SearchControl::new(&mut || false, &mut RepetitionTable::new(), depth as _);
+                let mut check_fn = || false;
+                let mut rt = RepetitionTable::new();
+                let mut sc = SearchControl::new(&mut check_fn, &mut rt, depth as _);
                 perft(&mut game, &mut sc, depth as _);
                 assert_eq!(sc.nodes, p_res);
             }