mirror of
https://github.com/sockspls/badfish
synced 2025-05-03 18:19:35 +00:00
remove blank line between function and it's description
- remove the blank line between the declaration of the function and it's comment, leads to better IDE support when hovering over a function to see it's description - remove the unnecessary duplication of the function name in the functions description - slightly refactored code for lsb, msb in bitboard.h There are still a few things we can be improved later on, move the description of a function where it was declared (instead of implemented) and add descriptions to functions which are behind macros ifdefs closes https://github.com/official-stockfish/Stockfish/pull/4840 No functional change
This commit is contained in:
parent
b187622233
commit
a105978bbd
24 changed files with 175 additions and 271 deletions
|
@ -97,7 +97,7 @@ const std::vector<std::string> Defaults = {
|
||||||
|
|
||||||
namespace Stockfish {
|
namespace Stockfish {
|
||||||
|
|
||||||
// setup_bench() builds a list of UCI commands to be run by bench. There
|
// Builds a list of UCI commands to be run by bench. There
|
||||||
// are five parameters: TT size in MB, number of search threads that
|
// are five parameters: TT size in MB, number of search threads that
|
||||||
// should be used, the limit value spent for each position, a file name
|
// should be used, the limit value spent for each position, a file name
|
||||||
// where to look for positions in FEN format, and the type of the limit:
|
// where to look for positions in FEN format, and the type of the limit:
|
||||||
|
@ -108,7 +108,6 @@ namespace Stockfish {
|
||||||
// bench 64 1 100000 default nodes : search default positions for 100K nodes each
|
// bench 64 1 100000 default nodes : search default positions for 100K nodes each
|
||||||
// bench 64 4 5000 current movetime : search current position with 4 threads for 5 sec
|
// bench 64 4 5000 current movetime : search current position with 4 threads for 5 sec
|
||||||
// bench 16 1 5 blah perft : run a perft 5 on positions in file "blah"
|
// bench 16 1 5 blah perft : run a perft 5 on positions in file "blah"
|
||||||
|
|
||||||
std::vector<std::string> setup_bench(const Position& current, std::istream& is) {
|
std::vector<std::string> setup_bench(const Position& current, std::istream& is) {
|
||||||
|
|
||||||
std::vector<std::string> fens, list;
|
std::vector<std::string> fens, list;
|
||||||
|
|
|
@ -46,18 +46,16 @@ void init_magics(PieceType pt, Bitboard table[], Magic magics[]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// safe_destination() returns the bitboard of target square for the given step
|
// Returns the bitboard of target square for the given step
|
||||||
// from the given square. If the step is off the board, returns empty bitboard.
|
// from the given square. If the step is off the board, returns empty bitboard.
|
||||||
|
|
||||||
inline Bitboard safe_destination(Square s, int step) {
|
inline Bitboard safe_destination(Square s, int step) {
|
||||||
Square to = Square(s + step);
|
Square to = Square(s + step);
|
||||||
return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0);
|
return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Bitboards::pretty() returns an ASCII representation of a bitboard suitable
|
// Returns an ASCII representation of a bitboard suitable
|
||||||
// to be printed to standard output. Useful for debugging.
|
// to be printed to standard output. Useful for debugging.
|
||||||
|
|
||||||
std::string Bitboards::pretty(Bitboard b) {
|
std::string Bitboards::pretty(Bitboard b) {
|
||||||
|
|
||||||
std::string s = "+---+---+---+---+---+---+---+---+\n";
|
std::string s = "+---+---+---+---+---+---+---+---+\n";
|
||||||
|
@ -75,9 +73,8 @@ std::string Bitboards::pretty(Bitboard b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Bitboards::init() initializes various bitboard tables. It is called at
|
// Initializes various bitboard tables. It is called at
|
||||||
// startup and relies on global objects to be already zero-initialized.
|
// startup and relies on global objects to be already zero-initialized.
|
||||||
|
|
||||||
void Bitboards::init() {
|
void Bitboards::init() {
|
||||||
|
|
||||||
for (unsigned i = 0; i < (1 << 16); ++i)
|
for (unsigned i = 0; i < (1 << 16); ++i)
|
||||||
|
@ -137,11 +134,10 @@ Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// init_magics() computes all rook and bishop attacks at startup. Magic
|
// Computes all rook and bishop attacks at startup. Magic
|
||||||
// bitboards are used to look up attacks of sliding pieces. As a reference see
|
// bitboards are used to look up attacks of sliding pieces. As a reference see
|
||||||
// www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so
|
// www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so
|
||||||
// called "fancy" approach.
|
// called "fancy" approach.
|
||||||
|
|
||||||
void init_magics(PieceType pt, Bitboard table[], Magic magics[]) {
|
void init_magics(PieceType pt, Bitboard table[], Magic magics[]) {
|
||||||
|
|
||||||
// Optimal PRNG seeds to pick the correct magics in the shortest time
|
// Optimal PRNG seeds to pick the correct magics in the shortest time
|
||||||
|
|
|
@ -125,8 +125,7 @@ constexpr Bitboard file_bb(File f) { return FileABB << f; }
|
||||||
constexpr Bitboard file_bb(Square s) { return file_bb(file_of(s)); }
|
constexpr Bitboard file_bb(Square s) { return file_bb(file_of(s)); }
|
||||||
|
|
||||||
|
|
||||||
// shift() moves a bitboard one or two steps as specified by the direction D
|
// Moves a bitboard one or two steps as specified by the direction D
|
||||||
|
|
||||||
template<Direction D>
|
template<Direction D>
|
||||||
constexpr Bitboard shift(Bitboard b) {
|
constexpr Bitboard shift(Bitboard b) {
|
||||||
return D == NORTH ? b << 8
|
return D == NORTH ? b << 8
|
||||||
|
@ -143,9 +142,8 @@ constexpr Bitboard shift(Bitboard b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// pawn_attacks_bb() returns the squares attacked by pawns of the given color
|
// Returns the squares attacked by pawns of the given color
|
||||||
// from the squares in the given bitboard.
|
// from the squares in the given bitboard.
|
||||||
|
|
||||||
template<Color C>
|
template<Color C>
|
||||||
constexpr Bitboard pawn_attacks_bb(Bitboard b) {
|
constexpr Bitboard pawn_attacks_bb(Bitboard b) {
|
||||||
return C == WHITE ? shift<NORTH_WEST>(b) | shift<NORTH_EAST>(b)
|
return C == WHITE ? shift<NORTH_WEST>(b) | shift<NORTH_EAST>(b)
|
||||||
|
@ -158,11 +156,10 @@ inline Bitboard pawn_attacks_bb(Color c, Square s) {
|
||||||
return PawnAttacks[c][s];
|
return PawnAttacks[c][s];
|
||||||
}
|
}
|
||||||
|
|
||||||
// line_bb() returns a bitboard representing an entire line (from board edge
|
// Returns a bitboard representing an entire line (from board edge
|
||||||
// to board edge) that intersects the two given squares. If the given squares
|
// to board edge) that intersects the two given squares. If the given squares
|
||||||
// are not on a same file/rank/diagonal, the function returns 0. For instance,
|
// are not on a same file/rank/diagonal, the function returns 0. For instance,
|
||||||
// line_bb(SQ_C4, SQ_F7) will return a bitboard with the A2-G8 diagonal.
|
// line_bb(SQ_C4, SQ_F7) will return a bitboard with the A2-G8 diagonal.
|
||||||
|
|
||||||
inline Bitboard line_bb(Square s1, Square s2) {
|
inline Bitboard line_bb(Square s1, Square s2) {
|
||||||
|
|
||||||
assert(is_ok(s1) && is_ok(s2));
|
assert(is_ok(s1) && is_ok(s2));
|
||||||
|
@ -171,14 +168,13 @@ inline Bitboard line_bb(Square s1, Square s2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// between_bb(s1, s2) returns a bitboard representing the squares in the semi-open
|
// Returns a bitboard representing the squares in the semi-open
|
||||||
// segment between the squares s1 and s2 (excluding s1 but including s2). If the
|
// segment between the squares s1 and s2 (excluding s1 but including s2). If the
|
||||||
// given squares are not on a same file/rank/diagonal, it returns s2. For instance,
|
// given squares are not on a same file/rank/diagonal, it returns s2. For instance,
|
||||||
// between_bb(SQ_C4, SQ_F7) will return a bitboard with squares D5, E6 and F7, but
|
// between_bb(SQ_C4, SQ_F7) will return a bitboard with squares D5, E6 and F7, but
|
||||||
// between_bb(SQ_E6, SQ_F8) will return a bitboard with the square F8. This trick
|
// between_bb(SQ_E6, SQ_F8) will return a bitboard with the square F8. This trick
|
||||||
// allows to generate non-king evasion moves faster: the defending piece must either
|
// allows to generate non-king evasion moves faster: the defending piece must either
|
||||||
// interpose itself to cover the check or capture the checking piece.
|
// interpose itself to cover the check or capture the checking piece.
|
||||||
|
|
||||||
inline Bitboard between_bb(Square s1, Square s2) {
|
inline Bitboard between_bb(Square s1, Square s2) {
|
||||||
|
|
||||||
assert(is_ok(s1) && is_ok(s2));
|
assert(is_ok(s1) && is_ok(s2));
|
||||||
|
@ -186,9 +182,8 @@ inline Bitboard between_bb(Square s1, Square s2) {
|
||||||
return BetweenBB[s1][s2];
|
return BetweenBB[s1][s2];
|
||||||
}
|
}
|
||||||
|
|
||||||
// aligned() returns true if the squares s1, s2 and s3 are aligned either on a
|
// Returns true if the squares s1, s2 and s3 are aligned either on a
|
||||||
// straight or on a diagonal line.
|
// straight or on a diagonal line.
|
||||||
|
|
||||||
inline bool aligned(Square s1, Square s2, Square s3) { return line_bb(s1, s2) & s3; }
|
inline bool aligned(Square s1, Square s2, Square s3) { return line_bb(s1, s2) & s3; }
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,14 +192,17 @@ inline bool aligned(Square s1, Square s2, Square s3) { return line_bb(s1, s2) &
|
||||||
|
|
||||||
template<typename T1 = Square>
|
template<typename T1 = Square>
|
||||||
inline int distance(Square x, Square y);
|
inline int distance(Square x, Square y);
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline int distance<File>(Square x, Square y) {
|
inline int distance<File>(Square x, Square y) {
|
||||||
return std::abs(file_of(x) - file_of(y));
|
return std::abs(file_of(x) - file_of(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline int distance<Rank>(Square x, Square y) {
|
inline int distance<Rank>(Square x, Square y) {
|
||||||
return std::abs(rank_of(x) - rank_of(y));
|
return std::abs(rank_of(x) - rank_of(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline int distance<Square>(Square x, Square y) {
|
inline int distance<Square>(Square x, Square y) {
|
||||||
return SquareDistance[x][y];
|
return SquareDistance[x][y];
|
||||||
|
@ -212,9 +210,8 @@ inline int distance<Square>(Square x, Square y) {
|
||||||
|
|
||||||
inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
|
inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
|
||||||
|
|
||||||
// attacks_bb(Square) returns the pseudo attacks of the given piece type
|
// Returns the pseudo attacks of the given piece type
|
||||||
// assuming an empty board.
|
// assuming an empty board.
|
||||||
|
|
||||||
template<PieceType Pt>
|
template<PieceType Pt>
|
||||||
inline Bitboard attacks_bb(Square s) {
|
inline Bitboard attacks_bb(Square s) {
|
||||||
|
|
||||||
|
@ -224,10 +221,9 @@ inline Bitboard attacks_bb(Square s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// attacks_bb(Square, Bitboard) returns the attacks by the given piece
|
// Returns the attacks by the given piece
|
||||||
// assuming the board is occupied according to the passed Bitboard.
|
// assuming the board is occupied according to the passed Bitboard.
|
||||||
// Sliding piece attacks do not continue passed an occupied square.
|
// Sliding piece attacks do not continue passed an occupied square.
|
||||||
|
|
||||||
template<PieceType Pt>
|
template<PieceType Pt>
|
||||||
inline Bitboard attacks_bb(Square s, Bitboard occupied) {
|
inline Bitboard attacks_bb(Square s, Bitboard occupied) {
|
||||||
|
|
||||||
|
@ -246,6 +242,9 @@ inline Bitboard attacks_bb(Square s, Bitboard occupied) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the attacks by the given piece
|
||||||
|
// assuming the board is occupied according to the passed Bitboard.
|
||||||
|
// Sliding piece attacks do not continue passed an occupied square.
|
||||||
inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) {
|
inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) {
|
||||||
|
|
||||||
assert((pt != PAWN) && (is_ok(s)));
|
assert((pt != PAWN) && (is_ok(s)));
|
||||||
|
@ -264,8 +263,7 @@ inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// popcount() counts the number of non-zero bits in a bitboard
|
// Counts the number of non-zero bits in a bitboard.
|
||||||
|
|
||||||
inline int popcount(Bitboard b) {
|
inline int popcount(Bitboard b) {
|
||||||
|
|
||||||
#ifndef USE_POPCNT
|
#ifndef USE_POPCNT
|
||||||
|
@ -287,43 +285,22 @@ inline int popcount(Bitboard b) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the least significant bit in a non-zero bitboard.
|
||||||
// lsb() and msb() return the least/most significant bit in a non-zero bitboard
|
inline Square lsb(Bitboard b) {
|
||||||
|
assert(b);
|
||||||
|
|
||||||
#if defined(__GNUC__) // GCC, Clang, ICX
|
#if defined(__GNUC__) // GCC, Clang, ICX
|
||||||
|
|
||||||
inline Square lsb(Bitboard b) {
|
|
||||||
assert(b);
|
|
||||||
return Square(__builtin_ctzll(b));
|
return Square(__builtin_ctzll(b));
|
||||||
}
|
|
||||||
|
|
||||||
inline Square msb(Bitboard b) {
|
|
||||||
assert(b);
|
|
||||||
return Square(63 ^ __builtin_clzll(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(_MSC_VER) // MSVC
|
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
#ifdef _WIN64 // MSVC, WIN64
|
#ifdef _WIN64 // MSVC, WIN64
|
||||||
|
|
||||||
inline Square lsb(Bitboard b) {
|
|
||||||
assert(b);
|
|
||||||
unsigned long idx;
|
unsigned long idx;
|
||||||
_BitScanForward64(&idx, b);
|
_BitScanForward64(&idx, b);
|
||||||
return (Square) idx;
|
return (Square) idx;
|
||||||
}
|
|
||||||
|
|
||||||
inline Square msb(Bitboard b) {
|
|
||||||
assert(b);
|
|
||||||
unsigned long idx;
|
|
||||||
_BitScanReverse64(&idx, b);
|
|
||||||
return (Square) idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // MSVC, WIN32
|
#else // MSVC, WIN32
|
||||||
|
|
||||||
inline Square lsb(Bitboard b) {
|
|
||||||
assert(b);
|
|
||||||
unsigned long idx;
|
unsigned long idx;
|
||||||
|
|
||||||
if (b & 0xffffffff)
|
if (b & 0xffffffff)
|
||||||
|
@ -336,10 +313,29 @@ inline Square lsb(Bitboard b) {
|
||||||
_BitScanForward(&idx, int32_t(b >> 32));
|
_BitScanForward(&idx, int32_t(b >> 32));
|
||||||
return Square(idx + 32);
|
return Square(idx + 32);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#else // Compiler is neither GCC nor MSVC compatible
|
||||||
|
#error "Compiler not supported."
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the most significant bit in a non-zero bitboard.
|
||||||
inline Square msb(Bitboard b) {
|
inline Square msb(Bitboard b) {
|
||||||
assert(b);
|
assert(b);
|
||||||
|
|
||||||
|
#if defined(__GNUC__) // GCC, Clang, ICX
|
||||||
|
|
||||||
|
return Square(63 ^ __builtin_clzll(b));
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#ifdef _WIN64 // MSVC, WIN64
|
||||||
|
|
||||||
|
unsigned long idx;
|
||||||
|
_BitScanReverse64(&idx, b);
|
||||||
|
return (Square) idx;
|
||||||
|
|
||||||
|
#else // MSVC, WIN32
|
||||||
|
|
||||||
unsigned long idx;
|
unsigned long idx;
|
||||||
|
|
||||||
if (b >> 32)
|
if (b >> 32)
|
||||||
|
@ -352,26 +348,20 @@ inline Square msb(Bitboard b) {
|
||||||
_BitScanReverse(&idx, int32_t(b));
|
_BitScanReverse(&idx, int32_t(b));
|
||||||
return Square(idx);
|
return Square(idx);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#else // Compiler is neither GCC nor MSVC compatible
|
||||||
|
#error "Compiler not supported."
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
// Returns the bitboard of the least significant
|
||||||
|
|
||||||
#else // Compiler is neither GCC nor MSVC compatible
|
|
||||||
|
|
||||||
#error "Compiler not supported."
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// least_significant_square_bb() returns the bitboard of the least significant
|
|
||||||
// square of a non-zero bitboard. It is equivalent to square_bb(lsb(bb)).
|
// square of a non-zero bitboard. It is equivalent to square_bb(lsb(bb)).
|
||||||
|
|
||||||
inline Bitboard least_significant_square_bb(Bitboard b) {
|
inline Bitboard least_significant_square_bb(Bitboard b) {
|
||||||
assert(b);
|
assert(b);
|
||||||
return b & -b;
|
return b & -b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// pop_lsb() finds and clears the least significant bit in a non-zero bitboard
|
// Finds and clears the least significant bit in a non-zero bitboard.
|
||||||
|
|
||||||
inline Square pop_lsb(Bitboard& b) {
|
inline Square pop_lsb(Bitboard& b) {
|
||||||
assert(b);
|
assert(b);
|
||||||
const Square s = lsb(b);
|
const Square s = lsb(b);
|
||||||
|
|
|
@ -57,14 +57,13 @@ namespace Eval {
|
||||||
|
|
||||||
std::string currentEvalFileName = "None";
|
std::string currentEvalFileName = "None";
|
||||||
|
|
||||||
// NNUE::init() tries to load a NNUE network at startup time, or when the engine
|
// Tries to load a NNUE network at startup time, or when the engine
|
||||||
// receives a UCI command "setoption name EvalFile value nn-[a-z0-9]{12}.nnue"
|
// receives a UCI command "setoption name EvalFile value nn-[a-z0-9]{12}.nnue"
|
||||||
// The name of the NNUE network is always retrieved from the EvalFile option.
|
// The name of the NNUE network is always retrieved from the EvalFile option.
|
||||||
// We search the given network in three locations: internally (the default
|
// We search the given network in three locations: internally (the default
|
||||||
// network may be embedded in the binary), in the active working directory and
|
// network may be embedded in the binary), in the active working directory and
|
||||||
// in the engine directory. Distro packagers may define the DEFAULT_NNUE_DIRECTORY
|
// in the engine directory. Distro packagers may define the DEFAULT_NNUE_DIRECTORY
|
||||||
// variable to have the engine search in a special directory in their distro.
|
// variable to have the engine search in a special directory in their distro.
|
||||||
|
|
||||||
void NNUE::init() {
|
void NNUE::init() {
|
||||||
|
|
||||||
std::string eval_file = std::string(Options["EvalFile"]);
|
std::string eval_file = std::string(Options["EvalFile"]);
|
||||||
|
@ -111,7 +110,7 @@ void NNUE::init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NNUE::verify() verifies that the last net used was loaded successfully
|
// Verifies that the last net used was loaded successfully
|
||||||
void NNUE::verify() {
|
void NNUE::verify() {
|
||||||
|
|
||||||
std::string eval_file = std::string(Options["EvalFile"]);
|
std::string eval_file = std::string(Options["EvalFile"]);
|
||||||
|
@ -145,19 +144,17 @@ void NNUE::verify() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// simple_eval() returns a static, purely materialistic evaluation of the position
|
// Returns a static, purely materialistic evaluation of the position
|
||||||
// from the point of view of the given color. It can be divided by PawnValue to get
|
// from the point of view of the given color. It can be divided by PawnValue to get
|
||||||
// an approximation of the material advantage on the board in terms of pawns.
|
// an approximation of the material advantage on the board in terms of pawns.
|
||||||
|
|
||||||
Value Eval::simple_eval(const Position& pos, Color c) {
|
Value Eval::simple_eval(const Position& pos, Color c) {
|
||||||
return PawnValue * (pos.count<PAWN>(c) - pos.count<PAWN>(~c))
|
return PawnValue * (pos.count<PAWN>(c) - pos.count<PAWN>(~c))
|
||||||
+ (pos.non_pawn_material(c) - pos.non_pawn_material(~c));
|
+ (pos.non_pawn_material(c) - pos.non_pawn_material(~c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// evaluate() is the evaluator for the outer world. It returns a static evaluation
|
// Evaluate is the evaluator for the outer world. It returns a static evaluation
|
||||||
// of the position from the point of view of the side to move.
|
// of the position from the point of view of the side to move.
|
||||||
|
|
||||||
Value Eval::evaluate(const Position& pos) {
|
Value Eval::evaluate(const Position& pos) {
|
||||||
|
|
||||||
assert(!pos.checkers());
|
assert(!pos.checkers());
|
||||||
|
@ -197,11 +194,10 @@ Value Eval::evaluate(const Position& pos) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
// trace() is like evaluate(), but instead of returning a value, it returns
|
// Like evaluate(), but instead of returning a value, it returns
|
||||||
// a string (suitable for outputting to stdout) that contains the detailed
|
// a string (suitable for outputting to stdout) that contains the detailed
|
||||||
// descriptions and values of each evaluation term. Useful for debugging.
|
// descriptions and values of each evaluation term. Useful for debugging.
|
||||||
// Trace scores are from white's point of view
|
// Trace scores are from white's point of view
|
||||||
|
|
||||||
std::string Eval::trace(Position& pos) {
|
std::string Eval::trace(Position& pos) {
|
||||||
|
|
||||||
if (pos.checkers())
|
if (pos.checkers())
|
||||||
|
|
19
src/misc.cpp
19
src/misc.cpp
|
@ -148,7 +148,7 @@ class Logger {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
// engine_info() returns the full name of the current Stockfish version.
|
// Returns the full name of the current Stockfish version.
|
||||||
// For local dev compiles we try to append the commit sha and commit date
|
// For local dev compiles we try to append the commit sha and commit date
|
||||||
// from git if that fails only the local compilation date is set and "nogit" is specified:
|
// from git if that fails only the local compilation date is set and "nogit" is specified:
|
||||||
// Stockfish dev-YYYYMMDD-SHA
|
// Stockfish dev-YYYYMMDD-SHA
|
||||||
|
@ -157,7 +157,6 @@ class Logger {
|
||||||
//
|
//
|
||||||
// For releases (non-dev builds) we only include the version number:
|
// For releases (non-dev builds) we only include the version number:
|
||||||
// Stockfish version
|
// Stockfish version
|
||||||
|
|
||||||
std::string engine_info(bool to_uci) {
|
std::string engine_info(bool to_uci) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Stockfish " << version << std::setfill('0');
|
ss << "Stockfish " << version << std::setfill('0');
|
||||||
|
@ -192,8 +191,7 @@ std::string engine_info(bool to_uci) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// compiler_info() returns a string trying to describe the compiler we use
|
// Returns a string trying to describe the compiler we use
|
||||||
|
|
||||||
std::string compiler_info() {
|
std::string compiler_info() {
|
||||||
|
|
||||||
#define make_version_string(major, minor, patch) \
|
#define make_version_string(major, minor, patch) \
|
||||||
|
@ -397,7 +395,6 @@ void dbg_print() {
|
||||||
|
|
||||||
// Used to serialize access to std::cout to avoid multiple threads writing at
|
// Used to serialize access to std::cout to avoid multiple threads writing at
|
||||||
// the same time.
|
// the same time.
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, SyncCout sc) {
|
std::ostream& operator<<(std::ostream& os, SyncCout sc) {
|
||||||
|
|
||||||
static std::mutex m;
|
static std::mutex m;
|
||||||
|
@ -416,9 +413,6 @@ std::ostream& operator<<(std::ostream& os, SyncCout sc) {
|
||||||
void start_logger(const std::string& fname) { Logger::start(fname); }
|
void start_logger(const std::string& fname) { Logger::start(fname); }
|
||||||
|
|
||||||
|
|
||||||
// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking
|
|
||||||
// function that doesn't stall the CPU waiting for data to be loaded from memory,
|
|
||||||
// which can be quite slow.
|
|
||||||
#ifdef NO_PREFETCH
|
#ifdef NO_PREFETCH
|
||||||
|
|
||||||
void prefetch(void*) {}
|
void prefetch(void*) {}
|
||||||
|
@ -437,10 +431,9 @@ void prefetch(void* addr) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// std_aligned_alloc() is our wrapper for systems where the c++17 implementation
|
// Wrapper for systems where the c++17 implementation
|
||||||
// does not guarantee the availability of aligned_alloc(). Memory allocated with
|
// does not guarantee the availability of aligned_alloc(). Memory allocated with
|
||||||
// std_aligned_alloc() must be freed with std_aligned_free().
|
// std_aligned_alloc() must be freed with std_aligned_free().
|
||||||
|
|
||||||
void* std_aligned_alloc(size_t alignment, size_t size) {
|
void* std_aligned_alloc(size_t alignment, size_t size) {
|
||||||
|
|
||||||
#if defined(POSIXALIGNEDALLOC)
|
#if defined(POSIXALIGNEDALLOC)
|
||||||
|
@ -607,10 +600,9 @@ void bindThisThread(size_t) {}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// best_node() retrieves logical processor information using Windows specific
|
// Retrieves logical processor information using Windows specific
|
||||||
// API and returns the best node id for the thread with index idx. Original
|
// API and returns the best node id for the thread with index idx. Original
|
||||||
// code from Texel by Peter Österlund.
|
// code from Texel by Peter Österlund.
|
||||||
|
|
||||||
static int best_node(size_t idx) {
|
static int best_node(size_t idx) {
|
||||||
|
|
||||||
int threads = 0;
|
int threads = 0;
|
||||||
|
@ -679,8 +671,7 @@ static int best_node(size_t idx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// bindThisThread() sets the group affinity of the current thread
|
// Sets the group affinity of the current thread
|
||||||
|
|
||||||
void bindThisThread(size_t idx) {
|
void bindThisThread(size_t idx) {
|
||||||
|
|
||||||
// Use only local variables to be thread-safe
|
// Use only local variables to be thread-safe
|
||||||
|
|
25
src/misc.h
25
src/misc.h
|
@ -33,13 +33,19 @@ namespace Stockfish {
|
||||||
|
|
||||||
std::string engine_info(bool to_uci = false);
|
std::string engine_info(bool to_uci = false);
|
||||||
std::string compiler_info();
|
std::string compiler_info();
|
||||||
void prefetch(void* addr);
|
|
||||||
void start_logger(const std::string& fname);
|
// Preloads the given address in L1/L2 cache. This is a non-blocking
|
||||||
void* std_aligned_alloc(size_t alignment, size_t size);
|
// function that doesn't stall the CPU waiting for data to be loaded from memory,
|
||||||
void std_aligned_free(void* ptr);
|
// which can be quite slow.
|
||||||
void* aligned_large_pages_alloc(
|
void prefetch(void* addr);
|
||||||
size_t size); // memory aligned by page size, min alignment: 4096 bytes
|
|
||||||
void aligned_large_pages_free(void* mem); // nop if mem == nullptr
|
void start_logger(const std::string& fname);
|
||||||
|
void* std_aligned_alloc(size_t alignment, size_t size);
|
||||||
|
void std_aligned_free(void* ptr);
|
||||||
|
// memory aligned by page size, min alignment: 4096 bytes
|
||||||
|
void* aligned_large_pages_alloc(size_t size);
|
||||||
|
// nop if mem == nullptr
|
||||||
|
void aligned_large_pages_free(void* mem);
|
||||||
|
|
||||||
void dbg_hit_on(bool cond, int slot = 0);
|
void dbg_hit_on(bool cond, int slot = 0);
|
||||||
void dbg_mean_of(int64_t value, int slot = 0);
|
void dbg_mean_of(int64_t value, int slot = 0);
|
||||||
|
@ -66,7 +72,7 @@ std::ostream& operator<<(std::ostream&, SyncCout);
|
||||||
#define sync_endl std::endl << IO_UNLOCK
|
#define sync_endl std::endl << IO_UNLOCK
|
||||||
|
|
||||||
|
|
||||||
// align_ptr_up() : get the first aligned element of an array.
|
// Get the first aligned element of an array.
|
||||||
// ptr must point to an array of size at least `sizeof(T) * N + alignment` bytes,
|
// ptr must point to an array of size at least `sizeof(T) * N + alignment` bytes,
|
||||||
// where N is the number of elements in the array.
|
// where N is the number of elements in the array.
|
||||||
template<uintptr_t Alignment, typename T>
|
template<uintptr_t Alignment, typename T>
|
||||||
|
@ -79,7 +85,7 @@ T* align_ptr_up(T* ptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// IsLittleEndian : true if and only if the binary is compiled on a little-endian machine
|
// True if and only if the binary is compiled on a little-endian machine
|
||||||
static inline const union {
|
static inline const union {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
char c[4];
|
char c[4];
|
||||||
|
@ -166,7 +172,6 @@ inline uint64_t mul_hi64(uint64_t a, uint64_t b) {
|
||||||
// cores. To overcome this, some special platform-specific API should be
|
// cores. To overcome this, some special platform-specific API should be
|
||||||
// called to set group affinity for each thread. Original code from Texel by
|
// called to set group affinity for each thread. Original code from Texel by
|
||||||
// Peter Österlund.
|
// Peter Österlund.
|
||||||
|
|
||||||
namespace WinProcGroup {
|
namespace WinProcGroup {
|
||||||
void bindThisThread(size_t idx);
|
void bindThisThread(size_t idx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,7 +241,6 @@ ExtMove* generate_all(const Position& pos, ExtMove* moveList) {
|
||||||
// except castling and promotions
|
// except castling and promotions
|
||||||
//
|
//
|
||||||
// Returns a pointer to the end of the move list.
|
// Returns a pointer to the end of the move list.
|
||||||
|
|
||||||
template<GenType Type>
|
template<GenType Type>
|
||||||
ExtMove* generate(const Position& pos, ExtMove* moveList) {
|
ExtMove* generate(const Position& pos, ExtMove* moveList) {
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ enum Stages {
|
||||||
QCHECK
|
QCHECK
|
||||||
};
|
};
|
||||||
|
|
||||||
// partial_insertion_sort() sorts moves in descending order up to and including
|
// Sort moves in descending order up to and including
|
||||||
// a given limit. The order of moves smaller than the limit is left unspecified.
|
// a given limit. The order of moves smaller than the limit is left unspecified.
|
||||||
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
|
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ MovePicker::MovePicker(const Position& p,
|
||||||
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) + !(ttm && pos.pseudo_legal(ttm));
|
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) + !(ttm && pos.pseudo_legal(ttm));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MovePicker constructor for quiescence search
|
// Constructor for quiescence search
|
||||||
MovePicker::MovePicker(const Position& p,
|
MovePicker::MovePicker(const Position& p,
|
||||||
Move ttm,
|
Move ttm,
|
||||||
Depth d,
|
Depth d,
|
||||||
|
@ -123,7 +123,7 @@ MovePicker::MovePicker(const Position& p,
|
||||||
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) + !(ttm && pos.pseudo_legal(ttm));
|
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) + !(ttm && pos.pseudo_legal(ttm));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MovePicker constructor for ProbCut: we generate captures with SEE greater
|
// Constructor for ProbCut: we generate captures with SEE greater
|
||||||
// than or equal to the given threshold.
|
// than or equal to the given threshold.
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) :
|
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) :
|
||||||
pos(p),
|
pos(p),
|
||||||
|
@ -136,7 +136,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePiece
|
||||||
+ !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm) && pos.see_ge(ttm, threshold));
|
+ !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm) && pos.see_ge(ttm, threshold));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MovePicker::score() assigns a numerical value to each move in a list, used
|
// Assigns a numerical value to each move in a list, used
|
||||||
// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring
|
// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring
|
||||||
// captures with a good history. Quiets moves are ordered using the history tables.
|
// captures with a good history. Quiets moves are ordered using the history tables.
|
||||||
template<GenType Type>
|
template<GenType Type>
|
||||||
|
@ -216,7 +216,7 @@ void MovePicker::score() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MovePicker::select() returns the next move satisfying a predicate function.
|
// Returns the next move satisfying a predicate function.
|
||||||
// It never returns the TT move.
|
// It never returns the TT move.
|
||||||
template<MovePicker::PickType T, typename Pred>
|
template<MovePicker::PickType T, typename Pred>
|
||||||
Move MovePicker::select(Pred filter) {
|
Move MovePicker::select(Pred filter) {
|
||||||
|
@ -234,7 +234,7 @@ Move MovePicker::select(Pred filter) {
|
||||||
return MOVE_NONE;
|
return MOVE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MovePicker::next_move() is the most important method of the MovePicker class. It
|
// Most important method of the MovePicker class. It
|
||||||
// returns a new pseudo-legal move every time it is called until there are no more
|
// returns a new pseudo-legal move every time it is called until there are no more
|
||||||
// moves left, picking the move with the highest score from a list of generated moves.
|
// moves left, picking the move with the highest score from a list of generated moves.
|
||||||
Move MovePicker::next_move(bool skipQuiets) {
|
Move MovePicker::next_move(bool skipQuiets) {
|
||||||
|
|
|
@ -233,7 +233,7 @@ static NnueEvalTrace trace_evaluate(const Position& pos) {
|
||||||
constexpr std::string_view PieceToChar(" PNBRQK pnbrqk");
|
constexpr std::string_view PieceToChar(" PNBRQK pnbrqk");
|
||||||
|
|
||||||
|
|
||||||
// format_cp_compact() converts a Value into (centi)pawns and writes it in a buffer.
|
// Converts a Value into (centi)pawns and writes it in a buffer.
|
||||||
// The buffer must have capacity for at least 5 chars.
|
// The buffer must have capacity for at least 5 chars.
|
||||||
static void format_cp_compact(Value v, char* buffer) {
|
static void format_cp_compact(Value v, char* buffer) {
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ static void format_cp_compact(Value v, char* buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// format_cp_aligned_dot() converts a Value into pawns, always keeping two decimals
|
// Converts a Value into pawns, always keeping two decimals
|
||||||
static void format_cp_aligned_dot(Value v, std::stringstream& stream) {
|
static void format_cp_aligned_dot(Value v, std::stringstream& stream) {
|
||||||
|
|
||||||
const double pawns = std::abs(0.01 * UCI::to_cp(v));
|
const double pawns = std::abs(0.01 * UCI::to_cp(v));
|
||||||
|
@ -282,7 +282,7 @@ static void format_cp_aligned_dot(Value v, std::stringstream& stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// trace() returns a string with the value of each piece on a board,
|
// Returns a string with the value of each piece on a board,
|
||||||
// and a table for (PSQT, Layers) values bucket by bucket.
|
// and a table for (PSQT, Layers) values bucket by bucket.
|
||||||
std::string trace(Position& pos) {
|
std::string trace(Position& pos) {
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ void HalfKAv2_hm::append_active_indices(const Position& pos, IndexList& active)
|
||||||
template void HalfKAv2_hm::append_active_indices<WHITE>(const Position& pos, IndexList& active);
|
template void HalfKAv2_hm::append_active_indices<WHITE>(const Position& pos, IndexList& active);
|
||||||
template void HalfKAv2_hm::append_active_indices<BLACK>(const Position& pos, IndexList& active);
|
template void HalfKAv2_hm::append_active_indices<BLACK>(const Position& pos, IndexList& active);
|
||||||
|
|
||||||
// append_changed_indices() : get a list of indices for recently changed features
|
// Get a list of indices for recently changed features
|
||||||
template<Color Perspective>
|
template<Color Perspective>
|
||||||
void HalfKAv2_hm::append_changed_indices(Square ksq,
|
void HalfKAv2_hm::append_changed_indices(Square ksq,
|
||||||
const DirtyPiece& dp,
|
const DirtyPiece& dp,
|
||||||
|
|
|
@ -85,7 +85,7 @@ constexpr IntType ceil_to_multiple(IntType n, IntType base) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// read_little_endian() is our utility to read an integer (signed or unsigned, any size)
|
// Utility to read an integer (signed or unsigned, any size)
|
||||||
// from a stream in little-endian order. We swap the byte order after the read if
|
// from a stream in little-endian order. We swap the byte order after the read if
|
||||||
// necessary to return a result with the byte ordering of the compiling machine.
|
// necessary to return a result with the byte ordering of the compiling machine.
|
||||||
template<typename IntType>
|
template<typename IntType>
|
||||||
|
@ -110,7 +110,7 @@ inline IntType read_little_endian(std::istream& stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// write_little_endian() is our utility to write an integer (signed or unsigned, any size)
|
// Utility to write an integer (signed or unsigned, any size)
|
||||||
// to a stream in little-endian order. We swap the byte order before the write if
|
// to a stream in little-endian order. We swap the byte order before the write if
|
||||||
// necessary to always write in little endian order, independently of the byte
|
// necessary to always write in little endian order, independently of the byte
|
||||||
// ordering of the compiling machine.
|
// ordering of the compiling machine.
|
||||||
|
@ -141,7 +141,7 @@ inline void write_little_endian(std::ostream& stream, IntType value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// read_little_endian(s, out, N) : read integers in bulk from a little indian stream.
|
// Read integers in bulk from a little indian stream.
|
||||||
// This reads N integers from stream s and put them in array out.
|
// This reads N integers from stream s and put them in array out.
|
||||||
template<typename IntType>
|
template<typename IntType>
|
||||||
inline void read_little_endian(std::istream& stream, IntType* out, std::size_t count) {
|
inline void read_little_endian(std::istream& stream, IntType* out, std::size_t count) {
|
||||||
|
@ -153,7 +153,7 @@ inline void read_little_endian(std::istream& stream, IntType* out, std::size_t c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// write_little_endian(s, values, N) : write integers in bulk to a little indian stream.
|
// Write integers in bulk to a little indian stream.
|
||||||
// This takes N integers from array values and writes them on stream s.
|
// This takes N integers from array values and writes them on stream s.
|
||||||
template<typename IntType>
|
template<typename IntType>
|
||||||
inline void write_little_endian(std::ostream& stream, const IntType* values, std::size_t count) {
|
inline void write_little_endian(std::ostream& stream, const IntType* values, std::size_t count) {
|
||||||
|
@ -165,7 +165,7 @@ inline void write_little_endian(std::ostream& stream, const IntType* values, std
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// read_leb_128(s, out, N) : read N signed integers from the stream s, putting them in
|
// Read N signed integers from the stream s, putting them in
|
||||||
// the array out. The stream is assumed to be compressed using the signed LEB128 format.
|
// the array out. The stream is assumed to be compressed using the signed LEB128 format.
|
||||||
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
|
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
|
||||||
template<typename IntType>
|
template<typename IntType>
|
||||||
|
@ -215,7 +215,7 @@ inline void read_leb_128(std::istream& stream, IntType* out, std::size_t count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// write_leb_128(s, values, N) : write signed integers to a stream with LEB128 compression.
|
// Write signed integers to a stream with LEB128 compression.
|
||||||
// This takes N integers from array values, compress them with the LEB128 algorithm and
|
// This takes N integers from array values, compress them with the LEB128 algorithm and
|
||||||
// writes the result on the stream s.
|
// writes the result on the stream s.
|
||||||
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
|
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
|
||||||
|
|
|
@ -61,8 +61,7 @@ constexpr Piece Pieces[] = {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
// operator<<(Position) returns an ASCII representation of the position
|
// Returns an ASCII representation of the position
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Position& pos) {
|
std::ostream& operator<<(std::ostream& os, const Position& pos) {
|
||||||
|
|
||||||
os << "\n +---+---+---+---+---+---+---+---+\n";
|
os << "\n +---+---+---+---+---+---+---+---+\n";
|
||||||
|
@ -114,8 +113,7 @@ Key cuckoo[8192];
|
||||||
Move cuckooMove[8192];
|
Move cuckooMove[8192];
|
||||||
|
|
||||||
|
|
||||||
// Position::init() initializes at startup the various arrays used to compute hash keys
|
// Initializes at startup the various arrays used to compute hash keys
|
||||||
|
|
||||||
void Position::init() {
|
void Position::init() {
|
||||||
|
|
||||||
PRNG rng(1070372);
|
PRNG rng(1070372);
|
||||||
|
@ -158,10 +156,9 @@ void Position::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::set() initializes the position object with the given FEN string.
|
// Initializes the position object with the given FEN string.
|
||||||
// This function is not very robust - make sure that input FENs are correct,
|
// This function is not very robust - make sure that input FENs are correct,
|
||||||
// this is assumed to be the responsibility of the GUI.
|
// this is assumed to be the responsibility of the GUI.
|
||||||
|
|
||||||
Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Thread* th) {
|
Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Thread* th) {
|
||||||
/*
|
/*
|
||||||
A FEN string defines a particular position using only the ASCII character set.
|
A FEN string defines a particular position using only the ASCII character set.
|
||||||
|
@ -298,9 +295,8 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::set_castling_right() is a helper function used to set castling
|
// Helper function used to set castling
|
||||||
// rights given the corresponding color and the rook starting square.
|
// rights given the corresponding color and the rook starting square.
|
||||||
|
|
||||||
void Position::set_castling_right(Color c, Square rfrom) {
|
void Position::set_castling_right(Color c, Square rfrom) {
|
||||||
|
|
||||||
Square kfrom = square<KING>(c);
|
Square kfrom = square<KING>(c);
|
||||||
|
@ -318,8 +314,7 @@ void Position::set_castling_right(Color c, Square rfrom) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::set_check_info() sets king attacks to detect if a move gives check
|
// Sets king attacks to detect if a move gives check
|
||||||
|
|
||||||
void Position::set_check_info() const {
|
void Position::set_check_info() const {
|
||||||
|
|
||||||
update_slider_blockers(WHITE);
|
update_slider_blockers(WHITE);
|
||||||
|
@ -336,10 +331,9 @@ void Position::set_check_info() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::set_state() computes the hash keys of the position, and other
|
// Computes the hash keys of the position, and other
|
||||||
// data that once computed is updated incrementally as moves are made.
|
// data that once computed is updated incrementally as moves are made.
|
||||||
// The function is only used when a new position is set up
|
// The function is only used when a new position is set up
|
||||||
|
|
||||||
void Position::set_state() const {
|
void Position::set_state() const {
|
||||||
|
|
||||||
st->key = st->materialKey = 0;
|
st->key = st->materialKey = 0;
|
||||||
|
@ -372,10 +366,9 @@ void Position::set_state() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::set() is an overload to initialize the position object with
|
// Overload to initialize the position object with
|
||||||
// the given endgame code string like "KBPKN". It is mainly a helper to
|
// the given endgame code string like "KBPKN". It is mainly a helper to
|
||||||
// get the material key out of an endgame code.
|
// get the material key out of an endgame code.
|
||||||
|
|
||||||
Position& Position::set(const string& code, Color c, StateInfo* si) {
|
Position& Position::set(const string& code, Color c, StateInfo* si) {
|
||||||
|
|
||||||
assert(code[0] == 'K');
|
assert(code[0] == 'K');
|
||||||
|
@ -395,9 +388,8 @@ Position& Position::set(const string& code, Color c, StateInfo* si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::fen() returns a FEN representation of the position. In case of
|
// Returns a FEN representation of the position. In case of
|
||||||
// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.
|
// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.
|
||||||
|
|
||||||
string Position::fen() const {
|
string Position::fen() const {
|
||||||
|
|
||||||
int emptyCnt;
|
int emptyCnt;
|
||||||
|
@ -444,7 +436,7 @@ string Position::fen() const {
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// update_slider_blockers() calculates st->blockersForKing[c] and st->pinners[~c],
|
// Calculates st->blockersForKing[c] and st->pinners[~c],
|
||||||
// which store respectively the pieces preventing king of color c from being in check
|
// which store respectively the pieces preventing king of color c from being in check
|
||||||
// and the slider pieces of color ~c pinning pieces of color c to the king.
|
// and the slider pieces of color ~c pinning pieces of color c to the king.
|
||||||
void Position::update_slider_blockers(Color c) const {
|
void Position::update_slider_blockers(Color c) const {
|
||||||
|
@ -475,9 +467,8 @@ void Position::update_slider_blockers(Color c) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::attackers_to() computes a bitboard of all pieces which attack a
|
// Computes a bitboard of all pieces which attack a
|
||||||
// given square. Slider attacks use the occupied bitboard to indicate occupancy.
|
// given square. Slider attacks use the occupied bitboard to indicate occupancy.
|
||||||
|
|
||||||
Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
|
Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
|
||||||
|
|
||||||
return (pawn_attacks_bb(BLACK, s) & pieces(WHITE, PAWN))
|
return (pawn_attacks_bb(BLACK, s) & pieces(WHITE, PAWN))
|
||||||
|
@ -489,8 +480,7 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::legal() tests whether a pseudo-legal move is legal
|
// Tests whether a pseudo-legal move is legal
|
||||||
|
|
||||||
bool Position::legal(Move m) const {
|
bool Position::legal(Move m) const {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(is_ok(m));
|
||||||
|
@ -549,10 +539,9 @@ bool Position::legal(Move m) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::pseudo_legal() takes a random move and tests whether the move is
|
// Takes a random move and tests whether the move is
|
||||||
// pseudo-legal. It is used to validate moves from TT that can be corrupted
|
// pseudo-legal. It is used to validate moves from TT that can be corrupted
|
||||||
// due to SMP concurrent access or hash position key aliasing.
|
// due to SMP concurrent access or hash position key aliasing.
|
||||||
|
|
||||||
bool Position::pseudo_legal(const Move m) const {
|
bool Position::pseudo_legal(const Move m) const {
|
||||||
|
|
||||||
Color us = sideToMove;
|
Color us = sideToMove;
|
||||||
|
@ -620,8 +609,7 @@ bool Position::pseudo_legal(const Move m) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::gives_check() tests whether a pseudo-legal move gives a check
|
// Tests whether a pseudo-legal move gives a check
|
||||||
|
|
||||||
bool Position::gives_check(Move m) const {
|
bool Position::gives_check(Move m) const {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(is_ok(m));
|
||||||
|
@ -669,10 +657,9 @@ bool Position::gives_check(Move m) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::do_move() makes a move, and saves all information necessary
|
// Makes a move, and saves all information necessary
|
||||||
// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
|
// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
|
||||||
// moves should be filtered out before this function is called.
|
// moves should be filtered out before this function is called.
|
||||||
|
|
||||||
void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(is_ok(m));
|
||||||
|
@ -867,9 +854,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::undo_move() unmakes a move. When it returns, the position should
|
// Unmakes a move. When it returns, the position should
|
||||||
// be restored to exactly the same state as before the move was made.
|
// be restored to exactly the same state as before the move was made.
|
||||||
|
|
||||||
void Position::undo_move(Move m) {
|
void Position::undo_move(Move m) {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(is_ok(m));
|
||||||
|
@ -931,7 +917,7 @@ void Position::undo_move(Move m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::do_castling() is a helper used to do/undo a castling move. This
|
// Helper used to do/undo a castling move. This
|
||||||
// is a bit tricky in Chess960 where from/to squares can overlap.
|
// is a bit tricky in Chess960 where from/to squares can overlap.
|
||||||
template<bool Do>
|
template<bool Do>
|
||||||
void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto) {
|
void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto) {
|
||||||
|
@ -963,9 +949,8 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::do_null_move() is used to do a "null move": it flips
|
// Used to do a "null move": it flips
|
||||||
// the side to move without executing any move on the board.
|
// the side to move without executing any move on the board.
|
||||||
|
|
||||||
void Position::do_null_move(StateInfo& newSt) {
|
void Position::do_null_move(StateInfo& newSt) {
|
||||||
|
|
||||||
assert(!checkers());
|
assert(!checkers());
|
||||||
|
@ -1003,8 +988,7 @@ void Position::do_null_move(StateInfo& newSt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::undo_null_move() must be used to undo a "null move"
|
// Must be used to undo a "null move"
|
||||||
|
|
||||||
void Position::undo_null_move() {
|
void Position::undo_null_move() {
|
||||||
|
|
||||||
assert(!checkers());
|
assert(!checkers());
|
||||||
|
@ -1014,10 +998,9 @@ void Position::undo_null_move() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::key_after() computes the new hash key after the given move. Needed
|
// Computes the new hash key after the given move. Needed
|
||||||
// for speculative prefetch. It doesn't recognize special moves like castling,
|
// for speculative prefetch. It doesn't recognize special moves like castling,
|
||||||
// en passant and promotions.
|
// en passant and promotions.
|
||||||
|
|
||||||
Key Position::key_after(Move m) const {
|
Key Position::key_after(Move m) const {
|
||||||
|
|
||||||
Square from = from_sq(m);
|
Square from = from_sq(m);
|
||||||
|
@ -1035,10 +1018,9 @@ Key Position::key_after(Move m) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::see_ge (Static Exchange Evaluation Greater or Equal) tests if the
|
// Tests if the SEE (Static Exchange Evaluation)
|
||||||
// SEE value of move is greater or equal to the given threshold. We'll use an
|
// value of move is greater or equal to the given threshold. We'll use an
|
||||||
// algorithm similar to alpha-beta pruning with a null window.
|
// algorithm similar to alpha-beta pruning with a null window.
|
||||||
|
|
||||||
bool Position::see_ge(Move m, Value threshold) const {
|
bool Position::see_ge(Move m, Value threshold) const {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(is_ok(m));
|
||||||
|
@ -1140,9 +1122,8 @@ bool Position::see_ge(Move m, Value threshold) const {
|
||||||
return bool(res);
|
return bool(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position::is_draw() tests whether the position is drawn by 50-move rule
|
// Tests whether the position is drawn by 50-move rule
|
||||||
// or by repetition. It does not detect stalemates.
|
// or by repetition. It does not detect stalemates.
|
||||||
|
|
||||||
bool Position::is_draw(int ply) const {
|
bool Position::is_draw(int ply) const {
|
||||||
|
|
||||||
if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
|
if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
|
||||||
|
@ -1154,9 +1135,8 @@ bool Position::is_draw(int ply) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::has_repeated() tests whether there has been at least one repetition
|
// Tests whether there has been at least one repetition
|
||||||
// of positions since the last capture or pawn move.
|
// of positions since the last capture or pawn move.
|
||||||
|
|
||||||
bool Position::has_repeated() const {
|
bool Position::has_repeated() const {
|
||||||
|
|
||||||
StateInfo* stc = st;
|
StateInfo* stc = st;
|
||||||
|
@ -1172,9 +1152,8 @@ bool Position::has_repeated() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::has_game_cycle() tests if the position has a move which draws by repetition,
|
// Tests if the position has a move which draws by repetition,
|
||||||
// or an earlier position has a move that directly reaches the current position.
|
// or an earlier position has a move that directly reaches the current position.
|
||||||
|
|
||||||
bool Position::has_game_cycle(int ply) const {
|
bool Position::has_game_cycle(int ply) const {
|
||||||
|
|
||||||
int j;
|
int j;
|
||||||
|
@ -1220,9 +1199,8 @@ bool Position::has_game_cycle(int ply) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::flip() flips position with the white and black sides reversed. This
|
// Flips position with the white and black sides reversed. This
|
||||||
// is only useful for debugging e.g. for finding evaluation symmetry bugs.
|
// is only useful for debugging e.g. for finding evaluation symmetry bugs.
|
||||||
|
|
||||||
void Position::flip() {
|
void Position::flip() {
|
||||||
|
|
||||||
string f, token;
|
string f, token;
|
||||||
|
@ -1255,10 +1233,9 @@ void Position::flip() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position::pos_is_ok() performs some consistency checks for the
|
// Performs some consistency checks for the
|
||||||
// position object and raise an assert if something wrong is detected.
|
// position object and raise an assert if something wrong is detected.
|
||||||
// This is meant to be helpful when debugging.
|
// This is meant to be helpful when debugging.
|
||||||
|
|
||||||
bool Position::pos_is_ok() const {
|
bool Position::pos_is_ok() const {
|
||||||
|
|
||||||
constexpr bool Fast = true; // Quick (default) or full check?
|
constexpr bool Fast = true; // Quick (default) or full check?
|
||||||
|
|
|
@ -148,7 +148,7 @@ void update_all_stats(const Position& pos,
|
||||||
int captureCount,
|
int captureCount,
|
||||||
Depth depth);
|
Depth depth);
|
||||||
|
|
||||||
// perft() is our utility to verify move generation. All the leaf nodes up
|
// Utility to verify move generation. All the leaf nodes up
|
||||||
// to the given depth are generated and counted, and the sum is returned.
|
// to the given depth are generated and counted, and the sum is returned.
|
||||||
template<bool Root>
|
template<bool Root>
|
||||||
uint64_t perft(Position& pos, Depth depth) {
|
uint64_t perft(Position& pos, Depth depth) {
|
||||||
|
@ -179,8 +179,7 @@ uint64_t perft(Position& pos, Depth depth) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
// Search::init() is called at startup to initialize various lookup tables
|
// Called at startup to initialize various lookup tables
|
||||||
|
|
||||||
void Search::init() {
|
void Search::init() {
|
||||||
|
|
||||||
for (int i = 1; i < MAX_MOVES; ++i)
|
for (int i = 1; i < MAX_MOVES; ++i)
|
||||||
|
@ -188,8 +187,7 @@ void Search::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Search::clear() resets search state to its initial value
|
// Resets search state to its initial value
|
||||||
|
|
||||||
void Search::clear() {
|
void Search::clear() {
|
||||||
|
|
||||||
Threads.main()->wait_for_search_finished();
|
Threads.main()->wait_for_search_finished();
|
||||||
|
@ -201,9 +199,8 @@ void Search::clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MainThread::search() is started when the program receives the UCI 'go'
|
// Called when the program receives the UCI 'go'
|
||||||
// command. It searches from the root position and outputs the "bestmove".
|
// command. It searches from the root position and outputs the "bestmove".
|
||||||
|
|
||||||
void MainThread::search() {
|
void MainThread::search() {
|
||||||
|
|
||||||
if (Limits.perft)
|
if (Limits.perft)
|
||||||
|
@ -277,10 +274,9 @@ void MainThread::search() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Thread::search() is the main iterative deepening loop. It calls search()
|
// Main iterative deepening loop. It calls search()
|
||||||
// repeatedly with increasing depth until the allocated thinking time has been
|
// repeatedly with increasing depth until the allocated thinking time has been
|
||||||
// consumed, the user stops the search, or the maximum search depth is reached.
|
// consumed, the user stops the search, or the maximum search depth is reached.
|
||||||
|
|
||||||
void Thread::search() {
|
void Thread::search() {
|
||||||
|
|
||||||
// Allocate stack with extra size to allow access from (ss-7) to (ss+2):
|
// Allocate stack with extra size to allow access from (ss-7) to (ss+2):
|
||||||
|
@ -521,8 +517,7 @@ void Thread::search() {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// search<>() is the main search function for both PV and non-PV nodes
|
// Main search function for both PV and non-PV nodes
|
||||||
|
|
||||||
template<NodeType nodeType>
|
template<NodeType nodeType>
|
||||||
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode) {
|
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode) {
|
||||||
|
|
||||||
|
@ -1346,7 +1341,7 @@ moves_loop: // When in check, search starts here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// qsearch() is the 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 recursively with further decreasing depth per call.
|
// function with zero depth, or recursively with further decreasing depth per call.
|
||||||
// (~155 Elo)
|
// (~155 Elo)
|
||||||
template<NodeType nodeType>
|
template<NodeType nodeType>
|
||||||
|
@ -1593,10 +1588,9 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// value_to_tt() adjusts a mate or TB score from "plies to mate from the root"
|
// Adjusts a mate or TB score from "plies to mate from the root"
|
||||||
// to "plies to mate from the current position". Standard scores are unchanged.
|
// to "plies to mate from the current position". Standard scores are unchanged.
|
||||||
// The function is called before storing a value in the transposition table.
|
// The function is called before storing a value in the transposition table.
|
||||||
|
|
||||||
Value value_to_tt(Value v, int ply) {
|
Value value_to_tt(Value v, int ply) {
|
||||||
|
|
||||||
assert(v != VALUE_NONE);
|
assert(v != VALUE_NONE);
|
||||||
|
@ -1605,12 +1599,11 @@ Value value_to_tt(Value v, int ply) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// value_from_tt() is the inverse of value_to_tt(): it adjusts a mate or TB score
|
// Inverse of value_to_tt(): it adjusts a mate or TB score
|
||||||
// from the transposition table (which refers to the plies to mate/be mated from
|
// from the transposition table (which refers to the plies to mate/be mated from
|
||||||
// current position) to "plies to mate/be mated (TB win/loss) from the root".
|
// current position) to "plies to mate/be mated (TB win/loss) from the root".
|
||||||
// However, to avoid potentially false mate scores related to the 50 moves rule
|
// However, to avoid potentially false mate scores related to the 50 moves rule
|
||||||
// and the graph history interaction problem, we return an optimal TB score instead.
|
// and the graph history interaction problem, we return an optimal TB score instead.
|
||||||
|
|
||||||
Value value_from_tt(Value v, int ply, int r50c) {
|
Value value_from_tt(Value v, int ply, int r50c) {
|
||||||
|
|
||||||
if (v == VALUE_NONE)
|
if (v == VALUE_NONE)
|
||||||
|
@ -1636,8 +1629,7 @@ Value value_from_tt(Value v, int ply, int r50c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// update_pv() adds current move and appends child pv[]
|
// Adds current move and appends child pv[]
|
||||||
|
|
||||||
void update_pv(Move* pv, Move move, const Move* childPv) {
|
void update_pv(Move* pv, Move move, const Move* childPv) {
|
||||||
|
|
||||||
for (*pv++ = move; childPv && *childPv != MOVE_NONE;)
|
for (*pv++ = move; childPv && *childPv != MOVE_NONE;)
|
||||||
|
@ -1646,8 +1638,7 @@ void update_pv(Move* pv, Move move, const Move* childPv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// update_all_stats() updates stats at the end of search() when a bestMove is found
|
// Updates stats at the end of search() when a bestMove is found
|
||||||
|
|
||||||
void update_all_stats(const Position& pos,
|
void update_all_stats(const Position& pos,
|
||||||
Stack* ss,
|
Stack* ss,
|
||||||
Move bestMove,
|
Move bestMove,
|
||||||
|
@ -1709,9 +1700,8 @@ void update_all_stats(const Position& pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// update_continuation_histories() updates histories of the move pairs formed
|
// Updates histories of the move pairs formed
|
||||||
// by moves at ply -1, -2, -4, and -6 with current move.
|
// by moves at ply -1, -2, -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) {
|
||||||
|
|
||||||
for (int i : {1, 2, 3, 4, 6})
|
for (int i : {1, 2, 3, 4, 6})
|
||||||
|
@ -1725,8 +1715,7 @@ void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// update_quiet_stats() updates move sorting heuristics
|
// Updates move sorting heuristics
|
||||||
|
|
||||||
void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus) {
|
void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus) {
|
||||||
|
|
||||||
// Update killers
|
// Update killers
|
||||||
|
@ -1751,7 +1740,6 @@ void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus) {
|
||||||
|
|
||||||
// When playing with strength handicap, choose the best move among a set of RootMoves
|
// When playing with strength handicap, choose the best move among a set of RootMoves
|
||||||
// using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
|
// using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
|
||||||
|
|
||||||
Move Skill::pick_best(size_t multiPV) {
|
Move Skill::pick_best(size_t multiPV) {
|
||||||
|
|
||||||
const RootMoves& rootMoves = Threads.main()->rootMoves;
|
const RootMoves& rootMoves = Threads.main()->rootMoves;
|
||||||
|
@ -1786,9 +1774,8 @@ Move Skill::pick_best(size_t multiPV) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
// MainThread::check_time() is used to print debug info and, more importantly,
|
// Used to print debug info and, more importantly,
|
||||||
// to detect when we are out of available time and thus stop the search.
|
// to detect when we are out of available time and thus stop the search.
|
||||||
|
|
||||||
void MainThread::check_time() {
|
void MainThread::check_time() {
|
||||||
|
|
||||||
if (--callsCnt > 0)
|
if (--callsCnt > 0)
|
||||||
|
@ -1819,9 +1806,8 @@ void MainThread::check_time() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// UCI::pv() formats PV information according to the UCI protocol. UCI requires
|
// Formats PV information according to the UCI protocol. UCI requires
|
||||||
// that all (if any) unsearched PV lines are sent using a previous search score.
|
// that all (if any) unsearched PV lines are sent using a previous search score.
|
||||||
|
|
||||||
string UCI::pv(const Position& pos, Depth depth) {
|
string UCI::pv(const Position& pos, Depth depth) {
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -1874,11 +1860,10 @@ string UCI::pv(const Position& pos, Depth depth) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// RootMove::extract_ponder_from_tt() is called in case we have no ponder move
|
// Called in case we have no ponder move
|
||||||
// before exiting the search, for instance, in case we stop the search during a
|
// before exiting the search, for instance, in case we stop the search during a
|
||||||
// fail high at root. We try hard to have a ponder move to return to the GUI,
|
// fail high at root. We try hard to have a ponder move to return to the GUI,
|
||||||
// otherwise in case of 'ponder on' we have nothing to think about.
|
// otherwise in case of 'ponder on' we have nothing to think about.
|
||||||
|
|
||||||
bool RootMove::extract_ponder_from_tt(Position& pos) {
|
bool RootMove::extract_ponder_from_tt(Position& pos) {
|
||||||
|
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
|
|
|
@ -36,7 +36,6 @@ namespace Search {
|
||||||
// Stack struct keeps track of the information we need to remember from nodes
|
// Stack struct keeps track of the information we need to remember from nodes
|
||||||
// shallower and deeper in the tree during the search. Each search thread has
|
// shallower and deeper in the tree during the search. Each search thread has
|
||||||
// its own array of Stack objects, indexed by the current ply.
|
// its own array of Stack objects, indexed by the current ply.
|
||||||
|
|
||||||
struct Stack {
|
struct Stack {
|
||||||
Move* pv;
|
Move* pv;
|
||||||
PieceToHistory* continuationHistory;
|
PieceToHistory* continuationHistory;
|
||||||
|
@ -58,14 +57,14 @@ struct Stack {
|
||||||
// RootMove struct is used for moves at the root of the tree. For each root move
|
// RootMove struct is used for moves at the root of the tree. For each root move
|
||||||
// we store a score and a PV (really a refutation in the case of moves which
|
// we store a score and a PV (really a refutation in the case of moves which
|
||||||
// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves.
|
// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves.
|
||||||
|
|
||||||
struct RootMove {
|
struct RootMove {
|
||||||
|
|
||||||
explicit RootMove(Move m) :
|
explicit RootMove(Move m) :
|
||||||
pv(1, m) {}
|
pv(1, m) {}
|
||||||
bool extract_ponder_from_tt(Position& pos);
|
bool extract_ponder_from_tt(Position& pos);
|
||||||
bool operator==(const Move& m) const { return pv[0] == m; }
|
bool operator==(const Move& m) const { return pv[0] == m; }
|
||||||
bool operator<(const RootMove& m) const { // Sort in descending order
|
// Sort in descending order
|
||||||
|
bool operator<(const RootMove& m) const {
|
||||||
return m.score != score ? m.score < score : m.previousScore < previousScore;
|
return m.score != score ? m.score < score : m.previousScore < previousScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +88,8 @@ using RootMoves = std::vector<RootMove>;
|
||||||
|
|
||||||
struct LimitsType {
|
struct LimitsType {
|
||||||
|
|
||||||
LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
|
// Init explicitly due to broken value-initialization of non POD in MSVC
|
||||||
|
LimitsType() {
|
||||||
time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = npmsec = movetime = TimePoint(0);
|
time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = npmsec = movetime = TimePoint(0);
|
||||||
movestogo = depth = mate = perft = infinite = 0;
|
movestogo = depth = mate = perft = infinite = 0;
|
||||||
nodes = 0;
|
nodes = 0;
|
||||||
|
|
|
@ -1317,7 +1317,7 @@ WDLScore search(Position& pos, ProbeState* result) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
// Tablebases::init() is called at startup and after every change to
|
// Called at startup and after every change to
|
||||||
// "SyzygyPath" UCI option to (re)create the various tables. It is not thread
|
// "SyzygyPath" UCI option to (re)create the various tables. It is not thread
|
||||||
// safe, nor it needs to be.
|
// safe, nor it needs to be.
|
||||||
void Tablebases::init(const std::string& paths) {
|
void Tablebases::init(const std::string& paths) {
|
||||||
|
|
|
@ -40,9 +40,8 @@ namespace Stockfish {
|
||||||
ThreadPool Threads; // Global object
|
ThreadPool Threads; // Global object
|
||||||
|
|
||||||
|
|
||||||
// Thread constructor launches the thread and waits until it goes to sleep
|
// Constructor launches the thread and waits until it goes to sleep
|
||||||
// in idle_loop(). Note that 'searching' and 'exit' should be already set.
|
// in idle_loop(). Note that 'searching' and 'exit' should be already set.
|
||||||
|
|
||||||
Thread::Thread(size_t n) :
|
Thread::Thread(size_t n) :
|
||||||
idx(n),
|
idx(n),
|
||||||
stdThread(&Thread::idle_loop, this) {
|
stdThread(&Thread::idle_loop, this) {
|
||||||
|
@ -51,9 +50,8 @@ Thread::Thread(size_t n) :
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Thread destructor wakes up the thread in idle_loop() and waits
|
// Destructor wakes up the thread in idle_loop() and waits
|
||||||
// for its termination. Thread should be already waiting.
|
// for its termination. Thread should be already waiting.
|
||||||
|
|
||||||
Thread::~Thread() {
|
Thread::~Thread() {
|
||||||
|
|
||||||
assert(!searching);
|
assert(!searching);
|
||||||
|
@ -64,8 +62,7 @@ Thread::~Thread() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Thread::clear() reset histories, usually before a new game
|
// Reset histories, usually before a new game
|
||||||
|
|
||||||
void Thread::clear() {
|
void Thread::clear() {
|
||||||
|
|
||||||
counterMoves.fill(MOVE_NONE);
|
counterMoves.fill(MOVE_NONE);
|
||||||
|
@ -80,8 +77,7 @@ void Thread::clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Thread::start_searching() wakes up the thread that will start the search
|
// Wakes up the thread that will start the search
|
||||||
|
|
||||||
void Thread::start_searching() {
|
void Thread::start_searching() {
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
searching = true;
|
searching = true;
|
||||||
|
@ -90,9 +86,8 @@ void Thread::start_searching() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Thread::wait_for_search_finished() blocks on the condition variable
|
// Blocks on the condition variable
|
||||||
// until the thread has finished searching.
|
// until the thread has finished searching.
|
||||||
|
|
||||||
void Thread::wait_for_search_finished() {
|
void Thread::wait_for_search_finished() {
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lk(mutex);
|
std::unique_lock<std::mutex> lk(mutex);
|
||||||
|
@ -100,7 +95,7 @@ void Thread::wait_for_search_finished() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Thread::idle_loop() is where the thread is parked, blocked on the
|
// Thread gets parked here, blocked on the
|
||||||
// condition variable, when it has no work to do.
|
// condition variable, when it has no work to do.
|
||||||
|
|
||||||
void Thread::idle_loop() {
|
void Thread::idle_loop() {
|
||||||
|
@ -129,10 +124,9 @@ void Thread::idle_loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ThreadPool::set() creates/destroys threads to match the requested number.
|
// Creates/destroys threads to match the requested number.
|
||||||
// Created and launched threads will immediately go to sleep in idle_loop.
|
// Created and launched threads will immediately go to sleep in idle_loop.
|
||||||
// Upon resizing, threads are recreated to allow for binding if necessary.
|
// Upon resizing, threads are recreated to allow for binding if necessary.
|
||||||
|
|
||||||
void ThreadPool::set(size_t requested) {
|
void ThreadPool::set(size_t requested) {
|
||||||
|
|
||||||
if (threads.size() > 0) // destroy any existing thread(s)
|
if (threads.size() > 0) // destroy any existing thread(s)
|
||||||
|
@ -160,8 +154,7 @@ void ThreadPool::set(size_t requested) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ThreadPool::clear() sets threadPool data to initial values
|
// Sets threadPool data to initial values
|
||||||
|
|
||||||
void ThreadPool::clear() {
|
void ThreadPool::clear() {
|
||||||
|
|
||||||
for (Thread* th : threads)
|
for (Thread* th : threads)
|
||||||
|
@ -174,9 +167,8 @@ void ThreadPool::clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ThreadPool::start_thinking() wakes up main thread waiting in idle_loop() and
|
// Wakes up main thread waiting in idle_loop() and
|
||||||
// returns immediately. Main thread will wake up other threads and start the search.
|
// returns immediately. Main thread will wake up other threads and start the search.
|
||||||
|
|
||||||
void ThreadPool::start_thinking(Position& pos,
|
void ThreadPool::start_thinking(Position& pos,
|
||||||
StateListPtr& states,
|
StateListPtr& states,
|
||||||
const Search::LimitsType& limits,
|
const Search::LimitsType& limits,
|
||||||
|
|
|
@ -38,7 +38,6 @@ namespace Stockfish {
|
||||||
// per-thread pawn and material hash tables so that once we get a
|
// per-thread pawn and material hash tables so that once we get a
|
||||||
// pointer to an entry its lifetime is unlimited and we don't have
|
// pointer to an entry its lifetime is unlimited and we don't have
|
||||||
// to care about someone changing the entry under our feet.
|
// to care about someone changing the entry under our feet.
|
||||||
|
|
||||||
class Thread {
|
class Thread {
|
||||||
|
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
|
@ -76,7 +75,6 @@ class Thread {
|
||||||
|
|
||||||
|
|
||||||
// MainThread is a derived class specific for main thread
|
// MainThread is a derived class specific for main thread
|
||||||
|
|
||||||
struct MainThread: public Thread {
|
struct MainThread: public Thread {
|
||||||
|
|
||||||
using Thread::Thread;
|
using Thread::Thread;
|
||||||
|
@ -97,7 +95,6 @@ struct MainThread: public Thread {
|
||||||
// ThreadPool struct handles all the threads-related stuff like init, starting,
|
// ThreadPool struct handles all the threads-related stuff like init, starting,
|
||||||
// parking and, most importantly, launching a thread. All the access to threads
|
// parking and, most importantly, launching a thread. All the access to threads
|
||||||
// is done through this class.
|
// is done through this class.
|
||||||
|
|
||||||
struct ThreadPool {
|
struct ThreadPool {
|
||||||
|
|
||||||
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
|
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
|
||||||
|
|
|
@ -29,11 +29,10 @@ namespace Stockfish {
|
||||||
TimeManagement Time; // Our global time management object
|
TimeManagement Time; // Our global time management object
|
||||||
|
|
||||||
|
|
||||||
// TimeManagement::init() is called at the beginning of the search and calculates
|
// Called at the beginning of the search and calculates
|
||||||
// the bounds of time allowed for the current game ply. We currently support:
|
// the bounds of time allowed for the current game ply. We currently support:
|
||||||
// 1) x basetime (+ z increment)
|
// 1) x basetime (+ z increment)
|
||||||
// 2) x moves in y seconds (+ z increment)
|
// 2) x moves in y seconds (+ z increment)
|
||||||
|
|
||||||
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
||||||
|
|
||||||
// If we have no time, no need to initialize TM, except for the start time,
|
// If we have no time, no need to initialize TM, except for the start time,
|
||||||
|
|
|
@ -30,7 +30,6 @@ namespace Stockfish {
|
||||||
|
|
||||||
// The TimeManagement class computes the optimal time to think depending on
|
// The TimeManagement class computes the optimal time to think depending on
|
||||||
// the maximum available time, the game move number, and other parameters.
|
// the maximum available time, the game move number, and other parameters.
|
||||||
|
|
||||||
class TimeManagement {
|
class TimeManagement {
|
||||||
public:
|
public:
|
||||||
void init(Search::LimitsType& limits, Color us, int ply);
|
void init(Search::LimitsType& limits, Color us, int ply);
|
||||||
|
|
16
src/tt.cpp
16
src/tt.cpp
|
@ -33,9 +33,8 @@ namespace Stockfish {
|
||||||
|
|
||||||
TranspositionTable TT; // Our global transposition table
|
TranspositionTable TT; // Our global transposition table
|
||||||
|
|
||||||
// TTEntry::save() 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(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) {
|
void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) {
|
||||||
|
|
||||||
// Preserve any existing move for the same position
|
// Preserve any existing move for the same position
|
||||||
|
@ -57,10 +56,9 @@ void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TranspositionTable::resize() sets the size of the transposition table,
|
// Sets the size of the transposition table,
|
||||||
// measured in megabytes. Transposition table consists of a power of 2 number
|
// measured in megabytes. Transposition table consists of a power of 2 number
|
||||||
// of clusters and each cluster consists of ClusterSize number of TTEntry.
|
// of clusters and each cluster consists of ClusterSize number of TTEntry.
|
||||||
|
|
||||||
void TranspositionTable::resize(size_t mbSize) {
|
void TranspositionTable::resize(size_t mbSize) {
|
||||||
|
|
||||||
Threads.main()->wait_for_search_finished();
|
Threads.main()->wait_for_search_finished();
|
||||||
|
@ -80,9 +78,8 @@ void TranspositionTable::resize(size_t mbSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TranspositionTable::clear() initializes the entire transposition table to zero,
|
// Initializes the entire transposition table to zero,
|
||||||
// in a multi-threaded way.
|
// in a multi-threaded way.
|
||||||
|
|
||||||
void TranspositionTable::clear() {
|
void TranspositionTable::clear() {
|
||||||
|
|
||||||
std::vector<std::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
|
@ -109,13 +106,12 @@ void TranspositionTable::clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TranspositionTable::probe() looks up the current position in the transposition
|
// Looks up the current position in the transposition
|
||||||
// table. It returns true and a pointer to the TTEntry if the position is found.
|
// table. It returns true and a pointer to the TTEntry if the position is found.
|
||||||
// Otherwise, it returns false and a pointer to an empty or least valuable TTEntry
|
// Otherwise, it returns false and a pointer to an empty or least valuable TTEntry
|
||||||
// to be replaced later. The replace value of an entry is calculated as its depth
|
// to be replaced later. The replace value of an entry is calculated as its depth
|
||||||
// minus 8 times its relative age. TTEntry t1 is considered more valuable than
|
// minus 8 times its relative age. TTEntry t1 is considered more valuable than
|
||||||
// TTEntry t2 if its replace value is greater than that of t2.
|
// TTEntry t2 if its replace value is greater than that of t2.
|
||||||
|
|
||||||
TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
|
TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
|
||||||
|
|
||||||
TTEntry* const tte = first_entry(key);
|
TTEntry* const tte = first_entry(key);
|
||||||
|
@ -148,7 +144,7 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TranspositionTable::hashfull() returns an approximation of the hashtable
|
// Returns an approximation of the hashtable
|
||||||
// occupation during a search. The hash is x permill full, as per UCI protocol.
|
// occupation during a search. The hash is x permill full, as per UCI protocol.
|
||||||
|
|
||||||
int TranspositionTable::hashfull() const {
|
int TranspositionTable::hashfull() const {
|
||||||
|
|
2
src/tt.h
2
src/tt.h
|
@ -37,7 +37,6 @@ namespace Stockfish {
|
||||||
// move 16 bit
|
// move 16 bit
|
||||||
// value 16 bit
|
// value 16 bit
|
||||||
// eval value 16 bit
|
// eval value 16 bit
|
||||||
|
|
||||||
struct TTEntry {
|
struct TTEntry {
|
||||||
|
|
||||||
Move move() const { return Move(move16); }
|
Move move() const { return Move(move16); }
|
||||||
|
@ -65,7 +64,6 @@ struct TTEntry {
|
||||||
// contains information on exactly one position. The size of a Cluster should
|
// contains information on exactly one position. The size of a Cluster should
|
||||||
// divide the size of a cache line for best performance, as the cacheline is
|
// divide the size of a cache line for best performance, as the cacheline is
|
||||||
// prefetched when possible.
|
// prefetched when possible.
|
||||||
|
|
||||||
class TranspositionTable {
|
class TranspositionTable {
|
||||||
|
|
||||||
static constexpr int ClusterSize = 3;
|
static constexpr int ClusterSize = 3;
|
||||||
|
|
20
src/types.h
20
src/types.h
|
@ -321,21 +321,17 @@ constexpr Square operator-(Square s, Direction d) { return Square(int(s) - int(d
|
||||||
inline Square& operator+=(Square& s, Direction d) { return s = s + d; }
|
inline Square& operator+=(Square& s, Direction d) { return s = s + d; }
|
||||||
inline Square& operator-=(Square& s, Direction d) { return s = s - d; }
|
inline Square& operator-=(Square& s, Direction d) { return s = s - d; }
|
||||||
|
|
||||||
constexpr Color operator~(Color c) {
|
// Toggle color
|
||||||
return Color(c ^ BLACK); // Toggle color
|
constexpr Color operator~(Color c) { return Color(c ^ BLACK); }
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Square flip_rank(Square s) { // Swap A1 <-> A8
|
// Swap A1 <-> A8
|
||||||
return Square(s ^ SQ_A8);
|
constexpr Square flip_rank(Square s) { return Square(s ^ SQ_A8); }
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Square flip_file(Square s) { // Swap A1 <-> H1
|
// Swap A1 <-> H1
|
||||||
return Square(s ^ SQ_H1);
|
constexpr Square flip_file(Square s) { return Square(s ^ SQ_H1); }
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Piece operator~(Piece pc) {
|
// Swap color of piece B_KNIGHT <-> W_KNIGHT
|
||||||
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT <-> W_KNIGHT
|
constexpr Piece operator~(Piece pc) { return Piece(pc ^ 8); }
|
||||||
}
|
|
||||||
|
|
||||||
constexpr CastlingRights operator&(Color c, CastlingRights cr) {
|
constexpr CastlingRights operator&(Color c, CastlingRights cr) {
|
||||||
return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr);
|
return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr);
|
||||||
|
|
30
src/uci.cpp
30
src/uci.cpp
|
@ -49,11 +49,10 @@ namespace {
|
||||||
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||||
|
|
||||||
|
|
||||||
// position() is called when the engine receives the "position" UCI command.
|
// Called when the engine receives the "position" UCI command.
|
||||||
// It sets up the position that is described in the given FEN string ("fen") or
|
// It sets up the position that is described in the given FEN string ("fen") or
|
||||||
// the initial position ("startpos") and then makes the moves given in the following
|
// the initial position ("startpos") and then makes the moves given in the following
|
||||||
// move list ("moves").
|
// move list ("moves").
|
||||||
|
|
||||||
void position(Position& pos, std::istringstream& is, StateListPtr& states) {
|
void position(Position& pos, std::istringstream& is, StateListPtr& states) {
|
||||||
|
|
||||||
Move m;
|
Move m;
|
||||||
|
@ -83,9 +82,8 @@ void position(Position& pos, std::istringstream& is, StateListPtr& states) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// trace_eval() prints the evaluation of the current position, consistent with
|
// Prints the evaluation of the current position, consistent with
|
||||||
// the UCI options set so far.
|
// the UCI options set so far.
|
||||||
|
|
||||||
void trace_eval(Position& pos) {
|
void trace_eval(Position& pos) {
|
||||||
|
|
||||||
StateListPtr states(new std::deque<StateInfo>(1));
|
StateListPtr states(new std::deque<StateInfo>(1));
|
||||||
|
@ -98,7 +96,7 @@ void trace_eval(Position& pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// setoption() is called when the engine receives the "setoption" UCI command.
|
// Called when the engine receives the "setoption" UCI command.
|
||||||
// The function updates the UCI option ("name") to the given value ("value").
|
// The function updates the UCI option ("name") to the given value ("value").
|
||||||
|
|
||||||
void setoption(std::istringstream& is) {
|
void setoption(std::istringstream& is) {
|
||||||
|
@ -124,7 +122,7 @@ void setoption(std::istringstream& is) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// go() is called when the engine receives the "go" UCI command. The function
|
// Called when the engine receives the "go" UCI command. The function
|
||||||
// sets the thinking time and other parameters from the input string, then starts
|
// sets the thinking time and other parameters from the input string, then starts
|
||||||
// with a search.
|
// with a search.
|
||||||
|
|
||||||
|
@ -170,7 +168,7 @@ void go(Position& pos, std::istringstream& is, StateListPtr& states) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// bench() is called when the engine receives the "bench" command.
|
// Called when the engine receives the "bench" command.
|
||||||
// First, a list of UCI commands is set up according to the bench
|
// First, a list of UCI commands is set up according to the bench
|
||||||
// parameters, then it is run one by one, printing a summary at the end.
|
// parameters, then it is run one by one, printing a summary at the end.
|
||||||
|
|
||||||
|
@ -252,12 +250,11 @@ int win_rate_model(Value v, int ply) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
// UCI::loop() waits for a command from the stdin, parses it, and then calls the appropriate
|
// Waits for a command from the stdin, parses it, and then calls the appropriate
|
||||||
// function. It also intercepts an end-of-file (EOF) indication from the stdin to ensure a
|
// function. It also intercepts an end-of-file (EOF) indication from the stdin to ensure a
|
||||||
// graceful exit if the GUI dies unexpectedly. When called with some command-line arguments,
|
// graceful exit if the GUI dies unexpectedly. When called with some command-line arguments,
|
||||||
// like running 'bench', the function returns immediately after the command is executed.
|
// like running 'bench', the function returns immediately after the command is executed.
|
||||||
// In addition to the UCI ones, some additional debug commands are also supported.
|
// In addition to the UCI ones, some additional debug commands are also supported.
|
||||||
|
|
||||||
void UCI::loop(int argc, char* argv[]) {
|
void UCI::loop(int argc, char* argv[]) {
|
||||||
|
|
||||||
Position pos;
|
Position pos;
|
||||||
|
@ -346,12 +343,11 @@ void UCI::loop(int argc, char* argv[]) {
|
||||||
// without treatment of mate and similar special scores.
|
// without treatment of mate and similar special scores.
|
||||||
int UCI::to_cp(Value v) { return 100 * v / UCI::NormalizeToPawnValue; }
|
int UCI::to_cp(Value v) { return 100 * v / UCI::NormalizeToPawnValue; }
|
||||||
|
|
||||||
// UCI::value() converts a Value to a string by adhering to the UCI protocol specification:
|
// Converts a Value to a string by adhering to the UCI protocol specification:
|
||||||
//
|
//
|
||||||
// cp <x> The score from the engine's point of view in centipawns.
|
// cp <x> The score from the engine's point of view in centipawns.
|
||||||
// mate <y> Mate in 'y' moves (not plies). If the engine is getting mated,
|
// mate <y> Mate in 'y' moves (not plies). If the engine is getting mated,
|
||||||
// uses negative values for 'y'.
|
// uses negative values for 'y'.
|
||||||
|
|
||||||
std::string UCI::value(Value v) {
|
std::string UCI::value(Value v) {
|
||||||
|
|
||||||
assert(-VALUE_INFINITE < v && v < VALUE_INFINITE);
|
assert(-VALUE_INFINITE < v && v < VALUE_INFINITE);
|
||||||
|
@ -372,9 +368,8 @@ std::string UCI::value(Value v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// UCI::wdl() reports the win-draw-loss (WDL) statistics given an evaluation
|
// Reports the win-draw-loss (WDL) statistics given an evaluation
|
||||||
// and a game ply based on the data gathered for fishtest LTC games.
|
// and a game ply based on the data gathered for fishtest LTC games.
|
||||||
|
|
||||||
std::string UCI::wdl(Value v, int ply) {
|
std::string UCI::wdl(Value v, int ply) {
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -388,18 +383,16 @@ std::string UCI::wdl(Value v, int ply) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// UCI::square() converts a Square to a string in algebraic notation (g1, a7, etc.)
|
// Converts a Square to a string in algebraic notation (g1, a7, etc.)
|
||||||
|
|
||||||
std::string UCI::square(Square s) {
|
std::string UCI::square(Square s) {
|
||||||
return std::string{char('a' + file_of(s)), char('1' + rank_of(s))};
|
return std::string{char('a' + file_of(s)), char('1' + rank_of(s))};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// UCI::move() converts a Move to a string in coordinate notation (g1f3, a7a8q).
|
// Converts a Move to a string in coordinate notation (g1f3, a7a8q).
|
||||||
// The only special case is castling where the e1g1 notation is printed in
|
// The only special case is castling where the e1g1 notation is printed in
|
||||||
// standard chess mode and in e1h1 notation it is printed in Chess960 mode.
|
// standard chess mode and in e1h1 notation it is printed in Chess960 mode.
|
||||||
// Internally, all castling moves are always encoded as 'king captures rook'.
|
// Internally, all castling moves are always encoded as 'king captures rook'.
|
||||||
|
|
||||||
std::string UCI::move(Move m, bool chess960) {
|
std::string UCI::move(Move m, bool chess960) {
|
||||||
|
|
||||||
if (m == MOVE_NONE)
|
if (m == MOVE_NONE)
|
||||||
|
@ -423,9 +416,8 @@ std::string UCI::move(Move m, bool chess960) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// UCI::to_move() converts a string representing a move in coordinate notation
|
// Converts a string representing a move in coordinate notation
|
||||||
// (g1f3, a7a8q) to the corresponding legal Move, if any.
|
// (g1f3, a7a8q) to the corresponding legal Move, if any.
|
||||||
|
|
||||||
Move UCI::to_move(const Position& pos, std::string& str) {
|
Move UCI::to_move(const Position& pos, std::string& str) {
|
||||||
|
|
||||||
if (str.length() == 5)
|
if (str.length() == 5)
|
||||||
|
|
|
@ -60,8 +60,7 @@ bool CaseInsensitiveLess::operator()(const string& s1, const string& s2) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// UCI::init() initializes the UCI options to their hard-coded default values
|
// Initializes the UCI options to their hard-coded default values
|
||||||
|
|
||||||
void init(OptionsMap& o) {
|
void init(OptionsMap& o) {
|
||||||
|
|
||||||
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
|
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
|
||||||
|
@ -89,9 +88,8 @@ void init(OptionsMap& o) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// operator<<() is used to print all the options default values in chronological
|
// Used to print all the options default values in chronological
|
||||||
// insertion order (the idx field) and in the format defined by the UCI protocol.
|
// insertion order (the idx field) and in the format defined by the UCI protocol.
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
|
std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
|
||||||
|
|
||||||
for (size_t idx = 0; idx < om.size(); ++idx)
|
for (size_t idx = 0; idx < om.size(); ++idx)
|
||||||
|
@ -172,7 +170,7 @@ bool Option::operator==(const char* s) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// operator<<() inits options and assigns idx in the correct printing order
|
// Inits options and assigns idx in the correct printing order
|
||||||
|
|
||||||
void Option::operator<<(const Option& o) {
|
void Option::operator<<(const Option& o) {
|
||||||
|
|
||||||
|
@ -183,10 +181,9 @@ void Option::operator<<(const Option& o) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// operator=() updates currentValue and triggers on_change() action. It's up to
|
// Updates currentValue and triggers on_change() action. It's up to
|
||||||
// the GUI to check for option's limits, but we could receive the new value
|
// the GUI to check for option's limits, but we could receive the new value
|
||||||
// from the user by console window, so let's check the bounds anyway.
|
// from the user by console window, so let's check the bounds anyway.
|
||||||
|
|
||||||
Option& Option::operator=(const string& v) {
|
Option& Option::operator=(const string& v) {
|
||||||
|
|
||||||
assert(!type.empty());
|
assert(!type.empty());
|
||||||
|
|
Loading…
Add table
Reference in a new issue