mirror of
https://github.com/sockspls/badfish
synced 2025-04-29 08:13:08 +00:00
Introduce separate butterfly history table for sorting root moves
Idea of this patch comes from the fact that current history heuristics are mostly populated by low depth entries since our stat bonus reaches maximum value at depth 5-6 and number of low depth nodes is much bigger than number of high depth nodes. But it doesn't make a whole lost of sense to use this low-depth centered histories to sort moves at root. Current patch introduces special history table that is used exclusively at root, it remembers which quiet moves were good and which quiet moves were not good there and uses this information for move ordering. Passed STC: https://tests.stockfishchess.org/tests/view/66dda74adc53972b68218cc9 LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 127680 W: 33579 L: 33126 D: 60975 Ptnml(0-2): 422, 15098, 32391, 15463, 466 Passed LTC: https://tests.stockfishchess.org/tests/view/66dead2adc53972b68218d34 LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 381978 W: 96958 L: 95923 D: 189097 Ptnml(0-2): 277, 42165, 105089, 43162, 296 closes https://github.com/official-stockfish/Stockfish/pull/5595 Bench: 1611283
This commit is contained in:
parent
5ce7f866a5
commit
240a5b1c72
4 changed files with 53 additions and 24 deletions
|
@ -82,16 +82,20 @@ MovePicker::MovePicker(const Position& p,
|
|||
Move ttm,
|
||||
Depth d,
|
||||
const ButterflyHistory* mh,
|
||||
const ButterflyHistory* rh,
|
||||
const CapturePieceToHistory* cph,
|
||||
const PieceToHistory** ch,
|
||||
const PawnHistory* ph) :
|
||||
const PawnHistory* ph,
|
||||
bool rn) :
|
||||
pos(p),
|
||||
mainHistory(mh),
|
||||
rootHistory(rh),
|
||||
captureHistory(cph),
|
||||
continuationHistory(ch),
|
||||
pawnHistory(ph),
|
||||
ttMove(ttm),
|
||||
depth(d) {
|
||||
depth(d),
|
||||
rootNode(rn) {
|
||||
|
||||
if (pos.checkers())
|
||||
stage = EVASION_TT + !(ttm && pos.pseudo_legal(ttm));
|
||||
|
@ -174,6 +178,9 @@ void MovePicker::score() {
|
|||
m.value -= (pt == QUEEN ? bool(to & threatenedByRook) * 49000
|
||||
: pt == ROOK ? bool(to & threatenedByMinor) * 24335
|
||||
: bool(to & threatenedByPawn) * 14900);
|
||||
|
||||
if (rootNode)
|
||||
m.value += 4 * (*rootHistory)[pos.side_to_move()][m.from_to()];
|
||||
}
|
||||
|
||||
else // Type == EVASIONS
|
||||
|
|
|
@ -171,9 +171,11 @@ class MovePicker {
|
|||
Move,
|
||||
Depth,
|
||||
const ButterflyHistory*,
|
||||
const ButterflyHistory*,
|
||||
const CapturePieceToHistory*,
|
||||
const PieceToHistory**,
|
||||
const PawnHistory*);
|
||||
const PawnHistory*,
|
||||
bool);
|
||||
MovePicker(const Position&, Move, int, const CapturePieceToHistory*);
|
||||
Move next_move(bool skipQuiets = false);
|
||||
|
||||
|
@ -187,6 +189,7 @@ class MovePicker {
|
|||
|
||||
const Position& pos;
|
||||
const ButterflyHistory* mainHistory;
|
||||
const ButterflyHistory* rootHistory;
|
||||
const CapturePieceToHistory* captureHistory;
|
||||
const PieceToHistory** continuationHistory;
|
||||
const PawnHistory* pawnHistory;
|
||||
|
@ -195,6 +198,7 @@ class MovePicker {
|
|||
int stage;
|
||||
int threshold;
|
||||
Depth depth;
|
||||
bool rootNode;
|
||||
ExtMove moves[MAX_MOVES];
|
||||
};
|
||||
|
||||
|
|
|
@ -101,16 +101,21 @@ Value value_to_tt(Value v, int ply);
|
|||
Value value_from_tt(Value v, int ply, int r50c);
|
||||
void update_pv(Move* pv, Move move, const Move* childPv);
|
||||
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
|
||||
void update_quiet_histories(
|
||||
const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus);
|
||||
void update_all_stats(const Position& pos,
|
||||
Stack* ss,
|
||||
Search::Worker& workerThread,
|
||||
Move bestMove,
|
||||
Square prevSq,
|
||||
ValueList<Move, 32>& quietsSearched,
|
||||
ValueList<Move, 32>& capturesSearched,
|
||||
Depth depth);
|
||||
void update_quiet_histories(const Position& pos,
|
||||
Stack* ss,
|
||||
Search::Worker& workerThread,
|
||||
Move move,
|
||||
int bonus,
|
||||
bool rootNode);
|
||||
void update_all_stats(const Position& pos,
|
||||
Stack* ss,
|
||||
Search::Worker& workerThread,
|
||||
Move bestMove,
|
||||
Square prevSq,
|
||||
ValueList<Move, 32>& quietsSearched,
|
||||
ValueList<Move, 32>& capturesSearched,
|
||||
Depth depth,
|
||||
bool rootNode);
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -264,6 +269,8 @@ void Search::Worker::iterative_deepening() {
|
|||
|
||||
int searchAgainCounter = 0;
|
||||
|
||||
rootHistory.fill(0);
|
||||
|
||||
// Iterative deepening loop until requested to stop or the target depth is reached
|
||||
while (++rootDepth < MAX_PLY && !threads.stop
|
||||
&& !(limits.depth && mainThread && rootDepth > limits.depth))
|
||||
|
@ -488,6 +495,7 @@ void Search::Worker::iterative_deepening() {
|
|||
// Reset histories, usually before a new game
|
||||
void Search::Worker::clear() {
|
||||
mainHistory.fill(0);
|
||||
rootHistory.fill(0);
|
||||
captureHistory.fill(-753);
|
||||
pawnHistory.fill(-1152);
|
||||
pawnCorrectionHistory.fill(0);
|
||||
|
@ -622,7 +630,7 @@ Value Search::Worker::search(
|
|||
{
|
||||
// Bonus for a quiet ttMove that fails high (~2 Elo)
|
||||
if (!ttCapture)
|
||||
update_quiet_histories(pos, ss, *this, ttData.move, stat_bonus(depth));
|
||||
update_quiet_histories(pos, ss, *this, ttData.move, stat_bonus(depth), rootNode);
|
||||
|
||||
// Extra penalty for early quiet moves of
|
||||
// the previous ply (~1 Elo on STC, ~2 Elo on LTC)
|
||||
|
@ -912,8 +920,8 @@ moves_loop: // When in check, search starts here
|
|||
(ss - 6)->continuationHistory};
|
||||
|
||||
|
||||
MovePicker mp(pos, ttData.move, depth, &thisThread->mainHistory, &thisThread->captureHistory,
|
||||
contHist, &thisThread->pawnHistory);
|
||||
MovePicker mp(pos, ttData.move, depth, &thisThread->mainHistory, &thisThread->rootHistory,
|
||||
&thisThread->captureHistory, contHist, &thisThread->pawnHistory, rootNode);
|
||||
|
||||
value = bestValue;
|
||||
|
||||
|
@ -1339,7 +1347,8 @@ moves_loop: // When in check, search starts here
|
|||
// If there is a move that produces search value greater than alpha,
|
||||
// we update the stats of searched moves.
|
||||
else if (bestMove)
|
||||
update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth);
|
||||
update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth,
|
||||
rootNode);
|
||||
|
||||
// Bonus for prior countermove that caused the fail low
|
||||
else if (!priorCapture && prevSq != SQ_NONE)
|
||||
|
@ -1533,8 +1542,9 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
|
|||
// Initialize a MovePicker object for the current position, and prepare to search
|
||||
// the moves. We presently use two stages of move generator in quiescence search:
|
||||
// captures, or evasions only when in check.
|
||||
MovePicker mp(pos, ttData.move, DEPTH_QS, &thisThread->mainHistory, &thisThread->captureHistory,
|
||||
contHist, &thisThread->pawnHistory);
|
||||
MovePicker mp(pos, ttData.move, DEPTH_QS, &thisThread->mainHistory, &thisThread->rootHistory,
|
||||
&thisThread->captureHistory, contHist, &thisThread->pawnHistory,
|
||||
nodeType == Root);
|
||||
|
||||
// Step 5. Loop through all pseudo-legal moves until no moves remain or a beta
|
||||
// cutoff occurs.
|
||||
|
@ -1751,7 +1761,8 @@ void update_all_stats(const Position& pos,
|
|||
Square prevSq,
|
||||
ValueList<Move, 32>& quietsSearched,
|
||||
ValueList<Move, 32>& capturesSearched,
|
||||
Depth depth) {
|
||||
Depth depth,
|
||||
bool rootNode) {
|
||||
|
||||
CapturePieceToHistory& captureHistory = workerThread.captureHistory;
|
||||
Piece moved_piece = pos.moved_piece(bestMove);
|
||||
|
@ -1762,11 +1773,11 @@ void update_all_stats(const Position& pos,
|
|||
|
||||
if (!pos.capture_stage(bestMove))
|
||||
{
|
||||
update_quiet_histories(pos, ss, workerThread, bestMove, quietMoveBonus);
|
||||
update_quiet_histories(pos, ss, workerThread, bestMove, quietMoveBonus, rootNode);
|
||||
|
||||
// Decrease stats for all non-best quiet moves
|
||||
for (Move move : quietsSearched)
|
||||
update_quiet_histories(pos, ss, workerThread, move, -quietMoveMalus);
|
||||
update_quiet_histories(pos, ss, workerThread, move, -quietMoveMalus, rootNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1808,11 +1819,17 @@ void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
|
|||
|
||||
// Updates move sorting heuristics
|
||||
|
||||
void update_quiet_histories(
|
||||
const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus) {
|
||||
void update_quiet_histories(const Position& pos,
|
||||
Stack* ss,
|
||||
Search::Worker& workerThread,
|
||||
Move move,
|
||||
int bonus,
|
||||
bool rootNode) {
|
||||
|
||||
Color us = pos.side_to_move();
|
||||
workerThread.mainHistory[us][move.from_to()] << bonus;
|
||||
if (rootNode)
|
||||
workerThread.rootHistory[us][move.from_to()] << bonus;
|
||||
|
||||
update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus);
|
||||
|
||||
|
|
|
@ -278,6 +278,7 @@ class Worker {
|
|||
|
||||
// Public because they need to be updatable by the stats
|
||||
ButterflyHistory mainHistory;
|
||||
ButterflyHistory rootHistory;
|
||||
CapturePieceToHistory captureHistory;
|
||||
ContinuationHistory continuationHistory[2][2];
|
||||
PawnHistory pawnHistory;
|
||||
|
|
Loading…
Add table
Reference in a new issue