X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fsearch.cpp;h=b58a344a597b61103c809706c4893aff48451553;hb=955edf1d1d4f5643b450b1ee1e95dc3f094e1884;hp=7019635dd34b6f4015822541621174fe5b90cb11;hpb=d5271af0ee28cb52e1033f183f3b34754aa5efa0;p=stockfish diff --git a/src/search.cpp b/src/search.cpp index 7019635d..b58a344a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -244,7 +244,7 @@ void MainThread::search() { // Send again PV info if we have a new best thread if (bestThread != this) - sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE) << sync_endl; + sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth) << sync_endl; sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960()); @@ -309,7 +309,6 @@ void Thread::search() { complexityAverage.set(155, 1); - trend = SCORE_ZERO; optimism[us] = optimism[~us] = VALUE_ZERO; int searchAgainCounter = 0; @@ -356,11 +355,7 @@ void Thread::search() { alpha = std::max(prev - delta,-VALUE_INFINITE); beta = std::min(prev + delta, VALUE_INFINITE); - // Adjust trend and optimism based on root move's previousScore - int tr = 116 * prev / (std::abs(prev) + 89); - trend = (us == WHITE ? make_score(tr, tr / 2) - : -make_score(tr, tr / 2)); - + // Adjust optimism based on root move's previousScore int opt = 118 * prev / (std::abs(prev) + 169); optimism[ us] = Value(opt); optimism[~us] = -optimism[us]; @@ -397,7 +392,7 @@ void Thread::search() { && multiPV == 1 && (bestValue <= alpha || bestValue >= beta) && Time.elapsed() > 3000) - sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl; + sync_cout << UCI::pv(rootPos, rootDepth) << sync_endl; // In case of failing low/high increase aspiration window and // re-search, otherwise exit the loop. @@ -428,7 +423,7 @@ void Thread::search() { if ( mainThread && (Threads.stop || pvIdx + 1 == multiPV || Time.elapsed() > 3000)) - sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl; + sync_cout << UCI::pv(rootPos, rootDepth) << sync_endl; } if (!Threads.stop) @@ -775,8 +770,7 @@ namespace { // Step 7. Razoring. // If eval is really low check with qsearch if it can exceed alpha, if it can't, // return a fail low. - if ( depth <= 7 - && eval < alpha - 369 - 254 * depth * depth) + if (eval < alpha - 369 - 254 * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); if (value < alpha) @@ -861,7 +855,7 @@ namespace { { assert(probCutBeta < VALUE_INFINITE); - MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, depth - 3, &captureHistory); + MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory); while ((move = mp.next_move()) != MOVE_NONE) if (move != excludedMove && pos.legal(move)) @@ -1073,7 +1067,10 @@ moves_loop: // When in check, search starts here if ( !PvNode && value < singularBeta - 25 && ss->doubleExtensions <= 9) + { extension = 2; + depth += depth < 12; + } } // Multi-cut pruning @@ -1162,13 +1159,13 @@ moves_loop: // When in check, search starts here if (singularQuietLMR) r--; - // Dicrease reduction if we move a threatened piece (~1 Elo) + // Decrease reduction if we move a threatened piece (~1 Elo) if ( depth > 9 && (mp.threatenedPieces & from_sq(move))) r--; // Increase reduction if next ply has a lot of fail high - if ((ss+1)->cutoffCnt > 3 && !PvNode) + if ((ss+1)->cutoffCnt > 3) r++; ss->statScore = 2 * thisThread->mainHistory[us][from_to(move)] @@ -1178,7 +1175,7 @@ moves_loop: // When in check, search starts here - 4433; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 13628; + r -= ss->statScore / (13628 + 4000 * (depth > 7 && depth < 19)); // In general we want to cap the LMR depth search at newDepth, but when // reduction is negative, we allow this move a limited search extension @@ -1190,8 +1187,15 @@ moves_loop: // When in check, search starts here // Do full depth search when reduced LMR search fails high if (value > alpha && d < newDepth) { + // Adjust full depth search based on LMR results - if result + // was good enough search deeper, if it was bad enough search shallower const bool doDeeperSearch = value > (alpha + 64 + 11 * (newDepth - d)); - value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth + doDeeperSearch, !cutNode); + const bool doShallowerSearch = value < bestValue + newDepth; + + newDepth += doDeeperSearch - doShallowerSearch; + + if (newDepth > d) + value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode); int bonus = value > alpha ? stat_bonus(newDepth) : -stat_bonus(newDepth); @@ -1243,8 +1247,18 @@ moves_loop: // When in check, search starts here // PV move or new best move? if (moveCount == 1 || value > alpha) { - rm.score = value; + rm.score = rm.uciScore = value; rm.selDepth = thisThread->selDepth; + rm.scoreLowerbound = rm.scoreUpperbound = false; + + if (value >= beta) { + rm.scoreLowerbound = true; + rm.uciScore = beta; + } + else if (value <= alpha) { + rm.scoreUpperbound = true; + rm.uciScore = alpha; + } rm.pv.resize(1); assert((ss+1)->pv); @@ -1286,7 +1300,7 @@ moves_loop: // When in check, search starts here && depth < 6 && beta < VALUE_KNOWN_WIN && alpha > -VALUE_KNOWN_WIN) - depth -= 1; + depth -= 1; assert(depth > 0); } @@ -1298,8 +1312,6 @@ moves_loop: // When in check, search starts here } } } - else - ss->cutoffCnt = 0; // If the move is worse than some previously searched move, remember it to update its stats later @@ -1513,7 +1525,6 @@ moves_loop: // When in check, search starts here && futilityBase > -VALUE_KNOWN_WIN && type_of(move) != PROMOTION) { - if (moveCount > 2) continue; @@ -1549,16 +1560,15 @@ moves_loop: // When in check, search starts here // Continuation history based pruning (~2 Elo) if ( !capture && bestValue > VALUE_TB_LOSS_IN_MAX_PLY - && (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < CounterMovePruneThreshold - && (*contHist[1])[pos.moved_piece(move)][to_sq(move)] < CounterMovePruneThreshold) + && (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < 0 + && (*contHist[1])[pos.moved_piece(move)][to_sq(move)] < 0) continue; - // movecount pruning for quiet check evasions + // We prune after 2nd quiet check evasion where being 'in check' is implicitly checked through the counter + // and being a 'quiet' apart from being a tt move is assumed after an increment because captures are pushed ahead. if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY - && quietCheckEvasions > 1 - && !capture - && ss->inCheck) - continue; + && quietCheckEvasions > 1) + break; quietCheckEvasions += !capture && ss->inCheck; @@ -1822,7 +1832,7 @@ void MainThread::check_time() { /// UCI::pv() formats PV information according to the UCI protocol. UCI requires /// that all (if any) unsearched PV lines are sent using a previous search score. -string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { +string UCI::pv(const Position& pos, Depth depth) { std::stringstream ss; TimePoint elapsed = Time.elapsed() + 1; @@ -1840,7 +1850,7 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { continue; Depth d = updated ? depth : std::max(1, depth - 1); - Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore; + Value v = updated ? rootMoves[i].uciScore : rootMoves[i].previousScore; if (v == -VALUE_INFINITE) v = VALUE_ZERO; @@ -1860,8 +1870,8 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { if (Options["UCI_ShowWDL"]) ss << UCI::wdl(v, pos.game_ply()); - if (!tb && i == pvIdx) - ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); + if (i == pvIdx && !tb && updated) // tablebase- and previous-scores are exact + ss << (rootMoves[i].scoreLowerbound ? " lowerbound" : (rootMoves[i].scoreUpperbound ? " upperbound" : "")); ss << " nodes " << nodesSearched << " nps " << nodesSearched * 1000 / elapsed