X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fsearch.cpp;h=defe00d6f16fde3353b1cdf9c99840d796b8b166;hb=54b3d44194fb0d36a2b4c3cd6d473ec50a4c1ef1;hp=b653ef9e70f1b33dcde02a8310ea35e24ab6d288;hpb=05a8c318b8cfc284906f6077fd934d35d891028c;p=stockfish diff --git a/src/search.cpp b/src/search.cpp index b653ef9e..defe00d6 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -289,6 +289,7 @@ namespace { Value refine_eval(const TTEntry* tte, Value defaultEval, int ply); void update_history(const Position& pos, Move move, Depth depth, Move movesSearched[], int moveCount); void update_killers(Move m, SearchStack& ss); + void update_gains(const Position& pos, Move move, Value before, Value after); bool fail_high_ply_1(); int current_search_time(); @@ -1165,21 +1166,14 @@ namespace { tte = TT.retrieve(pos.get_key()); } - // Evaluate the position statically isCheck = pos.is_check(); - EvalInfo ei; if (!isCheck) { + // Update gain statistics of the previous move that lead + // us in this position. + EvalInfo ei; ss[ply].eval = evaluate(pos, ei, threadID); - - // Store gain statistics - Move m = ss[ply - 1].currentMove; - if ( m != MOVE_NULL - && pos.captured_piece() == NO_PIECE_TYPE - && !move_is_castle(m) - && !move_is_promotion(m)) - MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), ss[ply - 1].eval, -ss[ply].eval); - + update_gains(pos, ss[ply - 1].currentMove, ss[ply - 1].eval, ss[ply].eval); } // Initialize a MovePicker object for the current position, and prepare @@ -1359,7 +1353,7 @@ namespace { Move ttMove, move; Depth ext, newDepth; Value bestValue, staticValue, nullValue, value, futilityValue, futilityValueScaled; - bool isCheck, useFutilityPruning, singleEvasion, moveIsCheck, captureOrPromotion, dangerous; + bool isCheck, singleEvasion, moveIsCheck, captureOrPromotion, dangerous; bool mateThreat = false; int moveCount = 0; futilityValue = staticValue = bestValue = value = -VALUE_INFINITE; @@ -1403,7 +1397,7 @@ namespace { // Calculate depth dependant futility pruning parameters const int FutilityMoveCountMargin = 3 + (1 << (3 * int(depth) / 8)); - const int FutilityValueMargin = 112 * bitScanReverse32(int(depth) * int(depth) / 2); + const int PostFutilityValueMargin = 112 * bitScanReverse32(int(depth) * int(depth) / 2); // Evaluate the position statically if (!isCheck) @@ -1417,21 +1411,14 @@ namespace { } ss[ply].eval = staticValue; - futilityValue = staticValue + FutilityValueMargin; + futilityValue = staticValue + PostFutilityValueMargin; //FIXME: Remove me, only for split staticValue = refine_eval(tte, staticValue, ply); // Enhance accuracy with TT value if possible - - // Store gain statistics - Move m = ss[ply - 1].currentMove; - if ( m != MOVE_NULL - && pos.captured_piece() == NO_PIECE_TYPE - && !move_is_castle(m) - && !move_is_promotion(m)) - MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), ss[ply - 1].eval, -ss[ply].eval); + update_gains(pos, ss[ply - 1].currentMove, ss[ply - 1].eval, ss[ply].eval); } // Post futility pruning - if (staticValue - FutilityValueMargin >= beta) - return (staticValue - FutilityValueMargin); + if (depth < SelectiveDepth && staticValue - PostFutilityValueMargin >= beta) + return (staticValue - PostFutilityValueMargin); // Null move search if ( allowNullmove @@ -1510,7 +1497,6 @@ namespace { // to search all moves. MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply]); CheckInfo ci(pos); - useFutilityPruning = depth < SelectiveDepth && !isCheck; // Loop through all legal moves until no moves remain or a beta cutoff occurs while ( bestValue < beta @@ -1556,8 +1542,31 @@ namespace { // Update current move movesSearched[moveCount++] = ss[ply].currentMove = move; + // Futility pruning for captures + Color them = opposite_color(pos.side_to_move()); + + if ( !isCheck + && newDepth < SelectiveDepth + && !dangerous + && pos.move_is_capture(move) + && !pos.move_is_check(move, ci) + && !move_is_promotion(move) + && move != ttMove + && !move_is_ep(move) + && (pos.type_of_piece_on(move_to(move)) != PAWN || !pos.pawn_is_passed(them, move_to(move)))) // Do not prune passed pawn captures + { + int preFutilityValueMargin = 0; + + if (newDepth >= OnePly) + preFutilityValueMargin = 112 * bitScanReverse32(int(newDepth) * int(newDepth) / 2); + + if (ss[ply].eval + pos.endgame_value_of_piece_on(move_to(move)) + preFutilityValueMargin + ei.futilityMargin + 90 < beta) + continue; + } + + // Futility pruning - if ( useFutilityPruning + if ( !isCheck && !dangerous && !captureOrPromotion && !move_is_castle(move) @@ -1570,13 +1579,29 @@ namespace { continue; // Value based pruning - futilityValueScaled = futilityValue - moveCount * IncrementalFutilityMargin; + Depth predictedDepth = newDepth; - if (futilityValueScaled < beta) + //FIXME HACK: awful code duplication + double red = 0.5 + ln(moveCount) * ln(depth / 2) / 3.0; + if (red >= 1.0) + predictedDepth -= int(floor(red * int(OnePly))); + + if (predictedDepth < SelectiveDepth) { - if (futilityValueScaled > bestValue) - bestValue = futilityValueScaled; - continue; + int preFutilityValueMargin = 0; + if (predictedDepth >= OnePly) + preFutilityValueMargin = 112 * bitScanReverse32(int(predictedDepth) * int(predictedDepth) / 2); + + preFutilityValueMargin += MG.retrieve(pos.piece_on(move_from(move)), move_from(move), move_to(move)) + 45; + + futilityValueScaled = ss[ply].eval + preFutilityValueMargin - moveCount * IncrementalFutilityMargin; + + if (futilityValueScaled < beta) + { + if (futilityValueScaled > bestValue) + bestValue = futilityValueScaled; + continue; + } } } @@ -1631,7 +1656,7 @@ namespace { && idle_thread_exists(threadID) && !AbortSearch && !thread_should_stop(threadID) - && split(pos, ss, ply, &beta, &beta, &bestValue, futilityValue, + && split(pos, ss, ply, &beta, &beta, &bestValue, futilityValue, //FIXME: SMP & futilityValue depth, &moveCount, &mp, threadID, false)) break; } @@ -1726,16 +1751,9 @@ namespace { if (!isCheck) { ss[ply].eval = staticValue; - // Store gain statistics - Move m = ss[ply - 1].currentMove; - if ( m != MOVE_NULL - && pos.captured_piece() == NO_PIECE_TYPE - && !move_is_castle(m) - && !move_is_promotion(m)) - MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), ss[ply - 1].eval, -ss[ply].eval); + update_gains(pos, ss[ply - 1].currentMove, ss[ply - 1].eval, ss[ply].eval); } - // Initialize "stand pat score", and return it immediately if it is // at least beta. bestValue = staticValue; @@ -2617,6 +2635,21 @@ namespace { } + // update_gains() updates the gains table of a non-capture move given + // the static position evaluation before and after the move. + + void update_gains(const Position& pos, Move m, Value before, Value after) { + + if ( m != MOVE_NULL + && before != VALUE_NONE + && after != VALUE_NONE + && pos.captured_piece() == NO_PIECE_TYPE + && !move_is_castle(m) + && !move_is_promotion(m)) + MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), -(before + after)); + } + + // 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 management.