/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (c) 2013 Ronald de Man
- Copyright (C) 2016 Marco Costalba, Lucas Braesch
+ Copyright (C) 2016-2017 Marco Costalba, Lucas Braesch
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
// like captures and pawn moves but we can easily recover the correct dtz of the
// previous move if we know the position's WDL score.
int dtz_before_zeroing(WDLScore wdl) {
- return wdl == WDLWin ? 1 :
- wdl == WDLCursedWin ? 101 :
- wdl == WDLCursedLoss ? -101 :
- wdl == WDLLoss ? -1 : 0;
+ return wdl == WDLWin ? 1 :
+ wdl == WDLCursedWin ? 101 :
+ wdl == WDLBlessedLoss ? -101 :
+ wdl == WDLLoss ? -1 : 0;
}
// Return the sign of a number (-1, 0, 1)
int groupLen[TBPIECES+1]; // Number of pieces in a given group: KRKN -> (3, 1)
};
-// Helper struct to avoid to manually define entry copy c'tor as we should
-// because default one is not compatible with std::atomic_bool.
+// Helper struct to avoid manually defining entry copy constructor as we
+// should because the default one is not compatible with std::atomic_bool.
struct Atomic {
Atomic() = default;
Atomic(const Atomic& e) { ready = e.ready.load(); } // MSVC 2013 wants assignment within body
std::atomic_bool ready;
};
-struct WDLEntry : public Atomic {
- WDLEntry(const std::string& code);
- ~WDLEntry();
+// We define types for the different parts of the WLDEntry and DTZEntry with
+// corresponding specializations for pieces or pawns.
+
+struct WLDEntryPiece {
+ PairsData* precomp;
+};
+
+struct WDLEntryPawn {
+ uint8_t pawnCount[2]; // [Lead color / other color]
+ WLDEntryPiece file[2][4]; // [wtm / btm][FILE_A..FILE_D]
+};
+
+struct DTZEntryPiece {
+ PairsData* precomp;
+ uint16_t map_idx[4]; // WDLWin, WDLLoss, WDLCursedWin, WDLBlessedLoss
+ uint8_t* map;
+};
+
+struct DTZEntryPawn {
+ uint8_t pawnCount[2];
+ DTZEntryPiece file[4];
+ uint8_t* map;
+};
+struct TBEntry : public Atomic {
void* baseAddress;
uint64_t mapping;
Key key;
int pieceCount;
bool hasPawns;
bool hasUniquePieces;
+};
+
+// Now the main types: WDLEntry and DTZEntry
+struct WDLEntry : public TBEntry {
+ WDLEntry(const std::string& code);
+ ~WDLEntry();
union {
- struct {
- PairsData* precomp;
- } pieceTable[2]; // [wtm / btm]
-
- struct {
- uint8_t pawnCount[2]; // [Lead color / other color]
- struct {
- PairsData* precomp;
- } file[2][4]; // [wtm / btm][FILE_A..FILE_D]
- } pawnTable;
+ WLDEntryPiece pieceTable[2]; // [wtm / btm]
+ WDLEntryPawn pawnTable;
};
};
-struct DTZEntry : public Atomic {
+struct DTZEntry : public TBEntry {
DTZEntry(const WDLEntry& wdl);
~DTZEntry();
-
- void* baseAddress;
- uint64_t mapping;
- Key key;
- Key key2;
- int pieceCount;
- bool hasPawns;
- bool hasUniquePieces;
union {
- struct {
- PairsData* precomp;
- uint16_t map_idx[4]; // WDLWin, WDLLoss, WDLCursedWin, WDLCursedLoss
- uint8_t* map;
- } pieceTable;
-
- struct {
- uint8_t pawnCount[2];
- struct {
- PairsData* precomp;
- uint16_t map_idx[4];
- } file[4];
- uint8_t* map;
- } pawnTable;
+ DTZEntryPiece pieceTable;
+ DTZEntryPawn pawnTable;
};
};
inline void swap_byte(T& x)
{
char tmp, *c = (char*)&x;
- if (Half) // Fix a MSVC 2015 warning
- for (int i = 0; i < Half; ++i)
- tmp = c[i], c[i] = c[End - i], c[End - i] = tmp;
+ for (int i = 0; i < Half; ++i)
+ tmp = c[i], c[i] = c[End - i], c[End - i] = tmp;
}
+template<> inline void swap_byte<uint8_t, 0, 0>(uint8_t&) {}
template<typename T, int LE> T number(void* addr)
{
const union { uint32_t i; char c[4]; } Le = { 0x01020304 };
const bool IsLittleEndian = (Le.c[0] == 4);
- T v = *((T*)addr);
+ T v;
+
+ if ((uintptr_t)addr & (alignof(T) - 1)) // Unaligned pointer (very rare)
+ std::memcpy(&v, addr, sizeof(T));
+ else
+ v = *((T*)addr);
+
if (LE != IsLittleEndian)
swap_byte(v);
return v;
if ( (wdl == WDLWin && !(flags & TBFlag::WinPlies))
|| (wdl == WDLLoss && !(flags & TBFlag::LossPlies))
|| wdl == WDLCursedWin
- || wdl == WDLCursedLoss)
+ || wdl == WDLBlessedLoss)
value *= 2;
return value + 1;
enum { Split = 1, HasPawns = 2 };
- uint8_t flags = *data++;
+ assert(e.hasPawns == !!(*data & HasPawns));
+ assert((e.key != e.key2) == !!(*data & Split));
- assert(e.hasPawns == !!(flags & HasPawns));
- assert((e.key != e.key2) == !!(flags & Split));
+ data++; // First byte stores flags
const int Sides = IsWDL && (e.key != e.key2) ? 2 : 1;
const File MaxFile = e.hasPawns ? FILE_D : FILE_A;
moveCount++;
- pos.do_move(move, st, pos.gives_check(move));
+ pos.do_move(move, st);
value = -search(pos, result);
pos.undo_move(move);
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 ((StepAttacksBB[KING][s1] | s1) & s2)
continue; // Illegal position
else
MapKK[idx][s2] = code++;
+ }
// Legal positions with both kings on diagonal are encoded as last ones
for (auto p : bothOnDiagonal)
return 0;
if (*result != CHANGE_STM)
- return (dtz + 100 * (wdl == WDLCursedLoss || wdl == WDLCursedWin)) * sign_of(wdl);
+ return (dtz + 100 * (wdl == WDLBlessedLoss || wdl == WDLCursedWin)) * sign_of(wdl);
// DTZ stores results for the other side, so we need to do a 1-ply search and
// find the winning move that minimizes DTZ.
{
bool zeroing = pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN;
- pos.do_move(move, st, pos.gives_check(move));
+ pos.do_move(move, st);
// For zeroing moves we want the dtz of the move _before_ doing it,
// otherwise we will get the dtz of the next move sequence. Search the
// Probe each move
for (size_t i = 0; i < rootMoves.size(); ++i) {
Move move = rootMoves[i].pv[0];
- pos.do_move(move, st, pos.gives_check(move));
+ pos.do_move(move, st);
int v = 0;
if (pos.checkers() && dtz > 0) {
// Use 50-move counter to determine whether the root position is
// won, lost or drawn.
- int wdl = 0;
+ WDLScore wdl = WDLDraw;
if (dtz > 0)
- wdl = (dtz + cnt50 <= 100) ? 2 : 1;
+ wdl = (dtz + cnt50 <= 100) ? WDLWin : WDLCursedWin;
else if (dtz < 0)
- wdl = (-dtz + cnt50 <= 100) ? -2 : -1;
+ wdl = (-dtz + cnt50 <= 100) ? WDLLoss : WDLBlessedLoss;
// Determine the score to report to the user.
score = WDL_to_value[wdl + 2];
// If the position is winning or losing, but too few moves left, adjust the
// score to show how close it is to winning or losing.
// NOTE: int(PawnValueEg) is used as scaling factor in score_to_uci().
- if (wdl == 1 && dtz <= 100)
+ if (wdl == WDLCursedWin && dtz <= 100)
score = (Value)(((200 - dtz - cnt50) * int(PawnValueEg)) / 200);
- else if (wdl == -1 && dtz >= -100)
+ else if (wdl == WDLBlessedLoss && dtz >= -100)
score = -(Value)(((200 + dtz - cnt50) * int(PawnValueEg)) / 200);
// Now be a bit smart about filtering out moves.
// Probe each move
for (size_t i = 0; i < rootMoves.size(); ++i) {
Move move = rootMoves[i].pv[0];
- pos.do_move(move, st, pos.gives_check(move));
+ pos.do_move(move, st);
WDLScore v = -Tablebases::probe_wdl(pos, &result);
pos.undo_move(move);