I just implemented my proposal:jhellis3 wrote:Here is the fix applied to vanilla SF if anyone is interested:
https://github.com/jhellis3/Stockfish/tree/tb_fix_1
[D]8/2P1P3/3k4/8/8/4K3/P2p1p2/8 b - -
512MB Hash, Single Thread:
Vanilla (with TBs) @ ~200 seconds: Depth 51, score +123.xx, short line displayed
Patch @ ~200 seconds: Depth 49, score Mate in 14, full line displayed (starts returning mate scores at d31)
Vanilla (sans TBs) @ ~80 seconds: Depth 40, score Mate in 14, full line displayed (starts returning mate scores at d35)
Code: Select all
info depth 34 seldepth 36 multipv 1 score cp 12351 nodes 7894099 nps 2877907 hashfull 57 tbhits 358787 time 2743 pv d2d1q c7c8n d6c5 e3f2
info depth 35 seldepth 45 multipv 1 score mate 58 lowerbound nodes 24467190 nps 3480892 hashfull 157 tbhits 1047957 time 7029 pv d2d1q
info depth 35 seldepth 47 multipv 1 score mate 49 lowerbound nodes 28435778 nps 3592644 hashfull 164 tbhits 1206702 time 7915 pv d2d1q
info depth 35 seldepth 50 multipv 1 score mate 35 lowerbound nodes 35874043 nps 3580958 hashfull 224 tbhits 1518902 time 10018 pv d2d1q
info depth 35 seldepth 50 multipv 1 score mate 18 nodes 42810493 nps 3657141 hashfull 241 tbhits 1797828 time 11706 pv d2d1q c7c8n d6c5 e3f2 d1a4 f2e3 a4e8 c8b6 c5b6 e3d4 e8e7 d4d5 b6b5 d5d4 e7e6 a2a3 e6f5 d4e3 b5c4 a3a4 c4d5 a4a5 f5e4 e3f2 d5d4 a5a6 e4f4 f2g1 d4e3 a6a7 f4g4 g1f1 g4g3 a7a8q g3f2
...
info depth 38 seldepth 50 multipv 1 score mate 14 nodes 74681482 nps 3813197 hashfull 354 tbhits 2914349 time 19585 pv d2d1q c7c8n d6c5 e3f2 d1d7 f2e3 d7c8 a2a4 c8d7 a4a5 d7e7 e3d3 c5d5 a5a6 e7c7 d3e2 d5e4 e2d2 e4d4 d2e2 c7g3 a6a7 g3g2 e2e1 d4d3 a7a8r g2g1
Code: Select all
diff --git a/src/search.cpp b/src/search.cpp
index 995204f..505df28 100644
--- a/src/search.cpp
+++ b/src/search.cpp
@@ -561,7 +561,7 @@ namespace {
Key posKey;
Move ttMove, move, excludedMove, bestMove;
Depth extension, newDepth, predictedDepth;
- Value bestValue, value, ttValue, eval, nullValue;
+ Value bestValue, value, ttValue, eval, nullValue, maxValue;
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
bool captureOrPromotion, doFullDepthSearch, moveCountPruning;
Piece moved_piece;
@@ -572,6 +572,7 @@ namespace {
inCheck = pos.checkers();
moveCount = quietCount = ss->moveCount = 0;
bestValue = -VALUE_INFINITE;
+ maxValue = VALUE_INFINITE;
ss->ply = (ss-1)->ply + 1;
// Check for the available remaining time
@@ -667,11 +668,29 @@ namespace {
: v > drawScore ? VALUE_MATE - MAX_PLY - ss->ply
: VALUE_DRAW + 2 * v * drawScore;
- tte->save(posKey, value_to_tt(value, ss->ply), BOUND_EXACT,
- std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY),
- MOVE_NONE, VALUE_NONE, TT.generation());
-
- return value;
+ if (abs(v) <= drawScore) {
+ tte->save(posKey, value_to_tt(value, ss->ply), BOUND_EXACT,
+ depth, MOVE_NONE, VALUE_NONE, TT.generation());
+ return value;
+ }
+ if (v < -drawScore) {
+ if (alpha >= value) {
+ tte->save(posKey, value_to_tt(value, ss->ply),
+ BOUND_UPPER, depth, MOVE_NONE, VALUE_NONE,
+ TT.generation());
+ return value;
+ }
+ maxValue = value;
+ }
+ else {
+ if (beta <= value) {
+ tte->save(posKey, value_to_tt(value, ss->ply),
+ BOUND_LOWER, depth, MOVE_NONE, VALUE_NONE,
+ TT.generation());
+ return value;
+ }
+ bestValue = value;
+ }
}
}
}
@@ -1125,6 +1144,9 @@ moves_loop: // When in check search starts from here
(ss-5)->counterMoves->update(pos.piece_on(prevSq), prevSq, bonus);
}
+ if (bestValue > maxValue)
+ bestValue = maxValue;
+
tte->save(posKey, value_to_tt(bestValue, ss->ply),
bestValue >= beta ? BOUND_LOWER :
PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
- probe as early as you can;
- if draw or outside (alpha,beta), take the TB cutoff;
- otherwise continue to search the subtree, but make sure the value returned is at least TBwin (bestValue = value) or at most -TBwin (maxValue = value) as the case may be.
It seems sufficient to test against maxValue only at the end of search().