diff --git a/src/search.cpp b/src/search.cpp index 6beb8d096..cad5d7f3b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -300,8 +300,8 @@ void Search::Worker::iterative_deepening() { for (int i = 7; i > 0; --i) { (ss - i)->continuationHistory = - &this->continuationHistory[0][0][NO_PIECE][0]; // Use as a sentinel - (ss - i)->continuationCorrectionHistory = &this->continuationCorrectionHistory[NO_PIECE][0]; + &continuationHistory[0][0][NO_PIECE][0]; // Use as a sentinel + (ss - i)->continuationCorrectionHistory = &continuationCorrectionHistory[NO_PIECE][0]; (ss - i)->staticEval = VALUE_NONE; } @@ -634,7 +634,7 @@ Value Search::Worker::search( // Check if we have an upcoming move that draws by repetition if (!rootNode && alpha < VALUE_DRAW && pos.upcoming_repetition(ss->ply)) { - alpha = value_draw(this->nodes); + alpha = value_draw(nodes); if (alpha >= beta) return alpha; } @@ -660,29 +660,27 @@ Value Search::Worker::search( SearchedList quietsSearched; // Step 1. Initialize node - Worker* thisThread = this; - ss->inCheck = pos.checkers(); - priorCapture = pos.captured_piece(); - Color us = pos.side_to_move(); - ss->moveCount = 0; - bestValue = -VALUE_INFINITE; - maxValue = VALUE_INFINITE; + ss->inCheck = pos.checkers(); + priorCapture = pos.captured_piece(); + Color us = pos.side_to_move(); + ss->moveCount = 0; + bestValue = -VALUE_INFINITE; + maxValue = VALUE_INFINITE; // Check for the available remaining time if (is_mainthread()) - main_manager()->check_time(*thisThread); + main_manager()->check_time(*this); // Used to send selDepth info to GUI (selDepth counts from 1, ply from 0) - if (PvNode && thisThread->selDepth < ss->ply + 1) - thisThread->selDepth = ss->ply + 1; + if (PvNode && selDepth < ss->ply + 1) + selDepth = ss->ply + 1; if (!rootNode) { // Step 2. Check for aborted search and immediate draw if (threads.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) - return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) - : value_draw(thisThread->nodes); + return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) : value_draw(nodes); // Step 3. Mate distance pruning. Even if we mate at the next move our score // would be at best mate_in(ss->ply + 1), but if alpha is already bigger because @@ -711,9 +709,7 @@ Value Search::Worker::search( auto [ttHit, ttData, ttWriter] = tt.probe(posKey); // Need further processing of the saved data ss->ttHit = ttHit; - ttData.move = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] - : ttHit ? ttData.move - : Move::none(); + ttData.move = rootNode ? rootMoves[pvIdx].pv[0] : ttHit ? ttData.move : Move::none(); ttData.value = ttHit ? value_from_tt(ttData.value, ss->ply, pos.rule50_count()) : VALUE_NONE; ss->ttPv = excludedMove ? ss->ttPv : PvNode || (ttHit && ttData.is_pv); ttCapture = ttData.move && pos.capture_stage(ttData.move); @@ -781,7 +777,7 @@ Value Search::Worker::search( if (err != TB::ProbeState::FAIL) { - thisThread->tbHits.fetch_add(1, std::memory_order_relaxed); + tbHits.fetch_add(1, std::memory_order_relaxed); int drawScore = tbConfig.useRule50 ? 1 : 0; @@ -798,10 +794,9 @@ Value Search::Worker::search( if (b == BOUND_EXACT || (b == BOUND_LOWER ? value >= beta : value <= alpha)) { - Distributed::save(tt, threads, thisThread, ttWriter, posKey, - value_to_tt(value, ss->ply), ss->ttPv, b, - std::min(MAX_PLY - 1, depth + 6), Move::none(), VALUE_NONE, - tt.generation()); + Distributed::save( + tt, threads, this, ttWriter, posKey, value_to_tt(value, ss->ply), ss->ttPv, b, + std::min(MAX_PLY - 1, depth + 6), Move::none(), VALUE_NONE, tt.generation()); return value; } @@ -819,7 +814,7 @@ Value Search::Worker::search( // Step 6. Static evaluation of the position Value unadjustedStaticEval = VALUE_NONE; - const auto correctionValue = correction_value(*thisThread, pos, ss); + const auto correctionValue = correction_value(*this, pos, ss); if (ss->inCheck) { // Skip early pruning when in check @@ -849,18 +844,17 @@ Value Search::Worker::search( ss->staticEval = eval = to_corrected_static_eval(unadjustedStaticEval, correctionValue); // Static evaluation is saved as it was before adjustment by correction history - Distributed::save(tt, threads, thisThread, ttWriter, posKey, VALUE_NONE, ss->ttPv, - BOUND_NONE, DEPTH_UNSEARCHED, Move::none(), unadjustedStaticEval, - tt.generation()); + Distributed::save(tt, threads, this, ttWriter, posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, + DEPTH_UNSEARCHED, Move::none(), unadjustedStaticEval, tt.generation()); } // Use static evaluation difference to improve quiet move ordering if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture && !ttHit) { int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1858, 1492) + 661; - thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 1057 / 1024; + mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 1057 / 1024; if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) - thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] + pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] << bonus * 1266 / 1024; } @@ -904,7 +898,7 @@ Value Search::Worker::search( // Step 9. Null move search with verification search if (cutNode && (ss - 1)->currentMove != Move::null() && eval >= beta && ss->staticEval >= beta - 19 * depth + 389 && !excludedMove && pos.non_pawn_material(us) - && ss->ply >= thisThread->nmpMinPly && !is_loss(beta)) + && ss->ply >= nmpMinPly && !is_loss(beta)) { assert(eval - beta >= 0); @@ -912,8 +906,8 @@ Value Search::Worker::search( Depth R = 7 + depth / 3; ss->currentMove = Move::null(); - ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; - ss->continuationCorrectionHistory = &thisThread->continuationCorrectionHistory[NO_PIECE][0]; + ss->continuationHistory = &continuationHistory[0][0][NO_PIECE][0]; + ss->continuationCorrectionHistory = &continuationCorrectionHistory[NO_PIECE][0]; do_null_move(pos, st); @@ -924,18 +918,18 @@ Value Search::Worker::search( // Do not return unproven mate or TB scores if (nullValue >= beta && !is_win(nullValue)) { - if (thisThread->nmpMinPly || depth < 16) + if (nmpMinPly || depth < 16) return nullValue; - assert(!thisThread->nmpMinPly); // Recursive verification is not allowed + assert(!nmpMinPly); // Recursive verification is not allowed // Do verification search at high depths, with null move pruning disabled // until ply exceeds nmpMinPly. - thisThread->nmpMinPly = ss->ply + 3 * (depth - R) / 4; + nmpMinPly = ss->ply + 3 * (depth - R) / 4; Value v = search(pos, ss, beta - 1, beta, depth - R, false); - thisThread->nmpMinPly = 0; + nmpMinPly = 0; if (v >= beta) return nullValue; @@ -962,7 +956,7 @@ Value Search::Worker::search( { assert(probCutBeta < VALUE_INFINITE && probCutBeta > beta); - MovePicker mp(pos, ttData.move, probCutBeta - ss->staticEval, &thisThread->captureHistory); + MovePicker mp(pos, ttData.move, probCutBeta - ss->staticEval, &captureHistory); Depth probCutDepth = std::max(depth - 5, 0); while ((move = mp.next_move()) != Move::none()) @@ -980,9 +974,9 @@ Value Search::Worker::search( ss->currentMove = move; ss->continuationHistory = - &this->continuationHistory[ss->inCheck][true][movedPiece][move.to_sq()]; + &continuationHistory[ss->inCheck][true][movedPiece][move.to_sq()]; ss->continuationCorrectionHistory = - &this->continuationCorrectionHistory[movedPiece][move.to_sq()]; + &continuationCorrectionHistory[movedPiece][move.to_sq()]; // Perform a preliminary qsearch to verify that the move holds value = -qsearch(pos, ss + 1, -probCutBeta, -probCutBeta + 1); @@ -997,9 +991,9 @@ Value Search::Worker::search( if (value >= probCutBeta) { // Save ProbCut data into transposition table - Distributed::save(tt, threads, thisThread, ttWriter, posKey, - value_to_tt(value, ss->ply), ss->ttPv, BOUND_LOWER, - probCutDepth + 1, move, unadjustedStaticEval, tt.generation()); + Distributed::save(tt, threads, this, ttWriter, posKey, value_to_tt(value, ss->ply), + ss->ttPv, BOUND_LOWER, probCutDepth + 1, move, + unadjustedStaticEval, tt.generation()); if (!is_decisive(value)) return value - (probCutBeta - beta); @@ -1020,8 +1014,8 @@ moves_loop: // When in check, search starts here (ss - 4)->continuationHistory, (ss - 5)->continuationHistory, (ss - 6)->continuationHistory}; - MovePicker mp(pos, ttData.move, depth, &thisThread->mainHistory, &thisThread->lowPlyHistory, - &thisThread->captureHistory, contHist, &thisThread->pawnHistory, ss->ply); + MovePicker mp(pos, ttData.move, depth, &mainHistory, &lowPlyHistory, &captureHistory, contHist, + &pawnHistory, ss->ply); value = bestValue; @@ -1043,9 +1037,7 @@ moves_loop: // When in check, search starts here // At root obey the "searchmoves" option and skip moves not listed in Root // Move List. In MultiPV mode we also skip PV moves that have been already // searched and those of lower "TB rank" if we are in a TB root position. - if (rootNode - && !std::count(thisThread->rootMoves.begin() + thisThread->pvIdx, - thisThread->rootMoves.begin() + thisThread->pvLast, move)) + if (rootNode && !std::count(rootMoves.begin() + pvIdx, rootMoves.begin() + pvLast, move)) continue; ss->moveCount = ++moveCount; @@ -1053,7 +1045,7 @@ moves_loop: // When in check, search starts here if (rootNode && Distributed::is_root() && is_mainthread() && nodes > 10000000) { main_manager()->updates.onIter( - {depth, UCIEngine::move(move, pos.is_chess960()), moveCount + thisThread->pvIdx}); + {depth, UCIEngine::move(move, pos.is_chess960()), moveCount + pvIdx}); } if (PvNode) (ss + 1)->pv = nullptr; @@ -1092,8 +1084,7 @@ moves_loop: // When in check, search starts here if (capture || givesCheck) { Piece capturedPiece = pos.piece_on(move.to_sq()); - int captHist = - thisThread->captureHistory[movedPiece][move.to_sq()][type_of(capturedPiece)]; + int captHist = captureHistory[movedPiece][move.to_sq()][type_of(capturedPiece)]; // Futility pruning for captures if (!givesCheck && lmrDepth < 7 && !ss->inCheck) @@ -1122,16 +1113,15 @@ moves_loop: // When in check, search starts here } else { - int history = - (*contHist[0])[movedPiece][move.to_sq()] - + (*contHist[1])[movedPiece][move.to_sq()] - + thisThread->pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()]; + int history = (*contHist[0])[movedPiece][move.to_sq()] + + (*contHist[1])[movedPiece][move.to_sq()] + + pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()]; // Continuation history based pruning if (history < -4229 * depth) continue; - history += 68 * thisThread->mainHistory[us][move.from_to()] / 32; + history += 68 * mainHistory[us][move.from_to()] / 32; lmrDepth += history / 3388; @@ -1170,7 +1160,7 @@ moves_loop: // When in check, search starts here // and lower extension margins scale well. if (!rootNode && move == ttData.move && !excludedMove - && depth >= 6 - (thisThread->completedDepth > 27) + ss->ttPv && is_valid(ttData.value) + && depth >= 6 - (completedDepth > 27) + ss->ttPv && is_valid(ttData.value) && !is_decisive(ttData.value) && (ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 3) { @@ -1185,10 +1175,9 @@ moves_loop: // When in check, search starts here { int corrValAdj = std::abs(correctionValue) / 248400; int doubleMargin = -4 + 244 * PvNode - 206 * !ttCapture - corrValAdj - - 997 * ttMoveHistory / 131072 - - (ss->ply > thisThread->rootDepth) * 47; + - 997 * ttMoveHistory / 131072 - (ss->ply > rootDepth) * 47; int tripleMargin = 84 + 269 * PvNode - 253 * !ttCapture + 91 * ss->ttPv - corrValAdj - - (ss->ply * 2 > thisThread->rootDepth * 3) * 54; + - (ss->ply * 2 > rootDepth * 3) * 54; extension = 1 + (value < singularBeta - doubleMargin) + (value < singularBeta - tripleMargin); @@ -1231,9 +1220,9 @@ moves_loop: // When in check, search starts here // Update the current move (this must be done after singular extension search) ss->currentMove = move; ss->continuationHistory = - &thisThread->continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()]; + &continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()]; ss->continuationCorrectionHistory = - &thisThread->continuationCorrectionHistory[movedPiece][move.to_sq()]; + &continuationCorrectionHistory[movedPiece][move.to_sq()]; uint64_t nodeCount = rootNode ? uint64_t(nodes) : 0; // Decrease reduction for PvNodes (*Scaler) @@ -1266,11 +1255,10 @@ moves_loop: // When in check, search starts here r -= 2006; if (capture) - ss->statScore = - 826 * int(PieceValue[pos.captured_piece()]) / 128 - + thisThread->captureHistory[movedPiece][move.to_sq()][type_of(pos.captured_piece())]; + ss->statScore = 826 * int(PieceValue[pos.captured_piece()]) / 128 + + captureHistory[movedPiece][move.to_sq()][type_of(pos.captured_piece())]; else - ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()] + ss->statScore = 2 * mainHistory[us][move.from_to()] + (*contHist[0])[movedPiece][move.to_sq()] + (*contHist[1])[movedPiece][move.to_sq()]; @@ -1335,7 +1323,7 @@ moves_loop: // When in check, search starts here (ss + 1)->pv[0] = Move::none(); // Extend move from transposition table if we are about to dive into qsearch. - if (move == ttData.move && thisThread->rootDepth > 8) + if (move == ttData.move && rootDepth > 8) newDepth = std::max(newDepth, 1); value = -search(pos, ss + 1, -beta, -alpha, newDepth, false); @@ -1355,8 +1343,7 @@ moves_loop: // When in check, search starts here if (rootNode) { - RootMove& rm = - *std::find(thisThread->rootMoves.begin(), thisThread->rootMoves.end(), move); + RootMove& rm = *std::find(rootMoves.begin(), rootMoves.end(), move); rm.effort += nodes - nodeCount; @@ -1371,7 +1358,7 @@ moves_loop: // When in check, search starts here if (moveCount == 1 || value > alpha) { rm.score = rm.uciScore = value; - rm.selDepth = thisThread->selDepth; + rm.selDepth = selDepth; rm.scoreLowerbound = rm.scoreUpperbound = false; if (value >= beta) @@ -1395,8 +1382,8 @@ moves_loop: // When in check, search starts here // We record how often the best move has been changed in each iteration. // This information is used for time management. In MultiPV mode, // we must take care to only do this for the first PV line. - if (moveCount > 1 && !thisThread->pvIdx) - ++thisThread->bestMoveChanges; + if (moveCount > 1 && !pvIdx) + ++bestMoveChanges; } else // All other moves but the PV, are set to the lowest value: this @@ -1407,8 +1394,8 @@ moves_loop: // When in check, search starts here // In case we have an alternative move equal in eval to the current bestmove, // promote it to bestmove by pretending it just exceeds alpha (but not beta). - int inc = (value == bestValue && ss->ply + 2 >= thisThread->rootDepth - && (int(nodes) & 15) == 0 && !is_win(std::abs(value) + 1)); + int inc = (value == bestValue && ss->ply + 2 >= rootDepth && (int(nodes) & 15) == 0 + && !is_win(std::abs(value) + 1)); if (value + inc > bestValue) { @@ -1490,11 +1477,10 @@ moves_loop: // When in check, search starts here update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, scaledBonus * 412 / 32768); - thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] - << scaledBonus * 203 / 32768; + mainHistory[~us][((ss - 1)->currentMove).from_to()] << scaledBonus * 203 / 32768; if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) - thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] + pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] << scaledBonus * 1040 / 32768; } @@ -1503,7 +1489,7 @@ moves_loop: // When in check, search starts here { Piece capturedPiece = pos.captured_piece(); assert(capturedPiece != NO_PIECE); - thisThread->captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)] << 1080; + captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)] << 1080; } if (PvNode) @@ -1516,9 +1502,9 @@ moves_loop: // When in check, search starts here // Write gathered information in transposition table. Note that the // static evaluation is saved as it was before correction history. - if (!excludedMove && !(rootNode && thisThread->pvIdx)) - Distributed::save(tt, threads, thisThread, ttWriter, posKey, - value_to_tt(bestValue, ss->ply), ss->ttPv, + if (!excludedMove && !(rootNode && pvIdx)) + Distributed::save(tt, threads, this, ttWriter, posKey, value_to_tt(bestValue, ss->ply), + ss->ttPv, bestValue >= beta ? BOUND_LOWER : PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, @@ -1532,7 +1518,7 @@ moves_loop: // When in check, search starts here { auto bonus = std::clamp(int(bestValue - ss->staticEval) * depth / 8, -CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4); - update_correction_history(pos, ss, *thisThread, bonus); + update_correction_history(pos, ss, *this, bonus); } assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); @@ -1559,7 +1545,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) // Check if we have an upcoming move that draws by repetition if (alpha < VALUE_DRAW && pos.upcoming_repetition(ss->ply)) { - alpha = value_draw(this->nodes); + alpha = value_draw(nodes); if (alpha >= beta) return alpha; } @@ -1580,14 +1566,13 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) ss->pv[0] = Move::none(); } - Worker* thisThread = this; - bestMove = Move::none(); - ss->inCheck = pos.checkers(); - moveCount = 0; + bestMove = Move::none(); + ss->inCheck = pos.checkers(); + moveCount = 0; // Used to send selDepth info to GUI (selDepth counts from 1, ply from 0) - if (PvNode && thisThread->selDepth < ss->ply + 1) - thisThread->selDepth = ss->ply + 1; + if (PvNode && selDepth < ss->ply + 1) + selDepth = ss->ply + 1; // Step 2. Check for an immediate draw or maximum ply reached if (pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) @@ -1616,7 +1601,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) bestValue = futilityBase = -VALUE_INFINITE; else { - const auto correctionValue = correction_value(*thisThread, pos, ss); + const auto correctionValue = correction_value(*this, pos, ss); if (ss->ttHit) { @@ -1646,7 +1631,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) if (!is_decisive(bestValue)) bestValue = (bestValue + beta) / 2; if (!ss->ttHit) - Distributed::save(tt, threads, thisThread, ttWriter, posKey, + Distributed::save(tt, threads, this, ttWriter, posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER, DEPTH_UNSEARCHED, Move::none(), unadjustedStaticEval, tt.generation()); @@ -1668,8 +1653,8 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) // Initialize a MovePicker object for the current position, and prepare to search // the moves. We presently use two stages of move generator in quiescence search: // captures, or evasions only when in check. - MovePicker mp(pos, ttData.move, DEPTH_QS, &thisThread->mainHistory, &thisThread->lowPlyHistory, - &thisThread->captureHistory, contHist, &thisThread->pawnHistory, ss->ply); + MovePicker mp(pos, ttData.move, DEPTH_QS, &mainHistory, &lowPlyHistory, &captureHistory, + contHist, &pawnHistory, ss->ply); // Step 5. Loop through all pseudo-legal moves until no moves remain or a beta // cutoff occurs. @@ -1717,8 +1702,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) // Continuation history based pruning if (!capture && (*contHist[0])[pos.moved_piece(move)][move.to_sq()] - + thisThread->pawnHistory[pawn_structure_index(pos)][pos.moved_piece(move)] - [move.to_sq()] + + pawnHistory[pawn_structure_index(pos)][pos.moved_piece(move)][move.to_sq()] <= 6218) continue; @@ -1735,9 +1719,9 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) // Update the current move ss->currentMove = move; ss->continuationHistory = - &thisThread->continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()]; + &continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()]; ss->continuationCorrectionHistory = - &thisThread->continuationCorrectionHistory[movedPiece][move.to_sq()]; + &continuationCorrectionHistory[movedPiece][move.to_sq()]; value = -qsearch(pos, ss + 1, -beta, -alpha); undo_move(pos, move); @@ -1794,8 +1778,8 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) // Save gathered info in transposition table. The static evaluation // is saved as it was before adjustment by correction history. - Distributed::save(tt, threads, thisThread, ttWriter, posKey, value_to_tt(bestValue, ss->ply), - pvHit, bestValue >= beta ? BOUND_LOWER : BOUND_UPPER, DEPTH_QS, bestMove, + Distributed::save(tt, threads, this, ttWriter, posKey, value_to_tt(bestValue, ss->ply), pvHit, + bestValue >= beta ? BOUND_LOWER : BOUND_UPPER, DEPTH_QS, bestMove, unadjustedStaticEval, tt.generation()); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);