+ {
+ value = probe_table<WDL>(pos, result);
+
+ if (*result == FAIL)
+ return WDLDraw;
+ }
+
+ // DTZ stores a "don't care" value if bestValue is a win
+ if (bestValue >= value)
+ return *result = ( bestValue > WDLDraw
+ || noMoreMoves ? ZEROING_BEST_MOVE : OK), bestValue;
+
+ return *result = OK, value;
+}
+
+} // namespace
+
+
+/// Tablebases::init() is called at startup and after every change to
+/// "SyzygyPath" UCI option to (re)create the various tables. It is not thread
+/// safe, nor it needs to be.
+void Tablebases::init(const std::string& paths) {
+
+ TBTables.clear();
+ MaxCardinality = 0;
+ TBFile::Paths = paths;
+
+ if (paths.empty() || paths == "<empty>")
+ return;
+
+ // MapB1H1H7[] encodes a square below a1-h8 diagonal to 0..27
+ int code = 0;
+ for (Square s = SQ_A1; s <= SQ_H8; ++s)
+ if (off_A1H8(s) < 0)
+ MapB1H1H7[s] = code++;
+
+ // MapA1D1D4[] encodes a square in the a1-d1-d4 triangle to 0..9
+ std::vector<Square> diagonal;
+ code = 0;
+ for (Square s = SQ_A1; s <= SQ_D4; ++s)
+ if (off_A1H8(s) < 0 && file_of(s) <= FILE_D)
+ MapA1D1D4[s] = code++;
+
+ else if (!off_A1H8(s) && file_of(s) <= FILE_D)
+ diagonal.push_back(s);
+
+ // Diagonal squares are encoded as last ones
+ for (auto s : diagonal)
+ MapA1D1D4[s] = code++;
+
+ // MapKK[] encodes all the 461 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;
+ code = 0;
+ for (int idx = 0; idx < 10; idx++)
+ for (Square s1 = SQ_A1; s1 <= SQ_D4; ++s1)
+ if (MapA1D1D4[s1] == idx && (idx || s1 == SQ_B1)) // SQ_B1 is mapped to 0
+ {
+ for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
+ if ((PseudoAttacks[KING][s1] | s1) & s2)
+ continue; // Illegal position
+
+ else if (!off_A1H8(s1) && off_A1H8(s2) > 0)
+ continue; // First on diagonal, second above
+
+ else if (!off_A1H8(s1) && !off_A1H8(s2))
+ bothOnDiagonal.emplace_back(idx, s2);
+
+ else
+ MapKK[idx][s2] = code++;
+ }
+
+ // Legal positions with both kings on diagonal are encoded as last ones
+ for (auto p : bothOnDiagonal)
+ MapKK[p.first][p.second] = code++;
+
+ // Binomial[] stores the Binomial Coefficents 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 n = 1; n < 64; n++) // Squares
+ for (int k = 0; k < 6 && k <= n; ++k) // Pieces
+ Binomial[k][n] = (k > 0 ? Binomial[k - 1][n - 1] : 0)
+ + (k < n ? Binomial[k ][n - 1] : 0);
+
+ // MapPawns[s] encodes squares a2-h7 to 0..47. This is the number of possible
+ // available squares when the leading one is in 's'. Moreover the pawn with
+ // highest MapPawns[] is the leading pawn, the one nearest the edge and,
+ // among pawns with same file, the one with lowest rank.
+ int availableSquares = 47; // Available squares when lead pawn is in a2
+
+ // Init the tables for the encoding of leading pawns group: with 7-men TB we
+ // can have up to 5 leading pawns (KPPPPPK).
+ 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
+ // by file, so we can reuse the same index for different files.
+ int idx = 0;
+
+ // Sum all possible combinations for a given file, starting with
+ // the leading pawn on rank 2 and increasing the rank.
+ for (Rank r = RANK_2; r <= RANK_7; ++r)
+ {
+ Square sq = make_square(f, r);
+
+ // Compute MapPawns[] at first pass.
+ // If sq is the leading pawn square, any other pawn cannot be
+ // below or more toward the edge of sq. There are 47 available
+ // squares when sq = a2 and reduced by 2 for any rank increase
+ // due to mirroring: sq == a3 -> no a2, h2, so MapPawns[a3] = 45
+ if (leadPawnsCnt == 1)
+ {
+ MapPawns[sq] = availableSquares--;
+ MapPawns[flip_file(sq)] = availableSquares--;
+ }
+ LeadPawnIdx[leadPawnsCnt][sq] = idx;
+ idx += Binomial[leadPawnsCnt - 1][MapPawns[sq]];
+ }
+ // After a file is traversed, store the cumulated per-file index
+ LeadPawnsSize[leadPawnsCnt][f] = idx;
+ }
+
+ // Add entries in TB tables if the corresponding ".rtbw" file exsists
+ for (PieceType p1 = PAWN; p1 < KING; ++p1) {
+ TBTables.add({KING, p1, KING});
+
+ for (PieceType p2 = PAWN; p2 <= p1; ++p2) {
+ TBTables.add({KING, p1, p2, KING});
+ TBTables.add({KING, p1, KING, p2});
+
+ for (PieceType p3 = PAWN; p3 < KING; ++p3)
+ TBTables.add({KING, p1, p2, KING, p3});
+
+ for (PieceType p3 = PAWN; p3 <= p2; ++p3) {
+ TBTables.add({KING, p1, p2, p3, KING});
+
+ for (PieceType p4 = PAWN; p4 <= p3; ++p4) {
+ TBTables.add({KING, p1, p2, p3, p4, KING});
+
+ for (PieceType p5 = PAWN; p5 <= p4; ++p5)
+ TBTables.add({KING, p1, p2, p3, p4, p5, KING});
+
+ for (PieceType p5 = PAWN; p5 < KING; ++p5)
+ TBTables.add({KING, p1, p2, p3, p4, KING, p5});
+ }
+
+ for (PieceType p4 = PAWN; p4 < KING; ++p4) {
+ TBTables.add({KING, p1, p2, p3, KING, p4});
+
+ for (PieceType p5 = PAWN; p5 <= p4; ++p5)
+ TBTables.add({KING, p1, p2, p3, KING, p4, p5});
+ }
+ }
+
+ for (PieceType p3 = PAWN; p3 <= p1; ++p3)
+ for (PieceType p4 = PAWN; p4 <= (p1 == p3 ? p2 : p3); ++p4)
+ TBTables.add({KING, p1, p2, KING, p3, p4});