/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <fstream>
#include <iostream>
#include <list>
+#include <mutex>
#include <sstream>
+#include <string_view>
#include <type_traits>
-#include <mutex>
#include "../bitboard.h"
#include "../movegen.h"
namespace {
constexpr int TBPIECES = 7; // Max number of supported pieces
+constexpr int MAX_DTZ = 1 << 18; // Max DTZ supported, large enough to deal with the syzygy TB limit.
enum { BigEndian, LittleEndian };
enum TBType { WDL, DTZ }; // Used as template parameter
inline WDLScore operator-(WDLScore d) { return WDLScore(-int(d)); }
inline Square operator^(Square s, int i) { return Square(int(s) ^ i); }
-const std::string PieceToChar = " PNBRQK pnbrqk";
+constexpr std::string_view PieceToChar = " PNBRQK pnbrqk";
int MapPawns[SQUARE_NB];
int MapB1H1H7[SQUARE_NB];
template<typename T, int LE> T number(void* addr)
{
- static const union { uint32_t i; char c[4]; } Le = { 0x01020304 };
- static const bool IsLittleEndian = (Le.c[0] == 4);
-
T v;
if ((uintptr_t)addr & (alignof(T) - 1)) // Unaligned pointer (very rare)
static_assert(sizeof(SparseEntry) == 6, "SparseEntry must be 6 bytes");
-typedef uint16_t Sym; // Huffman symbol
+using Sym = uint16_t; // Huffman symbol
struct LR {
enum Side { Left, Right };
}
}
- // Memory map the file and check it. File should be already open and will be
- // closed after mapping.
+ // Memory map the file and check it.
uint8_t* map(void** baseAddress, uint64_t* mapping, TBType type) {
-
- assert(is_open());
-
- close(); // Need to re-open to get native file descriptor
+ if (is_open())
+ close(); // Need to re-open to get native file descriptor
#ifndef _WIN32
struct stat statbuf;
// first access, when the corresponding file is memory mapped.
template<TBType Type>
struct TBTable {
- typedef typename std::conditional<Type == WDL, WDLScore, int>::type Ret;
+ using Ret = typename std::conditional<Type == WDL, WDLScore, int>::type;
static constexpr int Sides = Type == WDL ? 2 : 1;
goto encode_remaining; // With pawns we have finished special treatments
}
- // In positions withouth pawns, we further flip the squares to ensure leading
+ // In positions without pawns, we further flip the squares to ensure leading
// piece is below RANK_5.
if (rank_of(squares[0]) > RANK_4)
for (int i = 0; i < size; ++i)
// Rs "together" in 62 * 61 / 2 ways (we divide by 2 because rooks can be
// swapped and still get the same position.)
//
- // In case we have at least 3 unique pieces (inlcuded kings) we encode them
+ // In case we have at least 3 unique pieces (included kings) we encode them
// together.
if (entry->hasUniquePieces) {
+ (squares[1] - adjust1)) * 62
+ squares[2] - adjust2;
- // First piece is on a1-h8 diagonal, second below: map this occurence to
+ // First piece is on a1-h8 diagonal, second below: map this occurrence to
// 6 to differentiate from the above case, rank_of() maps a1-d4 diagonal
// to 0...3 and finally MapB1H1H7[] maps the b1-h1-h7 triangle to 0..27.
else if (off_A1H8(squares[1]))
idx *= d->groupIdx[0];
Square* groupSq = squares + d->groupLen[0];
- // Encode remainig pawns then pieces according to square, in ascending order
+ // Encode remaining pawns then pieces according to square, in ascending order
bool remainingPawns = entry->hasPawns && entry->pawnCount[1];
while (d->groupLen[++next])
// Group together pieces that will be encoded together. The general rule is that
// a group contains pieces of same type and color. The exception is the leading
-// group that, in case of positions withouth pawns, can be formed by 3 different
+// group that, in case of positions without pawns, can be formed by 3 different
// pieces (default) or by the king pair when there is not a unique piece apart
// from the kings. When there are pawns, pawns are always first in pieces[].
//
//
// This ensures unique encoding for the whole position. The order of the
// groups is a per-table parameter and could not follow the canonical leading
- // pawns/pieces -> remainig pawns -> remaining pieces. In particular the
+ // pawns/pieces -> remaining pawns -> remaining pieces. In particular the
// first group is at order[0] position and the remaining pawns, when present,
// are at order[1] position.
bool pp = e.hasPawns && e.pawnCount[1]; // Pawns on both sides
d->groupIdx[1] = idx;
idx *= Binomial[d->groupLen[1]][48 - d->groupLen[0]];
}
- else // Remainig pieces
+ else // Remaining pieces
{
d->groupIdx[next] = idx;
idx *= Binomial[d->groupLen[next]][freeSquares];
d->groupIdx[n] = idx;
}
-// In Recursive Pairing each symbol represents a pair of childern symbols. So
+// In Recursive Pairing each symbol represents a pair of children symbols. So
// read d->btree[] symbols data and expand each one in his left and right child
// symbol until reaching the leafs that represent the symbol value.
uint8_t set_symlen(PairsData* d, Sym s, std::vector<bool>& visited) {
for (auto s : diagonal)
MapA1D1D4[s] = code++;
- // MapKK[] encodes all the 461 possible legal positions of two kings where
+ // MapKK[] encodes all the 462 possible legal positions of two kings where
// the first is in the a1-d1-d4 triangle. If the first king is on the a1-d4
// diagonal, the other one shall not to be above the a1-h8 diagonal.
std::vector<std::pair<int, Square>> bothOnDiagonal;
for (auto p : bothOnDiagonal)
MapKK[p.first][p.second] = code++;
- // Binomial[] stores the Binomial Coefficents using Pascal rule. There
+ // Binomial[] stores the Binomial Coefficients using Pascal rule. There
// are Binomial[k][n] ways to choose k elements from a set of n elements.
Binomial[0][0] = 1;
for (int leadPawnsCnt = 1; leadPawnsCnt <= 5; ++leadPawnsCnt)
for (File f = FILE_A; f <= FILE_D; ++f)
{
- // Restart the index at every file because TB table is splitted
+ // Restart the index at every file because TB table is split
// by file, so we can reuse the same index for different files.
int idx = 0;
// A return value false indicates that not all probes were successful.
bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
- ProbeState result;
+ ProbeState result = OK;
StateInfo st;
// Obtain 50-move counter for the root position
// Check whether a position was repeated since the last zeroing move.
bool rep = pos.has_repeated();
- int dtz, bound = Options["Syzygy50MoveRule"] ? 900 : 1;
+ int dtz, bound = Options["Syzygy50MoveRule"] ? (MAX_DTZ - 100) : 1;
// Probe and rank each move
for (auto& m : rootMoves)
WDLScore wdl = -probe_wdl(pos, &result);
dtz = dtz_before_zeroing(wdl);
}
+ else if (pos.is_draw(1))
+ {
+ // In case a root move leads to a draw by repetition or
+ // 50-move rule, we set dtz to zero. Note: since we are
+ // only 1 ply from the root, this must be a true 3-fold
+ // repetition inside the game history.
+ dtz = 0;
+ }
else
{
// Otherwise, take dtz for the new position and correct by 1 ply
// Better moves are ranked higher. Certain wins are ranked equally.
// Losing moves are ranked equally unless a 50-move draw is in sight.
- int r = dtz > 0 ? (dtz + cnt50 <= 99 && !rep ? 1000 : 1000 - (dtz + cnt50))
- : dtz < 0 ? (-dtz * 2 + cnt50 < 100 ? -1000 : -1000 + (-dtz + cnt50))
+ int r = dtz > 0 ? (dtz + cnt50 <= 99 && !rep ? MAX_DTZ : MAX_DTZ - (dtz + cnt50))
+ : dtz < 0 ? (-dtz * 2 + cnt50 < 100 ? -MAX_DTZ : -MAX_DTZ + (-dtz + cnt50))
: 0;
m.tbRank = r;
// 1 cp to cursed wins and let it grow to 49 cp as the positions gets
// closer to a real win.
m.tbScore = r >= bound ? VALUE_MATE - MAX_PLY - 1
- : r > 0 ? Value((std::max( 3, r - 800) * int(PawnValueEg)) / 200)
+ : r > 0 ? Value((std::max( 3, r - (MAX_DTZ - 200)) * int(PawnValueEg)) / 200)
: r == 0 ? VALUE_DRAW
- : r > -bound ? Value((std::min(-3, r + 800) * int(PawnValueEg)) / 200)
+ : r > -bound ? Value((std::min(-3, r + (MAX_DTZ - 200)) * int(PawnValueEg)) / 200)
: -VALUE_MATE + MAX_PLY + 1;
}
// A return value false indicates that not all probes were successful.
bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves) {
- static const int WDL_to_rank[] = { -1000, -899, 0, 899, 1000 };
+ static const int WDL_to_rank[] = { -MAX_DTZ, -MAX_DTZ + 101, 0, MAX_DTZ - 101, MAX_DTZ };
- ProbeState result;
+ ProbeState result = OK;
StateInfo st;
+ WDLScore wdl;
bool rule50 = Options["Syzygy50MoveRule"];
{
pos.do_move(m.pv[0], st);
- WDLScore wdl = -probe_wdl(pos, &result);
+ if (pos.is_draw(1))
+ wdl = WDLDraw;
+ else
+ wdl = -probe_wdl(pos, &result);
pos.undo_move(m.pv[0]);