mirror of
https://github.com/sockspls/badfish
synced 2025-04-29 16:23:09 +00:00
Eliminate ONE_PLY
Simplification that eliminates ONE_PLY, based on a suggestion in the forum that support for fractional plies has never been used, and @mcostalba's openness to the idea of eliminating it. We lose a little bit of type safety by making Depth an integer, but in return we simplify the code in search.cpp quite significantly. No functional change ------------------------------------------ The argument favoring eliminating ONE_PLY: * The term “ONE_PLY” comes up in a lot of forum posts (474 to date) https://groups.google.com/forum/?fromgroups=#!searchin/fishcooking/ONE_PLY%7Csort:relevance * There is occasionally a commit that breaks invariance of the code with respect to ONE_PLY https://groups.google.com/forum/?fromgroups=#!searchin/fishcooking/ONE_PLY%7Csort:date/fishcooking/ZIPdYj6k0fk/KdNGcPWeBgAJ * To prevent such commits, there is a Travis CI hack that doubles ONE_PLY and rechecks bench * Sustaining ONE_PLY has, alas, not resulted in any improvements to the engine, despite many individuals testing many experiments over 5 years. The strongest argument in favor of preserving ONE_PLY comes from @locutus: “If we use par example ONE_PLY=256 the parameter space is increases by the factor 256. So it seems very unlikely that the optimal setting is in the subspace of ONE_PLY=1.” There is a strong theoretical impediment to fractional depth systems: the transposition table uses depth to determine when a stored result is good enough to supply an answer for a current search. If you have fractional depths, then different pathways to the position can be at fractionally different depths. In the end, there are three separate times when a proposal to remove ONE_PLY was defeated by the suggestion to “give it a few more months.” So… it seems like time to remove this distraction from the community. See the pull request here: https://github.com/official-stockfish/Stockfish/pull/2289
This commit is contained in:
parent
328bdd0947
commit
ca7d4e9ac7
7 changed files with 86 additions and 100 deletions
|
@ -56,9 +56,6 @@ script:
|
||||||
- make clean && make -j2 ARCH=x86-32 optimize=no debug=yes build && ../tests/signature.sh $benchref
|
- make clean && make -j2 ARCH=x86-32 optimize=no debug=yes build && ../tests/signature.sh $benchref
|
||||||
- make clean && make -j2 ARCH=x86-32 build && ../tests/signature.sh $benchref
|
- make clean && make -j2 ARCH=x86-32 build && ../tests/signature.sh $benchref
|
||||||
|
|
||||||
# Verify bench number is ONE_PLY independent by doubling its value
|
|
||||||
- sed -i'.bak' 's/.*\(ONE_PLY = [0-9]*\),.*/\1 * 2,/g' types.h
|
|
||||||
- make clean && make -j2 ARCH=x86-64 build && ../tests/signature.sh $benchref
|
|
||||||
#
|
#
|
||||||
# Check perft and reproducible search
|
# Check perft and reproducible search
|
||||||
- ../tests/perft.sh
|
- ../tests/perft.sh
|
||||||
|
|
|
@ -61,7 +61,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
|
||||||
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch),
|
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch),
|
||||||
refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) {
|
refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) {
|
||||||
|
|
||||||
assert(d > DEPTH_ZERO);
|
assert(d > 0);
|
||||||
|
|
||||||
stage = pos.checkers() ? EVASION_TT : MAIN_TT;
|
stage = pos.checkers() ? EVASION_TT : MAIN_TT;
|
||||||
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
|
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
|
||||||
|
@ -73,7 +73,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
|
||||||
const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs)
|
const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs)
|
||||||
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), recaptureSquare(rs), depth(d) {
|
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), recaptureSquare(rs), depth(d) {
|
||||||
|
|
||||||
assert(d <= DEPTH_ZERO);
|
assert(d <= 0);
|
||||||
|
|
||||||
stage = pos.checkers() ? EVASION_TT : QSEARCH_TT;
|
stage = pos.checkers() ? EVASION_TT : QSEARCH_TT;
|
||||||
ttMove = ttm
|
ttMove = ttm
|
||||||
|
@ -206,7 +206,7 @@ top:
|
||||||
endMoves = generate<QUIETS>(pos, cur);
|
endMoves = generate<QUIETS>(pos, cur);
|
||||||
|
|
||||||
score<QUIETS>();
|
score<QUIETS>();
|
||||||
partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY);
|
partial_insertion_sort(cur, endMoves, -4000 * depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
++stage;
|
++stage;
|
||||||
|
|
148
src/search.cpp
148
src/search.cpp
|
@ -64,15 +64,15 @@ namespace {
|
||||||
// Razor and futility margins
|
// Razor and futility margins
|
||||||
constexpr int RazorMargin = 661;
|
constexpr int RazorMargin = 661;
|
||||||
Value futility_margin(Depth d, bool improving) {
|
Value futility_margin(Depth d, bool improving) {
|
||||||
return Value(198 * (d / ONE_PLY - improving));
|
return Value(198 * (d - improving));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reductions lookup table, initialized at startup
|
// Reductions lookup table, initialized at startup
|
||||||
int Reductions[MAX_MOVES]; // [depth or moveNumber]
|
int Reductions[MAX_MOVES]; // [depth or moveNumber]
|
||||||
|
|
||||||
Depth reduction(bool i, Depth d, int mn) {
|
Depth reduction(bool i, Depth d, int mn) {
|
||||||
int r = Reductions[d / ONE_PLY] * Reductions[mn];
|
int r = Reductions[d] * Reductions[mn];
|
||||||
return ((r + 520) / 1024 + (!i && r > 999)) * ONE_PLY;
|
return (r + 520) / 1024 + (!i && r > 999);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int futility_move_count(bool improving, int depth) {
|
constexpr int futility_move_count(bool improving, int depth) {
|
||||||
|
@ -80,8 +80,7 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
// History and stats update bonus, based on depth
|
// History and stats update bonus, based on depth
|
||||||
int stat_bonus(Depth depth) {
|
int stat_bonus(Depth d) {
|
||||||
int d = depth / ONE_PLY;
|
|
||||||
return d > 17 ? -8 : 22 * d * d + 151 * d - 140;
|
return d > 17 ? -8 : 22 * d * d + 151 * d - 140;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +93,7 @@ namespace {
|
||||||
struct Skill {
|
struct Skill {
|
||||||
explicit Skill(int l) : level(l) {}
|
explicit Skill(int l) : level(l) {}
|
||||||
bool enabled() const { return level < 20; }
|
bool enabled() const { return level < 20; }
|
||||||
bool time_to_pick(Depth depth) const { return depth / ONE_PLY == 1 + level; }
|
bool time_to_pick(Depth depth) const { return depth == 1 + level; }
|
||||||
Move pick_best(size_t multiPV);
|
Move pick_best(size_t multiPV);
|
||||||
|
|
||||||
int level;
|
int level;
|
||||||
|
@ -148,7 +147,7 @@ namespace {
|
||||||
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
|
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
|
||||||
|
|
||||||
template <NodeType NT>
|
template <NodeType NT>
|
||||||
Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth = DEPTH_ZERO);
|
Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth = 0);
|
||||||
|
|
||||||
Value value_to_tt(Value v, int ply);
|
Value value_to_tt(Value v, int ply);
|
||||||
Value value_from_tt(Value v, int ply);
|
Value value_from_tt(Value v, int ply);
|
||||||
|
@ -164,16 +163,16 @@ namespace {
|
||||||
|
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
uint64_t cnt, nodes = 0;
|
uint64_t cnt, nodes = 0;
|
||||||
const bool leaf = (depth == 2 * ONE_PLY);
|
const bool leaf = (depth == 2);
|
||||||
|
|
||||||
for (const auto& m : MoveList<LEGAL>(pos))
|
for (const auto& m : MoveList<LEGAL>(pos))
|
||||||
{
|
{
|
||||||
if (Root && depth <= ONE_PLY)
|
if (Root && depth <= 1)
|
||||||
cnt = 1, nodes++;
|
cnt = 1, nodes++;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pos.do_move(m, st);
|
pos.do_move(m, st);
|
||||||
cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - ONE_PLY);
|
cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - 1);
|
||||||
nodes += cnt;
|
nodes += cnt;
|
||||||
pos.undo_move(m);
|
pos.undo_move(m);
|
||||||
}
|
}
|
||||||
|
@ -215,7 +214,7 @@ void MainThread::search() {
|
||||||
|
|
||||||
if (Limits.perft)
|
if (Limits.perft)
|
||||||
{
|
{
|
||||||
nodes = perft<true>(rootPos, Limits.perft * ONE_PLY);
|
nodes = perft<true>(rootPos, Limits.perft);
|
||||||
sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
|
sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -328,7 +327,7 @@ void Thread::search() {
|
||||||
Move pv[MAX_PLY+1];
|
Move pv[MAX_PLY+1];
|
||||||
Value bestValue, alpha, beta, delta;
|
Value bestValue, alpha, beta, delta;
|
||||||
Move lastBestMove = MOVE_NONE;
|
Move lastBestMove = MOVE_NONE;
|
||||||
Depth lastBestMoveDepth = DEPTH_ZERO;
|
Depth lastBestMoveDepth = 0;
|
||||||
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
|
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
|
||||||
double timeReduction = 1, totBestMoveChanges = 0;
|
double timeReduction = 1, totBestMoveChanges = 0;
|
||||||
Color us = rootPos.side_to_move();
|
Color us = rootPos.side_to_move();
|
||||||
|
@ -378,9 +377,9 @@ void Thread::search() {
|
||||||
: -make_score(ct, ct / 2));
|
: -make_score(ct, ct / 2));
|
||||||
|
|
||||||
// Iterative deepening loop until requested to stop or the target depth is reached
|
// Iterative deepening loop until requested to stop or the target depth is reached
|
||||||
while ( (rootDepth += ONE_PLY) < DEPTH_MAX
|
while ( ++rootDepth < MAX_PLY
|
||||||
&& !Threads.stop
|
&& !Threads.stop
|
||||||
&& !(Limits.depth && mainThread && rootDepth / ONE_PLY > Limits.depth))
|
&& !(Limits.depth && mainThread && rootDepth > Limits.depth))
|
||||||
{
|
{
|
||||||
// Age out PV variability metric
|
// Age out PV variability metric
|
||||||
if (mainThread)
|
if (mainThread)
|
||||||
|
@ -409,7 +408,7 @@ void Thread::search() {
|
||||||
selDepth = 0;
|
selDepth = 0;
|
||||||
|
|
||||||
// Reset aspiration window starting size
|
// Reset aspiration window starting size
|
||||||
if (rootDepth >= 4 * ONE_PLY)
|
if (rootDepth >= 4)
|
||||||
{
|
{
|
||||||
Value previousScore = rootMoves[pvIdx].previousScore;
|
Value previousScore = rootMoves[pvIdx].previousScore;
|
||||||
delta = Value(23);
|
delta = Value(23);
|
||||||
|
@ -429,7 +428,7 @@ void Thread::search() {
|
||||||
int failedHighCnt = 0;
|
int failedHighCnt = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Depth adjustedDepth = std::max(ONE_PLY, rootDepth - failedHighCnt * ONE_PLY);
|
Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt);
|
||||||
bestValue = ::search<PV>(rootPos, ss, alpha, beta, adjustedDepth, false);
|
bestValue = ::search<PV>(rootPos, ss, alpha, beta, adjustedDepth, false);
|
||||||
|
|
||||||
// Bring the best move to the front. It is critical that sorting
|
// Bring the best move to the front. It is critical that sorting
|
||||||
|
@ -519,7 +518,7 @@ void Thread::search() {
|
||||||
fallingEval = clamp(fallingEval, 0.5, 1.5);
|
fallingEval = clamp(fallingEval, 0.5, 1.5);
|
||||||
|
|
||||||
// If the bestMove is stable over several iterations, reduce time accordingly
|
// If the bestMove is stable over several iterations, reduce time accordingly
|
||||||
timeReduction = lastBestMoveDepth + 9 * ONE_PLY < completedDepth ? 1.97 : 0.98;
|
timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.97 : 0.98;
|
||||||
double reduction = (1.36 + mainThread->previousTimeReduction) / (2.29 * timeReduction);
|
double reduction = (1.36 + mainThread->previousTimeReduction) / (2.29 * timeReduction);
|
||||||
|
|
||||||
// Use part of the gained time from a previous stable move for the current move
|
// Use part of the gained time from a previous stable move for the current move
|
||||||
|
@ -579,14 +578,13 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dive into quiescence search when the depth reaches zero
|
// Dive into quiescence search when the depth reaches zero
|
||||||
if (depth < ONE_PLY)
|
if (depth <= 0)
|
||||||
return qsearch<NT>(pos, ss, alpha, beta);
|
return qsearch<NT>(pos, ss, alpha, beta);
|
||||||
|
|
||||||
assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE);
|
assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE);
|
||||||
assert(PvNode || (alpha == beta - 1));
|
assert(PvNode || (alpha == beta - 1));
|
||||||
assert(DEPTH_ZERO < depth && depth < DEPTH_MAX);
|
assert(0 < depth && depth < MAX_PLY);
|
||||||
assert(!(PvNode && cutNode));
|
assert(!(PvNode && cutNode));
|
||||||
assert(depth / ONE_PLY * ONE_PLY == depth);
|
|
||||||
|
|
||||||
Move pv[MAX_PLY+1], capturesSearched[32], quietsSearched[64];
|
Move pv[MAX_PLY+1], capturesSearched[32], quietsSearched[64];
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
|
@ -683,7 +681,7 @@ namespace {
|
||||||
|
|
||||||
// Extra penalty for early quiet moves of the previous ply
|
// Extra penalty for early quiet moves of the previous ply
|
||||||
if ((ss-1)->moveCount <= 2 && !pos.captured_piece())
|
if ((ss-1)->moveCount <= 2 && !pos.captured_piece())
|
||||||
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY));
|
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1));
|
||||||
}
|
}
|
||||||
// Penalty for a quiet ttMove that fails low
|
// Penalty for a quiet ttMove that fails low
|
||||||
else if (!pos.capture_or_promotion(ttMove))
|
else if (!pos.capture_or_promotion(ttMove))
|
||||||
|
@ -730,7 +728,7 @@ namespace {
|
||||||
|| (b == BOUND_LOWER ? value >= beta : value <= alpha))
|
|| (b == BOUND_LOWER ? value >= beta : value <= alpha))
|
||||||
{
|
{
|
||||||
tte->save(posKey, value_to_tt(value, ss->ply), ttPv, b,
|
tte->save(posKey, value_to_tt(value, ss->ply), ttPv, b,
|
||||||
std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY),
|
std::min(MAX_PLY - 1, depth + 6),
|
||||||
MOVE_NONE, VALUE_NONE);
|
MOVE_NONE, VALUE_NONE);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
@ -785,7 +783,7 @@ namespace {
|
||||||
|
|
||||||
// Step 7. Razoring (~2 Elo)
|
// Step 7. Razoring (~2 Elo)
|
||||||
if ( !rootNode // The required rootNode PV handling is not available in qsearch
|
if ( !rootNode // The required rootNode PV handling is not available in qsearch
|
||||||
&& depth < 2 * ONE_PLY
|
&& depth < 2
|
||||||
&& eval <= alpha - RazorMargin)
|
&& eval <= alpha - RazorMargin)
|
||||||
return qsearch<NT>(pos, ss, alpha, beta);
|
return qsearch<NT>(pos, ss, alpha, beta);
|
||||||
|
|
||||||
|
@ -794,7 +792,7 @@ namespace {
|
||||||
|
|
||||||
// Step 8. Futility pruning: child node (~30 Elo)
|
// Step 8. Futility pruning: child node (~30 Elo)
|
||||||
if ( !PvNode
|
if ( !PvNode
|
||||||
&& depth < 7 * ONE_PLY
|
&& depth < 7
|
||||||
&& eval - futility_margin(depth, improving) >= beta
|
&& eval - futility_margin(depth, improving) >= beta
|
||||||
&& eval < VALUE_KNOWN_WIN) // Do not return unproven wins
|
&& eval < VALUE_KNOWN_WIN) // Do not return unproven wins
|
||||||
return eval;
|
return eval;
|
||||||
|
@ -805,7 +803,7 @@ namespace {
|
||||||
&& (ss-1)->statScore < 22661
|
&& (ss-1)->statScore < 22661
|
||||||
&& eval >= beta
|
&& eval >= beta
|
||||||
&& eval >= ss->staticEval
|
&& eval >= ss->staticEval
|
||||||
&& ss->staticEval >= beta - 33 * depth / ONE_PLY + 299 - improving * 30
|
&& ss->staticEval >= beta - 33 * depth + 299 - improving * 30
|
||||||
&& !excludedMove
|
&& !excludedMove
|
||||||
&& pos.non_pawn_material(us)
|
&& pos.non_pawn_material(us)
|
||||||
&& (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
|
&& (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
|
||||||
|
@ -813,7 +811,7 @@ namespace {
|
||||||
assert(eval - beta >= 0);
|
assert(eval - beta >= 0);
|
||||||
|
|
||||||
// Null move dynamic reduction based on depth and value
|
// Null move dynamic reduction based on depth and value
|
||||||
Depth R = ((835 + 70 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 185, 3)) * ONE_PLY;
|
Depth R = (835 + 70 * depth) / 256 + std::min(int(eval - beta) / 185, 3);
|
||||||
|
|
||||||
ss->currentMove = MOVE_NULL;
|
ss->currentMove = MOVE_NULL;
|
||||||
ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0];
|
ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0];
|
||||||
|
@ -830,14 +828,14 @@ namespace {
|
||||||
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
|
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
|
||||||
nullValue = beta;
|
nullValue = beta;
|
||||||
|
|
||||||
if (thisThread->nmpMinPly || (abs(beta) < VALUE_KNOWN_WIN && depth < 13 * ONE_PLY))
|
if (thisThread->nmpMinPly || (abs(beta) < VALUE_KNOWN_WIN && depth < 13))
|
||||||
return nullValue;
|
return nullValue;
|
||||||
|
|
||||||
assert(!thisThread->nmpMinPly); // Recursive verification is not allowed
|
assert(!thisThread->nmpMinPly); // Recursive verification is not allowed
|
||||||
|
|
||||||
// Do verification search at high depths, with null move pruning disabled
|
// Do verification search at high depths, with null move pruning disabled
|
||||||
// for us, until ply exceeds nmpMinPly.
|
// for us, until ply exceeds nmpMinPly.
|
||||||
thisThread->nmpMinPly = ss->ply + 3 * (depth-R) / (4 * ONE_PLY);
|
thisThread->nmpMinPly = ss->ply + 3 * (depth-R) / 4;
|
||||||
thisThread->nmpColor = us;
|
thisThread->nmpColor = us;
|
||||||
|
|
||||||
Value v = search<NonPV>(pos, ss, beta-1, beta, depth-R, false);
|
Value v = search<NonPV>(pos, ss, beta-1, beta, depth-R, false);
|
||||||
|
@ -853,7 +851,7 @@ namespace {
|
||||||
// If we have a good enough capture and a reduced search returns a value
|
// If we have a good enough capture and a reduced search returns a value
|
||||||
// much above beta, we can (almost) safely prune the previous move.
|
// much above beta, we can (almost) safely prune the previous move.
|
||||||
if ( !PvNode
|
if ( !PvNode
|
||||||
&& depth >= 5 * ONE_PLY
|
&& depth >= 5
|
||||||
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
|
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
|
||||||
{
|
{
|
||||||
Value raisedBeta = std::min(beta + 191 - 46 * improving, VALUE_INFINITE);
|
Value raisedBeta = std::min(beta + 191 - 46 * improving, VALUE_INFINITE);
|
||||||
|
@ -869,7 +867,7 @@ namespace {
|
||||||
ss->currentMove = move;
|
ss->currentMove = move;
|
||||||
ss->continuationHistory = &thisThread->continuationHistory[pos.moved_piece(move)][to_sq(move)];
|
ss->continuationHistory = &thisThread->continuationHistory[pos.moved_piece(move)][to_sq(move)];
|
||||||
|
|
||||||
assert(depth >= 5 * ONE_PLY);
|
assert(depth >= 5);
|
||||||
|
|
||||||
pos.do_move(move, st);
|
pos.do_move(move, st);
|
||||||
|
|
||||||
|
@ -878,7 +876,7 @@ namespace {
|
||||||
|
|
||||||
// If the qsearch held, perform the regular search
|
// If the qsearch held, perform the regular search
|
||||||
if (value >= raisedBeta)
|
if (value >= raisedBeta)
|
||||||
value = -search<NonPV>(pos, ss+1, -raisedBeta, -raisedBeta+1, depth - 4 * ONE_PLY, !cutNode);
|
value = -search<NonPV>(pos, ss+1, -raisedBeta, -raisedBeta+1, depth - 4, !cutNode);
|
||||||
|
|
||||||
pos.undo_move(move);
|
pos.undo_move(move);
|
||||||
|
|
||||||
|
@ -888,9 +886,9 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 11. Internal iterative deepening (~2 Elo)
|
// Step 11. Internal iterative deepening (~2 Elo)
|
||||||
if (depth >= 7 * ONE_PLY && !ttMove)
|
if (depth >= 7 && !ttMove)
|
||||||
{
|
{
|
||||||
search<NT>(pos, ss, alpha, beta, depth - 7 * ONE_PLY, cutNode);
|
search<NT>(pos, ss, alpha, beta, depth - 7, cutNode);
|
||||||
|
|
||||||
tte = TT.probe(posKey, ttHit);
|
tte = TT.probe(posKey, ttHit);
|
||||||
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
|
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
|
||||||
|
@ -938,13 +936,13 @@ moves_loop: // When in check, search starts from here
|
||||||
ss->moveCount = ++moveCount;
|
ss->moveCount = ++moveCount;
|
||||||
|
|
||||||
if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000)
|
if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000)
|
||||||
sync_cout << "info depth " << depth / ONE_PLY
|
sync_cout << "info depth " << depth
|
||||||
<< " currmove " << UCI::move(move, pos.is_chess960())
|
<< " currmove " << UCI::move(move, pos.is_chess960())
|
||||||
<< " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl;
|
<< " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl;
|
||||||
if (PvNode)
|
if (PvNode)
|
||||||
(ss+1)->pv = nullptr;
|
(ss+1)->pv = nullptr;
|
||||||
|
|
||||||
extension = DEPTH_ZERO;
|
extension = 0;
|
||||||
captureOrPromotion = pos.capture_or_promotion(move);
|
captureOrPromotion = pos.capture_or_promotion(move);
|
||||||
movedPiece = pos.moved_piece(move);
|
movedPiece = pos.moved_piece(move);
|
||||||
givesCheck = pos.gives_check(move);
|
givesCheck = pos.gives_check(move);
|
||||||
|
@ -956,28 +954,28 @@ moves_loop: // When in check, search starts from here
|
||||||
// then that move is singular and should be extended. To verify this we do
|
// then that move is singular and should be extended. To verify this we do
|
||||||
// a reduced search on all the other moves but the ttMove and if the
|
// a reduced search on all the other moves but the ttMove and if the
|
||||||
// result is lower than ttValue minus a margin then we will extend the ttMove.
|
// result is lower than ttValue minus a margin then we will extend the ttMove.
|
||||||
if ( depth >= 6 * ONE_PLY
|
if ( depth >= 6
|
||||||
&& move == ttMove
|
&& move == ttMove
|
||||||
&& !rootNode
|
&& !rootNode
|
||||||
&& !excludedMove // Avoid recursive singular search
|
&& !excludedMove // Avoid recursive singular search
|
||||||
/* && ttValue != VALUE_NONE Already implicit in the next condition */
|
/* && ttValue != VALUE_NONE Already implicit in the next condition */
|
||||||
&& abs(ttValue) < VALUE_KNOWN_WIN
|
&& abs(ttValue) < VALUE_KNOWN_WIN
|
||||||
&& (tte->bound() & BOUND_LOWER)
|
&& (tte->bound() & BOUND_LOWER)
|
||||||
&& tte->depth() >= depth - 3 * ONE_PLY
|
&& tte->depth() >= depth - 3
|
||||||
&& pos.legal(move))
|
&& pos.legal(move))
|
||||||
{
|
{
|
||||||
Value singularBeta = ttValue - 2 * depth / ONE_PLY;
|
Value singularBeta = ttValue - 2 * depth;
|
||||||
Depth halfDepth = depth / (2 * ONE_PLY) * ONE_PLY; // ONE_PLY invariant
|
Depth halfDepth = depth / 2;
|
||||||
ss->excludedMove = move;
|
ss->excludedMove = move;
|
||||||
value = search<NonPV>(pos, ss, singularBeta - 1, singularBeta, halfDepth, cutNode);
|
value = search<NonPV>(pos, ss, singularBeta - 1, singularBeta, halfDepth, cutNode);
|
||||||
ss->excludedMove = MOVE_NONE;
|
ss->excludedMove = MOVE_NONE;
|
||||||
|
|
||||||
if (value < singularBeta)
|
if (value < singularBeta)
|
||||||
{
|
{
|
||||||
extension = ONE_PLY;
|
extension = 1;
|
||||||
singularLMR++;
|
singularLMR++;
|
||||||
|
|
||||||
if (value < singularBeta - std::min(4 * depth / ONE_PLY, 36))
|
if (value < singularBeta - std::min(4 * depth, 36))
|
||||||
singularLMR++;
|
singularLMR++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,27 +992,27 @@ moves_loop: // When in check, search starts from here
|
||||||
// Check extension (~2 Elo)
|
// Check extension (~2 Elo)
|
||||||
else if ( givesCheck
|
else if ( givesCheck
|
||||||
&& (pos.is_discovery_check_on_king(~us, move) || pos.see_ge(move)))
|
&& (pos.is_discovery_check_on_king(~us, move) || pos.see_ge(move)))
|
||||||
extension = ONE_PLY;
|
extension = 1;
|
||||||
|
|
||||||
// Shuffle extension
|
// Shuffle extension
|
||||||
else if ( PvNode
|
else if ( PvNode
|
||||||
&& pos.rule50_count() > 18
|
&& pos.rule50_count() > 18
|
||||||
&& depth < 3 * ONE_PLY
|
&& depth < 3
|
||||||
&& ++thisThread->shuffleExts < thisThread->nodes.load(std::memory_order_relaxed) / 4) // To avoid too many extensions
|
&& ++thisThread->shuffleExts < thisThread->nodes.load(std::memory_order_relaxed) / 4) // To avoid too many extensions
|
||||||
extension = ONE_PLY;
|
extension = 1;
|
||||||
|
|
||||||
// Passed pawn extension
|
// Passed pawn extension
|
||||||
else if ( move == ss->killers[0]
|
else if ( move == ss->killers[0]
|
||||||
&& pos.advanced_pawn_push(move)
|
&& pos.advanced_pawn_push(move)
|
||||||
&& pos.pawn_passed(us, to_sq(move)))
|
&& pos.pawn_passed(us, to_sq(move)))
|
||||||
extension = ONE_PLY;
|
extension = 1;
|
||||||
|
|
||||||
// Castling extension
|
// Castling extension
|
||||||
if (type_of(move) == CASTLING)
|
if (type_of(move) == CASTLING)
|
||||||
extension = ONE_PLY;
|
extension = 1;
|
||||||
|
|
||||||
// Calculate new depth for this move
|
// Calculate new depth for this move
|
||||||
newDepth = depth - ONE_PLY + extension;
|
newDepth = depth - 1 + extension;
|
||||||
|
|
||||||
// Step 14. Pruning at shallow depth (~170 Elo)
|
// Step 14. Pruning at shallow depth (~170 Elo)
|
||||||
if ( !rootNode
|
if ( !rootNode
|
||||||
|
@ -1022,7 +1020,7 @@ moves_loop: // When in check, search starts from here
|
||||||
&& bestValue > VALUE_MATED_IN_MAX_PLY)
|
&& bestValue > VALUE_MATED_IN_MAX_PLY)
|
||||||
{
|
{
|
||||||
// Skip quiet moves if movecount exceeds our FutilityMoveCount threshold
|
// Skip quiet moves if movecount exceeds our FutilityMoveCount threshold
|
||||||
moveCountPruning = moveCount >= futility_move_count(improving, depth / ONE_PLY);
|
moveCountPruning = moveCount >= futility_move_count(improving, depth);
|
||||||
|
|
||||||
if ( !captureOrPromotion
|
if ( !captureOrPromotion
|
||||||
&& !givesCheck
|
&& !givesCheck
|
||||||
|
@ -1033,8 +1031,7 @@ moves_loop: // When in check, search starts from here
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Reduced depth of the next LMR search
|
// Reduced depth of the next LMR search
|
||||||
int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), DEPTH_ZERO);
|
int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0);
|
||||||
lmrDepth /= ONE_PLY;
|
|
||||||
|
|
||||||
// Countermoves based pruning (~20 Elo)
|
// Countermoves based pruning (~20 Elo)
|
||||||
if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1)
|
if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1)
|
||||||
|
@ -1053,7 +1050,7 @@ moves_loop: // When in check, search starts from here
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if ( !(givesCheck && extension)
|
else if ( !(givesCheck && extension)
|
||||||
&& !pos.see_ge(move, Value(-199) * (depth / ONE_PLY))) // (~20 Elo)
|
&& !pos.see_ge(move, Value(-199) * depth)) // (~20 Elo)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,7 +1073,7 @@ moves_loop: // When in check, search starts from here
|
||||||
|
|
||||||
// Step 16. Reduced depth search (LMR). If the move fails high it will be
|
// Step 16. Reduced depth search (LMR). If the move fails high it will be
|
||||||
// re-searched at full depth.
|
// re-searched at full depth.
|
||||||
if ( depth >= 3 * ONE_PLY
|
if ( depth >= 3
|
||||||
&& moveCount > 1 + 2 * rootNode
|
&& moveCount > 1 + 2 * rootNode
|
||||||
&& (!rootNode || thisThread->best_move_count(move) == 0)
|
&& (!rootNode || thisThread->best_move_count(move) == 0)
|
||||||
&& ( !captureOrPromotion
|
&& ( !captureOrPromotion
|
||||||
|
@ -1088,35 +1085,35 @@ moves_loop: // When in check, search starts from here
|
||||||
|
|
||||||
// Reduction if other threads are searching this position.
|
// Reduction if other threads are searching this position.
|
||||||
if (th.marked())
|
if (th.marked())
|
||||||
r += ONE_PLY;
|
r++;
|
||||||
|
|
||||||
// Decrease reduction if position is or has been on the PV
|
// Decrease reduction if position is or has been on the PV
|
||||||
if (ttPv)
|
if (ttPv)
|
||||||
r -= 2 * ONE_PLY;
|
r -= 2;
|
||||||
|
|
||||||
// Decrease reduction if opponent's move count is high (~10 Elo)
|
// Decrease reduction if opponent's move count is high (~10 Elo)
|
||||||
if ((ss-1)->moveCount > 15)
|
if ((ss-1)->moveCount > 15)
|
||||||
r -= ONE_PLY;
|
r--;
|
||||||
|
|
||||||
// Decrease reduction if ttMove has been singularly extended
|
// Decrease reduction if ttMove has been singularly extended
|
||||||
r -= singularLMR * ONE_PLY;
|
r -= singularLMR;
|
||||||
|
|
||||||
if (!captureOrPromotion)
|
if (!captureOrPromotion)
|
||||||
{
|
{
|
||||||
// Increase reduction if ttMove is a capture (~0 Elo)
|
// Increase reduction if ttMove is a capture (~0 Elo)
|
||||||
if (ttCapture)
|
if (ttCapture)
|
||||||
r += ONE_PLY;
|
r++;
|
||||||
|
|
||||||
// Increase reduction for cut nodes (~5 Elo)
|
// Increase reduction for cut nodes (~5 Elo)
|
||||||
if (cutNode)
|
if (cutNode)
|
||||||
r += 2 * ONE_PLY;
|
r += 2;
|
||||||
|
|
||||||
// Decrease reduction for moves that escape a capture. Filter out
|
// Decrease reduction for moves that escape a capture. Filter out
|
||||||
// castling moves, because they are coded as "king captures rook" and
|
// castling moves, because they are coded as "king captures rook" and
|
||||||
// hence break make_move(). (~5 Elo)
|
// hence break make_move(). (~5 Elo)
|
||||||
else if ( type_of(move) == NORMAL
|
else if ( type_of(move) == NORMAL
|
||||||
&& !pos.see_ge(reverse_move(move)))
|
&& !pos.see_ge(reverse_move(move)))
|
||||||
r -= 2 * ONE_PLY;
|
r -= 2;
|
||||||
|
|
||||||
ss->statScore = thisThread->mainHistory[us][from_to(move)]
|
ss->statScore = thisThread->mainHistory[us][from_to(move)]
|
||||||
+ (*contHist[0])[movedPiece][to_sq(move)]
|
+ (*contHist[0])[movedPiece][to_sq(move)]
|
||||||
|
@ -1133,16 +1130,16 @@ moves_loop: // When in check, search starts from here
|
||||||
|
|
||||||
// Decrease/increase reduction by comparing opponent's stat score (~10 Elo)
|
// Decrease/increase reduction by comparing opponent's stat score (~10 Elo)
|
||||||
if (ss->statScore >= -99 && (ss-1)->statScore < -116)
|
if (ss->statScore >= -99 && (ss-1)->statScore < -116)
|
||||||
r -= ONE_PLY;
|
r--;
|
||||||
|
|
||||||
else if ((ss-1)->statScore >= -117 && ss->statScore < -144)
|
else if ((ss-1)->statScore >= -117 && ss->statScore < -144)
|
||||||
r += ONE_PLY;
|
r++;
|
||||||
|
|
||||||
// Decrease/increase reduction for moves with a good/bad history (~30 Elo)
|
// Decrease/increase reduction for moves with a good/bad history (~30 Elo)
|
||||||
r -= ss->statScore / 16384 * ONE_PLY;
|
r -= ss->statScore / 16384;
|
||||||
}
|
}
|
||||||
|
|
||||||
Depth d = clamp(newDepth - r, ONE_PLY, newDepth);
|
Depth d = clamp(newDepth - r, 1, newDepth);
|
||||||
|
|
||||||
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true);
|
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true);
|
||||||
|
|
||||||
|
@ -1276,18 +1273,18 @@ moves_loop: // When in check, search starts from here
|
||||||
// Quiet best move: update move sorting heuristics
|
// Quiet best move: update move sorting heuristics
|
||||||
if (!pos.capture_or_promotion(bestMove))
|
if (!pos.capture_or_promotion(bestMove))
|
||||||
update_quiet_stats(pos, ss, bestMove, quietsSearched, quietCount,
|
update_quiet_stats(pos, ss, bestMove, quietsSearched, quietCount,
|
||||||
stat_bonus(depth + (bestValue > beta + PawnValueMg ? ONE_PLY : DEPTH_ZERO)));
|
stat_bonus(depth + (bestValue > beta + PawnValueMg)));
|
||||||
|
|
||||||
update_capture_stats(pos, bestMove, capturesSearched, captureCount, stat_bonus(depth + ONE_PLY));
|
update_capture_stats(pos, bestMove, capturesSearched, captureCount, stat_bonus(depth + 1));
|
||||||
|
|
||||||
// Extra penalty for a quiet TT or main killer move in previous ply when it gets refuted
|
// Extra penalty for a quiet TT or main killer move in previous ply when it gets refuted
|
||||||
if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0]))
|
if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0]))
|
||||||
&& !pos.captured_piece())
|
&& !pos.captured_piece())
|
||||||
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY));
|
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1));
|
||||||
|
|
||||||
}
|
}
|
||||||
// Bonus for prior countermove that caused the fail low
|
// Bonus for prior countermove that caused the fail low
|
||||||
else if ( (depth >= 3 * ONE_PLY || PvNode)
|
else if ( (depth >= 3 || PvNode)
|
||||||
&& !pos.captured_piece())
|
&& !pos.captured_piece())
|
||||||
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth));
|
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth));
|
||||||
|
|
||||||
|
@ -1315,8 +1312,7 @@ moves_loop: // When in check, search starts from here
|
||||||
|
|
||||||
assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
|
assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
|
||||||
assert(PvNode || (alpha == beta - 1));
|
assert(PvNode || (alpha == beta - 1));
|
||||||
assert(depth <= DEPTH_ZERO);
|
assert(depth <= 0);
|
||||||
assert(depth / ONE_PLY * ONE_PLY == depth);
|
|
||||||
|
|
||||||
Move pv[MAX_PLY+1];
|
Move pv[MAX_PLY+1];
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
|
@ -1455,7 +1451,7 @@ moves_loop: // When in check, search starts from here
|
||||||
|
|
||||||
// Detect non-capture evasions that are candidates to be pruned
|
// Detect non-capture evasions that are candidates to be pruned
|
||||||
evasionPrunable = inCheck
|
evasionPrunable = inCheck
|
||||||
&& (depth != DEPTH_ZERO || moveCount > 2)
|
&& (depth != 0 || moveCount > 2)
|
||||||
&& bestValue > VALUE_MATED_IN_MAX_PLY
|
&& bestValue > VALUE_MATED_IN_MAX_PLY
|
||||||
&& !pos.capture(move);
|
&& !pos.capture(move);
|
||||||
|
|
||||||
|
@ -1480,7 +1476,7 @@ moves_loop: // When in check, search starts from here
|
||||||
|
|
||||||
// Make and search the move
|
// Make and search the move
|
||||||
pos.do_move(move, st, givesCheck);
|
pos.do_move(move, st, givesCheck);
|
||||||
value = -qsearch<NT>(pos, ss+1, -beta, -alpha, depth - ONE_PLY);
|
value = -qsearch<NT>(pos, ss+1, -beta, -alpha, depth - 1);
|
||||||
pos.undo_move(move);
|
pos.undo_move(move);
|
||||||
|
|
||||||
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
||||||
|
@ -1707,10 +1703,10 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) {
|
||||||
{
|
{
|
||||||
bool updated = (i <= pvIdx && rootMoves[i].score != -VALUE_INFINITE);
|
bool updated = (i <= pvIdx && rootMoves[i].score != -VALUE_INFINITE);
|
||||||
|
|
||||||
if (depth == ONE_PLY && !updated)
|
if (depth == 1 && !updated)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Depth d = updated ? depth : depth - ONE_PLY;
|
Depth d = updated ? depth : depth - 1;
|
||||||
Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore;
|
Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore;
|
||||||
|
|
||||||
bool tb = TB::RootInTB && abs(v) < VALUE_MATE - MAX_PLY;
|
bool tb = TB::RootInTB && abs(v) < VALUE_MATE - MAX_PLY;
|
||||||
|
@ -1720,7 +1716,7 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) {
|
||||||
ss << "\n";
|
ss << "\n";
|
||||||
|
|
||||||
ss << "info"
|
ss << "info"
|
||||||
<< " depth " << d / ONE_PLY
|
<< " depth " << d
|
||||||
<< " seldepth " << rootMoves[i].selDepth
|
<< " seldepth " << rootMoves[i].selDepth
|
||||||
<< " multipv " << i + 1
|
<< " multipv " << i + 1
|
||||||
<< " score " << UCI::value(v);
|
<< " score " << UCI::value(v);
|
||||||
|
@ -1779,7 +1775,7 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) {
|
||||||
|
|
||||||
RootInTB = false;
|
RootInTB = false;
|
||||||
UseRule50 = bool(Options["Syzygy50MoveRule"]);
|
UseRule50 = bool(Options["Syzygy50MoveRule"]);
|
||||||
ProbeDepth = int(Options["SyzygyProbeDepth"]) * ONE_PLY;
|
ProbeDepth = int(Options["SyzygyProbeDepth"]);
|
||||||
Cardinality = int(Options["SyzygyProbeLimit"]);
|
Cardinality = int(Options["SyzygyProbeLimit"]);
|
||||||
bool dtz_available = true;
|
bool dtz_available = true;
|
||||||
|
|
||||||
|
@ -1788,7 +1784,7 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) {
|
||||||
if (Cardinality > MaxCardinality)
|
if (Cardinality > MaxCardinality)
|
||||||
{
|
{
|
||||||
Cardinality = MaxCardinality;
|
Cardinality = MaxCardinality;
|
||||||
ProbeDepth = DEPTH_ZERO;
|
ProbeDepth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Cardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING))
|
if (Cardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING))
|
||||||
|
|
|
@ -204,7 +204,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
|
||||||
for (Thread* th : *this)
|
for (Thread* th : *this)
|
||||||
{
|
{
|
||||||
th->shuffleExts = th->nodes = th->tbHits = th->nmpMinPly = 0;
|
th->shuffleExts = th->nodes = th->tbHits = th->nmpMinPly = 0;
|
||||||
th->rootDepth = th->completedDepth = DEPTH_ZERO;
|
th->rootDepth = th->completedDepth = 0;
|
||||||
th->rootMoves = rootMoves;
|
th->rootMoves = rootMoves;
|
||||||
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
|
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,24 +35,22 @@ TranspositionTable TT; // Our global transposition table
|
||||||
|
|
||||||
void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) {
|
void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) {
|
||||||
|
|
||||||
assert(d / ONE_PLY * ONE_PLY == d);
|
|
||||||
|
|
||||||
// Preserve any existing move for the same position
|
// Preserve any existing move for the same position
|
||||||
if (m || (k >> 48) != key16)
|
if (m || (k >> 48) != key16)
|
||||||
move16 = (uint16_t)m;
|
move16 = (uint16_t)m;
|
||||||
|
|
||||||
// Overwrite less valuable entries
|
// Overwrite less valuable entries
|
||||||
if ( (k >> 48) != key16
|
if ( (k >> 48) != key16
|
||||||
||(d - DEPTH_OFFSET) / ONE_PLY > depth8 - 4
|
|| d - DEPTH_OFFSET > depth8 - 4
|
||||||
|| b == BOUND_EXACT)
|
|| b == BOUND_EXACT)
|
||||||
{
|
{
|
||||||
assert((d - DEPTH_OFFSET) / ONE_PLY >= 0);
|
assert(d >= DEPTH_OFFSET);
|
||||||
|
|
||||||
key16 = (uint16_t)(k >> 48);
|
key16 = (uint16_t)(k >> 48);
|
||||||
value16 = (int16_t)v;
|
value16 = (int16_t)v;
|
||||||
eval16 = (int16_t)ev;
|
eval16 = (int16_t)ev;
|
||||||
genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b);
|
genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b);
|
||||||
depth8 = (uint8_t)((d - DEPTH_OFFSET) / ONE_PLY);
|
depth8 = (uint8_t)(d - DEPTH_OFFSET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
src/tt.h
2
src/tt.h
|
@ -40,7 +40,7 @@ struct TTEntry {
|
||||||
Move move() const { return (Move )move16; }
|
Move move() const { return (Move )move16; }
|
||||||
Value value() const { return (Value)value16; }
|
Value value() const { return (Value)value16; }
|
||||||
Value eval() const { return (Value)eval16; }
|
Value eval() const { return (Value)eval16; }
|
||||||
Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)) + DEPTH_OFFSET; }
|
Depth depth() const { return (Depth)depth8 + DEPTH_OFFSET; }
|
||||||
bool is_pv() const { return (bool)(genBound8 & 0x4); }
|
bool is_pv() const { return (bool)(genBound8 & 0x4); }
|
||||||
Bound bound() const { return (Bound)(genBound8 & 0x3); }
|
Bound bound() const { return (Bound)(genBound8 & 0x3); }
|
||||||
void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev);
|
void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev);
|
||||||
|
|
17
src/types.h
17
src/types.h
|
@ -203,22 +203,18 @@ enum Piece {
|
||||||
|
|
||||||
extern Value PieceValue[PHASE_NB][PIECE_NB];
|
extern Value PieceValue[PHASE_NB][PIECE_NB];
|
||||||
|
|
||||||
enum Depth : int {
|
typedef int Depth;
|
||||||
|
|
||||||
ONE_PLY = 1,
|
enum : int {
|
||||||
|
|
||||||
DEPTH_ZERO = 0 * ONE_PLY,
|
DEPTH_QS_CHECKS = 0,
|
||||||
DEPTH_QS_CHECKS = 0 * ONE_PLY,
|
DEPTH_QS_NO_CHECKS = -1,
|
||||||
DEPTH_QS_NO_CHECKS = -1 * ONE_PLY,
|
DEPTH_QS_RECAPTURES = -5,
|
||||||
DEPTH_QS_RECAPTURES = -5 * ONE_PLY,
|
|
||||||
|
|
||||||
DEPTH_NONE = -6 * ONE_PLY,
|
DEPTH_NONE = -6,
|
||||||
DEPTH_OFFSET = DEPTH_NONE,
|
DEPTH_OFFSET = DEPTH_NONE,
|
||||||
DEPTH_MAX = MAX_PLY * ONE_PLY
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2");
|
|
||||||
|
|
||||||
enum Square : int {
|
enum Square : int {
|
||||||
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
|
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
|
||||||
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
|
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
|
||||||
|
@ -298,7 +294,6 @@ inline T& operator*=(T& d, int i) { return d = T(int(d) * i); } \
|
||||||
inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
|
inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
|
||||||
|
|
||||||
ENABLE_FULL_OPERATORS_ON(Value)
|
ENABLE_FULL_OPERATORS_ON(Value)
|
||||||
ENABLE_FULL_OPERATORS_ON(Depth)
|
|
||||||
ENABLE_FULL_OPERATORS_ON(Direction)
|
ENABLE_FULL_OPERATORS_ON(Direction)
|
||||||
|
|
||||||
ENABLE_INCR_OPERATORS_ON(PieceType)
|
ENABLE_INCR_OPERATORS_ON(PieceType)
|
||||||
|
|
Loading…
Add table
Reference in a new issue