]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Less aggressive razoring
[stockfish] / src / search.cpp
index 6f2c48c9cbbd67d60227815b730a2340f126f09e..054ef45d5d05858ad1c6e97c624dcc224edb5241 100644 (file)
@@ -267,6 +267,7 @@ namespace {
   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);
+  bool value_is_mate(Value value);
   bool move_is_killer(Move m, const SearchStack& ss);
   Depth extension(const Position &pos, Move m, bool pvNode, bool check, bool singleReply, bool mateThreat, bool* dangerous);
   bool ok_to_do_nullmove(const Position &pos);
@@ -1002,9 +1003,8 @@ namespace {
       movesSearched[moveCount++] = ss[ply].currentMove = move;
 
       if (moveIsCapture)
-          ss[ply].currentMoveCaptureValue = pos.midgame_value_of_piece_on(move_to(move));
-      else if (move_is_ep(move))
-          ss[ply].currentMoveCaptureValue = PawnValueMidgame;
+          ss[ply].currentMoveCaptureValue =
+          move_is_ep(move)? PawnValueMidgame : pos.midgame_value_of_piece_on(move_to(move));
       else
           ss[ply].currentMoveCaptureValue = Value(0);
 
@@ -1176,6 +1176,7 @@ namespace {
     if (    allowNullmove
         &&  depth > OnePly
         && !isCheck
+        && !value_is_mate(beta)
         &&  ok_to_do_nullmove(pos)
         &&  approximateEval >= beta - NullMoveMargin)
     {
@@ -1183,7 +1184,7 @@ namespace {
 
         UndoInfo u;
         pos.do_null_move(u);
-        int R = (depth > 7 ? 4 : 3);
+        int R = (depth >= 4 * OnePly ? 4 : 3); // Null move dynamic reduction
 
         Value nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID);
 
@@ -1193,6 +1194,7 @@ namespace {
         if (   UseNullDrivenIID
             && nullValue < beta
             && depth > 6 * OnePly
+            &&!value_is_mate(nullValue)
             && ttMove == MOVE_NONE
             && ss[ply + 1].currentMove != MOVE_NONE
             && pos.move_is_capture(ss[ply + 1].currentMove)
@@ -1201,7 +1203,11 @@ namespace {
 
         pos.undo_null_move(u);
 
-        if (nullValue >= beta)
+        if (value_is_mate(nullValue))
+        {
+            /* Do not return unproven mates */
+        }
+        else if (nullValue >= beta)
         {
             if (depth < 6 * OnePly)
                 return beta;
@@ -1230,11 +1236,12 @@ namespace {
         }
     }
     // Null move search not allowed, try razoring
-    else if (  (approximateEval < beta - RazorMargin && depth < RazorDepth)
-             ||(approximateEval < beta - PawnValueMidgame && depth <= OnePly))
+    else if (   !value_is_mate(beta)
+             && approximateEval < beta - RazorMargin
+             && depth < RazorDepth)
     {
         Value v = qsearch(pos, ss, beta-1, beta, Depth(0), ply, threadID);
-        if (v < beta)
+        if (v < beta - RazorMargin / 2)
             return v;
     }
 
@@ -1298,10 +1305,12 @@ namespace {
           && !moveIsCapture
           && !move_promotion(move))
       {
+          // History pruning. See ok_to_prune() definition.
           if (   moveCount >= 2 + int(depth)
               && ok_to_prune(pos, move, ss[ply].threatMove, depth))
               continue;
 
+          // Value based pruning.
           if (depth < 3 * OnePly && approximateEval < beta)
           {
               if (futilityValue == VALUE_NONE)
@@ -1428,14 +1437,15 @@ namespace {
         return value_from_tt(tte->value(), ply);
 
     // Evaluate the position statically
-    Value staticValue = evaluate(pos, ei, threadID);
+    bool isCheck = pos.is_check();
+    Value staticValue = (isCheck ? -VALUE_INFINITE : evaluate(pos, ei, threadID));
 
     if (ply == PLY_MAX - 1)
-        return staticValue;
+        return evaluate(pos, ei, threadID);
 
     // Initialize "stand pat score", and return it immediately if it is
     // at least beta.
-    Value bestValue = (pos.is_check() ? -VALUE_INFINITE : staticValue);
+    Value bestValue = staticValue;
 
     if (bestValue >= beta)
         return bestValue;
@@ -1446,12 +1456,11 @@ 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, false, MOVE_NONE, EmptySearchStack, depth, &ei);
+    bool pvNode = (beta - alpha != 1);
+    MovePicker mp = MovePicker(pos, pvNode, MOVE_NONE, EmptySearchStack, depth, isCheck ? NULL : &ei);
     Move move;
     int moveCount = 0;
     Bitboard dcCandidates = mp.discovered_check_candidates();
-    bool isCheck = pos.is_check();
-    bool pvNode = (beta - alpha != 1);
     bool enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMidgame;
 
     // Loop through the moves until no moves remain or a beta cutoff
@@ -1476,6 +1485,7 @@ namespace {
           Value futilityValue = staticValue
                               + Max(pos.midgame_value_of_piece_on(move_to(move)),
                                     pos.endgame_value_of_piece_on(move_to(move)))
+                              + (move_is_ep(move) ? PawnValueEndgame : Value(0))
                               + FutilityMargin0
                               + ei.futilityMargin;
 
@@ -1679,8 +1689,11 @@ namespace {
 
       assert(move_is_ok(move));
 
-      ss[sp->ply].currentMoveCaptureValue = move_is_ep(move)?
-        PawnValueMidgame : pos.midgame_value_of_piece_on(move_to(move));
+      if (moveIsCapture)
+          ss[sp->ply].currentMoveCaptureValue =
+          move_is_ep(move)? PawnValueMidgame : pos.midgame_value_of_piece_on(move_to(move));
+      else
+          ss[sp->ply].currentMoveCaptureValue = Value(0);
 
       lock_grab(&(sp->lock));
       int moveCount = ++sp->moves;
@@ -2120,6 +2133,18 @@ namespace {
   }
 
 
+  // value_is_mate() checks if the given value is a mate one
+  // eventually compensated for the ply.
+
+  bool value_is_mate(Value value) {
+
+    assert(abs(value) <= VALUE_INFINITE);
+
+    return   value <= value_mated_in(PLY_MAX)
+          || value >= value_mate_in(PLY_MAX);
+  }
+
+
   // move_is_killer() checks if the given move is among the
   // killer moves of that ply.
 
@@ -2144,6 +2169,8 @@ namespace {
   Depth extension(const Position &pos, Move m, bool pvNode, bool check,
                   bool singleReply, bool mateThreat, bool* dangerous) {
 
+    assert(m != MOVE_NONE);
+
     Depth result = Depth(0);
     *dangerous = check || singleReply || mateThreat;
 
@@ -2167,10 +2194,12 @@ namespace {
         *dangerous = true;
     }
 
-    if (   pos.midgame_value_of_piece_on(move_to(m)) >= RookValueMidgame
+    if (   pos.move_is_capture(m)
+        && 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_promotion(m)
+        && !move_is_ep(m))
     {
         result += PawnEndgameExtension[pvNode];
         *dangerous = true;
@@ -2236,7 +2265,7 @@ namespace {
     // value of the threatening piece, don't prune move which defend it.
     if (   !PruneDefendingMoves
         && threat != MOVE_NONE
-        && pos.type_of_piece_on(tto) != NO_PIECE_TYPE
+        && pos.move_is_capture(threat)
         && (   pos.midgame_value_of_piece_on(tfrom) >= pos.midgame_value_of_piece_on(tto)
             || pos.type_of_piece_on(tfrom) == KING)
         && pos.move_attacks_square(m, tto))