Merge commit 'e57fba7fc9be461cbb97c063b269a1e231cdd284' into cluster

This is the last commit before there are more conflicts.
This commit is contained in:
Steinar H. Gunderson
2025-12-25 16:54:13 +01:00
10 changed files with 126 additions and 140 deletions
+18 -2
View File
@@ -24,15 +24,31 @@ jobs:
with: with:
repository: vondele/matetrack repository: vondele/matetrack
path: matetrack path: matetrack
ref: 20287a1a145f30a166b7ef251eddb611e4e44fbf ref: 814160f82e6428ed2f6522dc06c2a6fa539cd413
persist-credentials: false persist-credentials: false
- name: matetrack install deps - name: matetrack install deps
working-directory: matetrack working-directory: matetrack
run: pip install -r requirements.txt run: pip install -r requirements.txt
- name: cache syzygy
id: cache-syzygy
uses: actions/cache@v4
with:
path: |
matetrack/3-4-5-wdl/
matetrack/3-4-5-dtz/
key: key-syzygy
- name: download syzygy 3-4-5 if needed
working-directory: matetrack
if: steps.cache-syzygy.outputs.cache-hit != 'true'
run: |
wget --no-verbose -r -nH --cut-dirs=2 --no-parent --reject="index.html*" -e robots=off https://tablebase.lichess.ovh/tables/standard/3-4-5-wdl/
wget --no-verbose -r -nH --cut-dirs=2 --no-parent --reject="index.html*" -e robots=off https://tablebase.lichess.ovh/tables/standard/3-4-5-dtz/
- name: Run matetrack - name: Run matetrack
working-directory: matetrack working-directory: matetrack
run: | run: |
python matecheck.py --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout.out python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout.out
! grep "issues were detected" matecheckout.out > /dev/null ! grep "issues were detected" matecheckout.out > /dev/null
+1
View File
@@ -20,6 +20,7 @@ Alexander Kure
Alexander Pagel (Lolligerhans) Alexander Pagel (Lolligerhans)
Alfredo Menezes (lonfom169) Alfredo Menezes (lonfom169)
Ali AlZhrani (Cooffe) Ali AlZhrani (Cooffe)
Andreas Jan van der Meulen (Andyson007)
Andreas Matthies (Matthies) Andreas Matthies (Matthies)
Andrei Vetrov (proukornew) Andrei Vetrov (proukornew)
Andrew Grant (AndyGrant) Andrew Grant (AndyGrant)
+1 -1
View File
@@ -93,7 +93,7 @@ Engine::Engine(std::string path) :
options["UCI_LimitStrength"] << Option(false); options["UCI_LimitStrength"] << Option(false);
options["UCI_Elo"] << Option(1320, 1320, 3190); options["UCI_Elo"] << Option(1320, 1320, 3190);
options["UCI_ShowWDL"] << Option(false); options["UCI_ShowWDL"] << Option(false);
options["SyzygyPath"] << Option("<empty>", [](const Option& o) { options["SyzygyPath"] << Option("", [](const Option& o) {
Tablebases::init(o); Tablebases::init(o);
return std::nullopt; return std::nullopt;
}); });
+6 -7
View File
@@ -66,24 +66,23 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks,
auto [psqt, positional] = smallNet ? networks.small.evaluate(pos, &caches.small) auto [psqt, positional] = smallNet ? networks.small.evaluate(pos, &caches.small)
: networks.big.evaluate(pos, &caches.big); : networks.big.evaluate(pos, &caches.big);
Value nnue = (125 * psqt + 131 * positional) / 128; Value nnue = (125 * psqt + 131 * positional) / 128;
int nnueComplexity = std::abs(psqt - positional);
// Re-evaluate the position when higher eval accuracy is worth the time spent // Re-evaluate the position when higher eval accuracy is worth the time spent
if (smallNet && (nnue * simpleEval < 0 || std::abs(nnue) < 227)) if (smallNet && (nnue * simpleEval < 0 || std::abs(nnue) < 227))
{ {
std::tie(psqt, positional) = networks.big.evaluate(pos, &caches.big); std::tie(psqt, positional) = networks.big.evaluate(pos, &caches.big);
nnue = (125 * psqt + 131 * positional) / 128; nnue = (125 * psqt + 131 * positional) / 128;
nnueComplexity = std::abs(psqt - positional);
smallNet = false; smallNet = false;
} }
// Blend optimism and eval with nnue complexity // Blend optimism and eval with nnue complexity
optimism += optimism * nnueComplexity / 457; int nnueComplexity = std::abs(psqt - positional);
nnue -= nnue * nnueComplexity / 19157; optimism += optimism * nnueComplexity / (smallNet ? 433 : 453);
nnue -= nnue * nnueComplexity / (smallNet ? 18815 : 17864);
int material = 554 * pos.count<PAWN>() + pos.non_pawn_material(); int material = (smallNet ? 553 : 532) * pos.count<PAWN>() + pos.non_pawn_material();
v = (nnue * (73921 + material) + optimism * (8112 + material)) / 73260; v = (nnue * (73921 + material) + optimism * (8112 + material)) / (smallNet ? 68104 : 74715);
// Evaluation grain (to get more alpha-beta cuts) with randomization (for robustness) // Evaluation grain (to get more alpha-beta cuts) with randomization (for robustness)
v = (v / 16) * 16 - 1 + (pos.key() & 0x2); v = (v / 16) * 16 - 1 + (pos.key() & 0x2);
+10 -40
View File
@@ -20,7 +20,6 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iterator>
#include <utility> #include <utility>
#include "bitboard.h" #include "bitboard.h"
@@ -35,7 +34,6 @@ enum Stages {
MAIN_TT, MAIN_TT,
CAPTURE_INIT, CAPTURE_INIT,
GOOD_CAPTURE, GOOD_CAPTURE,
REFUTATION,
QUIET_INIT, QUIET_INIT,
GOOD_QUIET, GOOD_QUIET,
BAD_CAPTURE, BAD_CAPTURE,
@@ -91,38 +89,21 @@ MovePicker::MovePicker(const Position& p,
const CapturePieceToHistory* cph, const CapturePieceToHistory* cph,
const PieceToHistory** ch, const PieceToHistory** ch,
const PawnHistory* ph, const PawnHistory* ph,
const Move* killers) : Move km) :
pos(p), pos(p),
mainHistory(mh), mainHistory(mh),
captureHistory(cph), captureHistory(cph),
continuationHistory(ch), continuationHistory(ch),
pawnHistory(ph), pawnHistory(ph),
ttMove(ttm), ttMove(ttm),
refutations{{killers[0], 0}, {killers[1], 0}}, killer(km),
depth(d) { depth(d) {
assert(d > 0);
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) + !(ttm && pos.pseudo_legal(ttm)); if (pos.checkers())
} stage = EVASION_TT + !(ttm && pos.pseudo_legal(ttm));
// Constructor for quiescence search else
MovePicker::MovePicker(const Position& p, stage = (depth > 0 ? MAIN_TT : QSEARCH_TT) + !(ttm && pos.pseudo_legal(ttm));
Move ttm,
Depth d,
const ButterflyHistory* mh,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
const PawnHistory* ph) :
pos(p),
mainHistory(mh),
captureHistory(cph),
continuationHistory(ch),
pawnHistory(ph),
ttMove(ttm),
depth(d) {
assert(d <= 0);
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) + !(ttm && pos.pseudo_legal(ttm));
} }
// Constructor for ProbCut: we generate captures with SEE greater than or equal // Constructor for ProbCut: we generate captures with SEE greater than or equal
@@ -185,6 +166,8 @@ void MovePicker::score() {
m.value += (*continuationHistory[3])[pc][to]; m.value += (*continuationHistory[3])[pc][to];
m.value += (*continuationHistory[5])[pc][to]; m.value += (*continuationHistory[5])[pc][to];
m.value += (m == killer) * 65536;
// bonus for checks // bonus for checks
m.value += bool(pos.check_squares(pt) & to) * 16384; m.value += bool(pos.check_squares(pt) & to) * 16384;
@@ -268,18 +251,6 @@ top:
})) }))
return *(cur - 1); return *(cur - 1);
// Prepare the pointers to loop over the refutations array
cur = std::begin(refutations);
endMoves = std::end(refutations);
++stage;
[[fallthrough]];
case REFUTATION :
if (select<Next>([&]() {
return *cur != Move::none() && !pos.capture_stage(*cur) && pos.pseudo_legal(*cur);
}))
return *(cur - 1);
++stage; ++stage;
[[fallthrough]]; [[fallthrough]];
@@ -297,8 +268,7 @@ top:
[[fallthrough]]; [[fallthrough]];
case GOOD_QUIET : case GOOD_QUIET :
if (!skipQuiets if (!skipQuiets && select<Next>([]() { return true; }))
&& select<Next>([&]() { return *cur != refutations[0] && *cur != refutations[1]; }))
{ {
if ((cur - 1)->value > -7998 || (cur - 1)->value <= quiet_threshold(depth)) if ((cur - 1)->value > -7998 || (cur - 1)->value <= quiet_threshold(depth))
return *(cur - 1); return *(cur - 1);
@@ -327,7 +297,7 @@ top:
case BAD_QUIET : case BAD_QUIET :
if (!skipQuiets) if (!skipQuiets)
return select<Next>([&]() { return *cur != refutations[0] && *cur != refutations[1]; }); return select<Next>([]() { return true; });
return Move::none(); return Move::none();
+7 -14
View File
@@ -160,14 +160,7 @@ class MovePicker {
const CapturePieceToHistory*, const CapturePieceToHistory*,
const PieceToHistory**, const PieceToHistory**,
const PawnHistory*, const PawnHistory*,
const Move*); Move killer = Move::none());
MovePicker(const Position&,
Move,
Depth,
const ButterflyHistory*,
const CapturePieceToHistory*,
const PieceToHistory**,
const PawnHistory*);
MovePicker(const Position&, Move, int, const CapturePieceToHistory*); MovePicker(const Position&, Move, int, const CapturePieceToHistory*);
Move next_move(bool skipQuiets = false); Move next_move(bool skipQuiets = false);
@@ -184,12 +177,12 @@ class MovePicker {
const CapturePieceToHistory* captureHistory; const CapturePieceToHistory* captureHistory;
const PieceToHistory** continuationHistory; const PieceToHistory** continuationHistory;
const PawnHistory* pawnHistory; const PawnHistory* pawnHistory;
Move ttMove; Move ttMove, killer;
ExtMove refutations[2], *cur, *endMoves, *endBadCaptures, *beginBadQuiets, *endBadQuiets; ExtMove * cur, *endMoves, *endBadCaptures, *beginBadQuiets, *endBadQuiets;
int stage; int stage;
int threshold; int threshold;
Depth depth; Depth depth;
ExtMove moves[MAX_MOVES]; ExtMove moves[MAX_MOVES];
}; };
} // namespace Stockfish } // namespace Stockfish
+70 -71
View File
@@ -76,14 +76,14 @@ Value futility_margin(Depth d, bool noTtCutNode, bool improving, bool oppWorseni
} }
constexpr int futility_move_count(bool improving, Depth depth) { constexpr int futility_move_count(bool improving, Depth depth) {
return improving ? (3 + depth * depth) : (3 + depth * depth) / 2; return (3 + depth * depth) / (2 - improving);
} }
// Add correctionHistory value to raw staticEval and guarantee evaluation // Add correctionHistory value to raw staticEval and guarantee evaluation
// does not hit the tablebase range. // does not hit the tablebase range.
Value to_corrected_static_eval(Value v, const Worker& w, const Position& pos) { Value to_corrected_static_eval(Value v, const Worker& w, const Position& pos) {
auto cv = w.correctionHistory[pos.side_to_move()][pawn_structure_index<Correction>(pos)]; auto cv = w.correctionHistory[pos.side_to_move()][pawn_structure_index<Correction>(pos)];
v += cv * std::abs(cv) / 5073; v += 66 * cv / 512;
return std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); return std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
} }
@@ -91,7 +91,7 @@ Value to_corrected_static_eval(Value v, const Worker& w, const Position& pos) {
int stat_bonus(Depth d) { return std::min(190 * d - 108, 1596); } int stat_bonus(Depth d) { return std::min(190 * d - 108, 1596); }
// History and stats update malus, based on depth // History and stats update malus, based on depth
int stat_malus(Depth d) { return (d < 4 ? 736 * d - 268 : 2044); } int stat_malus(Depth d) { return std::min(736 * d - 268, 2044); }
// Add a small random component to draw evaluations to avoid 3-fold blindness // 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); } Value value_draw(size_t nodes) { return VALUE_DRAW - 1 + Value(nodes & 0x2); }
@@ -124,21 +124,19 @@ Value value_to_tt(Value v, int ply);
Value value_from_tt(Value v, int ply, int r50c); Value value_from_tt(Value v, int ply, int r50c);
void update_pv(Move* pv, Move move, const Move* childPv); void update_pv(Move* pv, Move move, const Move* childPv);
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
void update_refutations(Stack* ss, Move move); void update_killer(Stack* ss, Move move);
void update_quiet_histories( void update_quiet_histories(
const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus); const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus);
void update_quiet_stats( void update_quiet_stats(
const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus); const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus);
void update_all_stats(const Position& pos, void update_all_stats(const Position& pos,
Stack* ss, Stack* ss,
Search::Worker& workerThread, Search::Worker& workerThread,
Move bestMove, Move bestMove,
Square prevSq, Square prevSq,
Move* quietsSearched, ValueList<Move, 32>& quietsSearched,
int quietCount, ValueList<Move, 32>& capturesSearched,
Move* capturesSearched, Depth depth);
int captureCount,
Depth depth);
} // namespace } // namespace
@@ -362,7 +360,7 @@ void Search::Worker::iterative_deepening() {
// Reset aspiration window starting size // Reset aspiration window starting size
Value avg = rootMoves[pvIdx].averageScore; Value avg = rootMoves[pvIdx].averageScore;
delta = 9 + avg * avg / 10424; delta = 5 + avg * avg / 13424;
alpha = std::max(avg - delta, -VALUE_INFINITE); alpha = std::max(avg - delta, -VALUE_INFINITE);
beta = std::min(avg + delta, VALUE_INFINITE); beta = std::min(avg + delta, VALUE_INFINITE);
@@ -602,7 +600,7 @@ Value Search::Worker::search(
assert(0 < depth && depth < MAX_PLY); assert(0 < depth && depth < MAX_PLY);
assert(!(PvNode && cutNode)); assert(!(PvNode && cutNode));
Move pv[MAX_PLY + 1], capturesSearched[32], quietsSearched[32]; Move pv[MAX_PLY + 1];
StateInfo st; StateInfo st;
ASSERT_ALIGNED(&st, Eval::NNUE::CacheLineSize); ASSERT_ALIGNED(&st, Eval::NNUE::CacheLineSize);
@@ -611,18 +609,20 @@ Value Search::Worker::search(
Depth extension, newDepth; Depth extension, newDepth;
Value bestValue, value, eval, maxValue, probCutBeta; Value bestValue, value, eval, maxValue, probCutBeta;
bool givesCheck, improving, priorCapture, opponentWorsening; bool givesCheck, improving, priorCapture, opponentWorsening;
bool capture, moveCountPruning, ttCapture; bool capture, ttCapture;
Piece movedPiece; Piece movedPiece;
int moveCount, captureCount, quietCount;
ValueList<Move, 32> capturesSearched;
ValueList<Move, 32> quietsSearched;
// Step 1. Initialize node // Step 1. Initialize node
Worker* thisThread = this; Worker* thisThread = this;
ss->inCheck = pos.checkers(); ss->inCheck = pos.checkers();
priorCapture = pos.captured_piece(); priorCapture = pos.captured_piece();
Color us = pos.side_to_move(); Color us = pos.side_to_move();
moveCount = captureCount = quietCount = ss->moveCount = 0; ss->moveCount = 0;
bestValue = -VALUE_INFINITE; bestValue = -VALUE_INFINITE;
maxValue = VALUE_INFINITE; maxValue = VALUE_INFINITE;
// Check for the available remaining time // Check for the available remaining time
if (is_mainthread()) if (is_mainthread())
@@ -656,9 +656,9 @@ Value Search::Worker::search(
assert(0 <= ss->ply && ss->ply < MAX_PLY); assert(0 <= ss->ply && ss->ply < MAX_PLY);
bestMove = Move::none(); bestMove = Move::none();
(ss + 2)->killers[0] = (ss + 2)->killers[1] = Move::none(); (ss + 1)->killer = Move::none();
(ss + 2)->cutoffCnt = 0; (ss + 2)->cutoffCnt = 0;
Square prevSq = ((ss - 1)->currentMove).is_ok() ? ((ss - 1)->currentMove).to_sq() : SQ_NONE; Square prevSq = ((ss - 1)->currentMove).is_ok() ? ((ss - 1)->currentMove).to_sq() : SQ_NONE;
ss->statScore = 0; ss->statScore = 0;
@@ -762,7 +762,7 @@ Value Search::Worker::search(
if (ss->inCheck) if (ss->inCheck)
{ {
// Skip early pruning when in check // Skip early pruning when in check
ss->staticEval = eval = VALUE_NONE; ss->staticEval = eval = (ss - 2)->staticEval;
improving = false; improving = false;
goto moves_loop; goto moves_loop;
} }
@@ -814,12 +814,9 @@ Value Search::Worker::search(
// Set up the improving flag, which is true if current static evaluation is // Set up the improving flag, which is true if current static evaluation is
// bigger than the previous static evaluation at our turn (if we were in // bigger than the previous static evaluation at our turn (if we were in
// check at our previous move we look at static evaluation at move prior to it // check at our previous move we go back until we weren't in check) and is
// and if we were in check at move prior to it flag is set to true) and is
// false otherwise. The improving flag is used in various pruning heuristics. // false otherwise. The improving flag is used in various pruning heuristics.
improving = (ss - 2)->staticEval != VALUE_NONE improving = ss->staticEval > (ss - 2)->staticEval;
? ss->staticEval > (ss - 2)->staticEval
: (ss - 4)->staticEval != VALUE_NONE && ss->staticEval > (ss - 4)->staticEval;
opponentWorsening = ss->staticEval + (ss - 1)->staticEval > 2; opponentWorsening = ss->staticEval + (ss - 1)->staticEval > 2;
@@ -844,7 +841,7 @@ Value Search::Worker::search(
return beta + (eval - beta) / 3; return beta + (eval - beta) / 3;
// Step 9. Null move search with verification search (~35 Elo) // Step 9. Null move search with verification search (~35 Elo)
if (!PvNode && (ss - 1)->currentMove != Move::null() && (ss - 1)->statScore < 14389 if (cutNode && (ss - 1)->currentMove != Move::null() && (ss - 1)->statScore < 14389
&& eval >= beta && ss->staticEval >= beta - 21 * depth + 390 && !excludedMove && eval >= beta && ss->staticEval >= beta - 21 * depth + 390 && !excludedMove
&& pos.non_pawn_material(us) && ss->ply >= thisThread->nmpMinPly && pos.non_pawn_material(us) && ss->ply >= thisThread->nmpMinPly
&& beta > VALUE_TB_LOSS_IN_MAX_PLY) && beta > VALUE_TB_LOSS_IN_MAX_PLY)
@@ -859,7 +856,7 @@ Value Search::Worker::search(
pos.do_null_move(st, tt); pos.do_null_move(st, tt);
Value nullValue = -search<NonPV>(pos, ss + 1, -beta, -beta + 1, depth - R, !cutNode); Value nullValue = -search<NonPV>(pos, ss + 1, -beta, -beta + 1, depth - R, false);
pos.undo_null_move(); pos.undo_null_move();
@@ -985,10 +982,12 @@ moves_loop: // When in check, search starts here
MovePicker mp(pos, ttData.move, depth, &thisThread->mainHistory, &thisThread->captureHistory, MovePicker mp(pos, ttData.move, depth, &thisThread->mainHistory, &thisThread->captureHistory,
contHist, &thisThread->pawnHistory, ss->killers); contHist, &thisThread->pawnHistory, ss->killer);
value = bestValue; value = bestValue;
moveCountPruning = false;
int moveCount = 0;
bool moveCountPruning = false;
// Step 13. Loop through all pseudo-legal moves until no moves remain // Step 13. Loop through all pseudo-legal moves until no moves remain
// or a beta cutoff occurs. // or a beta cutoff occurs.
@@ -1071,7 +1070,7 @@ moves_loop: // When in check, search starts here
+ thisThread->pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()]; + thisThread->pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()];
// Continuation history based pruning (~2 Elo) // Continuation history based pruning (~2 Elo)
if (lmrDepth < 6 && history < -4165 * depth) if (history < -4165 * depth)
continue; continue;
history += 2 * thisThread->mainHistory[us][move.from_to()]; history += 2 * thisThread->mainHistory[us][move.from_to()];
@@ -1086,7 +1085,7 @@ moves_loop: // When in check, search starts here
{ {
if (bestValue <= futilityValue && std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY if (bestValue <= futilityValue && std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY
&& futilityValue < VALUE_TB_WIN_IN_MAX_PLY) && futilityValue < VALUE_TB_WIN_IN_MAX_PLY)
bestValue = (bestValue + futilityValue * 3) / 4; bestValue = futilityValue;
continue; continue;
} }
@@ -1208,7 +1207,7 @@ moves_loop: // When in check, search starts here
// Increase reduction for cut nodes (~4 Elo) // Increase reduction for cut nodes (~4 Elo)
if (cutNode) if (cutNode)
r += 2 - (ttData.depth >= depth && ss->ttPv) r += 2 - (ttData.depth >= depth && ss->ttPv)
+ (!ss->ttPv && move != ttData.move && move != ss->killers[0]); + (!ss->ttPv && move != ttData.move && move != ss->killer);
// Increase reduction if ttMove is a capture (~3 Elo) // Increase reduction if ttMove is a capture (~3 Elo)
if (ttCapture) if (ttCapture)
@@ -1385,9 +1384,9 @@ moves_loop: // When in check, search starts here
if (move != bestMove && moveCount <= 32) if (move != bestMove && moveCount <= 32)
{ {
if (capture) if (capture)
capturesSearched[captureCount++] = move; capturesSearched.push_back(move);
else else
quietsSearched[quietCount++] = move; quietsSearched.push_back(move);
} }
} }
@@ -1409,18 +1408,20 @@ moves_loop: // When in check, search starts here
// If there is a move that produces search value greater than alpha, // If there is a move that produces search value greater than alpha,
// we update the stats of searched moves. // we update the stats of searched moves.
else if (bestMove) else if (bestMove)
update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, quietCount, update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth);
capturesSearched, captureCount, depth);
// Bonus for prior countermove that caused the fail low // Bonus for prior countermove that caused the fail low
else if (!priorCapture && prevSq != SQ_NONE) else if (!priorCapture && prevSq != SQ_NONE)
{ {
int bonus = (114 * (depth > 5) + 116 * (PvNode || cutNode) + 123 * ((ss - 1)->moveCount > 8) int bonus = (138 * (depth > 5) + 58 * (PvNode || cutNode) + 160 * ((ss - 1)->moveCount > 8)
+ 64 * (!ss->inCheck && bestValue <= ss->staticEval - 108) + 84 * (!ss->inCheck && bestValue <= ss->staticEval - 108)
+ 153 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 76)); + 153 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 76)
+ 32 * (!(ss - 1)->inCheck && bestValue > -(ss - 1)->staticEval + 76));
// Proportional to "how much damage we have to undo" // Proportional to "how much damage we have to undo"
bonus += std::clamp(-(ss - 1)->statScore / 100, -50, 274); bonus += std::clamp(-(ss - 1)->statScore / 100, -94, 300);
bonus = std::max(bonus, 0);
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
stat_bonus(depth) * bonus / 100); stat_bonus(depth) * bonus / 100);
@@ -1818,16 +1819,14 @@ void update_pv(Move* pv, Move move, const Move* childPv) {
// Updates stats at the end of search() when a bestMove is found // Updates stats at the end of search() when a bestMove is found
void update_all_stats(const Position& pos, void update_all_stats(const Position& pos,
Stack* ss, Stack* ss,
Search::Worker& workerThread, Search::Worker& workerThread,
Move bestMove, Move bestMove,
Square prevSq, Square prevSq,
Move* quietsSearched, ValueList<Move, 32>& quietsSearched,
int quietCount, ValueList<Move, 32>& capturesSearched,
Move* capturesSearched, Depth depth) {
int captureCount,
Depth depth) {
CapturePieceToHistory& captureHistory = workerThread.captureHistory; CapturePieceToHistory& captureHistory = workerThread.captureHistory;
Piece moved_piece = pos.moved_piece(bestMove); Piece moved_piece = pos.moved_piece(bestMove);
@@ -1841,8 +1840,8 @@ void update_all_stats(const Position& pos,
update_quiet_stats(pos, ss, workerThread, bestMove, quietMoveBonus); update_quiet_stats(pos, ss, workerThread, bestMove, quietMoveBonus);
// Decrease stats for all non-best quiet moves // Decrease stats for all non-best quiet moves
for (int i = 0; i < quietCount; ++i) for (Move move : quietsSearched)
update_quiet_histories(pos, ss, workerThread, quietsSearched[i], -quietMoveMalus); update_quiet_histories(pos, ss, workerThread, move, -quietMoveMalus);
} }
else else
{ {
@@ -1855,16 +1854,16 @@ void update_all_stats(const Position& pos,
// main killer move in previous ply when it gets refuted. // main killer move in previous ply when it gets refuted.
if (prevSq != SQ_NONE if (prevSq != SQ_NONE
&& ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit
|| ((ss - 1)->currentMove == (ss - 1)->killers[0])) || ((ss - 1)->currentMove == (ss - 1)->killer))
&& !pos.captured_piece()) && !pos.captured_piece())
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -quietMoveMalus); update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -quietMoveMalus);
// Decrease stats for all non-best capture moves // Decrease stats for all non-best capture moves
for (int i = 0; i < captureCount; ++i) for (Move move : capturesSearched)
{ {
moved_piece = pos.moved_piece(capturesSearched[i]); moved_piece = pos.moved_piece(move);
captured = type_of(pos.piece_on(capturesSearched[i].to_sq())); captured = type_of(pos.piece_on(move.to_sq()));
captureHistory[moved_piece][capturesSearched[i].to_sq()][captured] << -quietMoveMalus; captureHistory[moved_piece][move.to_sq()][captured] << -quietMoveMalus;
} }
} }
@@ -1886,14 +1885,10 @@ void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
} }
// Updates move sorting heuristics // Updates move sorting heuristics
void update_refutations(Stack* ss, Move move) { void update_killer(Stack* ss, Move move) {
// Update killers // Update killers
if (ss->killers[0] != move) ss->killer = move;
{
ss->killers[1] = ss->killers[0];
ss->killers[0] = move;
}
} }
void update_quiet_histories( void update_quiet_histories(
@@ -1912,7 +1907,7 @@ void update_quiet_histories(
void update_quiet_stats( void update_quiet_stats(
const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus) { const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus) {
update_refutations(ss, move); update_killer(ss, move);
update_quiet_histories(pos, ss, workerThread, move, bonus); update_quiet_histories(pos, ss, workerThread, move, bonus);
} }
@@ -2012,8 +2007,12 @@ void syzygy_extend_pv(const OptionsMap& options,
std::list<StateInfo> sts; std::list<StateInfo> sts;
// Step 0, do the rootMove, no correction allowed, as needed for MultiPV in TB.
auto& stRoot = sts.emplace_back();
pos.do_move(rootMove.pv[0], stRoot);
int ply = 1;
// Step 1, walk the PV to the last position in TB with correct decisive score // Step 1, walk the PV to the last position in TB with correct decisive score
int ply = 0;
while (size_t(ply) < rootMove.pv.size()) while (size_t(ply) < rootMove.pv.size())
{ {
Move& pvMove = rootMove.pv[ply]; Move& pvMove = rootMove.pv[ply];
+1 -1
View File
@@ -67,7 +67,7 @@ struct Stack {
int ply; int ply;
Move currentMove; Move currentMove;
Move excludedMove; Move excludedMove;
Move killers[2]; Move killer;
Value staticEval; Value staticEval;
int statScore; int statScore;
int moveCount; int moveCount;
+1 -1
View File
@@ -1346,7 +1346,7 @@ void Tablebases::init(const std::string& paths) {
MaxCardinality = 0; MaxCardinality = 0;
TBFile::Paths = paths; TBFile::Paths = paths;
if (paths.empty() || paths == "<empty>") if (paths.empty())
return; return;
// MapB1H1H7[] encodes a square below a1-h8 diagonal to 0..27 // MapB1H1H7[] encodes a square below a1-h8 diagonal to 0..27
+11 -3
View File
@@ -167,7 +167,9 @@ Option& Option::operator=(const std::string& v) {
return *this; return *this;
} }
if (type != "button") if (type == "string")
currentValue = v == "<empty>" ? "" : v;
else if (type != "button")
currentValue = v; currentValue = v;
if (on_change) if (on_change)
@@ -189,10 +191,16 @@ std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
const Option& o = it.second; const Option& o = it.second;
os << "\noption name " << it.first << " type " << o.type; os << "\noption name " << it.first << " type " << o.type;
if (o.type == "string" || o.type == "check" || o.type == "combo") if (o.type == "check" || o.type == "combo")
os << " default " << o.defaultValue; os << " default " << o.defaultValue;
if (o.type == "spin") else if (o.type == "string")
{
std::string defaultValue = o.defaultValue.empty() ? "<empty>" : o.defaultValue;
os << " default " << defaultValue;
}
else if (o.type == "spin")
os << " default " << int(stof(o.defaultValue)) << " min " << o.min << " max " os << " default " << int(stof(o.defaultValue)) << " min " << o.min << " max "
<< o.max; << o.max;