mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Merge commit 'e57fba7fc9be461cbb97c063b269a1e231cdd284' into cluster
This is the last commit before there are more conflicts.
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user