mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Original idea by Seer chess engine https://github.com/connormcmonigle/seer-nnue, coding done by @Disservin, code refactoring done by @locutus2 to match the style of other histories. This patch introduces pawn structure based history, which assings moves values based on last digits of pawn structure hash and piece type of moved piece and landing square of the move. Idea is that good places for pieces are quite often determined by pawn structure of position. Used in 3 different places - sorting of quiet moves, sorting of quiet check evasions and in history based pruning in search. Passed STC: https://tests.stockfishchess.org/tests/view/65391d08cc309ae83955dbaf LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 155488 W: 39408 L: 38913 D: 77167 Ptnml(0-2): 500, 18427, 39408, 18896, 513 Passed LTC: https://tests.stockfishchess.org/tests/view/653a36a2cc309ae83955f181 LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 70110 W: 17548 L: 17155 D: 35407 Ptnml(0-2): 33, 7859, 18889, 8230, 44 closes https://github.com/official-stockfish/Stockfish/pull/4849 Bench: 1257882 Co-Authored-By: Disservin <disservin.social@gmail.com> Co-Authored-By: Stefan Geschwentner <locutus2@users.noreply.github.com>
183 lines
6.5 KiB
C++
183 lines
6.5 KiB
C++
/*
|
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
|
|
|
Stockfish is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Stockfish is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef MOVEPICK_H_INCLUDED
|
|
#define MOVEPICK_H_INCLUDED
|
|
|
|
#include <array>
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <limits>
|
|
#include <type_traits> // IWYU pragma: keep
|
|
|
|
#include "movegen.h"
|
|
#include "types.h"
|
|
#include "position.h"
|
|
|
|
namespace Stockfish {
|
|
|
|
constexpr int PAWN_HISTORY_SIZE = 512;
|
|
|
|
inline int pawn_structure(const Position& pos) { return pos.pawn_key() & (PAWN_HISTORY_SIZE - 1); }
|
|
|
|
// StatsEntry stores the stat table value. It is usually a number but could
|
|
// be a move or even a nested history. We use a class instead of a naked value
|
|
// to directly call history update operator<<() on the entry so to use stats
|
|
// tables at caller sites as simple multi-dim arrays.
|
|
template<typename T, int D>
|
|
class StatsEntry {
|
|
|
|
T entry;
|
|
|
|
public:
|
|
void operator=(const T& v) { entry = v; }
|
|
T* operator&() { return &entry; }
|
|
T* operator->() { return &entry; }
|
|
operator const T&() const { return entry; }
|
|
|
|
void operator<<(int bonus) {
|
|
assert(abs(bonus) <= D); // Ensure range is [-D, D]
|
|
static_assert(D <= std::numeric_limits<T>::max(), "D overflows T");
|
|
|
|
entry += (bonus * D - entry * abs(bonus)) / (D * 5 / 4);
|
|
|
|
assert(abs(entry) <= D);
|
|
}
|
|
};
|
|
|
|
// Stats is a generic N-dimensional array used to store various statistics.
|
|
// The first template parameter T is the base type of the array, and the second
|
|
// template parameter D limits the range of updates in [-D, D] when we update
|
|
// values with the << operator, while the last parameters (Size and Sizes)
|
|
// encode the dimensions of the array.
|
|
template<typename T, int D, int Size, int... Sizes>
|
|
struct Stats: public std::array<Stats<T, D, Sizes...>, Size> {
|
|
using stats = Stats<T, D, Size, Sizes...>;
|
|
|
|
void fill(const T& v) {
|
|
|
|
// For standard-layout 'this' points to the first struct member
|
|
assert(std::is_standard_layout_v<stats>);
|
|
|
|
using entry = StatsEntry<T, D>;
|
|
entry* p = reinterpret_cast<entry*>(this);
|
|
std::fill(p, p + sizeof(*this) / sizeof(entry), v);
|
|
}
|
|
};
|
|
|
|
template<typename T, int D, int Size>
|
|
struct Stats<T, D, Size>: public std::array<StatsEntry<T, D>, Size> {};
|
|
|
|
// In stats table, D=0 means that the template parameter is not used
|
|
enum StatsParams {
|
|
NOT_USED = 0
|
|
};
|
|
enum StatsType {
|
|
NoCaptures,
|
|
Captures
|
|
};
|
|
|
|
// ButterflyHistory records how often quiet moves have been successful or
|
|
// unsuccessful during the current search, and is used for reduction and move
|
|
// ordering decisions. It uses 2 tables (one for each color) indexed by
|
|
// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards
|
|
// (~11 elo)
|
|
using ButterflyHistory = Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
|
|
|
|
// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
|
|
// move, see www.chessprogramming.org/Countermove_Heuristic
|
|
using CounterMoveHistory = Stats<Move, NOT_USED, PIECE_NB, SQUARE_NB>;
|
|
|
|
// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
|
|
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]
|
|
using PieceToHistory = Stats<int16_t, 29952, PIECE_NB, SQUARE_NB>;
|
|
|
|
// 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
|
|
// PieceToHistory instead of ButterflyBoards.
|
|
// (~63 elo)
|
|
using ContinuationHistory = Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB>;
|
|
|
|
// PawnStructureHistory is addressed by the pawn structure and a move's [piece][to]
|
|
using PawnHistory = Stats<int16_t, 8192, PAWN_HISTORY_SIZE, PIECE_NB, SQUARE_NB>;
|
|
|
|
// MovePicker class is used to pick one pseudo-legal move at a time from the
|
|
// current position. The most important method is next_move(), which returns a
|
|
// new pseudo-legal move each time it is called, until there are no moves left,
|
|
// when MOVE_NONE is returned. In order to improve the efficiency of the
|
|
// alpha-beta algorithm, MovePicker attempts to return the moves which are most
|
|
// likely to get a cut-off first.
|
|
class MovePicker {
|
|
|
|
enum PickType {
|
|
Next,
|
|
Best
|
|
};
|
|
|
|
public:
|
|
MovePicker(const MovePicker&) = delete;
|
|
MovePicker& operator=(const MovePicker&) = delete;
|
|
MovePicker(const Position&,
|
|
Move,
|
|
Depth,
|
|
const ButterflyHistory*,
|
|
const CapturePieceToHistory*,
|
|
const PieceToHistory**,
|
|
const PawnHistory&,
|
|
Move,
|
|
const Move*);
|
|
MovePicker(const Position&,
|
|
Move,
|
|
Depth,
|
|
const ButterflyHistory*,
|
|
const CapturePieceToHistory*,
|
|
const PieceToHistory**,
|
|
const PawnHistory&,
|
|
Square);
|
|
MovePicker(const Position&, Move, Value, const CapturePieceToHistory*, const PawnHistory&);
|
|
Move next_move(bool skipQuiets = false);
|
|
|
|
private:
|
|
template<PickType T, typename Pred>
|
|
Move select(Pred);
|
|
template<GenType>
|
|
void score();
|
|
ExtMove* begin() { return cur; }
|
|
ExtMove* end() { return endMoves; }
|
|
|
|
const Position& pos;
|
|
const ButterflyHistory* mainHistory;
|
|
const CapturePieceToHistory* captureHistory;
|
|
const PieceToHistory** continuationHistory;
|
|
const PawnHistory& pawnHistory;
|
|
Move ttMove;
|
|
ExtMove refutations[3], *cur, *endMoves, *endBadCaptures;
|
|
int stage;
|
|
Square recaptureSquare;
|
|
Value threshold;
|
|
Depth depth;
|
|
ExtMove moves[MAX_MOVES];
|
|
};
|
|
|
|
} // namespace Stockfish
|
|
|
|
#endif // #ifndef MOVEPICK_H_INCLUDED
|