closes https://github.com/official-stockfish/Stockfish/pull/2756
No functional change
18 files changed:
/// Overloads of bitwise operators between a Bitboard and a Square for testing
/// whether a given bit is set in a bitboard, and for setting and clearing bits.
/// Overloads of bitwise operators between a Bitboard and a Square for testing
/// whether a given bit is set in a bitboard, and for setting and clearing bits.
return shift<EAST>(file_bb(s)) | shift<WEST>(file_bb(s));
}
return shift<EAST>(file_bb(s)) | shift<WEST>(file_bb(s));
}
-/// line_bb(Square, Square) returns a Bitboard representing an entire line
-/// (from board edge to board edge) that intersects the given squares.
-/// If the given squares are not on a same file/rank/diagonal, return 0.
-/// Ex. line_bb(SQ_C4, SQ_F7) returns a bitboard with the A2-G8 diagonal.
+
+/// line_bb(Square, Square) returns a bitboard representing an entire line,
+/// from board edge to board edge, that intersects the given squares. If the
+/// given squares are not on a same file/rank/diagonal, returns 0. For instance,
+/// 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) {
-/// between_bb() returns a Bitboard representing squares that are linearly
-/// between the given squares (excluding the given squares).
-/// If the given squares are not on a same file/rank/diagonal, return 0.
-/// Ex. between_bb(SQ_C4, SQ_F7) returns a bitboard with squares D5 and E6.
+
+/// between_bb() returns a bitboard representing squares that are linearly
+/// between the given squares (excluding the given squares). If the given
+/// squares are not on a same file/rank/diagonal, return 0. For instance,
+/// between_bb(SQ_C4, SQ_F7) will return a bitboard with squares D5 and E6.
inline Bitboard between_bb(Square s1, Square s2) {
Bitboard b = line_bb(s1, s2) & ((AllSquares << s1) ^ (AllSquares << s2));
inline Bitboard between_bb(Square s1, Square s2) {
Bitboard b = line_bb(s1, s2) & ((AllSquares << s1) ^ (AllSquares << s2));
/// pawn_attack_span() returns a bitboard representing all the squares that can
/// pawn_attack_span() returns a bitboard representing all the squares that can
-/// be attacked by a pawn of the given color when it moves along its file,
-/// starting from the given square.
+/// be attacked by a pawn of the given color when it moves along its file, starting
+/// from the given square.
inline Bitboard pawn_attack_span(Color c, Square s) {
return forward_ranks_bb(c, s) & adjacent_files_bb(s);
inline Bitboard pawn_attack_span(Color c, Square s) {
return forward_ranks_bb(c, s) & adjacent_files_bb(s);
inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
inline int edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); }
inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
inline int edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); }
-/// Return the target square bitboard if we do not step off the board, empty otherwise
+
+/// safe_destination() returns the bitboard of target square for the given step
+/// 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)
{
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);
}
/// attacks_bb(Square) returns the pseudo attacks of the give piece type
/// assuming an empty board.
/// attacks_bb(Square) returns the pseudo attacks of the give piece type
/// assuming an empty board.
return PseudoAttacks[Pt][s];
}
return PseudoAttacks[Pt][s];
}
/// attacks_bb(Square, Bitboard) 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.
/// attacks_bb(Square, Bitboard) 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.
-/// KQ vs KR. This is almost identical to KX vs K: We give the attacking
+/// KQ vs KR. This is almost identical to KX vs K: we give the attacking
/// king a bonus for having the kings close together, and for forcing the
/// defending king towards the edge. If we also take care to avoid null move for
/// the defending side in the search, this is usually sufficient to win KQ vs KR.
/// king a bonus for having the kings close together, and for forcing the
/// defending king towards the edge. If we also take care to avoid null move for
/// the defending side in the search, this is usually sufficient to win KQ vs KR.
/// KNN vs KP. Very drawish, but there are some mate opportunities if we can
/// KNN vs KP. Very drawish, but there are some mate opportunities if we can
-// press the weakSide King to a corner before the pawn advances too much.
+/// press the weakSide King to a corner before the pawn advances too much.
template<>
Value Endgame<KNNKP>::operator()(const Position& pos) const {
template<>
Value Endgame<KNNKP>::operator()(const Position& pos) const {
Square weakPawn = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN));
// There's potential for a draw if our pawn is blocked on the 7th rank,
Square weakPawn = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN));
// There's potential for a draw if our pawn is blocked on the 7th rank,
- // the bishop cannot attack it or they only have one pawn left
+ // the bishop cannot attack it or they only have one pawn left.
if ( relative_rank(strongSide, weakPawn) == RANK_7
&& (strongPawns & (weakPawn + pawn_push(weakSide)))
&& (opposite_colors(strongBishop, weakPawn) || !more_than_one(strongPawns)))
if ( relative_rank(strongSide, weakPawn) == RANK_7
&& (strongPawns & (weakPawn + pawn_push(weakSide)))
&& (opposite_colors(strongBishop, weakPawn) || !more_than_one(strongPawns)))
// closer. (I think this rule only fails in practically
// unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w
// and positions where qsearch will immediately correct the
// closer. (I think this rule only fails in practically
// unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w
// and positions where qsearch will immediately correct the
- // problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w)
+ // problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w).
if ( relative_rank(strongSide, weakKing) >= RANK_7
&& weakKingDist <= 2
&& weakKingDist <= strongKingDist)
if ( relative_rank(strongSide, weakKing) >= RANK_7
&& weakKingDist <= 2
&& weakKingDist <= strongKingDist)
-/// K and two or more pawns vs K. There is just a single rule here: If all pawns
+/// K and two or more pawns vs K. There is just a single rule here: if all pawns
/// are on the same rook file and are blocked by the defending king, it's a draw.
template<>
ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
/// are on the same rook file and are blocked by the defending king, it's a draw.
template<>
ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
-/// KBP vs KN. There is a single rule: If the defending king is somewhere along
+/// KBP vs KN. There is a single rule: if the defending king is somewhere along
/// the path of the pawn, and the square of the king is not of the same color as
/// the stronger side's bishop, it's a draw.
template<>
/// the path of the pawn, and the square of the king is not of the same color as
/// the stronger side's bishop, it's a draw.
template<>
/// KP vs KP. This is done by removing the weakest side's pawn and probing the
/// KP vs KP. This is done by removing the weakest side's pawn and probing the
-/// KP vs K bitbase: If the weakest side has a draw without the pawn, it probably
+/// KP vs K bitbase: if the weakest side has a draw without the pawn, it probably
/// has at least a draw with the pawn as well. The exception is when the stronger
/// side's pawn is far advanced and not on a rook file; in this case it is often
/// possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
/// has at least a draw with the pawn as well. The exception is when the stronger
/// side's pawn is far advanced and not on a rook file; in this case it is often
/// possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
};
// Assorted bonuses and penalties
};
// Assorted bonuses and penalties
- constexpr Score BishopPawns = S( 3, 7);
+ constexpr Score BishopKingProtector = S( 6, 9);
constexpr Score BishopOnKingRing = S( 24, 0);
constexpr Score BishopOnKingRing = S( 24, 0);
+ constexpr Score BishopOutpost = S( 30, 23);
+ constexpr Score BishopPawns = S( 3, 7);
constexpr Score BishopXRayPawns = S( 4, 5);
constexpr Score CorneredBishop = S( 50, 50);
constexpr Score FlankAttacks = S( 8, 0);
constexpr Score Hanging = S( 69, 36);
constexpr Score BishopXRayPawns = S( 4, 5);
constexpr Score CorneredBishop = S( 50, 50);
constexpr Score FlankAttacks = S( 8, 0);
constexpr Score Hanging = S( 69, 36);
- constexpr Score BishopKingProtector = S( 6, 9);
constexpr Score KnightKingProtector = S( 8, 9);
constexpr Score KnightOnQueen = S( 16, 11);
constexpr Score KnightKingProtector = S( 8, 9);
constexpr Score KnightOnQueen = S( 16, 11);
+ constexpr Score KnightOutpost = S( 56, 36);
constexpr Score LongDiagonalBishop = S( 45, 0);
constexpr Score MinorBehindPawn = S( 18, 3);
constexpr Score LongDiagonalBishop = S( 45, 0);
constexpr Score MinorBehindPawn = S( 18, 3);
- constexpr Score KnightOutpost = S( 56, 36);
- constexpr Score BishopOutpost = S( 30, 23);
- constexpr Score ReachableOutpost = S( 31, 22);
constexpr Score PassedFile = S( 11, 8);
constexpr Score PawnlessFlank = S( 17, 95);
constexpr Score QueenInfiltration = S( -2, 14);
constexpr Score PassedFile = S( 11, 8);
constexpr Score PawnlessFlank = S( 17, 95);
constexpr Score QueenInfiltration = S( -2, 14);
+ constexpr Score ReachableOutpost = S( 31, 22);
constexpr Score RestrictedPiece = S( 7, 7);
constexpr Score RookOnKingRing = S( 16, 0);
constexpr Score RookOnQueenFile = S( 6, 11);
constexpr Score RestrictedPiece = S( 7, 7);
constexpr Score RookOnKingRing = S( 16, 0);
constexpr Score RookOnQueenFile = S( 6, 11);
constexpr Score ThreatByPawnPush = S( 48, 39);
constexpr Score ThreatBySafePawn = S(173, 94);
constexpr Score TrappedRook = S( 55, 13);
constexpr Score ThreatByPawnPush = S( 48, 39);
constexpr Score ThreatBySafePawn = S(173, 94);
constexpr Score TrappedRook = S( 55, 13);
- constexpr Score WeakQueen = S( 56, 15);
constexpr Score WeakQueenProtection = S( 14, 0);
constexpr Score WeakQueenProtection = S( 14, 0);
+ constexpr Score WeakQueen = S( 56, 15);
+
// Evaluation::initialize() computes king and pawn attacks, and the king ring
// bitboard for a given color. This is done at the beginning of the evaluation.
// Evaluation::initialize() computes king and pawn attacks, and the king ring
// bitboard for a given color. This is done at the beginning of the evaluation.
template<Tracing T> template<Color Us>
void Evaluation<T>::initialize() {
template<Tracing T> template<Color Us>
void Evaluation<T>::initialize() {
// Evaluation::pieces() scores pieces of a given color and type
// Evaluation::pieces() scores pieces of a given color and type
template<Tracing T> template<Color Us, PieceType Pt>
Score Evaluation<T>::pieces() {
template<Tracing T> template<Color Us, PieceType Pt>
Score Evaluation<T>::pieces() {
// Bonus for queen on weak square in enemy camp
if (relative_rank(Us, s) > RANK_4 && (~pe->pawn_attacks_span(Them) & s))
// Bonus for queen on weak square in enemy camp
if (relative_rank(Us, s) > RANK_4 && (~pe->pawn_attacks_span(Them) & s))
- score += QueenInfiltration;
+ score += QueenInfiltration;
// Evaluation::king() assigns bonuses and penalties to a king of a given color
// Evaluation::king() assigns bonuses and penalties to a king of a given color
template<Tracing T> template<Color Us>
Score Evaluation<T>::king() const {
template<Tracing T> template<Color Us>
Score Evaluation<T>::king() const {
// Evaluation::threats() assigns bonuses according to the types of the
// attacking and the attacked pieces.
// Evaluation::threats() assigns bonuses according to the types of the
// attacking and the attacked pieces.
template<Tracing T> template<Color Us>
Score Evaluation<T>::threats() const {
template<Tracing T> template<Color Us>
Score Evaluation<T>::threats() const {
// Evaluation::winnable() adjusts the mg and eg score components based on the
// Evaluation::winnable() adjusts the mg and eg score components based on the
- // known attacking/defending status of the players.
- // A single value is derived from the mg and eg values and returned.
+ // known attacking/defending status of the players. A single value is derived
+ // by interpolation from the mg and eg values and returned.
template<Tracing T>
Value Evaluation<T>::winnable(Score score) const {
template<Tracing T>
Value Evaluation<T>::winnable(Score score) const {
return pos.side_to_move() == WHITE ? v : -v;
// Main evaluation begins here
return pos.side_to_move() == WHITE ? v : -v;
// Main evaluation begins here
initialize<WHITE>();
initialize<BLACK>();
// Pieces evaluated first (also populates attackedBy, attackedBy2).
initialize<WHITE>();
initialize<BLACK>();
// Pieces evaluated first (also populates attackedBy, attackedBy2).
- // Note that the order of evaluation of the terms is left unspecified
+ // Note that the order of evaluation of the terms is left unspecified.
score += pieces<WHITE, KNIGHT>() - pieces<BLACK, KNIGHT>()
+ pieces<WHITE, BISHOP>() - pieces<BLACK, BISHOP>()
+ pieces<WHITE, ROOK >() - pieces<BLACK, ROOK >()
score += pieces<WHITE, KNIGHT>() - pieces<BLACK, KNIGHT>()
+ pieces<WHITE, BISHOP>() - pieces<BLACK, BISHOP>()
+ pieces<WHITE, ROOK >() - pieces<BLACK, ROOK >()
constexpr int QuadraticTheirs[][PIECE_TYPE_NB] = {
// THEIR PIECES
// pair pawn knight bishop rook queen
constexpr int QuadraticTheirs[][PIECE_TYPE_NB] = {
// THEIR PIECES
// pair pawn knight bishop rook queen
- { 0 }, // Bishop pair
- { 36, 0 }, // Pawn
- { 9, 63, 0 }, // Knight OUR PIECES
- { 59, 65, 42, 0 }, // Bishop
- { 46, 39, 24, -24, 0 }, // Rook
- { 97, 100, -42, 137, 268, 0 } // Queen
+ { }, // Bishop pair
+ { 36, }, // Pawn
+ { 9, 63, }, // Knight OUR PIECES
+ { 59, 65, 42, }, // Bishop
+ { 46, 39, 24, -24, }, // Rook
+ { 97, 100, -42, 137, 268, } // Queen
};
// Endgame evaluation and scaling functions are accessed directly and not through
};
// Endgame evaluation and scaling functions are accessed directly and not through
&& pos.count<PAWN>(~us) >= 1;
}
&& pos.count<PAWN>(~us) >= 1;
}
/// imbalance() calculates the imbalance by comparing the piece count of each
/// piece type for both colors.
/// imbalance() calculates the imbalance by comparing the piece count of each
/// piece type for both colors.
template<Color Us>
int imbalance(const int pieceCount[][PIECE_TYPE_NB]) {
template<Color Us>
int imbalance(const int pieceCount[][PIECE_TYPE_NB]) {
if (!pieceCount[Us][pt1])
continue;
if (!pieceCount[Us][pt1])
continue;
+ int v = QuadraticOurs[pt1][pt1] * pieceCount[Us][pt1];
- for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2)
+ for (int pt2 = NO_PIECE_TYPE; pt2 < pt1; ++pt2)
v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2]
+ QuadraticTheirs[pt1][pt2] * pieceCount[Them][pt2];
v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2]
+ QuadraticTheirs[pt1][pt2] * pieceCount[Them][pt2];
/// Material::probe() looks up the current position's material configuration in
/// the material hash table. It returns a pointer to the Entry if the position
/// is found. Otherwise a new Entry is computed and stored there, so we don't
/// Material::probe() looks up the current position's material configuration in
/// the material hash table. It returns a pointer to the Entry if the position
/// is found. Otherwise a new Entry is computed and stored there, so we don't
bool specialized_eval_exists() const { return evaluationFunction != nullptr; }
Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); }
bool specialized_eval_exists() const { return evaluationFunction != nullptr; }
Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); }
- // scale_factor takes a position and a color as input and returns a scale factor
+ // scale_factor() takes a position and a color as input and returns a scale factor
// for the given color. We have to provide the position in addition to the color
// because the scale factor may also be a function which should be applied to
// the position. For instance, in KBP vs K endgames, the scaling function looks
// for the given color. We have to provide the position in addition to the color
// because the scale factor may also be a function which should be applied to
// the position. For instance, in KBP vs K endgames, the scaling function looks
-/// aligned_ttmem_alloc will return suitably aligned memory, and if possible use large pages.
-/// The returned pointer is the aligned one, while the mem argument is the one that needs to be passed to free.
-/// With c++17 some of this functionality can be simplified.
+/// aligned_ttmem_alloc() will return suitably aligned memory, and if possible use large pages.
+/// The returned pointer is the aligned one, while the mem argument is the one that needs
+/// to be passed to free. With c++17 some of this functionality could be simplified.
+
#if defined(__linux__) && !defined(__ANDROID__)
void* aligned_ttmem_alloc(size_t allocSize, void*& mem) {
#if defined(__linux__) && !defined(__ANDROID__)
void* aligned_ttmem_alloc(size_t allocSize, void*& mem) {
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds,
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds,
- // we still need to query GetLastError() to ensure that the privileges were actually obtained...
+ // we still need to query GetLastError() to ensure that the privileges were actually obtained.
if (AdjustTokenPrivileges(
hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) &&
GetLastError() == ERROR_SUCCESS)
{
if (AdjustTokenPrivileges(
hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) &&
GetLastError() == ERROR_SUCCESS)
{
- // round up size to full pages and allocate
+ // Round up size to full pages and allocate
allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1);
mem = VirtualAlloc(
NULL, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1);
mem = VirtualAlloc(
NULL, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
- // privilege no longer needed, restore previous state
+ // Privilege no longer needed, restore previous state
AdjustTokenPrivileges(hProcessToken, FALSE, &prevTp, 0, NULL, NULL);
}
}
AdjustTokenPrivileges(hProcessToken, FALSE, &prevTp, 0, NULL, NULL);
}
}
static bool firstCall = true;
static bool firstCall = true;
- // try to allocate large pages
+ // Try to allocate large pages
mem = aligned_ttmem_alloc_large_pages(allocSize);
// Suppress info strings on the first call. The first call occurs before 'uci'
mem = aligned_ttmem_alloc_large_pages(allocSize);
// Suppress info strings on the first call. The first call occurs before 'uci'
- // fall back to regular, page aligned, allocation if necessary
+ // Fall back to regular, page aligned, allocation if necessary
if (!mem)
mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!mem)
mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
-/// aligned_ttmem_free will free the previously allocated ttmem
+
+/// aligned_ttmem_free() will free the previously allocated ttmem
+
#if defined(_WIN64)
void aligned_ttmem_free(void* mem) {
#if defined(_WIN64)
void aligned_ttmem_free(void* mem) {
+
+ /// evaluate() calculates a score for the static pawn structure of the given position.
+ /// We cannot use the location of pieces or king in this function, as the evaluation
+ /// of the pawn structure will be stored in a small cache for speed reasons, and will
+ /// be re-used even when the pieces have moved.
+
template<Color Us>
Score evaluate(const Position& pos, Pawns::Entry* e) {
template<Color Us>
Score evaluate(const Position& pos, Pawns::Entry* e) {
/// Pawns::probe() looks up the current position's pawns configuration in
/// the pawns hash table. It returns a pointer to the Entry if the position
/// is found. Otherwise a new Entry is computed and stored there, so we don't
/// Pawns::probe() looks up the current position's pawns configuration in
/// the pawns hash table. It returns a pointer to the Entry if the position
/// is found. Otherwise a new Entry is computed and stored there, so we don't
-/// Position::init() initializes at startup the various arrays used to compute
-/// hash keys.
+/// Position::init() initializes at startup the various arrays used to compute hash keys
/// Position::is_draw() tests whether the position is drawn by 50-move rule
/// or by repetition. It does not detect stalemates.
/// Position::is_draw() tests whether the position is drawn by 50-move rule
/// or by repetition. It does not detect stalemates.
/// A list to keep track of the position states along the setup moves (from the
/// start position to the position just before the search starts). Needed by
/// 'draw by repetition' detection. Use a std::deque because pointers to
/// A list to keep track of the position states along the setup moves (from the
/// start position to the position just before the search starts). Needed by
/// 'draw by repetition' detection. Use a std::deque because pointers to
Score psq[PIECE_NB][SQUARE_NB];
Score psq[PIECE_NB][SQUARE_NB];
-// init() initializes piece-square tables: the white halves of the tables are
-// copied from Bonus[] adding the piece value, then the black halves of the
-// tables are initialized by flipping and changing the sign of the white scores.
+
+// PSQT::init() initializes piece-square tables: the white halves of the tables are
+// copied from Bonus[] and PBonus[], adding the piece value, then the black halves of
+// the tables are initialized by flipping and changing the sign of the white scores.
void init() {
for (Piece pc : {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING})
void init() {
for (Piece pc : {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING})
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
File f = File(edge_distance(file_of(s)));
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
File f = File(edge_distance(file_of(s)));
- psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
- : Bonus[pc][rank_of(s)][f]);
+ psq[ pc][s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
+ : Bonus[pc][rank_of(s)][f]);
psq[~pc][flip_rank(s)] = -psq[pc][s];
}
}
psq[~pc][flip_rank(s)] = -psq[pc][s];
}
}
double totalTime = rootMoves.size() == 1 ? 0 :
Time.optimum() * fallingEval * reduction * bestMoveInstability;
double totalTime = rootMoves.size() == 1 ? 0 :
Time.optimum() * fallingEval * reduction * bestMoveInstability;
- // Stop the search if we have exceeded the totalTime, at least 1ms search.
+ // Stop the search if we have exceeded the totalTime, at least 1ms search
if (Time.elapsed() > totalTime)
{
// If we are allowed to ponder do not stop the search now but
if (Time.elapsed() > totalTime)
{
// If we are allowed to ponder do not stop the search now but
|| pos.is_draw(ss->ply)
|| ss->ply >= MAX_PLY)
return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos)
|| pos.is_draw(ss->ply)
|| ss->ply >= MAX_PLY)
return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos)
- : value_draw(pos.this_thread());
+ : value_draw(pos.this_thread());
// Step 3. Mate distance pruning. Even if we mate at the next move our score
// would be at best mate_in(ss->ply+1), but if alpha is already bigger because
// Step 3. Mate distance pruning. Even if we mate at the next move our score
// would be at best mate_in(ss->ply+1), but if alpha is already bigger because
// Step 6. Static evaluation of the position
if (ss->inCheck)
{
// Step 6. Static evaluation of the position
if (ss->inCheck)
{
+ // Skip early pruning when in check
ss->staticEval = eval = VALUE_NONE;
improving = false;
ss->staticEval = eval = VALUE_NONE;
improving = false;
- goto moves_loop; // Skip early pruning when in check
&& !(PvNode && abs(bestValue) < 2)
&& PieceValue[MG][type_of(movedPiece)] >= PieceValue[MG][type_of(pos.piece_on(to_sq(move)))]
&& !ss->inCheck
&& !(PvNode && abs(bestValue) < 2)
&& PieceValue[MG][type_of(movedPiece)] >= PieceValue[MG][type_of(pos.piece_on(to_sq(move)))]
&& !ss->inCheck
- && ss->staticEval + 267 + 391 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha)
+ && ss->staticEval + 267 + 391 * lmrDepth
+ + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha)
continue;
// See based pruning
continue;
// See based pruning
else if (singularBeta >= beta)
return singularBeta;
else if (singularBeta >= beta)
return singularBeta;
- // If the eval of ttMove is greater than beta we try also if there is an other move that
- // pushes it over beta, if so also produce a cutoff
+ // If the eval of ttMove is greater than beta we try also if there is another
+ // move that pushes it over beta, if so also produce a cutoff.
else if (ttValue >= beta)
{
ss->excludedMove = move;
else if (ttValue >= beta)
{
ss->excludedMove = move;
if (thisThread->ttHitAverage > 473 * TtHitAverageResolution * TtHitAverageWindow / 1024)
r--;
if (thisThread->ttHitAverage > 473 * TtHitAverageResolution * TtHitAverageWindow / 1024)
r--;
- // Reduction if other threads are searching this position.
+ // Reduction if other threads are searching this position
rm.pv.push_back(*m);
// We record how often the best move has been changed in each
rm.pv.push_back(*m);
// We record how often the best move has been changed in each
- // iteration. This information is used for time management: When
+ // iteration. This information is used for time management: when
// the best move changes frequently, we allocate some more time.
if (moveCount > 1)
++thisThread->bestMoveChanges;
// the best move changes frequently, we allocate some more time.
if (moveCount > 1)
++thisThread->bestMoveChanges;
- // Don't search moves with negative SEE values
+ // Do not search moves with negative SEE values
if ( !ss->inCheck && !pos.see_ge(move))
continue;
if ( !ss->inCheck && !pos.see_ge(move))
continue;
- // All legal moves have been searched. A special case: If we're in check
+ // All legal moves have been searched. A special case: if we're in check
// and no legal moves were found, it is checkmate.
if (ss->inCheck && bestValue == -VALUE_INFINITE)
return mated_in(ss->ply); // Plies to mate from the root
// and no legal moves were found, it is checkmate.
if (ss->inCheck && bestValue == -VALUE_INFINITE)
return mated_in(ss->ply); // Plies to mate from the root
// value_to_tt() adjusts a mate or TB score from "plies to mate from the root" to
// value_to_tt() 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.
+ // "plies to mate from the current position". Standard scores are unchanged.
// The function is called before storing a value in the transposition table.
Value value_to_tt(Value v, int ply) {
// The function is called before storing a value in the transposition table.
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
- // 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".
- // However, for mate scores, to avoid potentially false mate scores related to the 50 moves rule,
- // and the graph history interaction, return an optimal TB score instead.
+ // value_from_tt() is the 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
+ // current position) to "plies to mate/be mated (TB win/loss) from the root". However,
+ // for mate scores, to avoid potentially false mate scores related to the 50 moves rule
+ // and the graph history interaction, 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) {
/// MainThread::check_time() is used to print debug info and, more importantly,
/// to detect when we are out of available time and thus stop the search.
/// MainThread::check_time() is used to print debug info and, more importantly,
/// to detect when we are out of available time and thus stop the search.
/// Thread::bestMoveCount(Move move) return best move counter for the given root move
int Thread::best_move_count(Move move) const {
/// Thread::bestMoveCount(Move move) return best move counter for the given root move
int Thread::best_move_count(Move move) const {
return rm != rootMoves.begin() + pvLast ? rm->bestMoveCount : 0;
}
return rm != rootMoves.begin() + pvLast ? rm->bestMoveCount : 0;
}
/// Thread::clear() reset histories, usually before a new game
void Thread::clear() {
/// Thread::clear() reset histories, usually before a new game
void Thread::clear() {
/// Thread::start_searching() wakes up the thread that will start the search
void Thread::start_searching() {
/// Thread::start_searching() wakes up the thread that will start the search
void Thread::start_searching() {
-/// ThreadPool::clear() sets threadPool data to initial values.
+
+/// ThreadPool::clear() sets threadPool data to initial values
void ThreadPool::clear() {
void ThreadPool::clear() {
main()->previousTimeReduction = 1.0;
}
main()->previousTimeReduction = 1.0;
}
/// ThreadPool::start_thinking() wakes up main thread waiting in idle_loop() and
/// returns immediately. Main thread will wake up other threads and start the search.
/// ThreadPool::start_thinking() wakes up main thread waiting in idle_loop() and
/// returns immediately. Main thread will wake up other threads and start the search.
-/// Start non-main threads.
+
+/// Start non-main threads
void ThreadPool::start_searching() {
void ThreadPool::start_searching() {
-/// Wait for non-main threads.
+
+/// Wait for non-main threads
void ThreadPool::wait_for_search_finished() const {
void ThreadPool::wait_for_search_finished() const {
TimeManagement Time; // Our global time management object
TimeManagement Time; // Our global time management object
-/// init() is called at the beginning of the search and calculates the bounds
-/// of time allowed for the current game ply. We currently support:
-// 1) x basetime (+z increment)
-// 2) x moves in y seconds (+z increment)
+
+/// TimeManagement::init() is called at the beginning of the search and calculates
+/// the bounds of time allowed for the current game ply. We currently support:
+// 1) x basetime (+ 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) {
startTime = limits.startTime;
startTime = limits.startTime;
- //Maximum move horizon of 50 moves
+ // Maximum move horizon of 50 moves
int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50;
// Make sure timeLeft is > 0 since we may use it as a divisor
int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50;
// Make sure timeLeft is > 0 since we may use it as a divisor
TranspositionTable TT; // Our global transposition table
TranspositionTable TT; // Our global transposition table
-/// TTEntry::save populates the TTEntry with a new node's data, possibly
+/// TTEntry::save() populates the TTEntry with a new node's data, possibly
/// overwriting an old position. 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) {
/// overwriting an old position. 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) {
/// TranspositionTable::probe() looks up the current position in the transposition
/// 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
/// TranspositionTable::probe() looks up the current position in the transposition
/// 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
/// A TranspositionTable is an array of Cluster, of size clusterCount. Each
/// cluster consists of ClusterSize number of TTEntry. Each non-empty TTEntry
/// contains information on exactly one position. The size of a Cluster should
/// A TranspositionTable is an array of Cluster, of size clusterCount. Each
/// cluster consists of ClusterSize number of TTEntry. Each non-empty TTEntry
/// 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 prefetched when possible.
+/// divide the size of a cache line for best performance, as the cacheline is
+/// prefetched when possible.
class TranspositionTable {
class TranspositionTable {
Options[n] << UCI::Option(v, r(v).first, r(v).second, on_tune);
LastOption = &Options[n];
Options[n] << UCI::Option(v, r(v).first, r(v).second, on_tune);
LastOption = &Options[n];
- // Print formatted parameters, ready to be copy-pasted in fishtest
+ // Print formatted parameters, ready to be copy-pasted in Fishtest
std::cout << n << ","
<< v << ","
<< r(v).first << "," << r(v).second << ","
std::cout << n << ","
<< v << ","
<< r(v).first << "," << r(v).second << ","
return Color(c ^ BLACK); // Toggle color
}
return Color(c ^ BLACK); // Toggle color
}
-constexpr Square flip_rank(Square s) {
+constexpr Square flip_rank(Square s) { // Swap A1 <-> A8
return Square(s ^ SQ_A8);
}
return Square(s ^ SQ_A8);
}
-constexpr Square flip_file(Square s) {
+constexpr Square flip_file(Square s) { // Swap A1 <-> H1
return Square(s ^ SQ_H1);
}
constexpr Piece operator~(Piece pc) {
return Square(s ^ SQ_H1);
}
constexpr Piece operator~(Piece pc) {
- return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
+ return Piece(pc ^ 8); // Swap color of piece B_KNIGHT <-> W_KNIGHT
}
constexpr CastlingRights operator&(Color c, CastlingRights cr) {
}
constexpr CastlingRights operator&(Color c, CastlingRights cr) {
-/// init() initializes the UCI options to their hard-coded default values
+/// UCI::init() initializes the UCI options to their hard-coded default values
void init(OptionsMap& o) {
void init(OptionsMap& o) {