// 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());
&& 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.
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)
{
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))
if ( !PvNode
&& value < singularBeta - 25
&& ss->doubleExtensions <= 9)
+ {
extension = 2;
+ depth += depth < 12;
+ }
}
// Multi-cut pruning
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)]
// 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);
&& depth < 6
&& beta < VALUE_KNOWN_WIN
&& alpha > -VALUE_KNOWN_WIN)
- depth -= 1;
+ depth -= 1;
assert(depth > 0);
}
&& futilityBase > -VALUE_KNOWN_WIN
&& type_of(move) != PROMOTION)
{
-
if (moveCount > 2)
continue;
&& (*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;
/// 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;
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;
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