diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a826e6f06..b97aaa29c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -139,7 +139,7 @@ jobs: - name: Build Docker container if: matrix.config.base_image run: | - docker buildx build --load -t sf_builder - << EOF + docker buildx build --platform ${{ matrix.config.platform }} --load -t sf_builder - << EOF FROM ${{ matrix.config.base_image }} WORKDIR /app RUN apk update && apk add make g++ diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7c7b54a4f..bc86a7420 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -66,7 +66,7 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, Value nnue = (125 * psqt + 131 * positional) / 128; // Re-evaluate the position when higher eval accuracy is worth the time spent - if (smallNet && (nnue * psqt < 0 || std::abs(nnue) < 227)) + if (smallNet && (std::abs(nnue) < 236)) { std::tie(psqt, positional) = networks.big.evaluate(pos, &caches.big); nnue = (125 * psqt + 131 * positional) / 128; diff --git a/src/evaluate.h b/src/evaluate.h index 9bd436b58..4604321d3 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -33,7 +33,7 @@ namespace Eval { // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro or the location where this macro is defined, as it is used // in the Makefile/Fishtest. -#define EvalFileDefaultNameBig "nn-1cedc0ffeeee.nnue" +#define EvalFileDefaultNameBig "nn-1c0000000000.nnue" #define EvalFileDefaultNameSmall "nn-37f18f62d772.nnue" namespace NNUE { diff --git a/src/movepick.cpp b/src/movepick.cpp index 720f2e031..df722eceb 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -158,11 +158,11 @@ void MovePicker::score() { Square to = m.to_sq(); // histories - m.value = (*mainHistory)[pos.side_to_move()][m.from_to()]; + m.value = 2 * (*mainHistory)[pos.side_to_move()][m.from_to()]; m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to]; - m.value += 2 * (*continuationHistory[0])[pc][to]; + m.value += (*continuationHistory[0])[pc][to]; m.value += (*continuationHistory[1])[pc][to]; - m.value += (*continuationHistory[2])[pc][to] / 3; + m.value += (*continuationHistory[2])[pc][to]; m.value += (*continuationHistory[3])[pc][to]; m.value += (*continuationHistory[5])[pc][to]; diff --git a/src/nnue/nnue_accumulator.h b/src/nnue/nnue_accumulator.h index b8dcf1e48..b92901e4a 100644 --- a/src/nnue/nnue_accumulator.h +++ b/src/nnue/nnue_accumulator.h @@ -80,11 +80,6 @@ struct AccumulatorCaches { entry.clear(network.featureTransformer->biases); } - void clear(const BiasType* biases) { - for (auto& entry : entries) - entry.clear(biases); - } - std::array& operator[](Square sq) { return entries[sq]; } std::array, SQUARE_NB> entries; diff --git a/src/search.cpp b/src/search.cpp index f2b534272..cb4e182bc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -68,7 +68,7 @@ namespace { // Futility margin Value futility_margin(Depth d, bool noTtCutNode, bool improving, bool oppWorsening) { - Value futilityMult = 118 - 33 * noTtCutNode; + Value futilityMult = 109 - 27 * noTtCutNode; Value improvingDeduction = improving * futilityMult * 2; Value worseningDeduction = oppWorsening * futilityMult / 3; @@ -95,16 +95,16 @@ Value to_corrected_static_eval(Value v, const Worker& w, const Position& pos, St cntcv = int((*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()]); const auto cv = - (5932 * pcv + 3269 * macv + 5660 * micv + 6666 * (wnpcv + bnpcv) + 5555 * cntcv) / 131072; + (6384 * pcv + 3583 * macv + 6492 * micv + 6725 * (wnpcv + bnpcv) + cntcv * 5880) / 131072; v += cv; return std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); } // History and stats update bonus, based on depth -int stat_bonus(Depth d) { return std::min(179 * d - 108, 1598); } +int stat_bonus(Depth d) { return std::min(168 * d - 100, 1718); } // History and stats update malus, based on depth -int stat_malus(Depth d) { return std::min(820 * d - 261, 2246); } +int stat_malus(Depth d) { return std::min(768 * d - 257, 2351); } // Add a small random component to draw evaluations to avoid 3-fold blindness Value value_draw(size_t nodes) { return VALUE_DRAW - 1 + Value(nodes & 0x2); } @@ -353,13 +353,13 @@ void Search::Worker::iterative_deepening() { selDepth = 0; // Reset aspiration window starting size - delta = 5 + std::abs(rootMoves[pvIdx].meanSquaredScore) / 13797; + delta = 5 + std::abs(rootMoves[pvIdx].meanSquaredScore) / 13461; Value avg = rootMoves[pvIdx].averageScore; alpha = std::max(avg - delta, -VALUE_INFINITE); beta = std::min(avg + delta, VALUE_INFINITE); // Adjust optimism based on root move's averageScore (~4 Elo) - optimism[us] = 132 * avg / (std::abs(avg) + 89); + optimism[us] = 150 * avg / (std::abs(avg) + 85); optimism[~us] = -optimism[us]; // Start with a small aspiration window and, in the case of a fail @@ -550,8 +550,8 @@ void Search::Worker::iterative_deepening() { void Search::Worker::clear() { mainHistory.fill(0); lowPlyHistory.fill(0); - captureHistory.fill(-753); - pawnHistory.fill(-1152); + captureHistory.fill(-758); + pawnHistory.fill(-1158); pawnCorrectionHistory.fill(0); majorPieceCorrectionHistory.fill(0); minorPieceCorrectionHistory.fill(0); @@ -566,10 +566,10 @@ void Search::Worker::clear() { for (StatsType c : {NoCaptures, Captures}) for (auto& to : continuationHistory[inCheck][c]) for (auto& h : to) - h->fill(-678); + h->fill(-645); for (size_t i = 1; i < reductions.size(); ++i) - reductions[i] = int((18.43 + std::log(size_t(options["Threads"])) / 2) * std::log(i)); + reductions[i] = int((19.43 + std::log(size_t(options["Threads"])) / 2) * std::log(i)); refreshTable.clear(networks[numaAccessToken]); } @@ -684,7 +684,8 @@ Value Search::Worker::search( // At non-PV nodes we check for an early TT cutoff if (!PvNode && !excludedMove && ttData.depth > depth - (ttData.value <= beta) && ttData.value != VALUE_NONE // Can happen when !ttHit or when access race in probe() - && (ttData.bound & (ttData.value >= beta ? BOUND_LOWER : BOUND_UPPER))) + && (ttData.bound & (ttData.value >= beta ? BOUND_LOWER : BOUND_UPPER)) + && (cutNode == (ttData.value >= beta) || depth > 8)) { // If ttMove is quiet, update move sorting heuristics on TT hit (~2 Elo) if (ttData.move && ttData.value >= beta) @@ -810,11 +811,11 @@ Value Search::Worker::search( // Use static evaluation difference to improve quiet move ordering (~9 Elo) if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture) { - int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1641, 1423) + 760; + int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1831, 1428) + 623; thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus; 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] - << bonus / 2; + << bonus; } // Set up the improving flag, which is true if current static evaluation is @@ -828,7 +829,7 @@ Value Search::Worker::search( // Step 7. Razoring (~1 Elo) // If eval is really low, check with qsearch if we can exceed alpha. If the // search suggests we cannot exceed alpha, return a speculative fail low. - if (eval < alpha - 501 - 272 * depth * depth) + if (eval < alpha - 469 - 307 * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); if (value < alpha && std::abs(value) < VALUE_TB_WIN_IN_MAX_PLY) @@ -837,23 +838,25 @@ Value Search::Worker::search( // Step 8. Futility pruning: child node (~40 Elo) // The depth condition is important for mate finding. - if (!ss->ttPv && depth < 13 + if (!ss->ttPv && depth < 14 && eval - futility_margin(depth, cutNode && !ss->ttHit, improving, opponentWorsening) - - (ss - 1)->statScore / 272 + - (ss - 1)->statScore / 290 >= beta && eval >= beta && (!ttData.move || ttCapture) && beta > VALUE_TB_LOSS_IN_MAX_PLY && eval < VALUE_TB_WIN_IN_MAX_PLY) return beta + (eval - beta) / 3; + improving |= ss->staticEval >= beta + 100; + // Step 9. Null move search with verification search (~35 Elo) if (cutNode && (ss - 1)->currentMove != Move::null() && eval >= beta - && ss->staticEval >= beta - 23 * depth + 400 && !excludedMove && pos.non_pawn_material(us) + && ss->staticEval >= beta - 21 * depth + 421 && !excludedMove && pos.non_pawn_material(us) && ss->ply >= thisThread->nmpMinPly && beta > VALUE_TB_LOSS_IN_MAX_PLY) { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and eval - Depth R = std::min(int(eval - beta) / 209, 6) + depth / 3 + 5; + Depth R = std::min(int(eval - beta) / 235, 7) + depth / 3 + 5; ss->currentMove = Move::null(); ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; @@ -898,12 +901,12 @@ Value Search::Worker::search( // For cutNodes, if depth is high enough, decrease depth by 2 if there is no ttMove, // or by 1 if there is a ttMove with an upper bound. if (cutNode && depth >= 7 && (!ttData.move || ttData.bound == BOUND_UPPER)) - depth -= 2; + depth -= 1 + !ttData.move; // Step 11. ProbCut (~10 Elo) // If we have a good enough capture (or queen promotion) and a reduced search // returns a value much above beta, we can (almost) safely prune the previous move. - probCutBeta = beta + 189 - 53 * improving - 30 * opponentWorsening; + probCutBeta = beta + 187 - 53 * improving - 27 * opponentWorsening; if (!PvNode && depth > 3 && std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY // If value from transposition table is lower than probCutBeta, don't attempt @@ -936,7 +939,8 @@ Value Search::Worker::search( // Prefetch the TT entry for the resulting position prefetch(tt.first_entry(pos.key_after(move))); - ss->currentMove = move; + ss->currentMove = move; + ss->capturedPiece = captured; ss->continuationHistory = &this->continuationHistory[ss->inCheck][true][pos.moved_piece(move)][move.to_sq()]; ss->continuationCorrectionHistory = @@ -957,8 +961,7 @@ Value Search::Worker::search( if (value >= probCutBeta) { - thisThread->captureHistory[movedPiece][move.to_sq()][type_of(captured)] - << stat_bonus(depth - 2); + thisThread->captureHistory[movedPiece][move.to_sq()][type_of(captured)] << 1300; // Save ProbCut data into transposition table Distributed::save(tt, threads, thisThread, ttWriter, posKey, @@ -975,7 +978,7 @@ Value Search::Worker::search( moves_loop: // When in check, search starts here // Step 12. A small Probcut idea (~4 Elo) - probCutBeta = beta + 379; + probCutBeta = beta + 417; if ((ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 4 && ttData.value >= probCutBeta && std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY && std::abs(ttData.value) < VALUE_TB_WIN_IN_MAX_PLY) @@ -1048,7 +1051,7 @@ moves_loop: // When in check, search starts here mp.skip_quiet_moves(); // Reduced depth of the next LMR search - int lmrDepth = newDepth - r; + int lmrDepth = newDepth - r / 1024; if (capture || givesCheck) { @@ -1059,15 +1062,15 @@ moves_loop: // When in check, search starts here // Futility pruning for captures (~2 Elo) if (!givesCheck && lmrDepth < 7 && !ss->inCheck) { - Value futilityValue = ss->staticEval + 300 + 238 * lmrDepth + Value futilityValue = ss->staticEval + 287 + 253 * lmrDepth + PieceValue[capturedPiece] + captHist / 7; if (futilityValue <= alpha) continue; } // SEE based pruning for captures and checks (~11 Elo) - int seeHist = std::clamp(captHist / 32, -159 * depth, 160 * depth); - if (!pos.see_ge(move, -167 * depth - seeHist)) + int seeHist = std::clamp(captHist / 33, -161 * depth, 156 * depth); + if (!pos.see_ge(move, -162 * depth - seeHist)) continue; } else @@ -1078,15 +1081,15 @@ moves_loop: // When in check, search starts here + thisThread->pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()]; // Continuation history based pruning (~2 Elo) - if (history < -4071 * depth) + if (history < -3884 * depth) continue; history += 2 * thisThread->mainHistory[us][move.from_to()]; - lmrDepth += history / 3653; + lmrDepth += history / 3609; Value futilityValue = - ss->staticEval + (bestValue < ss->staticEval - 51 ? 145 : 49) + 144 * lmrDepth; + ss->staticEval + (bestValue < ss->staticEval - 45 ? 140 : 43) + 141 * lmrDepth; // Futility pruning: parent node (~13 Elo) if (!ss->inCheck && lmrDepth < 12 && futilityValue <= alpha) @@ -1100,7 +1103,7 @@ moves_loop: // When in check, search starts here lmrDepth = std::max(lmrDepth, 0); // Prune moves with negative SEE (~4 Elo) - if (!pos.see_ge(move, -24 * lmrDepth * lmrDepth)) + if (!pos.see_ge(move, -25 * lmrDepth * lmrDepth)) continue; } } @@ -1123,11 +1126,11 @@ moves_loop: // When in check, search starts here // and lower extension margins scale well. if (!rootNode && move == ttData.move && !excludedMove - && depth >= 4 - (thisThread->completedDepth > 36) + ss->ttPv + && depth >= 4 - (thisThread->completedDepth > 33) + ss->ttPv && std::abs(ttData.value) < VALUE_TB_WIN_IN_MAX_PLY && (ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 3) { - Value singularBeta = ttData.value - (54 + 77 * (ss->ttPv && !PvNode)) * depth / 64; + Value singularBeta = ttData.value - (56 + 79 * (ss->ttPv && !PvNode)) * depth / 64; Depth singularDepth = newDepth / 2; ss->excludedMove = move; @@ -1137,8 +1140,8 @@ moves_loop: // When in check, search starts here if (value < singularBeta) { - int doubleMargin = 262 * PvNode - 204 * !ttCapture; - int tripleMargin = 97 + 266 * PvNode - 255 * !ttCapture + 94 * ss->ttPv; + int doubleMargin = 249 * PvNode - 194 * !ttCapture; + int tripleMargin = 94 + 287 * PvNode - 249 * !ttCapture + 99 * ss->ttPv; extension = 1 + (value < singularBeta - doubleMargin) + (value < singularBeta - tripleMargin); @@ -1176,7 +1179,7 @@ moves_loop: // When in check, search starts here else if (PvNode && move.to_sq() == prevSq && thisThread->captureHistory[movedPiece][move.to_sq()] [type_of(pos.piece_on(move.to_sq()))] - > 4299) + > 4321) extension = 1; } @@ -1187,7 +1190,8 @@ moves_loop: // When in check, search starts here prefetch(tt.first_entry(pos.key_after(move))); // Update the current move (this must be done after singular extension search) - ss->currentMove = move; + ss->currentMove = move; + ss->capturedPiece = pos.piece_on(move.to_sq()); ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()]; ss->continuationCorrectionHistory = @@ -1205,36 +1209,39 @@ moves_loop: // When in check, search starts here // Decrease reduction if position is or has been on the PV (~7 Elo) if (ss->ttPv) - r -= 1 + (ttData.value > alpha) + (ttData.depth >= depth); + r -= 1024 + (ttData.value > alpha) * 1024 + (ttData.depth >= depth) * 1024; // Decrease reduction for PvNodes (~0 Elo on STC, ~2 Elo on LTC) if (PvNode) - r--; + r -= 1024; // These reduction adjustments have no proven non-linear scaling // Increase reduction for cut nodes (~4 Elo) if (cutNode) - r += 2 - (ttData.depth >= depth && ss->ttPv); + r += 2518 - (ttData.depth >= depth && ss->ttPv) * 991; // Increase reduction if ttMove is a capture but the current move is not a capture (~3 Elo) if (ttCapture && !capture) - r += 1 + (depth < 8); + r += 1043 + (depth < 8) * 999; // Increase reduction if next ply has a lot of fail high (~5 Elo) if ((ss + 1)->cutoffCnt > 3) - r += 1 + allNode; + r += 938 + allNode * 960; // For first picked move (ttMove) reduce reduction (~3 Elo) else if (move == ttData.move) - r -= 2; + r -= 1879; - ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()] - + (*contHist[0])[movedPiece][move.to_sq()] - + (*contHist[1])[movedPiece][move.to_sq()] - 4410; + if (capture) + ss->statScore = 0; + else + ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()] + + (*contHist[0])[movedPiece][move.to_sq()] + + (*contHist[1])[movedPiece][move.to_sq()] - 3996; // Decrease/increase reduction for moves with a good/bad history (~8 Elo) - r -= ss->statScore / 11016; + r -= ss->statScore * 1287 / 16384; // Step 17. Late moves reduction / extension (LMR, ~117 Elo) if (depth >= 2 && moveCount > 1) @@ -1244,7 +1251,7 @@ moves_loop: // When in check, search starts here // beyond the first move depth. // To prevent problems when the max value is less than the min value, // std::clamp has been replaced by a more robust implementation. - Depth d = std::max(1, std::min(newDepth - r, newDepth + !allNode)); + Depth d = std::max(1, std::min(newDepth - r / 1024, newDepth + !allNode)); value = -search(pos, ss + 1, -(alpha + 1), -alpha, d, true); @@ -1253,8 +1260,8 @@ moves_loop: // When in check, search starts here { // Adjust full-depth search based on LMR results - if the result was // good enough search deeper, if it was bad enough search shallower. - const bool doDeeperSearch = value > (bestValue + 38 + 2 * newDepth); // (~1 Elo) - const bool doShallowerSearch = value < bestValue + 8; // (~2 Elo) + const bool doDeeperSearch = value > (bestValue + 42 + 2 * newDepth); // (~1 Elo) + const bool doShallowerSearch = value < bestValue + 10; // (~2 Elo) newDepth += doDeeperSearch - doShallowerSearch; @@ -1272,10 +1279,11 @@ moves_loop: // When in check, search starts here { // Increase reduction if ttMove is not present (~6 Elo) if (!ttData.move) - r += 2; + r += 2037; // Note that if expected reduction is high, we reduce search depth by 1 here (~9 Elo) - value = -search(pos, ss + 1, -(alpha + 1), -alpha, newDepth - (r > 3), !cutNode); + value = + -search(pos, ss + 1, -(alpha + 1), -alpha, newDepth - (r > 2983), !cutNode); } // For PV nodes only, do a full PV search on the first move or after a fail high, @@ -1425,29 +1433,37 @@ moves_loop: // When in check, search starts here // Bonus for prior countermove that caused the fail low else if (!priorCapture && prevSq != SQ_NONE) { - int bonus = (118 * (depth > 5) + 38 * !allNode + 169 * ((ss - 1)->moveCount > 8) - + 116 * (!ss->inCheck && bestValue <= ss->staticEval - 101) - + 133 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 92)); + int bonus = (117 * (depth > 5) + 39 * !allNode + 168 * ((ss - 1)->moveCount > 8) + + 115 * (!ss->inCheck && bestValue <= ss->staticEval - 108) + + 119 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 83)); // Proportional to "how much damage we have to undo" - bonus += std::min(-(ss - 1)->statScore / 102, 305); + bonus += std::min(-(ss - 1)->statScore / 113, 300); bonus = std::max(bonus, 0); update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, - stat_bonus(depth) * bonus / 107); + stat_bonus(depth) * bonus / 93); thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] - << stat_bonus(depth) * bonus / 174; + << stat_bonus(depth) * bonus / 179; 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] - << stat_bonus(depth) * bonus / 25; + << stat_bonus(depth) * bonus / 24; + } + + else if (priorCapture && prevSq != SQ_NONE) + { + // bonus for prior countermoves that caused the fail low + Piece capturedPiece = (ss - 1)->capturedPiece; + thisThread->captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)] + << stat_bonus(depth) * 2; } // Bonus when search fails low and there is a TT move else if (ttData.move && !allNode) - thisThread->mainHistory[us][ttData.move.from_to()] << stat_bonus(depth) / 4; + thisThread->mainHistory[us][ttData.move.from_to()] << stat_bonus(depth) * 23 / 100; if (PvNode) bestValue = std::min(bestValue, maxValue); @@ -1468,22 +1484,22 @@ moves_loop: // When in check, search starts here depth, bestMove, unadjustedStaticEval, tt.generation()); // Adjust correction history - if (!ss->inCheck && (!bestMove || !pos.capture(bestMove)) - && !(bestValue >= beta && bestValue <= ss->staticEval) - && !(!bestMove && bestValue >= ss->staticEval)) + if (!ss->inCheck && !(bestMove && pos.capture(bestMove)) + && ((bestValue < ss->staticEval && bestValue < beta) // negative correction & no fail high + || (bestValue > ss->staticEval && bestMove))) // positive correction & no fail low { const auto m = (ss - 1)->currentMove; auto bonus = std::clamp(int(bestValue - ss->staticEval) * depth / 8, -CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4); thisThread->pawnCorrectionHistory[us][pawn_structure_index(pos)] - << bonus * 101 / 128; - thisThread->majorPieceCorrectionHistory[us][major_piece_index(pos)] << bonus * 157 / 128; - thisThread->minorPieceCorrectionHistory[us][minor_piece_index(pos)] << bonus * 153 / 128; + << bonus * 107 / 128; + thisThread->majorPieceCorrectionHistory[us][major_piece_index(pos)] << bonus * 162 / 128; + thisThread->minorPieceCorrectionHistory[us][minor_piece_index(pos)] << bonus * 148 / 128; thisThread->nonPawnCorrectionHistory[WHITE][us][non_pawn_index(pos)] - << bonus * 123 / 128; + << bonus * 122 / 128; thisThread->nonPawnCorrectionHistory[BLACK][us][non_pawn_index(pos)] - << bonus * 165 / 128; + << bonus * 185 / 128; if (m.is_ok()) (*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] << bonus; @@ -1617,7 +1633,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) if (bestValue > alpha) alpha = bestValue; - futilityBase = ss->staticEval + 280; + futilityBase = ss->staticEval + 306; } const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory, @@ -1680,11 +1696,11 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) + (*contHist[1])[pos.moved_piece(move)][move.to_sq()] + thisThread->pawnHistory[pawn_structure_index(pos)][pos.moved_piece(move)] [move.to_sq()] - <= 5036) + <= 5095) continue; // Do not search moves with bad enough SEE values (~5 Elo) - if (!pos.see_ge(move, -82)) + if (!pos.see_ge(move, -83)) continue; } @@ -1692,7 +1708,8 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) prefetch(tt.first_entry(pos.key_after(move))); // Update the current move - ss->currentMove = move; + ss->currentMove = move; + ss->capturedPiece = pos.piece_on(move.to_sq()); ss->continuationHistory = &thisThread ->continuationHistory[ss->inCheck][capture][pos.moved_piece(move)][move.to_sq()]; @@ -1752,7 +1769,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) Depth Search::Worker::reduction(bool i, Depth d, int mn, int delta) const { int reductionScale = reductions[d] * reductions[mn]; - return (reductionScale + 1239 - delta * 795 / rootDelta) / 1024 + (!i && reductionScale > 1341); + return (reductionScale + 1304 - delta * 814 / rootDelta) + (!i && reductionScale > 1423) * 1135; } // elapsed() returns the time elapsed since the search started. If the @@ -1883,7 +1900,7 @@ void update_all_stats(const Position& pos, // at ply -1, -2, -3, -4, and -6 with current move. void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { - bonus = bonus * 53 / 64; + bonus = bonus * 50 / 64; for (int i : {1, 2, 3, 4, 6}) { diff --git a/src/search.h b/src/search.h index 2fb67b4a1..87cfe19c9 100644 --- a/src/search.h +++ b/src/search.h @@ -68,6 +68,7 @@ struct Stack { CorrectionHistory* continuationCorrectionHistory; int ply; Move currentMove; + Piece capturedPiece; Move excludedMove; Value staticEval; int statScore; @@ -390,4 +391,4 @@ class Worker { } // namespace Stockfish -#endif // #ifndef SEARCH_H_INCLUDED +#endif // #ifndef SEARCH_H_INCLUDED \ No newline at end of file diff --git a/tests/instrumented.py b/tests/instrumented.py index a3747d4e9..db5ec8e08 100644 --- a/tests/instrumented.py +++ b/tests/instrumented.py @@ -352,10 +352,10 @@ class TestInteractive(metaclass=OrderedClassMembers): def test_fen_position_depth_27(self): self.stockfish.send_command("ucinewgame") self.stockfish.send_command( - "position fen 1NR2B2/5p2/5p2/1p1kpp2/1P2rp2/2P1pB2/2P1P1K1/8 b - -" + "position fen r1b2r1k/pp1p2pp/2p5/2B1q3/8/8/P1PN2PP/R4RK1 w - - 0 18" ) - self.stockfish.send_command("go depth 27") - self.stockfish.contains("score mate -2") + self.stockfish.send_command("go") + self.stockfish.contains("score mate 1") self.stockfish.starts_with("bestmove")