&& !pos.can_castle(ANY_CASTLING))
{
StateInfo st;
+ ASSERT_ALIGNED(&st, Eval::NNUE::kCacheLineSize);
+
Position p;
- p.set(pos.fen(), pos.is_chess960(), &st, pos.this_thread());
+ p.set(pos.variant(), pos.fen(), pos.is_chess960(), &st, pos.this_thread());
Tablebases::ProbeState s1, s2;
Tablebases::WDLScore wdl = Tablebases::probe_wdl(p, &s1);
int dtz = Tablebases::probe_dtz(p, &s2);
}
double bestMoveInstability = 1 + 2 * totBestMoveChanges / Threads.size();
- double totalTime = rootMoves.size() == 1 ? 0 :
- Time.optimum() * fallingEval * reduction * bestMoveInstability;
+ double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability;
+
+ // Cap used time in case of a single legal move for a better viewer experience in tournaments
+ // yielding correct scores and sufficiently fast moves.
+ if (rootMoves.size() == 1)
+ totalTime = std::min(500.0, totalTime);
+ if (completedDepth >= 8 && rootPos.two_boards() && Options["Protocol"] == "xboard")
+ {
+ if (Limits.time[us])
+ Partner.ptell<FAIRY>("time " + std::to_string((Limits.time[us] - Time.elapsed()) / 10));
+ if (Limits.time[~us])
+ Partner.ptell<FAIRY>("otim " + std::to_string(Limits.time[~us] / 10));
+ if (!Partner.weDead && bestValue <= VALUE_MATED_IN_MAX_PLY)
+ {
+ Partner.ptell("dead");
+ Partner.weDead = true;
+ }
+ else if (Partner.weDead && bestValue > VALUE_MATED_IN_MAX_PLY)
+ {
+ Partner.ptell("x");
+ Partner.weDead = false;
+ }
+ else if (!Partner.weWin && bestValue >= VALUE_MATE_IN_MAX_PLY && Limits.time[~us] < Partner.time * 10)
+ {
+ Partner.ptell("sit");
+ Partner.weWin = true;
+ }
+ else if (Partner.weWin && (bestValue < VALUE_MATE_IN_MAX_PLY || Limits.time[~us] > Partner.time * 10))
+ {
+ Partner.ptell("x");
+ Partner.weWin = false;
+ }
+ }
+
- // Stop the search if we have exceeded the totalTime, at least 1ms search
+ // Stop the search if we have exceeded the totalTime
if (Time.elapsed() > totalTime)
{
// If we are allowed to ponder do not stop the search now but
moveCount++;
// Futility pruning
- if ( !ss->inCheck
+ if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& !givesCheck
+ && !( pos.extinction_value() == -VALUE_MATE
+ && pos.piece_on(to_sq(move))
+ && pos.extinction_piece_types().find(type_of(pos.piece_on(to_sq(move)))) != pos.extinction_piece_types().end())
&& futilityBase > -VALUE_KNOWN_WIN
&& !pos.advanced_pawn_push(move))
{
// CounterMove based pruning
if ( !captureOrPromotion
- && moveCount
+ && 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])[history_slot(pos.moved_piece(move))][to_sq(move)] < CounterMovePruneThreshold
+ && (*contHist[1])[history_slot(pos.moved_piece(move))][to_sq(move)] < CounterMovePruneThreshold)
continue;
// Make and search the move
// All legal moves have been searched. A special case: if we're in check
// and no legal moves were found, it is checkmate.
if (ss->inCheck && bestValue == -VALUE_INFINITE)
+ {
+ assert(!MoveList<LEGAL>(pos).size());
+
- return mated_in(ss->ply); // Plies to mate from the root
+ return pos.checkmate_value(ss->ply); // Plies to mate from the root
+ }
tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit,
bestValue >= beta ? BOUND_LOWER :