X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fsyzygy%2Ftbprobe.cpp;h=13d271fce8a69c32e79cc265414806a826c228ea;hb=fce4cc1829f25fd52c5dd637ab54d867eec065fb;hp=a9378b4ba0914ef72a387743f4f53c4063d33b81;hpb=90c0385724a0d9b6c0737bc2711ad77e315d17ac;p=stockfish
diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp
index a9378b4b..13d271fc 100644
--- a/src/syzygy/tbprobe.cpp
+++ b/src/syzygy/tbprobe.cpp
@@ -1,7 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (c) 2013 Ronald de Man
- Copyright (C) 2016-2019 Marco Costalba, Lucas Braesch
+ 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
@@ -17,32 +16,38 @@
along with this program. If not, see .
*/
+#include "tbprobe.h"
+
+#include
#include
#include
+#include
#include
-#include // For std::memset and std::memcpy
+#include
+#include
#include
#include
+#include
#include
-#include
+#include
#include
+#include
#include
-#include
+#include
+#include
#include "../bitboard.h"
+#include "../misc.h"
#include "../movegen.h"
#include "../position.h"
#include "../search.h"
#include "../types.h"
#include "../uci.h"
-#include "tbprobe.h"
-
#ifndef _WIN32
#include
-#include
#include
-#include
+#include
#else
#define WIN32_LEAN_AND_MEAN
#ifndef NOMINMAX
@@ -51,25 +56,27 @@
#include
#endif
-using namespace Tablebases;
+using namespace Stockfish::Tablebases;
+
+int Stockfish::Tablebases::MaxCardinality;
-int Tablebases::MaxCardinality;
+namespace Stockfish {
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 { KEY, WDL, DTZ }; // Used as template parameter
+enum TBType { WDL, DTZ }; // Used as template parameter
// Each table has a set of flags: all of them refer to DTZ tables, the last one to WDL tables
enum TBFlag { STM = 1, Mapped = 2, WinPlies = 4, LossPlies = 8, Wide = 16, SingleValue = 128 };
inline WDLScore operator-(WDLScore d) { return WDLScore(-int(d)); }
-inline Square operator^=(Square& s, int i) { return s = Square(int(s) ^ i); }
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];
@@ -105,12 +112,9 @@ template<> inline void swap_endian(uint8_t&) {}
template 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)
+ if (uintptr_t(addr) & (alignof(T) - 1)) // Unaligned pointer (very rare)
std::memcpy(&v, addr, sizeof(T));
else
v = *((T*)addr);
@@ -143,7 +147,7 @@ struct SparseEntry {
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 };
@@ -192,7 +196,8 @@ public:
std::stringstream ss(Paths);
std::string path;
- while (std::getline(ss, path, SepChar)) {
+ while (std::getline(ss, path, SepChar))
+ {
fname = path + "/" + f;
std::ifstream::open(fname);
if (is_open())
@@ -200,13 +205,10 @@ public:
}
}
- // 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;
@@ -225,7 +227,9 @@ public:
*mapping = statbuf.st_size;
*baseAddress = mmap(nullptr, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+#if defined(MADV_RANDOM)
madvise(*baseAddress, statbuf.st_size, MADV_RANDOM);
+#endif
::close(fd);
if (*baseAddress == MAP_FAILED)
@@ -235,7 +239,7 @@ public:
}
#else
// Note FILE_FLAG_RANDOM_ACCESS is only a hint to Windows and as such may get ignored.
- HANDLE fd = CreateFile(fname.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
+ HANDLE fd = CreateFileA(fname.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr);
if (fd == INVALID_HANDLE_VALUE)
@@ -259,7 +263,7 @@ public:
exit(EXIT_FAILURE);
}
- *mapping = (uint64_t)mmap;
+ *mapping = uint64_t(mmap);
*baseAddress = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
if (!*baseAddress)
@@ -328,7 +332,7 @@ struct PairsData {
// first access, when the corresponding file is memory mapped.
template
struct TBTable {
- typedef typename std::conditional::type Ret;
+ using Ret = typename std::conditional::type;
static constexpr int Sides = Type == WDL ? 2 : 1;
@@ -404,7 +408,17 @@ TBTable::TBTable(const TBTable& wdl) : TBTable() {
// at init time, accessed at probe time.
class TBTables {
- typedef std::tuple*, TBTable*> Entry;
+ struct Entry
+ {
+ Key key;
+ TBTable* wdl;
+ TBTable* dtz;
+
+ template
+ TBTable* get() const {
+ return (TBTable*)(Type == WDL ? (void*)wdl : (void*)dtz);
+ }
+ };
static constexpr int Size = 1 << 12; // 4K table, indexed by key's 12 lsb
static constexpr int Overflow = 1; // Number of elements allowed to map to the last bucket
@@ -415,22 +429,22 @@ class TBTables {
std::deque> dtzTable;
void insert(Key key, TBTable* wdl, TBTable* dtz) {
- uint32_t homeBucket = (uint32_t)key & (Size - 1);
- Entry entry = std::make_tuple(key, wdl, dtz);
+ uint32_t homeBucket = uint32_t(key) & (Size - 1);
+ Entry entry{ key, wdl, dtz };
// Ensure last element is empty to avoid overflow when looking up
for (uint32_t bucket = homeBucket; bucket < Size + Overflow - 1; ++bucket) {
- Key otherKey = std::get(hashTable[bucket]);
- if (otherKey == key || !std::get(hashTable[bucket])) {
+ Key otherKey = hashTable[bucket].key;
+ if (otherKey == key || !hashTable[bucket].get()) {
hashTable[bucket] = entry;
return;
}
// Robin Hood hashing: If we've probed for longer than this element,
// insert here and search for a new spot for the other element instead.
- uint32_t otherHomeBucket = (uint32_t)otherKey & (Size - 1);
+ uint32_t otherHomeBucket = uint32_t(otherKey) & (Size - 1);
if (otherHomeBucket > homeBucket) {
- swap(entry, hashTable[bucket]);
+ std::swap(entry, hashTable[bucket]);
key = otherKey;
homeBucket = otherHomeBucket;
}
@@ -442,9 +456,9 @@ class TBTables {
public:
template
TBTable* get(Key key) {
- for (const Entry* entry = &hashTable[(uint32_t)key & (Size - 1)]; ; ++entry) {
- if (std::get(*entry) == key || !std::get(*entry))
- return std::get(*entry);
+ for (const Entry* entry = &hashTable[uint32_t(key) & (Size - 1)]; ; ++entry) {
+ if (entry->key == key || !entry->get())
+ return entry->get();
}
}
@@ -475,7 +489,7 @@ void TBTables::add(const std::vector& pieces) {
file.close();
- MaxCardinality = std::max((int)pieces.size(), MaxCardinality);
+ MaxCardinality = std::max(int(pieces.size()), MaxCardinality);
wdlTable.emplace_back(code);
dtzTable.emplace_back(wdlTable.back());
@@ -521,7 +535,7 @@ int decompress_pairs(PairsData* d, uint64_t idx) {
// I(k) = k * d->span + d->span / 2 (1)
// First step is to get the 'k' of the I(k) nearest to our idx, using definition (1)
- uint32_t k = idx / d->span;
+ uint32_t k = uint32_t(idx / d->span);
// Then we read the corresponding SparseIndex[] entry
uint32_t block = number(&d->sparseIndex[k].block);
@@ -546,7 +560,7 @@ int decompress_pairs(PairsData* d, uint64_t idx) {
offset -= d->blockLength[block++] + 1;
// Finally, we find the start address of our block of canonical Huffman symbols
- uint32_t* ptr = (uint32_t*)(d->data + ((uint64_t)block * d->sizeofBlock));
+ uint32_t* ptr = (uint32_t*)(d->data + (uint64_t(block) * d->sizeofBlock));
// Read the first 64 bits in our block, this is a (truncated) sequence of
// unknown number of symbols of unknown length but we know the first one
@@ -555,7 +569,8 @@ int decompress_pairs(PairsData* d, uint64_t idx) {
int buf64Size = 64;
Sym sym;
- while (true) {
+ while (true)
+ {
int len = 0; // This is the symbol length - d->min_sym_len
// Now get the symbol length. For any symbol s64 of length l right-padded
@@ -567,7 +582,7 @@ int decompress_pairs(PairsData* d, uint64_t idx) {
// All the symbols of a given length are consecutive integers (numerical
// sequence property), so we can compute the offset of our symbol of
// length len, stored at the beginning of buf64.
- sym = (buf64 - d->base64[len]) >> (64 - len - d->minSymLen);
+ sym = Sym((buf64 - d->base64[len]) >> (64 - len - d->minSymLen));
// Now add the value of the lowest symbol of length len to get our symbol
sym += number(&d->lowestSym[len]);
@@ -585,7 +600,7 @@ int decompress_pairs(PairsData* d, uint64_t idx) {
if (buf64Size <= 32) { // Refill the buffer
buf64Size += 32;
- buf64 |= (uint64_t)number(ptr++) << (64 - buf64Size);
+ buf64 |= uint64_t(number(ptr++)) << (64 - buf64Size);
}
}
@@ -593,8 +608,8 @@ int decompress_pairs(PairsData* d, uint64_t idx) {
// We binary-search for our value recursively expanding into the left and
// right child symbols until we reach a leaf node where symlen[sym] + 1 == 1
// that will store the value we need.
- while (d->symlen[sym]) {
-
+ while (d->symlen[sym])
+ {
Sym left = d->btree[sym].get();
// If a symbol contains 36 sub-symbols (d->symlen[sym] + 1 = 36) and
@@ -683,7 +698,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
bool blackStronger = (pos.material_key() != entry->key);
int flipColor = (symmetricBlackToMove || blackStronger) * 8;
- int flipSquares = (symmetricBlackToMove || blackStronger) * 070;
+ int flipSquares = (symmetricBlackToMove || blackStronger) * 56;
int stm = (symmetricBlackToMove || blackStronger) ^ pos.side_to_move();
// For pawns, TB files store 4 separate tables according if leading pawn is on
@@ -699,14 +714,14 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
leadPawns = b = pos.pieces(color_of(pc), PAWN);
do
- squares[size++] = pop_lsb(&b) ^ flipSquares;
+ squares[size++] = pop_lsb(b) ^ flipSquares;
while (b);
leadPawnsCnt = size;
std::swap(squares[0], *std::max_element(squares, squares + leadPawnsCnt, pawns_comp));
- tbFile = map_to_queenside(file_of(squares[0]));
+ tbFile = File(edge_distance(file_of(squares[0])));
}
// DTZ tables are one-sided, i.e. they store positions only for white to
@@ -719,7 +734,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
// directly map them to the correct color and square.
b = pos.pieces() ^ leadPawns;
do {
- Square s = pop_lsb(&b);
+ Square s = pop_lsb(b);
squares[size] = s ^ flipSquares;
pieces[size++] = Piece(pos.piece_on(s) ^ flipColor);
} while (b);
@@ -730,8 +745,8 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
// Then we reorder the pieces to have the same sequence as the one stored
// in pieces[i]: the sequence that ensures the best compression.
- for (int i = leadPawnsCnt; i < size; ++i)
- for (int j = i; j < size; ++j)
+ for (int i = leadPawnsCnt; i < size - 1; ++i)
+ for (int j = i + 1; j < size; ++j)
if (d->pieces[i] == pieces[j])
{
std::swap(pieces[i], pieces[j]);
@@ -743,14 +758,14 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
// the triangle A1-D1-D4.
if (file_of(squares[0]) > FILE_D)
for (int i = 0; i < size; ++i)
- squares[i] ^= 7; // Horizontal flip: SQ_H1 -> SQ_A1
+ squares[i] = flip_file(squares[i]);
// Encode leading pawns starting with the one with minimum MapPawns[] and
// proceeding in ascending order.
if (entry->hasPawns) {
idx = LeadPawnIdx[leadPawnsCnt][squares[0]];
- std::sort(squares + 1, squares + leadPawnsCnt, pawns_comp);
+ std::stable_sort(squares + 1, squares + leadPawnsCnt, pawns_comp);
for (int i = 1; i < leadPawnsCnt; ++i)
idx += Binomial[i][MapPawns[squares[i]]];
@@ -758,11 +773,11 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
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)
- squares[i] ^= 070; // Vertical flip: SQ_A8 -> SQ_A1
+ squares[i] = flip_rank(squares[i]);
// Look for the first piece of the leading group not on the A1-D4 diagonal
// and ensure it is mapped below the diagonal.
@@ -770,7 +785,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
if (!off_A1H8(squares[i]))
continue;
- if (off_A1H8(squares[i]) > 0) // A1-H8 diagonal flip: SQ_A3 -> SQ_C3
+ if (off_A1H8(squares[i]) > 0) // A1-H8 diagonal flip: SQ_A3 -> SQ_C1
for (int j = i; j < size; ++j)
squares[j] = Square(((squares[j] >> 3) | (squares[j] << 3)) & 63);
break;
@@ -801,7 +816,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
// 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) {
@@ -816,7 +831,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
+ (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]))
@@ -846,12 +861,12 @@ encode_remaining:
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])
{
- std::sort(groupSq, groupSq + d->groupLen[next]);
+ std::stable_sort(groupSq, groupSq + d->groupLen[next]);
uint64_t n = 0;
// Map down a square if "comes later" than a square in the previous
@@ -874,7 +889,7 @@ encode_remaining:
// 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[].
//
@@ -906,7 +921,7 @@ void set_groups(T& e, PairsData* d, int order[], File f) {
//
// 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
@@ -926,7 +941,7 @@ void set_groups(T& e, PairsData* d, int order[], File f) {
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];
@@ -936,7 +951,7 @@ void set_groups(T& e, PairsData* d, int order[], File f) {
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& visited) {
@@ -975,7 +990,7 @@ uint8_t* set_sizes(PairsData* d, uint8_t* data) {
d->sizeofBlock = 1ULL << *data++;
d->span = 1ULL << *data++;
- d->sparseIndexSize = (tbSize + d->span - 1) / d->span; // Round up
+ d->sparseIndexSize = size_t((tbSize + d->span - 1) / d->span); // Round up
auto padding = number(data++);
d->blocksNum = number(data); data += sizeof(uint32_t);
d->blockLengthSize = d->blocksNum + padding; // Padded to ensure SparseIndex[]
@@ -985,13 +1000,19 @@ uint8_t* set_sizes(PairsData* d, uint8_t* data) {
d->lowestSym = (Sym*)data;
d->base64.resize(d->maxSymLen - d->minSymLen + 1);
+ // See https://en.wikipedia.org/wiki/Huffman_coding
// The canonical code is ordered such that longer symbols (in terms of
// the number of bits of their Huffman code) have lower numeric value,
// so that d->lowestSym[i] >= d->lowestSym[i+1] (when read as LittleEndian).
// Starting from this we compute a base64[] table indexed by symbol length
// and containing 64 bit values so that d->base64[i] >= d->base64[i+1].
- // See http://www.eecs.harvard.edu/~michaelm/E210/huffman.pdf
- for (int i = d->base64.size() - 2; i >= 0; --i) {
+
+ // Implementation note: we first cast the unsigned size_t "base64.size()"
+ // to a signed int "base64_size" variable and then we are able to subtract 2,
+ // avoiding unsigned overflow warnings.
+
+ int base64_size = static_cast(d->base64.size());
+ for (int i = base64_size - 2; i >= 0; --i) {
d->base64[i] = (d->base64[i + 1] + number(&d->lowestSym[i])
- number(&d->lowestSym[i + 1])) / 2;
@@ -1002,10 +1023,10 @@ uint8_t* set_sizes(PairsData* d, uint8_t* data) {
// than d->base64[i+1] and given the above assert condition, we ensure that
// d->base64[i] >= d->base64[i+1]. Moreover for any symbol s64 of length i
// and right-padded to 64 bits holds d->base64[i-1] >= s64 >= d->base64[i].
- for (size_t i = 0; i < d->base64.size(); ++i)
+ for (int i = 0; i < base64_size; ++i)
d->base64[i] <<= 64 - i - d->minSymLen; // Right-padding to 64 bits
- data += d->base64.size() * sizeof(Sym);
+ data += base64_size * sizeof(Sym);
d->symlen.resize(number(data)); data += sizeof(uint16_t);
d->btree = (LR*)data;
@@ -1013,7 +1034,7 @@ uint8_t* set_sizes(PairsData* d, uint8_t* data) {
// frequent adjacent pair of symbols in the source message by a new symbol,
// reevaluating the frequencies of all of the symbol pairs with respect to
// the extended alphabet, and then repeating the process.
- // See http://www.larsson.dogma.net/dcc99.pdf
+ // See https://web.archive.org/web/20201106232444/http://www.larsson.dogma.net/dcc99.pdf
std::vector visited(d->symlen.size());
for (Sym sym = 0; sym < d->symlen.size(); ++sym)
@@ -1033,22 +1054,22 @@ uint8_t* set_dtz_map(TBTable& e, uint8_t* data, File maxFile) {
auto flags = e.get(0, f)->flags;
if (flags & TBFlag::Mapped) {
if (flags & TBFlag::Wide) {
- data += (uintptr_t)data & 1; // Word alignment, we may have a mixed table
+ data += uintptr_t(data) & 1; // Word alignment, we may have a mixed table
for (int i = 0; i < 4; ++i) { // Sequence like 3,x,x,x,1,x,0,2,x,x
- e.get(0, f)->map_idx[i] = (uint16_t)((uint16_t *)data - (uint16_t *)e.map + 1);
+ e.get(0, f)->map_idx[i] = uint16_t((uint16_t*)data - (uint16_t*)e.map + 1);
data += 2 * number(data) + 2;
}
}
else {
for (int i = 0; i < 4; ++i) {
- e.get(0, f)->map_idx[i] = (uint16_t)(data - e.map + 1);
+ e.get(0, f)->map_idx[i] = uint16_t(data - e.map + 1);
data += *data + 1;
}
}
}
}
- return data += (uintptr_t)data & 1; // Word alignment
+ return data += uintptr_t(data) & 1; // Word alignment
}
// Populate entry's PairsData records with data from the just memory mapped file.
@@ -1089,7 +1110,7 @@ void set(T& e, uint8_t* data) {
set_groups(e, e.get(i, f), order[i], f);
}
- data += (uintptr_t)data & 1; // Word alignment
+ data += uintptr_t(data) & 1; // Word alignment
for (File f = FILE_A; f <= maxFile; ++f)
for (int i = 0; i < sides; i++)
@@ -1111,7 +1132,7 @@ void set(T& e, uint8_t* data) {
for (File f = FILE_A; f <= maxFile; ++f)
for (int i = 0; i < sides; i++) {
- data = (uint8_t*)(((uintptr_t)data + 0x3F) & ~0x3F); // 64 byte alignment
+ data = (uint8_t*)((uintptr_t(data) + 0x3F) & ~0x3F); // 64 byte alignment
(d = e.get(i, f))->data = data;
data += d->blocksNum * d->sizeofBlock;
}
@@ -1131,7 +1152,7 @@ void* mapped(TBTable& e, const Position& pos) {
if (e.ready.load(std::memory_order_acquire))
return e.baseAddress; // Could be nullptr if file does not exist
- std::unique_lock lk(mutex);
+ std::scoped_lock lk(mutex);
if (e.ready.load(std::memory_order_relaxed)) // Recheck under lock
return e.baseAddress;
@@ -1191,7 +1212,7 @@ WDLScore search(Position& pos, ProbeState* result) {
auto moveList = MoveList(pos);
size_t totalCount = moveList.size(), moveCount = 0;
- for (const Move& move : moveList)
+ for (const Move move : moveList)
{
if ( !pos.capture(move)
&& (!CheckZeroingMoves || type_of(pos.moved_piece(move)) != PAWN))
@@ -1279,7 +1300,7 @@ void Tablebases::init(const std::string& paths) {
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> bothOnDiagonal;
@@ -1306,7 +1327,7 @@ void Tablebases::init(const std::string& paths) {
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;
@@ -1326,7 +1347,7 @@ void Tablebases::init(const std::string& paths) {
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;
@@ -1344,7 +1365,7 @@ void Tablebases::init(const std::string& paths) {
if (leadPawnsCnt == 1)
{
MapPawns[sq] = availableSquares--;
- MapPawns[sq ^ 7] = availableSquares--; // Horizontal flip
+ MapPawns[flip_file(sq)] = availableSquares--;
}
LeadPawnIdx[leadPawnsCnt][sq] = idx;
idx += Binomial[leadPawnsCnt - 1][MapPawns[sq]];
@@ -1353,7 +1374,7 @@ void Tablebases::init(const std::string& paths) {
LeadPawnsSize[leadPawnsCnt][f] = idx;
}
- // Add entries in TB tables if the corresponding ".rtbw" file exsists
+ // Add entries in TB tables if the corresponding ".rtbw" file exists
for (PieceType p1 = PAWN; p1 < KING; ++p1) {
TBTables.add({KING, p1, KING});
@@ -1430,7 +1451,7 @@ WDLScore Tablebases::probe_wdl(Position& pos, ProbeState* result) {
// If n = 100 immediately after a capture or pawn move, then the position
// is also certainly a win, and during the whole phase until the next
// capture or pawn move, the inequality to be preserved is
-// dtz + 50-movecounter <= 100.
+// dtz + 50-move-counter <= 100.
//
// In short, if a move is available resulting in dtz + 50-move-counter <= 99,
// then do not accept moves leading to dtz + 50-move-counter == 100.
@@ -1460,7 +1481,7 @@ int Tablebases::probe_dtz(Position& pos, ProbeState* result) {
StateInfo st;
int minDTZ = 0xFFFF;
- for (const Move& move : MoveList(pos))
+ for (const Move move : MoveList(pos))
{
bool zeroing = pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN;
@@ -1502,7 +1523,7 @@ int Tablebases::probe_dtz(Position& pos, ProbeState* result) {
// 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
@@ -1511,7 +1532,7 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
// 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)
@@ -1525,6 +1546,14 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& 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
@@ -1546,8 +1575,8 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
// 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;
@@ -1555,9 +1584,9 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
// 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(PawnValue)) / 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(PawnValue)) / 200)
: -VALUE_MATE + MAX_PLY + 1;
}
@@ -1571,10 +1600,11 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
// 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"];
@@ -1583,7 +1613,10 @@ bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves) {
{
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]);
@@ -1600,3 +1633,5 @@ bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves) {
return true;
}
+
+} // namespace Stockfish