mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 00:33:09 +00:00
Improve comments about DEPTH constants
Also "fix" movepicker to allow depths between CHECKS and NO_CHECKS, which makes them easier to tweak (not that they get tweaked hardly ever) (This was more beneficial when there was a third stage to DEPTH_QS, but it's still an improvement now) closes https://github.com/official-stockfish/Stockfish/pull/5205 No functional change
This commit is contained in:
parent
c14b69790a
commit
ed79745bb9
5 changed files with 43 additions and 26 deletions
|
@ -361,8 +361,8 @@ top:
|
||||||
if (select<Next>([]() { return true; }))
|
if (select<Next>([]() { return true; }))
|
||||||
return *(cur - 1);
|
return *(cur - 1);
|
||||||
|
|
||||||
// If we did not find any move and we do not try checks, we have finished
|
// If we found no move and the depth is too low to try checks, then we have finished
|
||||||
if (depth != DEPTH_QS_CHECKS)
|
if (depth <= DEPTH_QS_NORMAL)
|
||||||
return Move::none();
|
return Move::none();
|
||||||
|
|
||||||
++stage;
|
++stage;
|
||||||
|
|
|
@ -733,7 +733,7 @@ Value Search::Worker::search(
|
||||||
ss->staticEval = eval = to_corrected_static_eval(unadjustedStaticEval, *thisThread, pos);
|
ss->staticEval = eval = to_corrected_static_eval(unadjustedStaticEval, *thisThread, pos);
|
||||||
|
|
||||||
// Static evaluation is saved as it was before adjustment by correction history
|
// Static evaluation is saved as it was before adjustment by correction history
|
||||||
tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, Move::none(),
|
tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_UNSEARCHED, Move::none(),
|
||||||
unadjustedStaticEval, tt.generation());
|
unadjustedStaticEval, tt.generation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1387,8 +1387,11 @@ moves_loop: // When in check, search starts here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Quiescence search function, which is called by the main search
|
// Quiescence search function, which is called by the main search function with zero depth, or
|
||||||
// function with zero depth, or recursively with further decreasing depth per call.
|
// recursively with further decreasing depth per call. With depth <= 0, we "should" be using
|
||||||
|
// static eval only, but tactical moves may confuse the static eval. To fight this horizon effect,
|
||||||
|
// we implement this qsearch of tactical moves only.
|
||||||
|
// See https://www.chessprogramming.org/Horizon_Effect and https://www.chessprogramming.org/Quiescence_Search
|
||||||
// (~155 Elo)
|
// (~155 Elo)
|
||||||
template<NodeType nodeType>
|
template<NodeType nodeType>
|
||||||
Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
|
@ -1446,8 +1449,10 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta,
|
||||||
|
|
||||||
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
||||||
|
|
||||||
// Decide the replacement and cutoff priority of the qsearch TT entries
|
// Note that unlike regular search, which stores literal depth, in QS we only store the
|
||||||
ttDepth = ss->inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS : DEPTH_QS_NO_CHECKS;
|
// current movegen stage. If in check, we search all evasions and thus store
|
||||||
|
// DEPTH_QS_CHECKS. (Evasions may be quiet, and _CHECKS includes quiets.)
|
||||||
|
ttDepth = ss->inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS : DEPTH_QS_NORMAL;
|
||||||
|
|
||||||
// Step 3. Transposition table lookup
|
// Step 3. Transposition table lookup
|
||||||
posKey = pos.key();
|
posKey = pos.key();
|
||||||
|
@ -1499,8 +1504,8 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta,
|
||||||
if (std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY && !PvNode)
|
if (std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY && !PvNode)
|
||||||
bestValue = (3 * bestValue + beta) / 4;
|
bestValue = (3 * bestValue + beta) / 4;
|
||||||
if (!ss->ttHit)
|
if (!ss->ttHit)
|
||||||
tte->save(posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER, DEPTH_NONE,
|
tte->save(posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER,
|
||||||
Move::none(), unadjustedStaticEval, tt.generation());
|
DEPTH_UNSEARCHED, Move::none(), unadjustedStaticEval, tt.generation());
|
||||||
|
|
||||||
return bestValue;
|
return bestValue;
|
||||||
}
|
}
|
||||||
|
@ -1514,16 +1519,16 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta,
|
||||||
const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory,
|
const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory,
|
||||||
(ss - 2)->continuationHistory};
|
(ss - 2)->continuationHistory};
|
||||||
|
|
||||||
// Initialize a MovePicker object for the current position, and prepare
|
// Initialize a MovePicker object for the current position, and prepare to search the moves.
|
||||||
// to search the moves. Because the depth is <= 0 here, only captures,
|
// We presently use two stages of qs movegen, first captures+checks, then captures only.
|
||||||
// queen promotions, and other checks (only if depth >= DEPTH_QS_CHECKS)
|
// (When in check, we simply search all evasions.)
|
||||||
// will be generated.
|
// (Presently, having the checks stage is worth only 1 Elo, and may be removable in the near future,
|
||||||
|
// which would result in only a single stage of QS movegen.)
|
||||||
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;
|
||||||
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory,
|
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory,
|
||||||
contHist, &thisThread->pawnHistory);
|
contHist, &thisThread->pawnHistory);
|
||||||
|
|
||||||
// Step 5. Loop through all pseudo-legal moves until no moves remain
|
// Step 5. Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs.
|
||||||
// or a beta cutoff occurs.
|
|
||||||
while ((move = mp.next_move()) != Move::none())
|
while ((move = mp.next_move()) != Move::none())
|
||||||
{
|
{
|
||||||
assert(move.is_ok());
|
assert(move.is_ok());
|
||||||
|
|
12
src/tt.cpp
12
src/tt.cpp
|
@ -30,6 +30,10 @@
|
||||||
|
|
||||||
namespace Stockfish {
|
namespace Stockfish {
|
||||||
|
|
||||||
|
// DEPTH_ENTRY_OFFSET exists because 1) we use `bool(depth8)` as the occupancy check, but
|
||||||
|
// 2) we need to store negative depths for QS. (`depth8` is the only field with "spare bits":
|
||||||
|
// we sacrifice the ability to store depths greater than 1<<8 less the offset, as asserted below.)
|
||||||
|
|
||||||
// Populates the TTEntry with a new node's data, possibly
|
// Populates the TTEntry with a new node's data, possibly
|
||||||
// overwriting an old position. The update is not atomic and can be racy.
|
// overwriting an old position. The update is not atomic and can be racy.
|
||||||
void TTEntry::save(
|
void TTEntry::save(
|
||||||
|
@ -40,14 +44,14 @@ void TTEntry::save(
|
||||||
move16 = m;
|
move16 = m;
|
||||||
|
|
||||||
// Overwrite less valuable entries (cheapest checks first)
|
// Overwrite less valuable entries (cheapest checks first)
|
||||||
if (b == BOUND_EXACT || uint16_t(k) != key16 || d - DEPTH_OFFSET + 2 * pv > depth8 - 4
|
if (b == BOUND_EXACT || uint16_t(k) != key16 || d - DEPTH_ENTRY_OFFSET + 2 * pv > depth8 - 4
|
||||||
|| relative_age(generation8))
|
|| relative_age(generation8))
|
||||||
{
|
{
|
||||||
assert(d > DEPTH_OFFSET);
|
assert(d > DEPTH_ENTRY_OFFSET);
|
||||||
assert(d < 256 + DEPTH_OFFSET);
|
assert(d < 256 + DEPTH_ENTRY_OFFSET);
|
||||||
|
|
||||||
key16 = uint16_t(k);
|
key16 = uint16_t(k);
|
||||||
depth8 = uint8_t(d - DEPTH_OFFSET);
|
depth8 = uint8_t(d - DEPTH_ENTRY_OFFSET);
|
||||||
genBound8 = uint8_t(generation8 | uint8_t(pv) << 2 | b);
|
genBound8 = uint8_t(generation8 | uint8_t(pv) << 2 | b);
|
||||||
value16 = int16_t(v);
|
value16 = int16_t(v);
|
||||||
eval16 = int16_t(ev);
|
eval16 = int16_t(ev);
|
||||||
|
|
5
src/tt.h
5
src/tt.h
|
@ -37,12 +37,15 @@ namespace Stockfish {
|
||||||
// move 16 bit
|
// move 16 bit
|
||||||
// value 16 bit
|
// value 16 bit
|
||||||
// eval value 16 bit
|
// eval value 16 bit
|
||||||
|
//
|
||||||
|
// These fields are in the same order as accessed by TT::probe(), since memory is fastest sequentially.
|
||||||
|
// Equally, the store order in save() matches this order.
|
||||||
struct TTEntry {
|
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 + DEPTH_OFFSET); }
|
Depth depth() const { return Depth(depth8 + DEPTH_ENTRY_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, uint8_t generation8);
|
void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8);
|
||||||
|
|
15
src/types.h
15
src/types.h
|
@ -187,12 +187,17 @@ constexpr Value PieceValue[PIECE_NB] = {
|
||||||
using Depth = int;
|
using Depth = int;
|
||||||
|
|
||||||
enum : int {
|
enum : int {
|
||||||
|
// The following DEPTH_ constants are used for TT entries and QS movegen stages. In regular search,
|
||||||
|
// TT depth is literal: the search depth (effort) used to make the corresponding TT value.
|
||||||
|
// In qsearch, however, TT entries only store the current QS movegen stage (which should thus compare
|
||||||
|
// lower than any regular search depth).
|
||||||
DEPTH_QS_CHECKS = 0,
|
DEPTH_QS_CHECKS = 0,
|
||||||
DEPTH_QS_NO_CHECKS = -1,
|
DEPTH_QS_NORMAL = -1,
|
||||||
|
// For TT entries where no searching at all was done (whether regular or qsearch) we use
|
||||||
DEPTH_NONE = -6,
|
// _UNSEARCHED, which should thus compare lower than any QS or regular depth. _ENTRY_OFFSET is used
|
||||||
|
// only for the TT entry occupancy check (see tt.cpp), and should thus be lower than _UNSEARCHED.
|
||||||
DEPTH_OFFSET = -7 // value used only for TT entry occupancy check
|
DEPTH_UNSEARCHED = -6,
|
||||||
|
DEPTH_ENTRY_OFFSET = -7
|
||||||
};
|
};
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
Loading…
Add table
Reference in a new issue