X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=01d2a387e3aefa2592ff476d824063d41e1f81f4;hp=097faf90f7c2fc4d15f5845335c306fa792ae99f;hb=17ffc22279b33ef2015a76461e1e644909d43a10;hpb=41641e3b1eea0038ab6984766d2b3bca869be7fa diff --git a/src/search.cpp b/src/search.cpp index 097faf90..01d2a387 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -77,7 +77,7 @@ namespace { return (Depth) Reductions[PvNode][i][std::min(int(d) / ONE_PLY, 63)][std::min(mn, 63)]; } - size_t PVSize, PVIdx; + size_t MultiPV, PVIdx; TimeManager TimeMgr; double BestMoveChanges; Value DrawValue[COLOR_NB]; @@ -127,7 +127,7 @@ void Search::init() { // Init reductions array for (hd = 1; hd < 64; ++hd) for (mc = 1; mc < 64; ++mc) { - double pvRed = log(double(hd)) * log(double(mc)) / 3.0; + double pvRed = 0.00 + log(double(hd)) * log(double(mc)) / 3.00; double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25; Reductions[1][1][hd][mc] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(ONE_PLY)) : 0); Reductions[0][1][hd][mc] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(ONE_PLY)) : 0); @@ -145,8 +145,8 @@ void Search::init() { // Init futility move count array for (d = 0; d < 32; ++d) { - FutilityMoveCounts[0][d] = int(2.4 + 0.222 * pow(d + 0.0, 1.8)); - FutilityMoveCounts[1][d] = int(3.0 + 0.3 * pow(d + 0.98, 1.8)); + FutilityMoveCounts[0][d] = int(2.4 + 0.222 * pow(d + 0.00, 1.8)); + FutilityMoveCounts[1][d] = int(3.0 + 0.300 * pow(d + 0.98, 1.8)); } } @@ -306,21 +306,21 @@ namespace { Countermoves.clear(); Followupmoves.clear(); - PVSize = Options["MultiPV"]; + MultiPV = Options["MultiPV"]; Skill skill(Options["Skill Level"]); // Do we have to play with skill handicap? In this case enable MultiPV search // that we will use behind the scenes to retrieve a set of possible moves. - if (skill.enabled() && PVSize < 4) - PVSize = 4; + if (skill.enabled() && MultiPV < 4) + MultiPV = 4; - PVSize = std::min(PVSize, RootMoves.size()); + MultiPV = std::min(MultiPV, RootMoves.size()); // Iterative deepening loop until requested to stop or target depth reached while (++depth <= MAX_PLY && !Signals.stop && (!Limits.depth || depth <= Limits.depth)) { // Age out PV variability metric - BestMoveChanges *= 0.8; + BestMoveChanges *= 0.5; // Save the last iteration's scores before first PV line is searched and // all the move scores except the (new) PV are set to -VALUE_INFINITE. @@ -328,7 +328,7 @@ namespace { RootMoves[i].prevScore = RootMoves[i].score; // MultiPV loop. We perform a full root search for each PV line - for (PVIdx = 0; PVIdx < PVSize && !Signals.stop; ++PVIdx) + for (PVIdx = 0; PVIdx < MultiPV && !Signals.stop; ++PVIdx) { // Reset aspiration window starting size if (depth >= 5) @@ -393,7 +393,7 @@ namespace { // Sort the PV lines searched so far and update the GUI std::stable_sort(RootMoves.begin(), RootMoves.begin() + PVIdx + 1); - if (PVIdx + 1 == PVSize || Time::now() - SearchTime > 3000) + if (PVIdx + 1 == MultiPV || Time::now() - SearchTime > 3000) sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl; } @@ -426,14 +426,13 @@ namespace { bool stop = false; // Local variable, not the volatile Signals.stop // Take some extra time if the best move has changed - if (depth > 4 && depth < 50 && PVSize == 1) + if (depth > 4 && depth < 50 && MultiPV == 1) TimeMgr.pv_instability(BestMoveChanges); - // Stop the search if only one legal move is available or most - // of the available time has been used. We probably don't have - // enough time to search the first move at the next iteration anyway. + // Stop the search if only one legal move is available or all + // of the available time has been used. if ( RootMoves.size() == 1 - || IterationTime > (TimeMgr.available_time() * 62) / 100) + || IterationTime > TimeMgr.available_time() ) stop = true; if (stop) @@ -464,7 +463,7 @@ namespace { const bool SpNode = (NT == SplitPointPV || NT == SplitPointNonPV || NT == SplitPointRoot); const bool RootNode = (NT == Root || NT == SplitPointRoot); - assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); + assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE); assert(PvNode || (alpha == beta - 1)); assert(depth > DEPTH_ZERO); @@ -513,7 +512,7 @@ namespace { { // Step 2. Check for aborted search and immediate draw if (Signals.stop || pos.is_draw() || ss->ply > MAX_PLY) - return DrawValue[pos.side_to_move()]; + return ss->ply > MAX_PLY && !inCheck ? evaluate(pos) : DrawValue[pos.side_to_move()]; // Step 3. Mate distance pruning. Even if we mate at the next move our score // would be at best mate_in(ss->ply+1), but if alpha is already bigger because @@ -640,8 +639,24 @@ namespace { (ss+1)->skipNullMove = false; pos.undo_null_move(); - if (nullValue >= beta) // Do not return unproven mate scores - return nullValue >= VALUE_MATE_IN_MAX_PLY ? beta : nullValue; + if (nullValue >= beta) + { + // Do not return unproven mate scores + if (nullValue >= VALUE_MATE_IN_MAX_PLY) + nullValue = beta; + + if (depth < 12 * ONE_PLY) + return nullValue; + + // Do verification search at high depths + ss->skipNullMove = true; + Value v = depth-R < ONE_PLY ? qsearch(pos, ss, beta-1, beta, DEPTH_ZERO) + : search(pos, ss, beta-1, beta, depth-R, false); + ss->skipNullMove = false; + + if (v >= beta) + return nullValue; + } } // Step 9. ProbCut (skipped when in check) @@ -676,8 +691,8 @@ namespace { } // Step 10. Internal iterative deepening (skipped when in check) - if ( depth >= (PvNode ? 5 * ONE_PLY : 8 * ONE_PLY) - && ttMove == MOVE_NONE + if ( depth >= (PvNode ? 5 * ONE_PLY : 8 * ONE_PLY) + && !ttMove && (PvNode || ss->staticEval + Value(256) >= beta)) { Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4); @@ -1063,7 +1078,7 @@ moves_loop: // When in check and at SpNode search starts from here // Check for an instant draw or if the maximum ply has been reached if (pos.is_draw() || ss->ply > MAX_PLY) - return DrawValue[pos.side_to_move()]; + return ss->ply > MAX_PLY && !InCheck ? evaluate(pos) : DrawValue[pos.side_to_move()]; // Decide whether or not to include checks: this fixes also the type of // TT entry depth that we are going to use. Note that in qsearch we use @@ -1305,7 +1320,7 @@ moves_loop: // When in check and at SpNode search starts from here rk.rand(); // RootMoves are already sorted by score in descending order - int variance = std::min(RootMoves[0].score - RootMoves[PVSize - 1].score, PawnValueMg); + int variance = std::min(RootMoves[0].score - RootMoves[MultiPV - 1].score, PawnValueMg); int weakness = 120 - 2 * level; int max_s = -VALUE_INFINITE; best = MOVE_NONE; @@ -1313,7 +1328,7 @@ moves_loop: // When in check and at SpNode search starts from here // Choose best move. For each move score we add two terms both dependent on // weakness. One deterministic and bigger for weaker moves, and one random, // then we choose the move with the resulting highest score. - for (size_t i = 0; i < PVSize; ++i) + for (size_t i = 0; i < MultiPV; ++i) { int s = RootMoves[i].score; @@ -1612,9 +1627,8 @@ void check_time() { Time::point elapsed = Time::now() - SearchTime; bool stillAtFirstMove = Signals.firstRootMove && !Signals.failedLowAtRoot - && ( elapsed > TimeMgr.available_time() - || ( elapsed > (TimeMgr.available_time() * 62) / 100 - && elapsed > IterationTime * 1.4)); + && elapsed > TimeMgr.available_time() + && elapsed > IterationTime * 1.4; bool noMoreTime = elapsed > TimeMgr.maximum_time() - 2 * TimerThread::Resolution || stillAtFirstMove;