]> git.sesse.net Git - stockfish/commitdiff
Introduce Null Threat extension
authorMarco Costalba <mcostalba@gmail.com>
Mon, 24 Dec 2012 08:07:17 +0000 (09:07 +0100)
committerMarco Costalba <mcostalba@gmail.com>
Tue, 25 Dec 2012 18:17:27 +0000 (19:17 +0100)
In case of null search at low depths returns a fail low
due to a threat then, rather than return beta-1 (to cause
a re-search at full depth in the parent node), we set a flag
threatExtension = true (false by default) that will cause
moves that prevent the threat to be extended of one ply
in the following search.

Idea and patch is by Lucas Braesch.

Lucas also did the tests:
1500 games in 5"+0.05":
SF_threatExtension vs SF_20121222: 366 - 331 - 803 [51.2%] LOS=90.8%

3000 games in 10"+0.1":
SF_threatExtension vs SF_20121222: 610 - 559 - 1831 [50.8%] LOS=93.2%

Tests confirmed by Gary after 10570 games,
ELO: 2.79 +- 99%: 8.72 95%: 6.63
LOS: 94.08%
Wins: 1523 Losses: 1438 Draws: 7607

And finally by me at 15"+0.05, single thread, 3824 games
threatExtension vs master 768 - 692 - 2364  +7 ELO

bench 4918443

src/search.cpp

index bfcb53c989c1df9bad45ca4b11ede6eaadbabb74..c05a714578be3ce0da1b7d4fb0d3fca841b6d96d 100644 (file)
@@ -485,12 +485,13 @@ namespace {
     Value bestValue, value, ttValue;
     Value eval, nullValue, futilityValue;
     bool inCheck, givesCheck, pvMove, singularExtensionNode;
     Value bestValue, value, ttValue;
     Value eval, nullValue, futilityValue;
     bool inCheck, givesCheck, pvMove, singularExtensionNode;
-    bool captureOrPromotion, dangerous, doFullDepthSearch;
+    bool captureOrPromotion, dangerous, doFullDepthSearch, threatExtension;
     int moveCount, playedMoveCount;
 
     // Step 1. Initialize node
     Thread* thisThread = pos.this_thread();
     moveCount = playedMoveCount = 0;
     int moveCount, playedMoveCount;
 
     // Step 1. Initialize node
     Thread* thisThread = pos.this_thread();
     moveCount = playedMoveCount = 0;
+    threatExtension = false;
     inCheck = pos.checkers();
 
     if (SpNode)
     inCheck = pos.checkers();
 
     if (SpNode)
@@ -675,16 +676,15 @@ namespace {
             // 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
             // 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).
+            // move which was reduced. If a connection is found extend moves that
+            // defend against threat.
             threatMove = (ss+1)->currentMove;
 
             if (   depth < 5 * ONE_PLY
                 && (ss-1)->reduction
                 && threatMove != MOVE_NONE
                 && yields_to_threat(pos, (ss-1)->currentMove, threatMove))
             threatMove = (ss+1)->currentMove;
 
             if (   depth < 5 * ONE_PLY
                 && (ss-1)->reduction
                 && threatMove != MOVE_NONE
                 && yields_to_threat(pos, (ss-1)->currentMove, threatMove))
-                return beta - 1;
+                threatExtension = true;
         }
     }
 
         }
     }
 
@@ -802,6 +802,9 @@ split_point_start: // At split points actual search starts from here
       if (PvNode && dangerous)
           ext = ONE_PLY;
 
       if (PvNode && dangerous)
           ext = ONE_PLY;
 
+      else if (threatExtension && prevents_threat(pos, move, threatMove))
+          ext = ONE_PLY;
+
       else if (givesCheck && pos.see_sign(move) >= 0)
           ext = ONE_PLY / 2;
 
       else if (givesCheck && pos.see_sign(move) >= 0)
           ext = ONE_PLY / 2;