if (mainThread)
{
-
- int rootComplexity;
- Eval::evaluate(rootPos, &rootComplexity);
-
- mainThread->complexity = std::min(1.03 + (rootComplexity - 241) / 1552.0, 1.45);
-
if (mainThread->bestPreviousScore == VALUE_INFINITE)
for (int i = 0; i < 4; ++i)
mainThread->iterValue[i] = VALUE_ZERO;
double reduction = (1.4 + mainThread->previousTimeReduction) / (2.08 * timeReduction);
double bestMoveInstability = 1 + 1.8 * totBestMoveChanges / Threads.size();
- double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * mainThread->complexity;
+ 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.
bool givesCheck, improving, priorCapture, singularQuietLMR;
bool capture, moveCountPruning, ttCapture;
Piece movedPiece;
- int moveCount, captureCount, quietCount, improvement, complexity;
+ int moveCount, captureCount, quietCount, improvement;
// Step 1. Initialize node
Thread* thisThread = pos.this_thread();
ss->staticEval = eval = VALUE_NONE;
improving = false;
improvement = 0;
- complexity = 0;
goto moves_loop;
}
else if (excludedMove)
// Providing the hint that this node's accumulator will be used often brings significant Elo gain (13 Elo)
Eval::NNUE::hint_common_parent_position(pos);
eval = ss->staticEval;
- complexity = abs(ss->staticEval - pos.psq_eg_stm());
}
else if (ss->ttHit)
{
// Never assume anything about values stored in TT
ss->staticEval = eval = tte->eval();
if (eval == VALUE_NONE)
- ss->staticEval = eval = evaluate(pos, &complexity);
- else // Fall back to (semi)classical complexity for TT hits, the NNUE complexity is lost
+ ss->staticEval = eval = evaluate(pos);
+ else
{
- complexity = abs(ss->staticEval - pos.psq_eg_stm());
if (PvNode)
Eval::NNUE::hint_common_parent_position(pos);
}
}
else
{
- ss->staticEval = eval = evaluate(pos, &complexity);
+ ss->staticEval = eval = evaluate(pos);
// Save static evaluation into transposition table
tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval);
}
&& (ss-1)->statScore < 18755
&& eval >= beta
&& eval >= ss->staticEval
- && ss->staticEval >= beta - 20 * depth - improvement / 13 + 253 + complexity / 25
+ && ss->staticEval >= beta - 20 * depth - improvement / 13 + 253
&& !excludedMove
&& pos.non_pawn_material(us)
- && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
+ && (ss->ply >= thisThread->nmpMinPly))
{
assert(eval - beta >= 0);
- // Null move dynamic reduction based on depth, eval and complexity of position
- Depth R = std::min(int(eval - beta) / 172, 6) + depth / 3 + 4 - (complexity > 825);
+ // Null move dynamic reduction based on depth and eval
+ Depth R = std::min(int(eval - beta) / 172, 6) + depth / 3 + 4;
ss->currentMove = MOVE_NULL;
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
assert(!thisThread->nmpMinPly); // Recursive verification is not allowed
// Do verification search at high depths, with null move pruning disabled
- // for us, until ply exceeds nmpMinPly.
+ // until ply exceeds nmpMinPly.
thisThread->nmpMinPly = ss->ply + 3 * (depth-R) / 4;
- thisThread->nmpColor = us;
Value v = search<NonPV>(pos, ss, beta-1, beta, depth-R, false);
{
if (depth < 2 - capture)
continue;
- // don't prune move if a heavy enemy piece (KQR) is under attack after the exchanges
- Bitboard leftEnemies = (pos.pieces(~us, QUEEN, ROOK) | pos.pieces(~us, KING)) & occupied;
+ // Don't prune the move if opp. King/Queen/Rook is attacked by a slider after the exchanges.
+ // Since in see_ge we don't update occupied when the king recaptures, we also don't prune the
+ // move when the opp. King gets a discovered slider attack DURING the exchanges.
+ Bitboard leftEnemies = pos.pieces(~us, ROOK, QUEEN, KING) & occupied;
Bitboard attacks = 0;
occupied |= to_sq(move);
while (leftEnemies && !attacks)
{
Square sq = pop_lsb(leftEnemies);
- attacks |= pos.attackers_to(sq, occupied) & pos.pieces(us) & occupied;
- // exclude Queen/Rook(s) which were already threatened before SEE
- if (attacks && (sq != pos.square<KING>(~us) && (pos.attackers_to(sq, pos.pieces()) & pos.pieces(us))))
+ attacks = pos.attackers_to(sq, occupied) & pos.pieces(us) & occupied;
+ // Exclude Queen/Rook(s) which were already threatened before SEE
+ if (attacks && sq != pos.square<KING>(~us) && (pos.attackers_to(sq, pos.pieces()) & pos.pieces(us)))
attacks = 0;
}
if (!attacks)
if ((ss+1)->cutoffCnt > 3)
r++;
- // Decrease reduction if move is a killer and we have a good history (~1 Elo)
- if (move == ss->killers[0]
- && (*contHist[0])[movedPiece][to_sq(move)] >= 3722)
- r--;
-
ss->statScore = 2 * thisThread->mainHistory[us][from_to(move)]
+ (*contHist[0])[movedPiece][to_sq(move)]
+ (*contHist[1])[movedPiece][to_sq(move)]
if (newDepth > d)
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
- int bonus = value > alpha ? stat_bonus(newDepth)
- : -stat_bonus(newDepth);
+ int bonus = value <= alpha ? -stat_bonus(newDepth)
+ : value >= beta ? stat_bonus(newDepth)
+ : 0;
update_continuation_histories(ss, movedPiece, to_sq(move), bonus);
}
(ss+1)->pv[0] = MOVE_NONE;
value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth, false);
-
- if (moveCount > 1 && newDepth >= depth && !capture)
- update_continuation_histories(ss, movedPiece, to_sq(move), -stat_bonus(newDepth));
}
// Step 19. Undo move
if (PvNode && value < beta) // Update alpha! Always alpha < beta
{
-
// Reduce other moves if we have found at least one score improvement (~1 Elo)
if ( depth > 1
- && ((improving && complexity > 971) || (value < (5 * alpha + 75 * beta) / 87) || depth < 6)
&& beta < 12535
- && value > -12535) {
- bool extraReduction = depth > 2 && alpha > -12535 && bestValue != -VALUE_INFINITE && (value - bestValue) > (7 * (beta - alpha)) / 8;
- depth -= 1 + extraReduction;
- }
+ && value > -12535)
+ depth -= 1;
assert(depth > 0);
alpha = value;