mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Merge commit 'b822fdf2f2f00758c794cb61a25a044424d2bc0a' into cluster
This is the last commit before there are more conflicts.
This commit is contained in:
@@ -45,6 +45,7 @@ Bruno de Melo Costa (BM123499)
|
|||||||
Bruno Pellanda (pellanda)
|
Bruno Pellanda (pellanda)
|
||||||
Bryan Cross (crossbr)
|
Bryan Cross (crossbr)
|
||||||
candirufish
|
candirufish
|
||||||
|
Carlos Esparza Sánchez (ces42)
|
||||||
Chess13234
|
Chess13234
|
||||||
Chris Cain (ceebo)
|
Chris Cain (ceebo)
|
||||||
Ciekce
|
Ciekce
|
||||||
|
|||||||
@@ -147,6 +147,11 @@ where the source code can be found) to generate the exact binary you are
|
|||||||
distributing. If you make any changes to the source code, these changes must
|
distributing. If you make any changes to the source code, these changes must
|
||||||
also be made available under GPL v3.
|
also be made available under GPL v3.
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
Stockfish uses neural networks trained on [data provided by the Leela Chess Zero
|
||||||
|
project][lc0-data-link], which is made available under the [Open Database License][odbl-link] (ODbL).
|
||||||
|
|
||||||
|
|
||||||
[authors-link]: https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS
|
[authors-link]: https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS
|
||||||
[build-link]: https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml
|
[build-link]: https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml
|
||||||
@@ -171,6 +176,8 @@ also be made available under GPL v3.
|
|||||||
[wiki-uci-link]: https://github.com/official-stockfish/Stockfish/wiki/UCI-&-Commands
|
[wiki-uci-link]: https://github.com/official-stockfish/Stockfish/wiki/UCI-&-Commands
|
||||||
[wiki-usage-link]: https://github.com/official-stockfish/Stockfish/wiki/Download-and-usage
|
[wiki-usage-link]: https://github.com/official-stockfish/Stockfish/wiki/Download-and-usage
|
||||||
[worker-link]: https://github.com/official-stockfish/fishtest/wiki/Running-the-worker
|
[worker-link]: https://github.com/official-stockfish/fishtest/wiki/Running-the-worker
|
||||||
|
[lc0-data-link]: https://storage.lczero.org/files/training_data
|
||||||
|
[odbl-link]: https://opendatacommons.org/licenses/odbl/odbl-10.txt
|
||||||
|
|
||||||
[build-badge]: https://img.shields.io/github/actions/workflow/status/official-stockfish/Stockfish/stockfish.yml?branch=master&style=for-the-badge&label=stockfish&logo=github
|
[build-badge]: https://img.shields.io/github/actions/workflow/status/official-stockfish/Stockfish/stockfish.yml?branch=master&style=for-the-badge&label=stockfish&logo=github
|
||||||
[commits-badge]: https://img.shields.io/github/commits-since/official-stockfish/Stockfish/latest?style=for-the-badge
|
[commits-badge]: https://img.shields.io/github/commits-since/official-stockfish/Stockfish/latest?style=for-the-badge
|
||||||
|
|||||||
+1
-1
@@ -138,7 +138,7 @@ using LowPlyHistory = Stats<int16_t, 7183, LOW_PLY_HISTORY_SIZE, int(SQUARE_NB)
|
|||||||
using CapturePieceToHistory = Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
|
using CapturePieceToHistory = Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
|
||||||
|
|
||||||
// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
|
// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
|
||||||
using PieceToHistory = Stats<int16_t, 29952, PIECE_NB, SQUARE_NB>;
|
using PieceToHistory = Stats<int16_t, 30000, PIECE_NB, SQUARE_NB>;
|
||||||
|
|
||||||
// ContinuationHistory is the combined history of a given pair of moves, usually
|
// ContinuationHistory is the combined history of a given pair of moves, usually
|
||||||
// the current one given a previous one. The nested history table is based on
|
// the current one given a previous one. The nested history table is based on
|
||||||
|
|||||||
+10
-19
@@ -18,11 +18,9 @@
|
|||||||
|
|
||||||
#include "movepick.h"
|
#include "movepick.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "bitboard.h"
|
#include "bitboard.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
@@ -199,19 +197,13 @@ void MovePicker::score() {
|
|||||||
|
|
||||||
// Returns the next move satisfying a predicate function.
|
// Returns the next move satisfying a predicate function.
|
||||||
// This never returns the TT move, as it was emitted before.
|
// This never returns the TT move, as it was emitted before.
|
||||||
template<MovePicker::PickType T, typename Pred>
|
template<typename Pred>
|
||||||
Move MovePicker::select(Pred filter) {
|
Move MovePicker::select(Pred filter) {
|
||||||
|
|
||||||
while (cur < endMoves)
|
for (; cur < endMoves; ++cur)
|
||||||
{
|
|
||||||
if constexpr (T == Best)
|
|
||||||
std::swap(*cur, *std::max_element(cur, endMoves));
|
|
||||||
|
|
||||||
if (*cur != ttMove && filter())
|
if (*cur != ttMove && filter())
|
||||||
return *cur++;
|
return *cur++;
|
||||||
|
|
||||||
cur++;
|
|
||||||
}
|
|
||||||
return Move::none();
|
return Move::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +237,7 @@ top:
|
|||||||
goto top;
|
goto top;
|
||||||
|
|
||||||
case GOOD_CAPTURE :
|
case GOOD_CAPTURE :
|
||||||
if (select<Next>([&]() {
|
if (select([&]() {
|
||||||
// Move losing capture to endBadCaptures to be tried later
|
// Move losing capture to endBadCaptures to be tried later
|
||||||
return pos.see_ge(*cur, -cur->value / 18) ? true
|
return pos.see_ge(*cur, -cur->value / 18) ? true
|
||||||
: (*endBadCaptures++ = *cur, false);
|
: (*endBadCaptures++ = *cur, false);
|
||||||
@@ -269,7 +261,7 @@ top:
|
|||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
case GOOD_QUIET :
|
case GOOD_QUIET :
|
||||||
if (!skipQuiets && select<Next>([]() { return true; }))
|
if (!skipQuiets && select([]() { return true; }))
|
||||||
{
|
{
|
||||||
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);
|
||||||
@@ -286,7 +278,7 @@ top:
|
|||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
case BAD_CAPTURE :
|
case BAD_CAPTURE :
|
||||||
if (select<Next>([]() { return true; }))
|
if (select([]() { return true; }))
|
||||||
return *(cur - 1);
|
return *(cur - 1);
|
||||||
|
|
||||||
// Prepare the pointers to loop over the bad quiets
|
// Prepare the pointers to loop over the bad quiets
|
||||||
@@ -298,7 +290,7 @@ top:
|
|||||||
|
|
||||||
case BAD_QUIET :
|
case BAD_QUIET :
|
||||||
if (!skipQuiets)
|
if (!skipQuiets)
|
||||||
return select<Next>([]() { return true; });
|
return select([]() { return true; });
|
||||||
|
|
||||||
return Move::none();
|
return Move::none();
|
||||||
|
|
||||||
@@ -307,17 +299,16 @@ top:
|
|||||||
endMoves = generate<EVASIONS>(pos, cur);
|
endMoves = generate<EVASIONS>(pos, cur);
|
||||||
|
|
||||||
score<EVASIONS>();
|
score<EVASIONS>();
|
||||||
|
partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
|
||||||
++stage;
|
++stage;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
case EVASION :
|
case EVASION :
|
||||||
return select<Best>([]() { return true; });
|
case QCAPTURE :
|
||||||
|
return select([]() { return true; });
|
||||||
|
|
||||||
case PROBCUT :
|
case PROBCUT :
|
||||||
return select<Next>([&]() { return pos.see_ge(*cur, threshold); });
|
return select([&]() { return pos.see_ge(*cur, threshold); });
|
||||||
|
|
||||||
case QCAPTURE :
|
|
||||||
return select<Next>([]() { return true; });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|||||||
+1
-6
@@ -35,11 +35,6 @@ class Position;
|
|||||||
// a cut-off first.
|
// a cut-off first.
|
||||||
class MovePicker {
|
class MovePicker {
|
||||||
|
|
||||||
enum PickType {
|
|
||||||
Next,
|
|
||||||
Best
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MovePicker(const MovePicker&) = delete;
|
MovePicker(const MovePicker&) = delete;
|
||||||
MovePicker& operator=(const MovePicker&) = delete;
|
MovePicker& operator=(const MovePicker&) = delete;
|
||||||
@@ -57,7 +52,7 @@ class MovePicker {
|
|||||||
void skip_quiet_moves();
|
void skip_quiet_moves();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<PickType T, typename Pred>
|
template<typename Pred>
|
||||||
Move select(Pred);
|
Move select(Pred);
|
||||||
template<GenType>
|
template<GenType>
|
||||||
void score();
|
void score();
|
||||||
|
|||||||
+4
-4
@@ -360,7 +360,7 @@ void Position::set_state() const {
|
|||||||
{
|
{
|
||||||
st->nonPawnMaterial[color_of(pc)] += PieceValue[pc];
|
st->nonPawnMaterial[color_of(pc)] += PieceValue[pc];
|
||||||
|
|
||||||
if (type_of(pc) == QUEEN || type_of(pc) == ROOK)
|
if (type_of(pc) >= ROOK)
|
||||||
st->majorPieceKey ^= Zobrist::psq[pc][s];
|
st->majorPieceKey ^= Zobrist::psq[pc][s];
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -759,7 +759,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||||||
st->nonPawnMaterial[them] -= PieceValue[captured];
|
st->nonPawnMaterial[them] -= PieceValue[captured];
|
||||||
st->nonPawnKey[them] ^= Zobrist::psq[captured][capsq];
|
st->nonPawnKey[them] ^= Zobrist::psq[captured][capsq];
|
||||||
|
|
||||||
if (type_of(captured) == QUEEN || type_of(captured) == ROOK)
|
if (type_of(captured) >= ROOK)
|
||||||
st->majorPieceKey ^= Zobrist::psq[captured][capsq];
|
st->majorPieceKey ^= Zobrist::psq[captured][capsq];
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -844,7 +844,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||||||
st->materialKey ^=
|
st->materialKey ^=
|
||||||
Zobrist::psq[promotion][pieceCount[promotion] - 1] ^ Zobrist::psq[pc][pieceCount[pc]];
|
Zobrist::psq[promotion][pieceCount[promotion] - 1] ^ Zobrist::psq[pc][pieceCount[pc]];
|
||||||
|
|
||||||
if (promotionType == QUEEN || promotionType == ROOK)
|
if (promotionType >= ROOK)
|
||||||
st->majorPieceKey ^= Zobrist::psq[promotion][to];
|
st->majorPieceKey ^= Zobrist::psq[promotion][to];
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -871,7 +871,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||||||
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type_of(pc) == QUEEN || type_of(pc) == ROOK)
|
else if (type_of(pc) >= ROOK)
|
||||||
st->majorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
st->majorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|||||||
+53
-49
@@ -317,7 +317,7 @@ void Search::Worker::iterative_deepening() {
|
|||||||
|
|
||||||
int searchAgainCounter = 0;
|
int searchAgainCounter = 0;
|
||||||
|
|
||||||
lowPlyHistory.fill(0);
|
lowPlyHistory.fill(106);
|
||||||
|
|
||||||
// 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 < MAX_PLY && !threads.stop
|
while (++rootDepth < MAX_PLY && !threads.stop
|
||||||
@@ -548,10 +548,10 @@ void Search::Worker::iterative_deepening() {
|
|||||||
|
|
||||||
// Reset histories, usually before a new game
|
// Reset histories, usually before a new game
|
||||||
void Search::Worker::clear() {
|
void Search::Worker::clear() {
|
||||||
mainHistory.fill(0);
|
mainHistory.fill(61);
|
||||||
lowPlyHistory.fill(0);
|
lowPlyHistory.fill(106);
|
||||||
captureHistory.fill(-758);
|
captureHistory.fill(-598);
|
||||||
pawnHistory.fill(-1158);
|
pawnHistory.fill(-1181);
|
||||||
pawnCorrectionHistory.fill(0);
|
pawnCorrectionHistory.fill(0);
|
||||||
majorPieceCorrectionHistory.fill(0);
|
majorPieceCorrectionHistory.fill(0);
|
||||||
minorPieceCorrectionHistory.fill(0);
|
minorPieceCorrectionHistory.fill(0);
|
||||||
@@ -566,7 +566,7 @@ void Search::Worker::clear() {
|
|||||||
for (StatsType c : {NoCaptures, Captures})
|
for (StatsType c : {NoCaptures, Captures})
|
||||||
for (auto& to : continuationHistory[inCheck][c])
|
for (auto& to : continuationHistory[inCheck][c])
|
||||||
for (auto& h : to)
|
for (auto& h : to)
|
||||||
h->fill(-645);
|
h->fill(-427);
|
||||||
|
|
||||||
for (size_t i = 1; i < reductions.size(); ++i)
|
for (size_t i = 1; i < reductions.size(); ++i)
|
||||||
reductions[i] = int((19.43 + std::log(size_t(options["Threads"])) / 2) * std::log(i));
|
reductions[i] = int((19.43 + std::log(size_t(options["Threads"])) / 2) * std::log(i));
|
||||||
@@ -692,13 +692,13 @@ Value Search::Worker::search(
|
|||||||
{
|
{
|
||||||
// Bonus for a quiet ttMove that fails high (~2 Elo)
|
// Bonus for a quiet ttMove that fails high (~2 Elo)
|
||||||
if (!ttCapture)
|
if (!ttCapture)
|
||||||
update_quiet_histories(pos, ss, *this, ttData.move, stat_bonus(depth));
|
update_quiet_histories(pos, ss, *this, ttData.move, stat_bonus(depth) * 747 / 1024);
|
||||||
|
|
||||||
// Extra penalty for early quiet moves of
|
// Extra penalty for early quiet moves of
|
||||||
// the previous ply (~1 Elo on STC, ~2 Elo on LTC)
|
// the previous ply (~1 Elo on STC, ~2 Elo on LTC)
|
||||||
if (prevSq != SQ_NONE && (ss - 1)->moveCount <= 2 && !priorCapture)
|
if (prevSq != SQ_NONE && (ss - 1)->moveCount <= 2 && !priorCapture)
|
||||||
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
|
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
|
||||||
-stat_malus(depth + 1));
|
-stat_malus(depth + 1) * 1091 / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partial workaround for the graph history interaction problem
|
// Partial workaround for the graph history interaction problem
|
||||||
@@ -812,10 +812,10 @@ Value Search::Worker::search(
|
|||||||
if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture)
|
if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture)
|
||||||
{
|
{
|
||||||
int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1831, 1428) + 623;
|
int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1831, 1428) + 623;
|
||||||
thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus;
|
thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 1340 / 1024;
|
||||||
if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION)
|
if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION)
|
||||||
thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq]
|
thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq]
|
||||||
<< bonus;
|
<< bonus * 1159 / 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@@ -905,7 +905,7 @@ Value Search::Worker::search(
|
|||||||
// Step 11. ProbCut (~10 Elo)
|
// Step 11. ProbCut (~10 Elo)
|
||||||
// If we have a good enough capture (or queen promotion) and a reduced search
|
// If we have a good enough capture (or queen promotion) and a reduced search
|
||||||
// returns a value much above beta, we can (almost) safely prune the previous move.
|
// returns a value much above beta, we can (almost) safely prune the previous move.
|
||||||
probCutBeta = beta + 187 - 53 * improving - 27 * opponentWorsening;
|
probCutBeta = beta + 187 - 56 * improving;
|
||||||
if (!PvNode && depth > 3
|
if (!PvNode && depth > 3
|
||||||
&& !is_decisive(beta)
|
&& !is_decisive(beta)
|
||||||
// If value from transposition table is lower than probCutBeta, don't attempt
|
// If value from transposition table is lower than probCutBeta, don't attempt
|
||||||
@@ -938,8 +938,7 @@ Value Search::Worker::search(
|
|||||||
// Prefetch the TT entry for the resulting position
|
// Prefetch the TT entry for the resulting position
|
||||||
prefetch(tt.first_entry(pos.key_after(move)));
|
prefetch(tt.first_entry(pos.key_after(move)));
|
||||||
|
|
||||||
ss->currentMove = move;
|
ss->currentMove = move;
|
||||||
ss->capturedPiece = captured;
|
|
||||||
ss->continuationHistory =
|
ss->continuationHistory =
|
||||||
&this->continuationHistory[ss->inCheck][true][pos.moved_piece(move)][move.to_sq()];
|
&this->continuationHistory[ss->inCheck][true][pos.moved_piece(move)][move.to_sq()];
|
||||||
ss->continuationCorrectionHistory =
|
ss->continuationCorrectionHistory =
|
||||||
@@ -960,7 +959,7 @@ Value Search::Worker::search(
|
|||||||
|
|
||||||
if (value >= probCutBeta)
|
if (value >= probCutBeta)
|
||||||
{
|
{
|
||||||
thisThread->captureHistory[movedPiece][move.to_sq()][type_of(captured)] << 1300;
|
thisThread->captureHistory[movedPiece][move.to_sq()][type_of(captured)] << 1226;
|
||||||
|
|
||||||
// Save ProbCut data into transposition table
|
// Save ProbCut data into transposition table
|
||||||
Distributed::save(tt, threads, thisThread, ttWriter, posKey,
|
Distributed::save(tt, threads, thisThread, ttWriter, posKey,
|
||||||
@@ -1187,8 +1186,7 @@ moves_loop: // When in check, search starts here
|
|||||||
prefetch(tt.first_entry(pos.key_after(move)));
|
prefetch(tt.first_entry(pos.key_after(move)));
|
||||||
|
|
||||||
// Update the current move (this must be done after singular extension search)
|
// Update the current move (this must be done after singular extension search)
|
||||||
ss->currentMove = move;
|
ss->currentMove = move;
|
||||||
ss->capturedPiece = pos.piece_on(move.to_sq());
|
|
||||||
ss->continuationHistory =
|
ss->continuationHistory =
|
||||||
&thisThread->continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()];
|
&thisThread->continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()];
|
||||||
ss->continuationCorrectionHistory =
|
ss->continuationCorrectionHistory =
|
||||||
@@ -1231,7 +1229,10 @@ moves_loop: // When in check, search starts here
|
|||||||
r -= 1879;
|
r -= 1879;
|
||||||
|
|
||||||
if (capture)
|
if (capture)
|
||||||
ss->statScore = 0;
|
ss->statScore =
|
||||||
|
7 * int(PieceValue[pos.captured_piece()])
|
||||||
|
+ thisThread->captureHistory[movedPiece][move.to_sq()][type_of(pos.captured_piece())]
|
||||||
|
- 5000;
|
||||||
else
|
else
|
||||||
ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()]
|
ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()]
|
||||||
+ (*contHist[0])[movedPiece][move.to_sq()]
|
+ (*contHist[0])[movedPiece][move.to_sq()]
|
||||||
@@ -1266,8 +1267,8 @@ moves_loop: // When in check, search starts here
|
|||||||
value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha, newDepth, !cutNode);
|
value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha, newDepth, !cutNode);
|
||||||
|
|
||||||
// Post LMR continuation history updates (~1 Elo)
|
// Post LMR continuation history updates (~1 Elo)
|
||||||
int bonus = 2 * (value >= beta) * stat_bonus(newDepth);
|
int bonus = (value >= beta) * stat_bonus(newDepth);
|
||||||
update_continuation_histories(ss, movedPiece, move.to_sq(), bonus);
|
update_continuation_histories(ss, movedPiece, move.to_sq(), bonus * 1427 / 1024);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1429,37 +1430,39 @@ moves_loop: // When in check, search starts here
|
|||||||
// 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 = (117 * (depth > 5) + 39 * !allNode + 168 * ((ss - 1)->moveCount > 8)
|
int bonusScale = (117 * (depth > 5) + 39 * !allNode + 168 * ((ss - 1)->moveCount > 8)
|
||||||
+ 115 * (!ss->inCheck && bestValue <= ss->staticEval - 108)
|
+ 115 * (!ss->inCheck && bestValue <= ss->staticEval - 108)
|
||||||
+ 119 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 83));
|
+ 119 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 83));
|
||||||
|
|
||||||
// Proportional to "how much damage we have to undo"
|
// Proportional to "how much damage we have to undo"
|
||||||
bonus += std::min(-(ss - 1)->statScore / 113, 300);
|
bonusScale += std::min(-(ss - 1)->statScore / 113, 300);
|
||||||
|
|
||||||
bonus = std::max(bonus, 0);
|
bonusScale = std::max(bonusScale, 0);
|
||||||
|
|
||||||
|
const int scaledBonus = stat_bonus(depth) * bonusScale / 32;
|
||||||
|
|
||||||
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
|
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
|
||||||
stat_bonus(depth) * bonus / 93);
|
scaledBonus * 416 / 1024);
|
||||||
thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()]
|
|
||||||
<< stat_bonus(depth) * bonus / 179;
|
|
||||||
|
|
||||||
|
thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << scaledBonus * 212 / 1024;
|
||||||
|
|
||||||
if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION)
|
if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION)
|
||||||
thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq]
|
thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq]
|
||||||
<< stat_bonus(depth) * bonus / 24;
|
<< scaledBonus * 1073 / 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (priorCapture && prevSq != SQ_NONE)
|
else if (priorCapture && prevSq != SQ_NONE)
|
||||||
{
|
{
|
||||||
// bonus for prior countermoves that caused the fail low
|
// bonus for prior countermoves that caused the fail low
|
||||||
Piece capturedPiece = (ss - 1)->capturedPiece;
|
Piece capturedPiece = pos.captured_piece();
|
||||||
|
assert(capturedPiece != NO_PIECE);
|
||||||
thisThread->captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)]
|
thisThread->captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)]
|
||||||
<< stat_bonus(depth) * 2;
|
<< stat_bonus(depth) * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bonus when search fails low and there is a TT move
|
// Bonus when search fails low and there is a TT move
|
||||||
else if (ttData.move && !allNode)
|
else if (ttData.move && !allNode)
|
||||||
thisThread->mainHistory[us][ttData.move.from_to()] << stat_bonus(depth) * 23 / 100;
|
thisThread->mainHistory[us][ttData.move.from_to()] << stat_bonus(depth) * 287 / 1024;
|
||||||
|
|
||||||
if (PvNode)
|
if (PvNode)
|
||||||
bestValue = std::min(bestValue, maxValue);
|
bestValue = std::min(bestValue, maxValue);
|
||||||
@@ -1484,7 +1487,8 @@ moves_loop: // When in check, search starts here
|
|||||||
&& ((bestValue < ss->staticEval && bestValue < beta) // negative correction & no fail high
|
&& ((bestValue < ss->staticEval && bestValue < beta) // negative correction & no fail high
|
||||||
|| (bestValue > ss->staticEval && bestMove))) // positive correction & no fail low
|
|| (bestValue > ss->staticEval && bestMove))) // positive correction & no fail low
|
||||||
{
|
{
|
||||||
const auto m = (ss - 1)->currentMove;
|
const auto m = (ss - 1)->currentMove;
|
||||||
|
static const int nonPawnWeight = 154;
|
||||||
|
|
||||||
auto bonus = std::clamp(int(bestValue - ss->staticEval) * depth / 8,
|
auto bonus = std::clamp(int(bestValue - ss->staticEval) * depth / 8,
|
||||||
-CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4);
|
-CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4);
|
||||||
@@ -1493,9 +1497,9 @@ moves_loop: // When in check, search starts here
|
|||||||
thisThread->majorPieceCorrectionHistory[us][major_piece_index(pos)] << bonus * 162 / 128;
|
thisThread->majorPieceCorrectionHistory[us][major_piece_index(pos)] << bonus * 162 / 128;
|
||||||
thisThread->minorPieceCorrectionHistory[us][minor_piece_index(pos)] << bonus * 148 / 128;
|
thisThread->minorPieceCorrectionHistory[us][minor_piece_index(pos)] << bonus * 148 / 128;
|
||||||
thisThread->nonPawnCorrectionHistory[WHITE][us][non_pawn_index<WHITE>(pos)]
|
thisThread->nonPawnCorrectionHistory[WHITE][us][non_pawn_index<WHITE>(pos)]
|
||||||
<< bonus * 122 / 128;
|
<< bonus * nonPawnWeight / 128;
|
||||||
thisThread->nonPawnCorrectionHistory[BLACK][us][non_pawn_index<BLACK>(pos)]
|
thisThread->nonPawnCorrectionHistory[BLACK][us][non_pawn_index<BLACK>(pos)]
|
||||||
<< bonus * 185 / 128;
|
<< bonus * nonPawnWeight / 128;
|
||||||
|
|
||||||
if (m.is_ok())
|
if (m.is_ok())
|
||||||
(*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] << bonus;
|
(*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] << bonus;
|
||||||
@@ -1704,8 +1708,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
|
|||||||
prefetch(tt.first_entry(pos.key_after(move)));
|
prefetch(tt.first_entry(pos.key_after(move)));
|
||||||
|
|
||||||
// Update the current move
|
// Update the current move
|
||||||
ss->currentMove = move;
|
ss->currentMove = move;
|
||||||
ss->capturedPiece = pos.piece_on(move.to_sq());
|
|
||||||
ss->continuationHistory =
|
ss->continuationHistory =
|
||||||
&thisThread
|
&thisThread
|
||||||
->continuationHistory[ss->inCheck][capture][pos.moved_piece(move)][move.to_sq()];
|
->continuationHistory[ss->inCheck][capture][pos.moved_piece(move)][move.to_sq()];
|
||||||
@@ -1860,30 +1863,30 @@ void update_all_stats(const Position& pos,
|
|||||||
|
|
||||||
if (!pos.capture_stage(bestMove))
|
if (!pos.capture_stage(bestMove))
|
||||||
{
|
{
|
||||||
update_quiet_histories(pos, ss, workerThread, bestMove, bonus);
|
update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 1131 / 1024);
|
||||||
|
|
||||||
// Decrease stats for all non-best quiet moves
|
// Decrease stats for all non-best quiet moves
|
||||||
for (Move move : quietsSearched)
|
for (Move move : quietsSearched)
|
||||||
update_quiet_histories(pos, ss, workerThread, move, -malus);
|
update_quiet_histories(pos, ss, workerThread, move, -malus * 1028 / 1024);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Increase stats for the best move in case it was a capture move
|
// Increase stats for the best move in case it was a capture move
|
||||||
captured = type_of(pos.piece_on(bestMove.to_sq()));
|
captured = type_of(pos.piece_on(bestMove.to_sq()));
|
||||||
captureHistory[moved_piece][bestMove.to_sq()][captured] << bonus;
|
captureHistory[moved_piece][bestMove.to_sq()][captured] << bonus * 1291 / 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra penalty for a quiet early move that was not a TT move in
|
// Extra penalty for a quiet early move that was not a TT move in
|
||||||
// previous ply when it gets refuted.
|
// previous ply when it gets refuted.
|
||||||
if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece())
|
if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece())
|
||||||
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus);
|
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus * 919 / 1024);
|
||||||
|
|
||||||
// Decrease stats for all non-best capture moves
|
// Decrease stats for all non-best capture moves
|
||||||
for (Move move : capturesSearched)
|
for (Move move : capturesSearched)
|
||||||
{
|
{
|
||||||
moved_piece = pos.moved_piece(move);
|
moved_piece = pos.moved_piece(move);
|
||||||
captured = type_of(pos.piece_on(move.to_sq()));
|
captured = type_of(pos.piece_on(move.to_sq()));
|
||||||
captureHistory[moved_piece][move.to_sq()][captured] << -malus;
|
captureHistory[moved_piece][move.to_sq()][captured] << -malus * 1090 / 1024;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1891,16 +1894,16 @@ void update_all_stats(const Position& pos,
|
|||||||
// Updates histories of the move pairs formed by moves
|
// Updates histories of the move pairs formed by moves
|
||||||
// at ply -1, -2, -3, -4, and -6 with current move.
|
// at ply -1, -2, -3, -4, and -6 with current move.
|
||||||
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
|
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
|
||||||
|
static constexpr std::array<ConthistBonus, 5> conthist_bonuses = {
|
||||||
|
{{1, 1024}, {2, 571}, {3, 339}, {4, 500}, {6, 592}}};
|
||||||
|
|
||||||
bonus = bonus * 50 / 64;
|
for (const auto [i, weight] : conthist_bonuses)
|
||||||
|
|
||||||
for (int i : {1, 2, 3, 4, 6})
|
|
||||||
{
|
{
|
||||||
// Only update the first 2 continuation histories if we are in check
|
// Only update the first 2 continuation histories if we are in check
|
||||||
if (ss->inCheck && i > 2)
|
if (ss->inCheck && i > 2)
|
||||||
break;
|
break;
|
||||||
if (((ss - i)->currentMove).is_ok())
|
if (((ss - i)->currentMove).is_ok())
|
||||||
(*(ss - i)->continuationHistory)[pc][to] << bonus / (1 + (i == 3));
|
(*(ss - i)->continuationHistory)[pc][to] << bonus * weight / 1024;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1910,14 +1913,15 @@ 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) {
|
||||||
|
|
||||||
Color us = pos.side_to_move();
|
Color us = pos.side_to_move();
|
||||||
workerThread.mainHistory[us][move.from_to()] << bonus;
|
workerThread.mainHistory[us][move.from_to()] << bonus; // Untuned to prevent duplicate effort
|
||||||
if (ss->ply < LOW_PLY_HISTORY_SIZE)
|
|
||||||
workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus;
|
|
||||||
|
|
||||||
update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus);
|
if (ss->ply < LOW_PLY_HISTORY_SIZE)
|
||||||
|
workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus * 874 / 1024;
|
||||||
|
|
||||||
|
update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus * 853 / 1024);
|
||||||
|
|
||||||
int pIndex = pawn_structure_index(pos);
|
int pIndex = pawn_structure_index(pos);
|
||||||
workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] << bonus / 2;
|
workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] << bonus * 628 / 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -68,7 +68,6 @@ struct Stack {
|
|||||||
CorrectionHistory<PieceTo>* continuationCorrectionHistory;
|
CorrectionHistory<PieceTo>* continuationCorrectionHistory;
|
||||||
int ply;
|
int ply;
|
||||||
Move currentMove;
|
Move currentMove;
|
||||||
Piece capturedPiece;
|
|
||||||
Move excludedMove;
|
Move excludedMove;
|
||||||
Value staticEval;
|
Value staticEval;
|
||||||
int statScore;
|
int statScore;
|
||||||
@@ -386,9 +385,14 @@ class Worker {
|
|||||||
friend class SearchManager;
|
friend class SearchManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ConthistBonus {
|
||||||
|
int index;
|
||||||
|
int weight;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace Search
|
} // namespace Search
|
||||||
|
|
||||||
} // namespace Stockfish
|
} // namespace Stockfish
|
||||||
|
|
||||||
#endif // #ifndef SEARCH_H_INCLUDED
|
#endif // #ifndef SEARCH_H_INCLUDED
|
||||||
|
|||||||
Reference in New Issue
Block a user