]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Implement Last Seconds Noise (LSN) filtering
[stockfish] / src / search.cpp
index 2a6ba30b8367e93a6d84869d31b2c7fa5ca01a4f..ee7d906e61698010afd4b7e64336c44505493b2e 100644 (file)
@@ -152,6 +152,12 @@ namespace {
   Depth RazorDepth = 4*OnePly;
   Value RazorMargin = Value(0x300);
 
+  // Last seconds noise filtering (LSN)
+  bool UseLSNFiltering = false;
+  bool looseOnTime = false;
+  int LSNTime = 4 * 1000; // In milliseconds
+  Value LSNValue = Value(0x200);
+
   // Extensions.  Array index 0 is used at non-PV nodes, index 1 at PV nodes.
   Depth CheckExtension[2] = {OnePly, OnePly};
   Depth SingleReplyExtension[2] = {OnePly / 2, OnePly / 2};
@@ -220,7 +226,7 @@ namespace {
 
   /// Functions
 
-  void id_loop(const Position &pos, Move searchMoves[]);
+  Value id_loop(const Position &pos, Move searchMoves[]);
   Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml);
   Value search_pv(Position &pos, SearchStack ss[], Value alpha, Value beta,
                   Depth depth, int ply, int threadID);
@@ -394,6 +400,10 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
   RazorDepth = (get_option_value_int("Maximum Razoring Depth") + 1) * OnePly;
   RazorMargin = value_from_centipawns(get_option_value_int("Razoring Margin"));
 
+  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");
@@ -468,7 +478,21 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
 
   // We're ready to start thinking.  Call the iterative deepening loop
   // function:
-  id_loop(pos, searchMoves);
+  if (!looseOnTime)
+  {
+      Value v = id_loop(pos, searchMoves);
+      looseOnTime = (   UseLSNFiltering
+                     && myTime < LSNTime
+                     && myIncrement == 0
+                     && v < -LSNValue);
+  }
+  else
+  {
+      looseOnTime = false; // reset for next match
+      while (SearchStartTime + myTime + 1000 > get_system_time())
+          ; // wait here
+      id_loop(pos, searchMoves); // to fail gracefully
+  }
 
   if(UseLogFile)
     LogFile.close();
@@ -570,7 +594,7 @@ namespace {
   // been consumed, the user stops the search, or the maximum search depth is
   // reached.
 
-  void id_loop(const Position &pos, Move searchMoves[]) {
+  Value id_loop(const Position &pos, Move searchMoves[]) {
     Position p(pos);
     SearchStack ss[PLY_MAX_PLUS_2];
 
@@ -694,6 +718,7 @@ namespace {
       LogFile << "Ponder move: " << move_to_san(p, ss[0].pv[1]) << '\n';
       LogFile << std::endl;
     }
+    return rml.get_move_score(0);
   }
 
 
@@ -1122,7 +1147,8 @@ namespace {
         }
     }
     // Null move search not allowed, try razoring
-    else if (depth < RazorDepth && approximateEval < beta - RazorMargin)
+    else if (  (approximateEval < beta - RazorMargin && depth < RazorDepth)
+             ||(approximateEval < beta - PawnValueMidgame && depth <= OnePly))
     {
         Value v = qsearch(pos, ss, beta-1, beta, Depth(0), ply, threadID);
         if (v < beta)
@@ -1147,7 +1173,6 @@ namespace {
     Value value, bestValue = -VALUE_INFINITE;
     Bitboard dcCandidates = mp.discovered_check_candidates();
     Value futilityValue = VALUE_NONE;
-    MovePicker::MovegenPhase moveType;
     bool isCheck = pos.is_check();
     bool useFutilityPruning =   UseFutilityPruning
                              && depth < SelectiveDepth
@@ -1156,14 +1181,14 @@ namespace {
     // Loop through all legal moves until no moves remain or a beta cutoff
     // occurs.
     while (   bestValue < beta
-           && (move = mp.get_next_move(&moveType)) != MOVE_NONE
+           && (move = mp.get_next_move()) != MOVE_NONE
            && !thread_should_stop(threadID))
     {
       assert(move_is_ok(move));
 
       bool singleReply = (isCheck && mp.number_of_moves() == 1);
       bool moveIsCheck = pos.move_is_check(move, dcCandidates);
-      bool moveIsGoodCapture = (moveType == MovePicker::PH_GOOD_CAPTURES);
+      bool moveIsCapture = pos.move_is_capture(move);
       bool moveIsPassedPawnPush = pos.move_is_passed_pawn_push(move);
 
       movesSearched[moveCount++] = ss[ply].currentMove = move;
@@ -1175,7 +1200,7 @@ namespace {
       // Futility pruning
       if (    useFutilityPruning
           &&  ext == Depth(0)
-          && !moveIsGoodCapture
+          && !moveIsCapture
           && !moveIsPassedPawnPush
           && !move_promotion(move))
       {
@@ -1207,7 +1232,7 @@ namespace {
       if (   depth >= 2*OnePly
           && ext == Depth(0)
           && moveCount >= LMRNonPVMoves
-          && !moveIsGoodCapture
+          && !moveIsCapture
           && !move_promotion(move)
           && !moveIsPassedPawnPush
           && !move_is_castle(move)
@@ -2021,6 +2046,7 @@ namespace {
     assert(threat == MOVE_NONE || move_is_ok(threat));
     assert(!move_promotion(m));
     assert(!pos.move_is_check(m));
+    assert(!pos.move_is_capture(m));
     assert(!pos.move_is_passed_pawn_push(m));
     assert(d >= OnePly);
 
@@ -2172,6 +2198,12 @@ namespace {
     {
         lastInfoTime = t;
         lock_grab(&IOLock);
+        if (dbg_show_mean)
+            dbg_print_mean();
+
+        if (dbg_show_hit_rate)
+            dbg_print_hit_rate();
+
         std::cout << "info nodes " << nodes_searched() << " nps " << nps()
                   << " time " << t << " hashfull " << TT.full() << std::endl;
         lock_release(&IOLock);