Implemented perft
authorJoona Kiiski <joona.kiiski@gmail.com>
Fri, 2 Oct 2009 04:09:24 +0000 (07:09 +0300)
committerMarco Costalba <mcostalba@gmail.com>
Sun, 1 Nov 2009 16:05:00 +0000 (17:05 +0100)
Patch from Joona with extension to benchmark and inclusion
of Depth(0) moves generation by me.

Note that to test also qsearch and in particulary checks
generations a change in the end condition is needed.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
src/benchmark.cpp
src/main.cpp
src/search.cpp
src/search.h
src/uci.cpp

index b90d3fcb151f6172f7ea22a2b81d766778acd050..d79726497e085d3bef9d0f80b695a9b4d54b405b 100644 (file)
@@ -104,7 +104,7 @@ void benchmark(const string& commandLine) {
 
   if (limitType == "time")
       secsPerPos = val * 1000;
-  else if (limitType == "depth")
+  else if (limitType == "depth" || limitType == "perft")
       maxDepth = val;
   else
       maxNodes = val;
@@ -153,7 +153,9 @@ void benchmark(const string& commandLine) {
       int dummy[2] = {0, 0};
       Position pos(*it);
       cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
-      if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
+      if (limitType == "perft")
+          totalNodes += perft(pos, maxDepth * OnePly);
+      else if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
           break;
       totalNodes += nodes_searched();
   }
index c57b1f414ca23fdf38385787a373b80631a6acb4..47a03ad160ca8a22b003b40f6ca6897cdd040460 100644 (file)
@@ -63,7 +63,7 @@ int main(int argc, char *argv[]) {
       if (string(argv[1]) != "bench" || argc < 4 || argc > 8)
           cout << "Usage: stockfish bench <hash size> <threads> "
                << "[time = 60s] [fen positions file = default] "
-               << "[time, depth or node limited = time] "
+               << "[time, depth, perft or node limited = time] "
                << "[timing file name = none]" << endl;
       else
       {
index d073b7da31a2e14056bee54e2c4d45dbfd8b0ba7..3e4341c09031a73e2310a9b1b2e11044ce46beda 100644 (file)
@@ -326,6 +326,32 @@ namespace {
 //// Functions
 ////
 
+
+/// perft() is our utility to verify move generation is bug free. All the
+/// legal moves up to given depth are generated and counted and the sum returned.
+
+int perft(Position& pos, Depth depth)
+{
+    if (depth <= Depth(0)) // Replace with '<' to test also qsearch
+      return 1;
+
+    Move move;
+    MovePicker mp = MovePicker(pos, MOVE_NONE, depth, H);
+    Bitboard dcCandidates = mp.discovered_check_candidates();
+    int sum = 0;
+
+    // Loop through all legal moves
+    while ((move = mp.get_next_move()) != MOVE_NONE)
+    {
+      StateInfo st;
+      pos.do_move(move, st, dcCandidates);
+      sum += perft(pos, depth - OnePly);
+      pos.undo_move(move);
+    }
+    return sum;
+}
+
+
 /// think() is the external interface to Stockfish's search, and is called when
 /// the program receives the UCI 'go' command. It initializes various
 /// search-related global variables, and calls root_search(). It returns false
@@ -447,7 +473,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
       if (movesToGo == 1)
       {
           MaxSearchTime = myTime / 2;
-          AbsoluteMaxSearchTime = 
+          AbsoluteMaxSearchTime =
              (myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4);
       } else {
           MaxSearchTime = myTime / Min(movesToGo, 20);
@@ -976,7 +1002,7 @@ namespace {
                 std::cout << std::endl;
 
                 if (UseLogFile)
-                    LogFile << pretty_pv(pos, current_search_time(), Iteration, nodes_searched(), value, 
+                    LogFile << pretty_pv(pos, current_search_time(), Iteration, nodes_searched(), value,
                                          ((value >= beta)? VALUE_TYPE_LOWER
                                           : ((value <= alpha)? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT)),
                                          ss[0].pv)
index 91f484a1a344a4d400ef792817f8d2f761df015d..e87d0d2c2c33020f4c4b992f19872abe5dde75a1 100644 (file)
@@ -69,6 +69,7 @@ extern void stop_threads();
 extern bool think(const Position &pos, bool infinite, bool ponder, int side_to_move,
                   int time[], int increment[], int movesToGo, int maxDepth,
                   int maxNodes, int maxTime, Move searchMoves[]);
+extern int perft(Position &pos, Depth depth);
 extern int64_t nodes_searched();
 
 
index 36848d83cd387b4f91ecdbc3df3bfb8f80aa021e..b90240961e56ca803e2f3d30fdf3b7044f4f3a9e 100644 (file)
@@ -61,6 +61,7 @@ namespace {
   void set_option(UCIInputParser& uip);
   void set_position(UCIInputParser& uip);
   bool go(UCIInputParser& uip);
+  void perft(UCIInputParser& uip);
 }
 
 
@@ -155,6 +156,8 @@ namespace {
         cout << "key: " << hex << RootPosition.get_key()
              << "\nmaterial key: " << RootPosition.get_material_key()
              << "\npawn key: " << RootPosition.get_pawn_key() << endl;
+    else if (token == "perft")
+        perft(uip);
     else
     {
         cout << "Unknown command: " << command << endl;
@@ -318,4 +321,24 @@ namespace {
                  time, inc, movesToGo, depth, nodes, moveTime, searchMoves);
   }
 
+  void perft(UCIInputParser& uip) {
+
+    string token;
+    int depth = 0;
+
+    while (!uip.eof())
+    {
+        uip >> token;
+
+        if (token == "depth")
+            uip >> depth;
+    }
+    Position pos = RootPosition;
+    int tm = get_system_time();
+    int n = perft(pos, depth * OnePly);
+    tm = get_system_time() - tm;
+    std::cout << "\nNodes " << n
+              << "\nTime (ms) " << tm
+              << "\nNodes/second " << (int)(n/(tm/1000.0)) << std::endl;
+  }
 }