1
0
Fork 0
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:
Brian Sheppard 2019-09-28 16:27:23 -04:00 committed by Stéphane Nicolet
parent 328bdd0947
commit ca7d4e9ac7
7 changed files with 86 additions and 100 deletions

View file

@ -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 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
- ../tests/perft.sh

View file

@ -61,7 +61,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch),
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;
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)
: 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;
ttMove = ttm
@ -206,7 +206,7 @@ top:
endMoves = generate<QUIETS>(pos, cur);
score<QUIETS>();
partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY);
partial_insertion_sort(cur, endMoves, -4000 * depth);
}
++stage;

View file

@ -64,15 +64,15 @@ namespace {
// Razor and futility margins
constexpr int RazorMargin = 661;
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
int Reductions[MAX_MOVES]; // [depth or moveNumber]
Depth reduction(bool i, Depth d, int mn) {
int r = Reductions[d / ONE_PLY] * Reductions[mn];
return ((r + 520) / 1024 + (!i && r > 999)) * ONE_PLY;
int r = Reductions[d] * Reductions[mn];
return (r + 520) / 1024 + (!i && r > 999);
}
constexpr int futility_move_count(bool improving, int depth) {
@ -80,8 +80,7 @@ namespace {
}
// History and stats update bonus, based on depth
int stat_bonus(Depth depth) {
int d = depth / ONE_PLY;
int stat_bonus(Depth d) {
return d > 17 ? -8 : 22 * d * d + 151 * d - 140;
}
@ -94,7 +93,7 @@ namespace {
struct Skill {
explicit Skill(int l) : level(l) {}
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);
int level;
@ -148,7 +147,7 @@ namespace {
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
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_from_tt(Value v, int ply);
@ -164,16 +163,16 @@ namespace {
StateInfo st;
uint64_t cnt, nodes = 0;
const bool leaf = (depth == 2 * ONE_PLY);
const bool leaf = (depth == 2);
for (const auto& m : MoveList<LEGAL>(pos))
{
if (Root && depth <= ONE_PLY)
if (Root && depth <= 1)
cnt = 1, nodes++;
else
{
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;
pos.undo_move(m);
}
@ -215,7 +214,7 @@ void MainThread::search() {
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;
return;
}
@ -328,7 +327,7 @@ void Thread::search() {
Move pv[MAX_PLY+1];
Value bestValue, alpha, beta, delta;
Move lastBestMove = MOVE_NONE;
Depth lastBestMoveDepth = DEPTH_ZERO;
Depth lastBestMoveDepth = 0;
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
double timeReduction = 1, totBestMoveChanges = 0;
Color us = rootPos.side_to_move();
@ -378,9 +377,9 @@ void Thread::search() {
: -make_score(ct, ct / 2));
// 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
&& !(Limits.depth && mainThread && rootDepth / ONE_PLY > Limits.depth))
&& !(Limits.depth && mainThread && rootDepth > Limits.depth))
{
// Age out PV variability metric
if (mainThread)
@ -409,7 +408,7 @@ void Thread::search() {
selDepth = 0;
// Reset aspiration window starting size
if (rootDepth >= 4 * ONE_PLY)
if (rootDepth >= 4)
{
Value previousScore = rootMoves[pvIdx].previousScore;
delta = Value(23);
@ -429,7 +428,7 @@ void Thread::search() {
int failedHighCnt = 0;
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);
// 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);
// 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);
// 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
if (depth < ONE_PLY)
if (depth <= 0)
return qsearch<NT>(pos, ss, alpha, beta);
assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE);
assert(PvNode || (alpha == beta - 1));
assert(DEPTH_ZERO < depth && depth < DEPTH_MAX);
assert(0 < depth && depth < MAX_PLY);
assert(!(PvNode && cutNode));
assert(depth / ONE_PLY * ONE_PLY == depth);
Move pv[MAX_PLY+1], capturesSearched[32], quietsSearched[64];
StateInfo st;
@ -683,7 +681,7 @@ namespace {
// Extra penalty for early quiet moves of the previous ply
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
else if (!pos.capture_or_promotion(ttMove))
@ -730,7 +728,7 @@ namespace {
|| (b == BOUND_LOWER ? value >= beta : value <= alpha))
{
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);
return value;
@ -785,7 +783,7 @@ namespace {
// Step 7. Razoring (~2 Elo)
if ( !rootNode // The required rootNode PV handling is not available in qsearch
&& depth < 2 * ONE_PLY
&& depth < 2
&& eval <= alpha - RazorMargin)
return qsearch<NT>(pos, ss, alpha, beta);
@ -794,7 +792,7 @@ namespace {
// Step 8. Futility pruning: child node (~30 Elo)
if ( !PvNode
&& depth < 7 * ONE_PLY
&& depth < 7
&& eval - futility_margin(depth, improving) >= beta
&& eval < VALUE_KNOWN_WIN) // Do not return unproven wins
return eval;
@ -805,7 +803,7 @@ namespace {
&& (ss-1)->statScore < 22661
&& eval >= beta
&& eval >= ss->staticEval
&& ss->staticEval >= beta - 33 * depth / ONE_PLY + 299 - improving * 30
&& ss->staticEval >= beta - 33 * depth + 299 - improving * 30
&& !excludedMove
&& pos.non_pawn_material(us)
&& (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
@ -813,7 +811,7 @@ namespace {
assert(eval - beta >= 0);
// 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->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0];
@ -830,14 +828,14 @@ namespace {
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
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;
assert(!thisThread->nmpMinPly); // Recursive verification is not allowed
// Do verification search at high depths, with null move pruning disabled
// 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;
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
// much above beta, we can (almost) safely prune the previous move.
if ( !PvNode
&& depth >= 5 * ONE_PLY
&& depth >= 5
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
{
Value raisedBeta = std::min(beta + 191 - 46 * improving, VALUE_INFINITE);
@ -869,7 +867,7 @@ namespace {
ss->currentMove = 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);
@ -878,7 +876,7 @@ namespace {
// If the qsearch held, perform the regular search
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);
@ -888,9 +886,9 @@ namespace {
}
// 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);
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;
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())
<< " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl;
if (PvNode)
(ss+1)->pv = nullptr;
extension = DEPTH_ZERO;
extension = 0;
captureOrPromotion = pos.capture_or_promotion(move);
movedPiece = pos.moved_piece(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
// 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.
if ( depth >= 6 * ONE_PLY
if ( depth >= 6
&& move == ttMove
&& !rootNode
&& !excludedMove // Avoid recursive singular search
/* && ttValue != VALUE_NONE Already implicit in the next condition */
&& abs(ttValue) < VALUE_KNOWN_WIN
&& (tte->bound() & BOUND_LOWER)
&& tte->depth() >= depth - 3 * ONE_PLY
&& tte->depth() >= depth - 3
&& pos.legal(move))
{
Value singularBeta = ttValue - 2 * depth / ONE_PLY;
Depth halfDepth = depth / (2 * ONE_PLY) * ONE_PLY; // ONE_PLY invariant
Value singularBeta = ttValue - 2 * depth;
Depth halfDepth = depth / 2;
ss->excludedMove = move;
value = search<NonPV>(pos, ss, singularBeta - 1, singularBeta, halfDepth, cutNode);
ss->excludedMove = MOVE_NONE;
if (value < singularBeta)
{
extension = ONE_PLY;
extension = 1;
singularLMR++;
if (value < singularBeta - std::min(4 * depth / ONE_PLY, 36))
if (value < singularBeta - std::min(4 * depth, 36))
singularLMR++;
}
@ -994,27 +992,27 @@ moves_loop: // When in check, search starts from here
// Check extension (~2 Elo)
else if ( givesCheck
&& (pos.is_discovery_check_on_king(~us, move) || pos.see_ge(move)))
extension = ONE_PLY;
extension = 1;
// Shuffle extension
else if ( PvNode
&& 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
extension = ONE_PLY;
extension = 1;
// Passed pawn extension
else if ( move == ss->killers[0]
&& pos.advanced_pawn_push(move)
&& pos.pawn_passed(us, to_sq(move)))
extension = ONE_PLY;
extension = 1;
// Castling extension
if (type_of(move) == CASTLING)
extension = ONE_PLY;
extension = 1;
// Calculate new depth for this move
newDepth = depth - ONE_PLY + extension;
newDepth = depth - 1 + extension;
// Step 14. Pruning at shallow depth (~170 Elo)
if ( !rootNode
@ -1022,7 +1020,7 @@ moves_loop: // When in check, search starts from here
&& bestValue > VALUE_MATED_IN_MAX_PLY)
{
// 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
&& !givesCheck
@ -1033,8 +1031,7 @@ moves_loop: // When in check, search starts from here
continue;
// Reduced depth of the next LMR search
int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), DEPTH_ZERO);
lmrDepth /= ONE_PLY;
int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0);
// Countermoves based pruning (~20 Elo)
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;
}
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;
}
@ -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
// re-searched at full depth.
if ( depth >= 3 * ONE_PLY
if ( depth >= 3
&& moveCount > 1 + 2 * rootNode
&& (!rootNode || thisThread->best_move_count(move) == 0)
&& ( !captureOrPromotion
@ -1088,35 +1085,35 @@ moves_loop: // When in check, search starts from here
// Reduction if other threads are searching this position.
if (th.marked())
r += ONE_PLY;
r++;
// Decrease reduction if position is or has been on the PV
if (ttPv)
r -= 2 * ONE_PLY;
r -= 2;
// Decrease reduction if opponent's move count is high (~10 Elo)
if ((ss-1)->moveCount > 15)
r -= ONE_PLY;
r--;
// Decrease reduction if ttMove has been singularly extended
r -= singularLMR * ONE_PLY;
r -= singularLMR;
if (!captureOrPromotion)
{
// Increase reduction if ttMove is a capture (~0 Elo)
if (ttCapture)
r += ONE_PLY;
r++;
// Increase reduction for cut nodes (~5 Elo)
if (cutNode)
r += 2 * ONE_PLY;
r += 2;
// Decrease reduction for moves that escape a capture. Filter out
// castling moves, because they are coded as "king captures rook" and
// hence break make_move(). (~5 Elo)
else if ( type_of(move) == NORMAL
&& !pos.see_ge(reverse_move(move)))
r -= 2 * ONE_PLY;
r -= 2;
ss->statScore = thisThread->mainHistory[us][from_to(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)
if (ss->statScore >= -99 && (ss-1)->statScore < -116)
r -= ONE_PLY;
r--;
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)
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);
@ -1276,18 +1273,18 @@ moves_loop: // When in check, search starts from here
// Quiet best move: update move sorting heuristics
if (!pos.capture_or_promotion(bestMove))
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
if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0]))
&& !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
else if ( (depth >= 3 * ONE_PLY || PvNode)
else if ( (depth >= 3 || PvNode)
&& !pos.captured_piece())
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(PvNode || (alpha == beta - 1));
assert(depth <= DEPTH_ZERO);
assert(depth / ONE_PLY * ONE_PLY == depth);
assert(depth <= 0);
Move pv[MAX_PLY+1];
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
evasionPrunable = inCheck
&& (depth != DEPTH_ZERO || moveCount > 2)
&& (depth != 0 || moveCount > 2)
&& bestValue > VALUE_MATED_IN_MAX_PLY
&& !pos.capture(move);
@ -1480,7 +1476,7 @@ moves_loop: // When in check, search starts from here
// Make and search the move
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);
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);
if (depth == ONE_PLY && !updated)
if (depth == 1 && !updated)
continue;
Depth d = updated ? depth : depth - ONE_PLY;
Depth d = updated ? depth : depth - 1;
Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore;
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 << "info"
<< " depth " << d / ONE_PLY
<< " depth " << d
<< " seldepth " << rootMoves[i].selDepth
<< " multipv " << i + 1
<< " score " << UCI::value(v);
@ -1779,7 +1775,7 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) {
RootInTB = false;
UseRule50 = bool(Options["Syzygy50MoveRule"]);
ProbeDepth = int(Options["SyzygyProbeDepth"]) * ONE_PLY;
ProbeDepth = int(Options["SyzygyProbeDepth"]);
Cardinality = int(Options["SyzygyProbeLimit"]);
bool dtz_available = true;
@ -1788,7 +1784,7 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) {
if (Cardinality > MaxCardinality)
{
Cardinality = MaxCardinality;
ProbeDepth = DEPTH_ZERO;
ProbeDepth = 0;
}
if (Cardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING))

View file

@ -204,7 +204,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
for (Thread* th : *this)
{
th->shuffleExts = th->nodes = th->tbHits = th->nmpMinPly = 0;
th->rootDepth = th->completedDepth = DEPTH_ZERO;
th->rootDepth = th->completedDepth = 0;
th->rootMoves = rootMoves;
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
}

View file

@ -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) {
assert(d / ONE_PLY * ONE_PLY == d);
// Preserve any existing move for the same position
if (m || (k >> 48) != key16)
move16 = (uint16_t)m;
// Overwrite less valuable entries
if ( (k >> 48) != key16
||(d - DEPTH_OFFSET) / ONE_PLY > depth8 - 4
|| d - DEPTH_OFFSET > depth8 - 4
|| b == BOUND_EXACT)
{
assert((d - DEPTH_OFFSET) / ONE_PLY >= 0);
assert(d >= DEPTH_OFFSET);
key16 = (uint16_t)(k >> 48);
value16 = (int16_t)v;
eval16 = (int16_t)ev;
genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b);
depth8 = (uint8_t)((d - DEPTH_OFFSET) / ONE_PLY);
depth8 = (uint8_t)(d - DEPTH_OFFSET);
}
}

View file

@ -40,7 +40,7 @@ struct TTEntry {
Move move() const { return (Move )move16; }
Value value() const { return (Value)value16; }
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); }
Bound bound() const { return (Bound)(genBound8 & 0x3); }
void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev);

View file

@ -203,22 +203,18 @@ enum Piece {
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 * ONE_PLY,
DEPTH_QS_NO_CHECKS = -1 * ONE_PLY,
DEPTH_QS_RECAPTURES = -5 * ONE_PLY,
DEPTH_QS_CHECKS = 0,
DEPTH_QS_NO_CHECKS = -1,
DEPTH_QS_RECAPTURES = -5,
DEPTH_NONE = -6 * ONE_PLY,
DEPTH_NONE = -6,
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 {
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,
@ -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); }
ENABLE_FULL_OPERATORS_ON(Value)
ENABLE_FULL_OPERATORS_ON(Depth)
ENABLE_FULL_OPERATORS_ON(Direction)
ENABLE_INCR_OPERATORS_ON(PieceType)