// Futility and reductions lookup tables, initialized at startup
int FutilityMoveCounts[2][16]; // [improving][depth]
- int Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber]
+ int Reductions[2][64][64]; // [improving][depth][moveNumber]
template <bool PvNode> Depth reduction(bool i, Depth d, int mn) {
- return Reductions[PvNode][i][std::min(d / ONE_PLY, 63)][std::min(mn, 63)] * ONE_PLY;
+ return (Reductions[i][std::min(d / ONE_PLY, 63)][std::min(mn, 63)] - PvNode) * ONE_PLY;
}
// History and stats update bonus, based on depth
{
double r = log(d) * log(mc) / 1.95;
- Reductions[NonPV][imp][d][mc] = int(std::round(r));
- Reductions[PV][imp][d][mc] = std::max(Reductions[NonPV][imp][d][mc] - 1, 0);
+ Reductions[imp][d][mc] = std::round(r);
// Increase reduction for non-PV nodes when eval is not improving
if (!imp && r > 1.0)
- Reductions[NonPV][imp][d][mc]++;
+ Reductions[imp][d][mc]++;
}
for (int d = 0; d < 16; ++d)
// Threads.stop. However, if we are pondering or in an infinite search,
// the UCI protocol states that we shouldn't print the best move before the
// GUI sends a "stop" or "ponderhit" command. We therefore simply wait here
- // until the GUI sends one of those commands (which also raises Threads.stop).
- Threads.stopOnPonderhit = true;
+ // until the GUI sends one of those commands.
- while (!Threads.stop && (Threads.ponder || Limits.infinite))
+ while (!Threads.stop && (ponder || Limits.infinite))
{} // Busy wait for a stop or a ponder reset
// Stop the threads if not already stopped (also raise the stop if
// Find out minimum score and reset votes for moves which can be voted
for (Thread* th: Threads)
- {
minScore = std::min(minScore, th->rootMoves[0].score);
- votes[th->rootMoves[0].pv[0]] = 0;
- }
// Vote according to score and depth
- auto square = [](int64_t x) { return x * x; };
for (Thread* th : Threads)
- votes[th->rootMoves[0].pv[0]] += 200 + (square(th->rootMoves[0].score - minScore + 1)
- * int64_t(th->completedDepth));
+ {
+ int64_t s = th->rootMoves[0].score - minScore + 1;
+ votes[th->rootMoves[0].pv[0]] += 200 + s * s * int(th->completedDepth);
+ }
// Select best thread
- int64_t bestVote = votes[this->rootMoves[0].pv[0]];
+ auto bestVote = votes[this->rootMoves[0].pv[0]];
for (Thread* th : Threads)
- {
if (votes[th->rootMoves[0].pv[0]] > bestVote)
{
bestVote = votes[th->rootMoves[0].pv[0]];
bestThread = th;
}
- }
}
previousScore = bestThread->rootMoves[0].score;
{
failedHighCnt = 0;
failedLow = true;
- Threads.stopOnPonderhit = false;
+ mainThread->stopOnPonderhit = false;
}
}
else if (bestValue >= beta)
// Do we have time for the next iteration? Can we stop searching now?
if ( Limits.use_time_management()
&& !Threads.stop
- && !Threads.stopOnPonderhit)
+ && !mainThread->stopOnPonderhit)
{
double fallingEval = (306 + 119 * failedLow + 6 * (mainThread->previousScore - bestValue)) / 581.0;
fallingEval = std::max(0.5, std::min(1.5, fallingEval));
{
// If we are allowed to ponder do not stop the search now but
// keep pondering until the GUI sends "ponderhit" or "stop".
- if (Threads.ponder)
- Threads.stopOnPonderhit = true;
+ if (mainThread->ponder)
+ mainThread->stopOnPonderhit = true;
else
Threads.stop = true;
}
Move ttMove, move, excludedMove, bestMove;
Depth extension, newDepth;
Value bestValue, value, ttValue, eval, maxValue, pureStaticEval;
- bool ttHit, pvHit, inCheck, givesCheck, improving;
- bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture;
+ bool ttHit, ttPv, inCheck, givesCheck, improving;
+ bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture;
Piece movedPiece;
int moveCount, captureCount, quietCount;
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0]
: ttHit ? tte->move() : MOVE_NONE;
- pvHit = (ttHit && tte->pv_hit()) || (PvNode && depth > 4 * ONE_PLY);
+ ttPv = (ttHit && tte->is_pv()) || (PvNode && depth > 4 * ONE_PLY);
// At non-PV nodes we check for an early TT cutoff
if ( !PvNode
if ( b == BOUND_EXACT
|| (b == BOUND_LOWER ? value >= beta : value <= alpha))
{
- tte->save(posKey, value_to_tt(value, ss->ply), pvHit, b,
+ tte->save(posKey, value_to_tt(value, ss->ply), ttPv, b,
std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY),
MOVE_NONE, VALUE_NONE);
{
if ((ss-1)->currentMove != MOVE_NULL)
{
- int p = (ss-1)->statScore;
- int bonus = p > 0 ? (-p - 2500) / 512 :
- p < 0 ? (-p + 2500) / 512 : 0;
+ int bonus = -(ss-1)->statScore / 512;
pureStaticEval = evaluate(pos);
ss->staticEval = eval = pureStaticEval + bonus;
else
ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::Tempo;
- tte->save(posKey, VALUE_NONE, pvHit, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval);
+ tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval);
}
// Step 7. Razoring (~2 Elo)
int probCutCount = 0;
while ( (move = mp.next_move()) != MOVE_NONE
- && probCutCount < 3)
+ && probCutCount < 2 + 2 * cutNode)
if (move != excludedMove && pos.legal(move))
{
probCutCount++;
tte = TT.probe(posKey, ttHit);
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
ttMove = ttHit ? tte->move() : MOVE_NONE;
- pvHit = ttHit && tte->pv_hit();
}
moves_loop: // When in check, search starts from here
ss->killers);
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
- skipQuiets = false;
+ moveCountPruning = false;
ttCapture = ttMove && pos.capture_or_promotion(ttMove);
// Step 12. Loop through all pseudo-legal moves until no moves remain
// or a beta cutoff occurs.
- while ((move = mp.next_move(skipQuiets)) != MOVE_NONE)
+ while ((move = mp.next_move(moveCountPruning)) != MOVE_NONE)
{
assert(is_ok(move));
movedPiece = pos.moved_piece(move);
givesCheck = gives_check(pos, move);
- moveCountPruning = depth < 16 * ONE_PLY
- && moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY];
+ // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold
+ moveCountPruning = depth < 16 * ONE_PLY
+ && moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY];
// Step 13. Extensions (~70 Elo)
else if (cutNode && singularBeta > beta)
return beta;
}
- else if ( givesCheck // Check extension (~2 Elo)
- && pos.see_ge(move))
+
+ // Check extension (~2 Elo)
+ else if ( givesCheck
+ && (pos.blockers_for_king(~us) & from_sq(move) || pos.see_ge(move)))
extension = ONE_PLY;
- // Extension if castling
+ // Castling extension
else if (type_of(move) == CASTLING)
extension = ONE_PLY;
{
// Move count based pruning (~30 Elo)
if (moveCountPruning)
- {
- skipQuiets = true;
continue;
- }
// Reduced depth of the next LMR search
int lmrDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO) / ONE_PLY;
Depth r = reduction<PvNode>(improving, depth, moveCount);
// Decrease reduction if position is or has been on the PV
- if (pvHit)
+ if (ttPv)
r -= ONE_PLY;
// Decrease reduction if opponent's move count is high (~10 Elo)
bestValue = std::min(bestValue, maxValue);
if (!excludedMove)
- tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit,
+ tte->save(posKey, value_to_tt(bestValue, ss->ply), ttPv,
bestValue >= beta ? BOUND_LOWER :
PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
depth, bestMove, pureStaticEval);
tte = TT.probe(posKey, ttHit);
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
ttMove = ttHit ? tte->move() : MOVE_NONE;
- pvHit = ttHit && tte->pv_hit();
+ pvHit = ttHit && tte->is_pv();
if ( !PvNode
&& ttHit
}
// We should not stop pondering until told so by the GUI
- if (Threads.ponder)
+ if (ponder)
return;
- if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10)
+ if ( (Limits.use_time_management() && (elapsed > Time.maximum() - 10 || stopOnPonderhit))
|| (Limits.movetime && elapsed >= Limits.movetime)
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
Threads.stop = true;