]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Prune all negative see moves at low depths
[stockfish] / src / search.cpp
index 9649c2da76b269d00ae9380e1fbfd4c018883fbb..f7718ce442d50136b9508405bc6f3bdb76e34654 100644 (file)
@@ -59,6 +59,10 @@ namespace {
   // Used for debugging SMP code.
   const bool FakeSplit = false;
 
+  // Fast lookup table of sliding pieces indexed by Piece
+  const bool Slidings[18] = { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 };
+  inline bool piece_is_slider(Piece p) { return Slidings[p]; }
+
   // ThreadsManager class is used to handle all the threads related stuff in search,
   // init, starting, parking and, the most important, launching a slave thread at a
   // split point are what this class does. All the access to shared thread data is
@@ -90,7 +94,7 @@ namespace {
     int ActiveThreads;
     volatile bool AllThreadsShouldExit;
     Thread threads[MAX_THREADS];
-    Lock MPLock;
+    Lock MPLock, WaitLock;
     WaitCondition WaitCond[MAX_THREADS];
   };
 
@@ -228,7 +232,10 @@ namespace {
   const Value EasyMoveMargin = Value(0x200);
 
 
-  /// Global variables
+  /// Namespace variables
+
+  // Book object
+  Book OpeningBook;
 
   // Iteration counter
   int Iteration;
@@ -407,12 +414,12 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   UseTimeManagement = !ExactMaxTime && !MaxDepth && !MaxNodes && !InfiniteSearch;
 
   // Look for a book move, only during games, not tests
-  if (UseTimeManagement && get_option_value_bool("OwnBook"))
+  if (UseTimeManagement && Options["OwnBook"].value<bool>())
   {
-      if (get_option_value_string("Book File") != OpeningBook.file_name())
-          OpeningBook.open(get_option_value_string("Book File"));
+      if (Options["Book File"].value<std::string>() != OpeningBook.file_name())
+          OpeningBook.open(Options["Book File"].value<std::string>());
 
-      Move bookMove = OpeningBook.get_move(pos, get_option_value_bool("Best Book Move"));
+      Move bookMove = OpeningBook.get_move(pos, Options["Best Book Move"].value<bool>());
       if (bookMove != MOVE_NONE)
       {
           if (PonderSearch)
@@ -424,41 +431,48 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   }
 
   // Read UCI option values
-  TT.set_size(get_option_value_int("Hash"));
-  if (button_was_pressed("Clear Hash"))
+  TT.set_size(Options["Hash"].value<int>());
+  if (Options["Clear Hash"].value<bool>())
+  {
+      Options["Clear Hash"].set_value("false");
       TT.clear();
+  }
 
-  CheckExtension[1]         = Depth(get_option_value_int("Check Extension (PV nodes)"));
-  CheckExtension[0]         = Depth(get_option_value_int("Check Extension (non-PV nodes)"));
-  SingleEvasionExtension[1] = Depth(get_option_value_int("Single Evasion Extension (PV nodes)"));
-  SingleEvasionExtension[0] = Depth(get_option_value_int("Single Evasion Extension (non-PV nodes)"));
-  PawnPushTo7thExtension[1] = Depth(get_option_value_int("Pawn Push to 7th Extension (PV nodes)"));
-  PawnPushTo7thExtension[0] = Depth(get_option_value_int("Pawn Push to 7th Extension (non-PV nodes)"));
-  PassedPawnExtension[1]    = Depth(get_option_value_int("Passed Pawn Extension (PV nodes)"));
-  PassedPawnExtension[0]    = Depth(get_option_value_int("Passed Pawn Extension (non-PV nodes)"));
-  PawnEndgameExtension[1]   = Depth(get_option_value_int("Pawn Endgame Extension (PV nodes)"));
-  PawnEndgameExtension[0]   = Depth(get_option_value_int("Pawn Endgame Extension (non-PV nodes)"));
-  MateThreatExtension[1]    = Depth(get_option_value_int("Mate Threat Extension (PV nodes)"));
-  MateThreatExtension[0]    = Depth(get_option_value_int("Mate Threat Extension (non-PV nodes)"));
-
-  MinimumSplitDepth       = get_option_value_int("Minimum Split Depth") * ONE_PLY;
-  MaxThreadsPerSplitPoint = get_option_value_int("Maximum Number of Threads per Split Point");
-  MultiPV                 = get_option_value_int("MultiPV");
-  UseLogFile              = get_option_value_bool("Use Search Log");
+  CheckExtension[1]         = Options["Check Extension (PV nodes)"].value<Depth>();
+  CheckExtension[0]         = Options["Check Extension (non-PV nodes)"].value<Depth>();
+  SingleEvasionExtension[1] = Options["Single Evasion Extension (PV nodes)"].value<Depth>();
+  SingleEvasionExtension[0] = Options["Single Evasion Extension (non-PV nodes)"].value<Depth>();
+  PawnPushTo7thExtension[1] = Options["Pawn Push to 7th Extension (PV nodes)"].value<Depth>();
+  PawnPushTo7thExtension[0] = Options["Pawn Push to 7th Extension (non-PV nodes)"].value<Depth>();
+  PassedPawnExtension[1]    = Options["Passed Pawn Extension (PV nodes)"].value<Depth>();
+  PassedPawnExtension[0]    = Options["Passed Pawn Extension (non-PV nodes)"].value<Depth>();
+  PawnEndgameExtension[1]   = Options["Pawn Endgame Extension (PV nodes)"].value<Depth>();
+  PawnEndgameExtension[0]   = Options["Pawn Endgame Extension (non-PV nodes)"].value<Depth>();
+  MateThreatExtension[1]    = Options["Mate Threat Extension (PV nodes)"].value<Depth>();
+  MateThreatExtension[0]    = Options["Mate Threat Extension (non-PV nodes)"].value<Depth>();
+
+  MinimumSplitDepth       = Options["Minimum Split Depth"].value<int>() * ONE_PLY;
+  MaxThreadsPerSplitPoint = Options["Maximum Number of Threads per Split Point"].value<int>();
+  MultiPV                 = Options["MultiPV"].value<int>();
+  UseLogFile              = Options["Use Search Log"].value<bool>();
 
   if (UseLogFile)
-      LogFile.open(get_option_value_string("Search Log Filename").c_str(), std::ios::out | std::ios::app);
+      LogFile.open(Options["Search Log Filename"].value<std::string>().c_str(), std::ios::out | std::ios::app);
 
   read_weights(pos.side_to_move());
 
   // Set the number of active threads
-  int newActiveThreads = get_option_value_int("Threads");
+  int newActiveThreads = Options["Threads"].value<int>();
   if (newActiveThreads != ThreadsMgr.active_threads())
   {
       ThreadsMgr.set_active_threads(newActiveThreads);
       init_eval(ThreadsMgr.active_threads());
   }
 
+  // Wake up needed threads
+  for (int i = 1; i < newActiveThreads; i++)
+      ThreadsMgr.wake_sleeping_thread(i);
+
   // Set thinking time
   int myTime = time[pos.side_to_move()];
   int myIncrement = increment[pos.side_to_move()];
@@ -491,6 +505,9 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   if (UseLogFile)
       LogFile.close();
 
+  // This makes all the threads to go to sleep
+  ThreadsMgr.set_active_threads(1);
+
   return !Quit;
 }
 
@@ -644,7 +661,7 @@ namespace {
              << " time " << current_search_time() << endl;
 
     // Print the best move and the ponder move to the standard output
-    if (pv[0] == MOVE_NONE)
+    if (pv[0] == MOVE_NONE || MultiPV > 1)
     {
         pv[0] = rml.move(0);
         pv[1] = MOVE_NONE;
@@ -1270,6 +1287,17 @@ split_point_start: // At split points actual search starts from here
 
               continue;
           }
+
+          // Prune neg. see moves at low depths
+          if (   predictedDepth < 2 * ONE_PLY
+              && bestValue > value_mated_in(PLY_MAX)
+              && pos.see_sign(move) < 0)
+          {
+              if (SpNode)
+                  lock_grab(&(sp->lock));
+
+              continue;
+          }
       }
 
       // Step 13. Make the move
@@ -1924,7 +1952,7 @@ split_point_start: // At split points actual search starts from here
     int t = current_search_time();
 
     //  Poll for input
-    if (Bioskey())
+    if (data_available())
     {
         // We are line oriented, don't read single chars
         std::string command;
@@ -2185,9 +2213,7 @@ split_point_start: // At split points actual search starts from here
 
         // If we are not thinking, wait for a condition to be signaled
         // instead of wasting CPU time polling for work.
-        while (   threadID >= ActiveThreads
-               || threads[threadID].state == THREAD_INITIALIZING
-               || (!sp && threads[threadID].state == THREAD_AVAILABLE))
+        while (threadID >= ActiveThreads || threads[threadID].state == THREAD_INITIALIZING)
         {
             assert(!sp);
             assert(threadID != 0);
@@ -2195,21 +2221,14 @@ split_point_start: // At split points actual search starts from here
             if (AllThreadsShouldExit)
                 break;
 
-            lock_grab(&MPLock);
+            threads[threadID].state = THREAD_AVAILABLE;
 
-            // Retest condition under lock protection
-            if (!(   threadID >= ActiveThreads
-                  || threads[threadID].state == THREAD_INITIALIZING
-                  || (!sp && threads[threadID].state == THREAD_AVAILABLE)))
-            {
-                lock_release(&MPLock);
-                continue;
-            }
+            lock_grab(&WaitLock);
 
-            // Put thread to sleep
-            threads[threadID].state = THREAD_AVAILABLE;
-            cond_wait(&WaitCond[threadID], &MPLock);
-            lock_release(&MPLock);
+            if (threadID >= ActiveThreads || threads[threadID].state == THREAD_INITIALIZING)
+                cond_wait(&WaitCond[threadID], &WaitLock);
+
+            lock_release(&WaitLock);
         }
 
         // If this thread has been assigned work, launch a search
@@ -2269,6 +2288,7 @@ split_point_start: // At split points actual search starts from here
 
     // Initialize global locks
     lock_init(&MPLock);
+    lock_init(&WaitLock);
 
     for (i = 0; i < MAX_THREADS; i++)
         cond_init(&WaitCond[i]);
@@ -2304,7 +2324,7 @@ split_point_start: // At split points actual search starts from here
         if (!ok)
         {
             cout << "Failed to create thread number " << i << endl;
-            Application::exit_with_failure();
+            exit(EXIT_FAILURE);
         }
 
         // Wait until the thread has finished launching and is gone to sleep
@@ -2332,6 +2352,7 @@ split_point_start: // At split points actual search starts from here
         for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
             lock_destroy(&(threads[i].splitPoints[j].lock));
 
+    lock_destroy(&WaitLock);
     lock_destroy(&MPLock);
 
     // Now we can safely destroy the wait conditions
@@ -2497,8 +2518,6 @@ split_point_start: // At split points actual search starts from here
             assert(i == master || threads[i].state == THREAD_BOOKED);
 
             threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop()
-            if (i != master)
-                wake_sleeping_thread(i);
         }
 
     // Everything is set up. The master thread enters the idle loop, from
@@ -2527,9 +2546,9 @@ split_point_start: // At split points actual search starts from here
 
   void ThreadsManager::wake_sleeping_thread(int threadID) {
 
-     lock_grab(&MPLock);
+     lock_grab(&WaitLock);
      cond_signal(&WaitCond[threadID]);
-     lock_release(&MPLock);
+     lock_release(&WaitLock);
   }