]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Use special null move technique in low depth.
[stockfish] / src / search.cpp
index 7e501fc41fa1278b143222641ffe414085a690b5..944d9c6926a6b8a4e71eb0617f03743e5f380e0a 100644 (file)
@@ -28,6 +28,7 @@
 #include <iostream>
 #include <sstream>
 
+#include "bitcount.h"
 #include "book.h"
 #include "evaluate.h"
 #include "history.h"
@@ -189,12 +190,19 @@ namespace {
   // Remaining depth:                 1 ply         1.5 ply       2 ply         2.5 ply       3 ply         3.5 ply
   const Value RazorApprMargins[6] = { Value(0x520), Value(0x300), Value(0x300), Value(0x300), Value(0x300), Value(0x300) };
 
-  // The main transposition table
-  TranspositionTable TT;
-
 
   /// Variables initialized by UCI options
 
+  // Adjustable playing strength
+  int Slowdown = 0;
+  const int SlowdownArray[32] = {
+    19, 41, 70, 110, 160, 230, 320, 430, 570, 756, 1000, 1300, 1690, 2197,
+    2834, 3600, 4573, 5809, 7700, 9863, 12633, 16181, 20726, 26584, 34005,
+    43557, 55792, 71463, 91536, 117247, 150180, 192363
+  };
+  int Strength;
+  const int MaxStrength = 25;
+
   // Minimum number of full depth (i.e. non-reduced) moves at PV and non-PV nodes
   int LMRPVMoves, LMRNonPVMoves; // heavy SMP read access for the latter
 
@@ -202,10 +210,10 @@ namespace {
   Depth ThreatDepth; // heavy SMP read access
 
   // Last seconds noise filtering (LSN)
-  bool UseLSNFiltering;
-  bool looseOnTime = false;
-  int LSNTime; // In milliseconds
-  Value LSNValue;
+  const bool UseLSNFiltering = true;
+  const int LSNTime = 4000; // In milliseconds
+  const Value LSNValue = value_from_centipawns(200);
+  bool loseOnTime = false;
 
   // Extensions. Array index 0 is used at non-PV nodes, index 1 at PV nodes.
   // There is heavy SMP read access on these arrays
@@ -226,8 +234,7 @@ namespace {
   // Time managment variables
   int SearchStartTime;
   int MaxNodes, MaxDepth;
-  int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime;
-  Move EasyMove;
+  int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
   int RootMoveNumber;
   bool InfiniteSearch;
   bool PonderSearch;
@@ -237,8 +244,6 @@ namespace {
   bool FailHigh;
   bool FailLow;
   bool Problem;
-  bool PonderingEnabled;
-  int ExactMaxTime;
 
   // Show current line?
   bool ShowCurrentLine;
@@ -271,6 +276,9 @@ namespace {
   int NodesSincePoll;
   int NodesBetweenPolls = 30000;
 
+  // History table
+  History H;
+
 
   /// Functions
 
@@ -281,7 +289,7 @@ namespace {
   Value qsearch(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID);
   void sp_search(SplitPoint* sp, int threadID);
   void sp_search_pv(SplitPoint* sp, int threadID);
-  void init_node(SearchStack ss[], int ply, int threadID);
+  void init_node(const Position& pos, SearchStack ss[], int ply, int threadID);
   void update_pv(SearchStack ss[], int ply);
   void sp_update_pv(SearchStack* pss, SearchStack ss[], int ply);
   bool connected_moves(const Position& pos, Move m1, Move m2);
@@ -289,11 +297,12 @@ namespace {
   bool move_is_killer(Move m, const SearchStack& ss);
   Depth extension(const Position& pos, Move m, bool pvNode, bool capture, bool check, bool singleReply, bool mateThreat, bool* dangerous);
   bool ok_to_do_nullmove(const Position& pos);
-  bool ok_to_prune(const Position& pos, Move m, Move threat, Depth d, const History& H);
+  bool ok_to_prune(const Position& pos, Move m, Move threat, Depth d);
   bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply);
   bool ok_to_history(const Position& pos, Move m);
-  void update_history(const Position& pos, Move m, Depth depth, History& H, Move movesSearched[], int moveCount);
+  void update_history(const Position& pos, Move m, Depth depth, Move movesSearched[], int moveCount);
   void update_killers(Move m, SearchStack& ss);
+  void slowdown(const Position& pos);
 
   bool fail_high_ply_1();
   int current_search_time();
@@ -354,7 +363,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
   // Initialize global search variables
   Idle = false;
   SearchStartTime = get_system_time();
-  EasyMove = MOVE_NONE;
   for (int i = 0; i < THREAD_MAX; i++)
   {
       Threads[i].nodes = 0ULL;
@@ -374,9 +382,12 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
   // Read UCI option values
   TT.set_size(get_option_value_int("Hash"));
   if (button_was_pressed("Clear Hash"))
+  {
       TT.clear();
+      loseOnTime = false; // reset at the beginning of a new game
+  }
 
-  PonderingEnabled = get_option_value_bool("Ponder");
+  bool PonderingEnabled = get_option_value_bool("Ponder");
   MultiPV = get_option_value_int("MultiPV");
 
   CheckExtension[1] = Depth(get_option_value_int("Check Extension (PV nodes)"));
@@ -407,16 +418,15 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
   if (UseLogFile)
       LogFile.open(get_option_value_string("Search Log Filename").c_str(), std::ios::out | std::ios::app);
 
-  UseLSNFiltering = get_option_value_bool("LSN filtering");
-  LSNTime = get_option_value_int("LSN Time Margin (sec)") * 1000;
-  LSNValue = value_from_centipawns(get_option_value_int("LSN Value Margin"));
-
   MinimumSplitDepth = get_option_value_int("Minimum Split Depth") * OnePly;
   MaxThreadsPerSplitPoint = get_option_value_int("Maximum Number of Threads per Split Point");
 
   read_weights(pos.side_to_move());
 
-  int newActiveThreads = get_option_value_int("Threads");
+  // Set the number of active threads. If UCI_LimitStrength is enabled, never
+  // use more than one thread.
+  int newActiveThreads =
+    get_option_value_bool("UCI_LimitStrength")? 1 : get_option_value_int("Threads");
   if (newActiveThreads != ActiveThreads)
   {
       ActiveThreads = newActiveThreads;
@@ -429,6 +439,19 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
   for (int i = 1; i < ActiveThreads; i++)
       assert(thread_is_available(i, 0));
 
+  // Set playing strength
+  if (get_option_value_bool("UCI_LimitStrength"))
+  {
+      Strength = (get_option_value_int("UCI_Elo") - 2100) / 25;
+      Slowdown =
+        (Strength == MaxStrength)? 0 : SlowdownArray[Max(0, 31-Strength)];
+  }
+  else
+  {
+      Strength = MaxStrength;
+      Slowdown = 0;
+  }
+
   // Set thinking time
   int myTime = time[side_to_move];
   int myIncrement = increment[side_to_move];
@@ -473,10 +496,16 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
       NodesBetweenPolls = Min(MaxNodes, 30000);
       InfiniteSearch = true; // HACK
   }
+  else if (Slowdown) {
+      if (Slowdown > 50000) NodesBetweenPolls = 30;
+      else if (Slowdown > 10000) NodesBetweenPolls = 100;
+      else if (Slowdown > 1000) NodesBetweenPolls = 500;
+      else if (Slowdown > 100) NodesBetweenPolls = 3000;
+      else NodesBetweenPolls = 15000;
+  }
   else
       NodesBetweenPolls = 30000;
 
-
   // Write information to search log file
   if (UseLogFile)
       LogFile << "Searching: " << pos.to_fen() << std::endl
@@ -488,17 +517,19 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
 
 
   // We're ready to start thinking. Call the iterative deepening loop function
-  if (!looseOnTime)
+  //
+  // FIXME we really need to cleanup all this LSN ugliness
+  if (!loseOnTime)
   {
       Value v = id_loop(pos, searchMoves);
-      looseOnTime = (   UseLSNFiltering
+      loseOnTime = (   UseLSNFiltering
                      && myTime < LSNTime
                      && myIncrement == 0
                      && v < -LSNValue);
   }
   else
   {
-      looseOnTime = false; // reset for next match
+      loseOnTime = false; // reset for next match
       while (SearchStartTime + myTime + 1000 > get_system_time())
           ; // wait here
       id_loop(pos, searchMoves); // to fail gracefully
@@ -629,9 +660,7 @@ namespace {
 
     // Initialize
     TT.new_search();
-    for (int i = 0; i < THREAD_MAX; i++)
-        Threads[i].H.clear();
-
+    H.clear();
     for (int i = 0; i < 3; i++)
     {
         ss[i].init(i);
@@ -640,7 +669,7 @@ namespace {
     IterationInfo[1] = IterationInfoType(rml.get_move_score(0), rml.get_move_score(0));
     Iteration = 1;
 
-    EasyMove = rml.scan_for_easy_move();
+    Move EasyMove = rml.scan_for_easy_move();
 
     // Iterative deepening loop
     while (Iteration < PLY_MAX)
@@ -860,8 +889,9 @@ namespace {
                       << " currmovenumber " << i + 1 << std::endl;
 
         // Decide search depth for this move
+        bool moveIsCapture = pos.move_is_capture(move);
         bool dangerous;
-        ext = extension(pos, move, true, pos.move_is_capture(move), pos.move_is_check(move), false, false, &dangerous);
+        ext = extension(pos, move, true, moveIsCapture, pos.move_is_check(move), false, false, &dangerous);
         newDepth = (Iteration - 2) * OnePly + ext + InitialDepth;
 
         // Make the move, and search it
@@ -885,15 +915,30 @@ namespace {
         }
         else
         {
-            value = -search(pos, ss, -alpha, newDepth, 1, true, 0);
+            if (   newDepth >= 3*OnePly
+                && i >= MultiPV + LMRPVMoves - 2 // Remove -2 and decrease LMRPVMoves instead ?
+                && !dangerous
+                && !moveIsCapture
+                && !move_is_promotion(move)
+                && !move_is_castle(move))
+            {
+                ss[0].reduction = OnePly;
+                value = -search(pos, ss, -alpha, newDepth-OnePly, 1, true, 0);
+            } else
+                value = alpha + 1; // Just to trigger next condition
+
             if (value > alpha)
             {
-                // Fail high! Set the boolean variable FailHigh to true, and
-                // re-search the move with a big window. The variable FailHigh is
-                // used for time managment: We try to avoid aborting the search
-                // prematurely during a fail high research.
-                FailHigh = true;
-                value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
+                value = -search(pos, ss, -alpha, newDepth, 1, true, 0);
+                if (value > alpha)
+                {
+                    // Fail high! Set the boolean variable FailHigh to true, and
+                    // re-search the move with a big window. The variable FailHigh is
+                    // used for time managment: We try to avoid aborting the search
+                    // prematurely during a fail high research.
+                    FailHigh = true;
+                    value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
+                }
             }
         }
 
@@ -927,6 +972,7 @@ namespace {
             // Update PV
             rml.set_move_score(i, value);
             update_pv(ss, 0);
+            TT.extract_pv(pos, ss[0].pv);
             rml.set_move_pv(i, ss[0].pv);
 
             if (MultiPV == 1)
@@ -940,6 +986,8 @@ namespace {
                 // Print search information to the standard output
                 std::cout << "info depth " << Iteration
                           << " score " << value_to_string(value)
+                          << ((value >= beta)?
+                              " lowerbound" : ((value <= alpha)? " upperbound" : ""))
                           << " time " << current_search_time()
                           << " nodes " << nodes_searched()
                           << " nps " << nps()
@@ -1008,7 +1056,7 @@ namespace {
 
     // Initialize, and make an early exit in case of an aborted search,
     // an instant draw, maximum ply reached, etc.
-    init_node(ss, ply, threadID);
+    init_node(pos, ss, ply, threadID);
 
     // After init_node() that calls poll()
     if (AbortSearch || thread_should_stop(threadID))
@@ -1043,7 +1091,7 @@ namespace {
 
     // Initialize a MovePicker object for the current position, and prepare
     // to search all moves
-    MovePicker mp = MovePicker(pos, ttMove, depth, Threads[threadID].H, &ss[ply]);
+    MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply]);
 
     Move move, movesSearched[256];
     int moveCount = 0;
@@ -1082,11 +1130,11 @@ namespace {
       {
         // Try to reduce non-pv search depth by one ply if move seems not problematic,
         // if the move fails high will be re-searched at full depth.
-        if (    depth >= 2*OnePly
+        if (    depth >= 3*OnePly
             &&  moveCount >= LMRPVMoves
             && !dangerous
             && !moveIsCapture
-            && !move_promotion(move)
+            && !move_is_promotion(move)
             && !move_is_castle(move)
             && !move_is_killer(move, ss[ply]))
         {
@@ -1172,7 +1220,7 @@ namespace {
         Move m = ss[ply].pv[ply];
         if (ok_to_history(pos, m)) // Only non capture moves are considered
         {
-            update_history(pos, m, depth, Threads[threadID].H, movesSearched, moveCount);
+            update_history(pos, m, depth, movesSearched, moveCount);
             update_killers(m, ss[ply]);
         }
         TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, depth, m);
@@ -1198,7 +1246,7 @@ namespace {
 
     // Initialize, and make an early exit in case of an aborted search,
     // an instant draw, maximum ply reached, etc.
-    init_node(ss, ply, threadID);
+    init_node(pos, ss, ply, threadID);
 
     // After init_node() that calls poll()
     if (AbortSearch || thread_should_stop(threadID))
@@ -1233,61 +1281,21 @@ namespace {
     bool mateThreat = false;
     bool isCheck = pos.is_check();
 
-    // Null move search
-    if (    allowNullmove
-        &&  depth > OnePly
-        && !isCheck
-        && !value_is_mate(beta)
-        &&  ok_to_do_nullmove(pos)
-        &&  approximateEval >= beta - NullMoveMargin)
-    {
-        ss[ply].currentMove = MOVE_NULL;
-
-        StateInfo st;
-        pos.do_null_move(st);
-        int R = (depth >= 5 * OnePly ? 4 : 3); // Null move dynamic reduction
-
-        Value nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID);
+    bool useNullMove = (    allowNullmove
+                        //&&  depth > OnePly
+                        && !isCheck
+                        && !value_is_mate(beta)
+                        &&  ok_to_do_nullmove(pos)
+                        &&  approximateEval >= beta - NullMoveMargin);
 
-        pos.undo_null_move();
-
-        if (value_is_mate(nullValue))
-        {
-            /* Do not return unproven mates */
-        }
-        else if (nullValue >= beta)
-        {
-            if (depth < 6 * OnePly)
-                return beta;
-
-            // Do zugzwang verification search
-            Value v = search(pos, ss, beta, depth-5*OnePly, ply, false, threadID);
-            if (v >= beta)
-                return beta;
-        } else {
-            // The null move failed low, which means that we may be faced with
-            // some kind of threat. If the previous move was reduced, check if
-            // the move that refuted the null move was somehow connected to the
-            // move which was reduced. If a connection is found, return a fail
-            // low score (which will cause the reduced move to fail high in the
-            // parent node, which will trigger a re-search with full depth).
-            if (nullValue == value_mated_in(ply + 2))
-                mateThreat = true;
-
-            ss[ply].threatMove = ss[ply + 1].currentMove;
-            if (   depth < ThreatDepth
-                && ss[ply - 1].reduction
-                && connected_moves(pos, ss[ply - 1].currentMove, ss[ply].threatMove))
-                return beta - 1;
-        }
-    }
     // Null move search not allowed, try razoring
-    else if (   !value_is_mate(beta)
-             && depth < RazorDepth
-             && approximateEval < beta - RazorApprMargins[int(depth) - 2]
-             && ss[ply - 1].currentMove != MOVE_NULL
-             && ttMove == MOVE_NONE
-             && !pos.has_pawn_on_7th(pos.side_to_move()))
+    if (    !useNullMove
+         && !value_is_mate(beta)
+         && depth < RazorDepth
+         && approximateEval < beta - RazorApprMargins[int(depth) - 2]
+         && ss[ply - 1].currentMove != MOVE_NULL
+         && ttMove == MOVE_NONE
+         && !pos.has_pawn_on_7th(pos.side_to_move()))
     {
         Value v = qsearch(pos, ss, beta-1, beta, Depth(0), ply, threadID);
         if (v < beta - RazorMargins[int(depth) - 2])
@@ -1304,7 +1312,7 @@ namespace {
 
     // Initialize a MovePicker object for the current position, and prepare
     // to search all moves.
-    MovePicker mp = MovePicker(pos, ttMove, depth, Threads[threadID].H, &ss[ply]);
+    MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply], useNullMove);
 
     Move move, movesSearched[256];
     int moveCount = 0;
@@ -1320,6 +1328,48 @@ namespace {
            && (move = mp.get_next_move()) != MOVE_NONE
            && !thread_should_stop(threadID))
     {
+
+      // Null move search
+      if (move == MOVE_NULL)
+      {
+          ss[ply].currentMove = MOVE_NULL;
+
+          StateInfo st;
+          pos.do_null_move(st);
+          int R = (depth >= 5 * OnePly ? 4 : 3); // Null move dynamic reduction
+
+          Value nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID);
+
+          pos.undo_null_move();
+
+          if (nullValue >= beta)
+          {
+              if (depth < 6 * OnePly)
+                  return beta;
+
+              // Do zugzwang verification search
+              Value v = search(pos, ss, beta, depth-5*OnePly, ply, false, threadID);
+              if (v >= beta)
+                  return beta;
+          } else {
+              // The null move failed low, which means that we may be faced with
+              // some kind of threat. If the previous move was reduced, check if
+              // the move that refuted the null move was somehow connected to the
+              // move which was reduced. If a connection is found, return a fail
+              // low score (which will cause the reduced move to fail high in the
+              // parent node, which will trigger a re-search with full depth).
+              if (nullValue == value_mated_in(ply + 2))
+                  mateThreat = true;
+
+              ss[ply].threatMove = ss[ply + 1].currentMove;
+              if (   depth < ThreatDepth
+                  && ss[ply - 1].reduction
+                  && connected_moves(pos, ss[ply - 1].currentMove, ss[ply].threatMove))
+                  return beta - 1;
+          }
+          continue;
+      }
+
       assert(move_is_ok(move));
 
       bool singleReply = (isCheck && mp.number_of_moves() == 1);
@@ -1337,11 +1387,11 @@ namespace {
       if (    useFutilityPruning
           && !dangerous
           && !moveIsCapture
-          && !move_promotion(move))
+          && !move_is_promotion(move))
       {
           // History pruning. See ok_to_prune() definition
           if (   moveCount >= 2 + int(depth)
-              && ok_to_prune(pos, move, ss[ply].threatMove, depth, Threads[threadID].H))
+              && ok_to_prune(pos, move, ss[ply].threatMove, depth))
               continue;
 
           // Value based pruning
@@ -1366,11 +1416,11 @@ namespace {
 
       // Try to reduce non-pv search depth by one ply if move seems not problematic,
       // if the move fails high will be re-searched at full depth.
-      if (    depth >= 2*OnePly
+      if (    depth >= 3*OnePly
           &&  moveCount >= LMRNonPVMoves
           && !dangerous
           && !moveIsCapture
-          && !move_promotion(move)
+          && !move_is_promotion(move)
           && !move_is_castle(move)
           && !move_is_killer(move, ss[ply]))
       {
@@ -1431,7 +1481,7 @@ namespace {
         Move m = ss[ply].pv[ply];
         if (ok_to_history(pos, m)) // Only non capture moves are considered
         {
-            update_history(pos, m, depth, Threads[threadID].H, movesSearched, moveCount);
+            update_history(pos, m, depth, movesSearched, moveCount);
             update_killers(m, ss[ply]);
         }
         TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, depth, m);
@@ -1458,7 +1508,7 @@ namespace {
 
     // Initialize, and make an early exit in case of an aborted search,
     // an instant draw, maximum ply reached, etc.
-    init_node(ss, ply, threadID);
+    init_node(pos, ss, ply, threadID);
 
     // After init_node() that calls poll()
     if (AbortSearch || thread_should_stop(threadID))
@@ -1494,7 +1544,6 @@ namespace {
     else if (tte && tte->type() == VALUE_TYPE_EVAL)
     {
         // Use the cached evaluation score if possible
-        assert(tte->value() == evaluate(pos, ei, threadID));
         assert(ei.futilityMargin == Value(0));
 
         staticValue = tte->value();
@@ -1524,7 +1573,7 @@ namespace {
     // Initialize a MovePicker object for the current position, and prepare
     // to search the moves.  Because the depth is <= 0 here, only captures,
     // queen promotions and checks (only if depth == 0) will be generated.
-    MovePicker mp = MovePicker(pos, ttMove, depth, Threads[threadID].H);
+    MovePicker mp = MovePicker(pos, ttMove, depth, H);
     Move move;
     int moveCount = 0;
     Bitboard dcCandidates = mp.discovered_check_candidates();
@@ -1545,7 +1594,7 @@ namespace {
       if (   enoughMaterial
           && !isCheck
           && !pvNode
-          && !move_promotion(move)
+          && !move_is_promotion(move)
           && !pos.move_is_check(move, dcCandidates)
           && !pos.move_is_passed_pawn_push(move))
       {
@@ -1566,10 +1615,8 @@ namespace {
 
       // Don't search captures and checks with negative SEE values
       if (   !isCheck
-          && !move_promotion(move)
-          && (pos.midgame_value_of_piece_on(move_from(move)) >
-              pos.midgame_value_of_piece_on(move_to(move)))
-          &&  pos.see(move) < 0)
+          && !move_is_promotion(move)
+          &&  pos.see_sign(move) < 0)
           continue;
 
       // Make and search the move.
@@ -1663,9 +1710,9 @@ namespace {
       if (    useFutilityPruning
           && !dangerous
           && !moveIsCapture
-          && !move_promotion(move)
+          && !move_is_promotion(move)
           &&  moveCount >= 2 + int(sp->depth)
-          &&  ok_to_prune(pos, move, ss[sp->ply].threatMove, sp->depth, Threads[threadID].H))
+          &&  ok_to_prune(pos, move, ss[sp->ply].threatMove, sp->depth))
         continue;
 
       // Make and search the move.
@@ -1677,7 +1724,7 @@ namespace {
       if (   !dangerous
           &&  moveCount >= LMRNonPVMoves
           && !moveIsCapture
-          && !move_promotion(move)
+          && !move_is_promotion(move)
           && !move_is_castle(move)
           && !move_is_killer(move, ss[sp->ply]))
       {
@@ -1780,7 +1827,7 @@ namespace {
       if (   !dangerous
           &&  moveCount >= LMRPVMoves
           && !moveIsCapture
-          && !move_promotion(move)
+          && !move_is_promotion(move)
           && !move_is_castle(move)
           && !move_is_killer(move, ss[sp->ply]))
       {
@@ -2048,11 +2095,14 @@ namespace {
   // NodesBetweenPolls nodes, init_node() also calls poll(), which polls
   // for user input and checks whether it is time to stop the search.
 
-  void init_node(SearchStack ss[], int ply, int threadID) {
+  void init_node(const Position& pos, SearchStack ss[], int ply, int threadID) {
 
     assert(ply >= 0 && ply < PLY_MAX);
     assert(threadID >= 0 && threadID < ActiveThreads);
 
+    if (Slowdown && Iteration >= 3)
+      slowdown(pos);
+
     Threads[threadID].nodes++;
 
     if (threadID == 0)
@@ -2207,25 +2257,29 @@ namespace {
     assert(m != MOVE_NONE);
 
     Depth result = Depth(0);
-    *dangerous = check || singleReply || mateThreat;
+    *dangerous = check | singleReply | mateThreat;
 
-    if (check)
-        result += CheckExtension[pvNode];
+    if (*dangerous)
+    {
+        if (check)
+            result += CheckExtension[pvNode];
 
-    if (singleReply)
-        result += SingleReplyExtension[pvNode];
+        if (singleReply)
+            result += SingleReplyExtension[pvNode];
 
-    if (mateThreat)
-        result += MateThreatExtension[pvNode];
+        if (mateThreat)
+            result += MateThreatExtension[pvNode];
+    }
 
     if (pos.type_of_piece_on(move_from(m)) == PAWN)
     {
-        if (pos.move_is_pawn_push_to_7th(m))
+        Color c = pos.side_to_move();
+        if (relative_rank(c, move_to(m)) == RANK_7)
         {
             result += PawnPushTo7thExtension[pvNode];
             *dangerous = true;
         }
-        if (pos.move_is_passed_pawn_push(m))
+        if (pos.pawn_is_passed(c, move_to(m)))
         {
             result += PassedPawnExtension[pvNode];
             *dangerous = true;
@@ -2236,7 +2290,7 @@ namespace {
         && pos.type_of_piece_on(move_to(m)) != PAWN
         && (  pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
             - pos.midgame_value_of_piece_on(move_to(m)) == Value(0))
-        && !move_promotion(m)
+        && !move_is_promotion(m)
         && !move_is_ep(m))
     {
         result += PawnEndgameExtension[pvNode];
@@ -2246,7 +2300,7 @@ namespace {
     if (   pvNode
         && capture
         && pos.type_of_piece_on(move_to(m)) != PAWN
-        && pos.see(m) >= 0)
+        && pos.see_sign(m) >= 0)
     {
         result += OnePly/2;
         *dangerous = true;
@@ -2274,11 +2328,11 @@ namespace {
   // non-tactical moves late in the move list close to the leaves are
   // candidates for pruning.
 
-  bool ok_to_prune(const Position& pos, Move m, Move threat, Depth d, const History& H) {
+  bool ok_to_prune(const Position& pos, Move m, Move threat, Depth d) {
 
     assert(move_is_ok(m));
     assert(threat == MOVE_NONE || move_is_ok(threat));
-    assert(!move_promotion(m));
+    assert(!move_is_promotion(m));
     assert(!pos.move_is_check(m));
     assert(!pos.move_is_capture(m));
     assert(!pos.move_is_passed_pawn_push(m));
@@ -2319,7 +2373,7 @@ namespace {
         && threat != MOVE_NONE
         && piece_is_slider(pos.piece_on(tfrom))
         && bit_is_set(squares_between(tfrom, tto), mto)
-        && pos.see(m) >= 0)
+        && pos.see_sign(m) >= 0)
         return false;
 
     return true;
@@ -2347,14 +2401,14 @@ namespace {
 
   bool ok_to_history(const Position& pos, Move m) {
 
-    return !pos.move_is_capture(m) && !move_promotion(m);
+    return !pos.move_is_capture(m) && !move_is_promotion(m);
   }
 
 
   // update_history() registers a good move that produced a beta-cutoff
   // in history and marks as failures all the other moves of that ply.
 
-  void update_history(const Position& pos, Move m, Depth depth, History& H,
+  void update_history(const Position& pos, Move m, Depth depth,
                       Move movesSearched[], int moveCount) {
 
     H.success(pos.piece_on(move_from(m)), move_to(m), depth);
@@ -2382,6 +2436,21 @@ namespace {
     ss.killers[0] = m;
   }
 
+
+  // slowdown() simply wastes CPU cycles doing nothing useful. It's used
+  // in strength handicap mode.
+
+  void slowdown(const Position &pos) {
+    int i, n;
+    n = Slowdown;
+    for (i = 0; i < n; i++)  {
+        Square s = Square(i&63);
+        if (count_1s(pos.attacks_to(s)) > 63)
+            std::cout << "This can't happen, but I put this string here anyway, in order to prevent the compiler from optimizing away the useless computation." << std::endl;
+    }
+  }
+
+
   // fail_high_ply_1() checks if some thread is currently resolving a fail
   // high at ply 1 at the node below the first root node.  This information
   // is used for time managment.