Bladeren bron

adding perft + test

Nicolas Winkler 3 jaren geleden
bovenliggende
commit
921fd5c7b8
4 gewijzigde bestanden met toevoegingen van 76 en 2 verwijderingen
  1. 16 0
      src/engine.rs
  2. 3 0
      src/interface.rs
  3. 1 1
      src/movegen.rs
  4. 56 1
      src/search.rs

+ 16 - 0
src/engine.rs

@@ -32,6 +32,7 @@ pub struct SearchInfo {
     pub winc: Option<isize>,
     pub binc: Option<isize>,
     pub movestogo: Option<isize>,
+    pub perft: bool,
     pub infinite: bool
 }
 
@@ -58,6 +59,7 @@ impl SearchInfo {
             winc: None,
             binc: None,
             movestogo: None,
+            perft: false,
             infinite: false
         }
     }
@@ -182,6 +184,20 @@ impl Engine {
         let mut best_move = Move::default();
         let mut best_val: PosValue;
 
+        if si.perft {
+            if let Some(dep) = si.depth {
+                depth = dep;
+            }
+            let invalid = perft(&mut self.game, &mut sc, depth as i32);
+            if !invalid {
+                let elapsed = before.elapsed();
+                let nodes = sc.nodes;
+                let nps = (nodes as f64 / elapsed.as_nanos() as f64 * 1000000000.0) as i64;
+                println!("info depth {} nodes {} nps {}", depth, nodes, nps);
+            }
+            return;
+        }
+
         let mut alpha = crate::evaluate::MIN_VALUE;
         let mut beta = crate::evaluate::MAX_VALUE;
         let window_size = 50;

+ 3 - 0
src/interface.rs

@@ -102,6 +102,9 @@ fn cmd_go(args: Vec<&str>, _r: &Receiver<InterfaceMsg>, s: &Sender<EngineMsg>) {
         else if arg == "infinite" {
             si.infinite = true;
         }
+        else if arg == "perft" {
+            si.perft = true;
+        }
         else {
             opt_name = Some(arg);
         } 

+ 1 - 1
src/movegen.rs

@@ -48,7 +48,7 @@ pub struct MoveUndo {
 
 impl Default for Move {
     fn default() -> Move {
-        Move::Default{ mov: SimpleMove { from: 0, to: 0 }, piece_type: NO_PIECE, captured: None }
+        Move::Nullmove
     }
 }
 

+ 56 - 1
src/search.rs

@@ -4,7 +4,6 @@ use game::Game;
 use evaluate::*;
 use log::info;
 use rand::prelude::*;
-use zobrist;
 use hash::*;
 
 
@@ -381,3 +380,59 @@ pub fn apply_move(game: &Game, mov: Move) -> Game {
     }
     return new_game;
 }
+
+
+pub fn perft(game: &mut Game, sc: &mut SearchControl, depth: i32) -> bool {
+    let moves = generate_legal_moves(game, game.turn);
+
+    if depth <= 1 {
+        sc.nodes += moves.len();
+        if sc.nodes % 1024 < moves.len() {
+            if (sc.check)() {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    
+    for mov in moves {
+        let undo = game.apply(mov);
+        let do_return = perft(game, sc, depth - 1);
+        if do_return {
+            game.undo_move(undo);
+            return true;
+        }
+        game.undo_move(undo);
+    }
+
+    return false;
+}
+
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    #[test]
+    fn test_move_generation() {
+        let positions = [
+            "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8",
+            "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10"
+        ];
+        let perft_results: [Vec<usize>; 2] = [
+            vec![44, 1486, 62379, 2103487],
+            vec![46, 2079, 89890, 3894594]
+        ];
+
+        for (i, &position) in positions.iter().enumerate() {
+            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{ nodes: 0, check: &mut (|| false), move_history: &mut RepetitionTable::new(), initial_depth: depth as _ };
+                perft(&mut game, &mut sc, depth as _);
+                assert_eq!(sc.nodes, p_res);
+            }
+        }
+    }
+}