mirror of
https://github.com/sockspls/badfish
synced 2025-05-02 01:29:36 +00:00
syzygy clean-up + unit test
This commit is contained in:
parent
ee7a68ea5f
commit
9173d29c41
4 changed files with 4181 additions and 1897 deletions
2016
src/syzygy/syzygy.epd
Normal file
2016
src/syzygy/syzygy.epd
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -5,30 +5,20 @@
|
|||
#ifndef TBCORE_H
|
||||
#define TBCORE_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pthread.h>
|
||||
#define SEP_CHAR ':'
|
||||
#define FD int
|
||||
#define FD_ERR -1
|
||||
#else
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#define SEP_CHAR ';'
|
||||
#define FD HANDLE
|
||||
#define FD_ERR INVALID_HANDLE_VALUE
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#define LOCK_T pthread_mutex_t
|
||||
#define LOCK_INIT(x) pthread_mutex_init(&(x), NULL)
|
||||
#define LOCK(x) pthread_mutex_lock(&(x))
|
||||
#define UNLOCK(x) pthread_mutex_unlock(&(x))
|
||||
#else
|
||||
#define LOCK_T HANDLE
|
||||
#define LOCK_INIT(x) do { x = CreateMutex(NULL, FALSE, NULL); } while (0)
|
||||
#define LOCK(x) WaitForSingleObject(x, INFINITE)
|
||||
#define UNLOCK(x) ReleaseMutex(x)
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#define BSWAP32(v) __builtin_bswap32(v)
|
||||
#define BSWAP64(v) __builtin_bswap64(v)
|
||||
|
@ -43,27 +33,22 @@
|
|||
#define DTZDIR "RTBZDIR"
|
||||
#define TBPIECES 6
|
||||
|
||||
typedef unsigned long long uint64;
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned char ubyte;
|
||||
typedef unsigned short ushort;
|
||||
|
||||
const ubyte WDL_MAGIC[4] = { 0x71, 0xe8, 0x23, 0x5d };
|
||||
const ubyte DTZ_MAGIC[4] = { 0xd7, 0x66, 0x0c, 0xa5 };
|
||||
const uint8_t WDL_MAGIC[4] = { 0x71, 0xe8, 0x23, 0x5d };
|
||||
const uint8_t DTZ_MAGIC[4] = { 0xd7, 0x66, 0x0c, 0xa5 };
|
||||
|
||||
#define TBHASHBITS 10
|
||||
|
||||
struct TBHashEntry;
|
||||
|
||||
typedef uint64 base_t;
|
||||
typedef uint64_t base_t;
|
||||
|
||||
struct PairsData {
|
||||
char *indextable;
|
||||
ushort *sizetable;
|
||||
ubyte *data;
|
||||
ushort *offset;
|
||||
ubyte *symlen;
|
||||
ubyte *sympat;
|
||||
uint16_t *sizetable;
|
||||
uint8_t *data;
|
||||
uint16_t *offset;
|
||||
uint8_t *symlen;
|
||||
uint8_t *sympat;
|
||||
int blocksize;
|
||||
int idxbits;
|
||||
int min_len;
|
||||
|
@ -72,12 +57,12 @@ struct PairsData {
|
|||
|
||||
struct TBEntry {
|
||||
char *data;
|
||||
uint64 key;
|
||||
uint64 mapping;
|
||||
ubyte ready;
|
||||
ubyte num;
|
||||
ubyte symmetric;
|
||||
ubyte has_pawns;
|
||||
uint64_t key;
|
||||
uint64_t mapping;
|
||||
uint8_t ready;
|
||||
uint8_t num;
|
||||
uint8_t symmetric;
|
||||
uint8_t has_pawns;
|
||||
}
|
||||
#ifndef _WIN32
|
||||
__attribute__((__may_alias__))
|
||||
|
@ -86,82 +71,82 @@ __attribute__((__may_alias__))
|
|||
|
||||
struct TBEntry_piece {
|
||||
char *data;
|
||||
uint64 key;
|
||||
uint64 mapping;
|
||||
ubyte ready;
|
||||
ubyte num;
|
||||
ubyte symmetric;
|
||||
ubyte has_pawns;
|
||||
ubyte enc_type;
|
||||
uint64_t key;
|
||||
uint64_t mapping;
|
||||
uint8_t ready;
|
||||
uint8_t num;
|
||||
uint8_t symmetric;
|
||||
uint8_t has_pawns;
|
||||
uint8_t enc_type;
|
||||
struct PairsData *precomp[2];
|
||||
int factor[2][TBPIECES];
|
||||
ubyte pieces[2][TBPIECES];
|
||||
ubyte norm[2][TBPIECES];
|
||||
uint8_t pieces[2][TBPIECES];
|
||||
uint8_t norm[2][TBPIECES];
|
||||
};
|
||||
|
||||
struct TBEntry_pawn {
|
||||
char *data;
|
||||
uint64 key;
|
||||
uint64 mapping;
|
||||
ubyte ready;
|
||||
ubyte num;
|
||||
ubyte symmetric;
|
||||
ubyte has_pawns;
|
||||
ubyte pawns[2];
|
||||
uint64_t key;
|
||||
uint64_t mapping;
|
||||
uint8_t ready;
|
||||
uint8_t num;
|
||||
uint8_t symmetric;
|
||||
uint8_t has_pawns;
|
||||
uint8_t pawns[2];
|
||||
struct {
|
||||
struct PairsData *precomp[2];
|
||||
int factor[2][TBPIECES];
|
||||
ubyte pieces[2][TBPIECES];
|
||||
ubyte norm[2][TBPIECES];
|
||||
uint8_t pieces[2][TBPIECES];
|
||||
uint8_t norm[2][TBPIECES];
|
||||
} file[4];
|
||||
};
|
||||
|
||||
struct DTZEntry_piece {
|
||||
char *data;
|
||||
uint64 key;
|
||||
uint64 mapping;
|
||||
ubyte ready;
|
||||
ubyte num;
|
||||
ubyte symmetric;
|
||||
ubyte has_pawns;
|
||||
ubyte enc_type;
|
||||
uint64_t key;
|
||||
uint64_t mapping;
|
||||
uint8_t ready;
|
||||
uint8_t num;
|
||||
uint8_t symmetric;
|
||||
uint8_t has_pawns;
|
||||
uint8_t enc_type;
|
||||
struct PairsData *precomp;
|
||||
int factor[TBPIECES];
|
||||
ubyte pieces[TBPIECES];
|
||||
ubyte norm[TBPIECES];
|
||||
ubyte flags; // accurate, mapped, side
|
||||
ushort map_idx[4];
|
||||
ubyte *map;
|
||||
uint8_t pieces[TBPIECES];
|
||||
uint8_t norm[TBPIECES];
|
||||
uint8_t flags; // accurate, mapped, side
|
||||
uint16_t map_idx[4];
|
||||
uint8_t *map;
|
||||
};
|
||||
|
||||
struct DTZEntry_pawn {
|
||||
char *data;
|
||||
uint64 key;
|
||||
uint64 mapping;
|
||||
ubyte ready;
|
||||
ubyte num;
|
||||
ubyte symmetric;
|
||||
ubyte has_pawns;
|
||||
ubyte pawns[2];
|
||||
uint64_t key;
|
||||
uint64_t mapping;
|
||||
uint8_t ready;
|
||||
uint8_t num;
|
||||
uint8_t symmetric;
|
||||
uint8_t has_pawns;
|
||||
uint8_t pawns[2];
|
||||
struct {
|
||||
struct PairsData *precomp;
|
||||
int factor[TBPIECES];
|
||||
ubyte pieces[TBPIECES];
|
||||
ubyte norm[TBPIECES];
|
||||
uint8_t pieces[TBPIECES];
|
||||
uint8_t norm[TBPIECES];
|
||||
} file[4];
|
||||
ubyte flags[4];
|
||||
ushort map_idx[4][4];
|
||||
ubyte *map;
|
||||
uint8_t flags[4];
|
||||
uint16_t map_idx[4][4];
|
||||
uint8_t *map;
|
||||
};
|
||||
|
||||
struct TBHashEntry {
|
||||
uint64 key;
|
||||
uint64_t key;
|
||||
struct TBEntry *ptr;
|
||||
};
|
||||
|
||||
struct DTZTableEntry {
|
||||
uint64 key1;
|
||||
uint64 key2;
|
||||
uint64_t key1;
|
||||
uint64_t key2;
|
||||
struct TBEntry *entry;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
this code to other chess engines.
|
||||
*/
|
||||
|
||||
#define NOMINMAX
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../position.h"
|
||||
|
@ -29,41 +27,41 @@ int Tablebases::MaxCardinality = 0;
|
|||
|
||||
// Given a position with 6 or fewer pieces, produce a text string
|
||||
// of the form KQPvKRP, where "KQP" represents the white pieces if
|
||||
// mirror == 0 and the black pieces if mirror == 1.
|
||||
static void prt_str(Position& pos, char *str, int mirror)
|
||||
// mirror == false and the black pieces if mirror == true.
|
||||
static std::string prt_str(Position& pos, bool mirror)
|
||||
{
|
||||
Color color;
|
||||
PieceType pt;
|
||||
int i;
|
||||
std::string s;
|
||||
|
||||
color = !mirror ? WHITE : BLACK;
|
||||
for (pt = KING; pt >= PAWN; --pt)
|
||||
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
||||
*str++ = pchr[6 - pt];
|
||||
*str++ = 'v';
|
||||
color = ~color;
|
||||
for (pt = KING; pt >= PAWN; --pt)
|
||||
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
||||
*str++ = pchr[6 - pt];
|
||||
*str++ = 0;
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
Color color = Color(i ^ mirror);
|
||||
|
||||
for (PieceType pt = KING; pt >= PAWN; --pt)
|
||||
for (Bitboard b = pos.pieces(color, pt); b; b &= b - 1)
|
||||
s += pchr[pt];
|
||||
|
||||
if (i == 0)
|
||||
s += 'v';
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// Given a position, produce a 64-bit material signature key.
|
||||
// If the engine supports such a key, it should equal the engine's key.
|
||||
static uint64 calc_key(Position& pos, int mirror)
|
||||
static uint64_t calc_key(Position& pos, bool mirror)
|
||||
{
|
||||
Color color;
|
||||
PieceType pt;
|
||||
int i;
|
||||
uint64 key = 0;
|
||||
uint64_t key = 0;
|
||||
|
||||
color = !mirror ? WHITE : BLACK;
|
||||
for (pt = PAWN; pt <= KING; ++pt)
|
||||
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
||||
Color color = mirror ? BLACK: WHITE;
|
||||
|
||||
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
||||
for (int i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
||||
key ^= Zobrist::psq[WHITE][pt][i - 1];
|
||||
|
||||
color = ~color;
|
||||
for (pt = PAWN; pt <= KING; ++pt)
|
||||
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
||||
|
||||
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
||||
for (int i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
||||
key ^= Zobrist::psq[BLACK][pt][i - 1];
|
||||
|
||||
return key;
|
||||
|
@ -73,26 +71,27 @@ static uint64 calc_key(Position& pos, int mirror)
|
|||
// defined by pcs[16], where pcs[1], ..., pcs[6] is the number of white
|
||||
// pawns, ..., kings and pcs[9], ..., pcs[14] is the number of black
|
||||
// pawns, ..., kings.
|
||||
static uint64 calc_key_from_pcs(int *pcs, int mirror)
|
||||
static uint64_t calc_key_from_pcs(int *pcs, bool mirror)
|
||||
{
|
||||
int color;
|
||||
PieceType pt;
|
||||
int i;
|
||||
uint64 key = 0;
|
||||
uint64_t key = 0;
|
||||
|
||||
color = !mirror ? 0 : 8;
|
||||
for (pt = PAWN; pt <= KING; ++pt)
|
||||
for (i = 0; i < pcs[color + pt]; i++)
|
||||
Color color = mirror ? BLACK : WHITE;
|
||||
|
||||
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
||||
for (int i = 0; i < pcs[8 * color + pt]; i++)
|
||||
key ^= Zobrist::psq[WHITE][pt][i];
|
||||
color ^= 8;
|
||||
for (pt = PAWN; pt <= KING; ++pt)
|
||||
for (i = 0; i < pcs[color + pt]; i++)
|
||||
|
||||
color = ~color;
|
||||
|
||||
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
||||
for (int i = 0; i < pcs[8 * color + pt]; i++)
|
||||
key ^= Zobrist::psq[BLACK][pt][i];
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
bool is_little_endian() {
|
||||
bool is_little_endian()
|
||||
{
|
||||
union {
|
||||
int i;
|
||||
char c[sizeof(int)];
|
||||
|
@ -101,7 +100,7 @@ bool is_little_endian() {
|
|||
return x.c[0] == 1;
|
||||
}
|
||||
|
||||
static ubyte decompress_pairs(struct PairsData *d, uint64 idx)
|
||||
static uint8_t decompress_pairs(PairsData *d, uint64_t idx)
|
||||
{
|
||||
static const bool isLittleEndian = is_little_endian();
|
||||
return isLittleEndian ? decompress_pairs<true >(d, idx)
|
||||
|
@ -111,12 +110,12 @@ static ubyte decompress_pairs(struct PairsData *d, uint64 idx)
|
|||
// probe_wdl_table and probe_dtz_table require similar adaptations.
|
||||
static int probe_wdl_table(Position& pos, int *success)
|
||||
{
|
||||
struct TBEntry *ptr;
|
||||
struct TBHashEntry *ptr2;
|
||||
uint64 idx;
|
||||
uint64 key;
|
||||
TBEntry *ptr;
|
||||
TBHashEntry *ptr2;
|
||||
uint64_t idx;
|
||||
uint64_t key;
|
||||
int i;
|
||||
ubyte res;
|
||||
uint8_t res;
|
||||
int p[TBPIECES];
|
||||
|
||||
// Obtain the position's material signature key.
|
||||
|
@ -127,25 +126,31 @@ static int probe_wdl_table(Position& pos, int *success)
|
|||
return 0;
|
||||
|
||||
ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
|
||||
|
||||
for (i = 0; i < HSHMAX; i++)
|
||||
if (ptr2[i].key == key) break;
|
||||
if (ptr2[i].key == key)
|
||||
break;
|
||||
|
||||
if (i == HSHMAX) {
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr = ptr2[i].ptr;
|
||||
|
||||
if (!ptr->ready) {
|
||||
LOCK(TB_mutex);
|
||||
TB_mutex.lock();
|
||||
|
||||
if (!ptr->ready) {
|
||||
char str[16];
|
||||
prt_str(pos, str, ptr->key != key);
|
||||
if (!init_table_wdl(ptr, str)) {
|
||||
std::string s = prt_str(pos, ptr->key != key);
|
||||
|
||||
if (!init_table_wdl(ptr, s)) {
|
||||
ptr2[i].key = 0ULL;
|
||||
*success = 0;
|
||||
UNLOCK(TB_mutex);
|
||||
TB_mutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Memory barrier to ensure ptr->ready = 1 is not reordered.
|
||||
#ifdef _MSC_VER
|
||||
_ReadWriteBarrier();
|
||||
|
@ -154,10 +159,12 @@ static int probe_wdl_table(Position& pos, int *success)
|
|||
#endif
|
||||
ptr->ready = 1;
|
||||
}
|
||||
UNLOCK(TB_mutex);
|
||||
|
||||
TB_mutex.unlock();
|
||||
}
|
||||
|
||||
int bside, mirror, cmirror;
|
||||
|
||||
if (!ptr->symmetric) {
|
||||
if (key != ptr->key) {
|
||||
cmirror = 8;
|
||||
|
@ -177,34 +184,42 @@ static int probe_wdl_table(Position& pos, int *success)
|
|||
// pc[i] ^ cmirror, where 1 = white pawn, ..., 14 = black king.
|
||||
// Pieces of the same type are guaranteed to be consecutive.
|
||||
if (!ptr->has_pawns) {
|
||||
struct TBEntry_piece *entry = (struct TBEntry_piece *)ptr;
|
||||
ubyte *pc = entry->pieces[bside];
|
||||
TBEntry_piece *entry = (TBEntry_piece *)ptr;
|
||||
uint8_t *pc = entry->pieces[bside];
|
||||
|
||||
for (i = 0; i < entry->num;) {
|
||||
Bitboard bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
|
||||
(PieceType)(pc[i] & 0x07));
|
||||
|
||||
do {
|
||||
p[i++] = pop_lsb(&bb);
|
||||
} while (bb);
|
||||
}
|
||||
|
||||
idx = encode_piece(entry, entry->norm[bside], p, entry->factor[bside]);
|
||||
res = decompress_pairs(entry->precomp[bside], idx);
|
||||
} else {
|
||||
struct TBEntry_pawn *entry = (struct TBEntry_pawn *)ptr;
|
||||
TBEntry_pawn *entry = (TBEntry_pawn *)ptr;
|
||||
int k = entry->file[0].pieces[0][0] ^ cmirror;
|
||||
Bitboard bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07));
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
p[i++] = pop_lsb(&bb) ^ mirror;
|
||||
} while (bb);
|
||||
|
||||
int f = pawn_file(entry, p);
|
||||
ubyte *pc = entry->file[f].pieces[bside];
|
||||
uint8_t *pc = entry->file[f].pieces[bside];
|
||||
|
||||
for (; i < entry->num;) {
|
||||
bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
|
||||
(PieceType)(pc[i] & 0x07));
|
||||
|
||||
do {
|
||||
p[i++] = pop_lsb(&bb) ^ mirror;
|
||||
} while (bb);
|
||||
}
|
||||
|
||||
idx = encode_pawn(entry, entry->file[f].norm[bside], p, entry->file[f].factor[bside]);
|
||||
res = decompress_pairs(entry->file[f].precomp[bside], idx);
|
||||
}
|
||||
|
@ -214,49 +229,61 @@ static int probe_wdl_table(Position& pos, int *success)
|
|||
|
||||
static int probe_dtz_table(Position& pos, int wdl, int *success)
|
||||
{
|
||||
struct TBEntry *ptr;
|
||||
uint64 idx;
|
||||
TBEntry *ptr;
|
||||
uint64_t idx;
|
||||
int i, res;
|
||||
int p[TBPIECES];
|
||||
|
||||
// Obtain the position's material signature key.
|
||||
uint64 key = pos.material_key();
|
||||
uint64_t key = pos.material_key();
|
||||
|
||||
if (DTZ_table[0].key1 != key && DTZ_table[0].key2 != key) {
|
||||
for (i = 1; i < DTZ_ENTRIES; i++)
|
||||
if (DTZ_table[i].key1 == key) break;
|
||||
if (DTZ_table[i].key1 == key)
|
||||
break;
|
||||
|
||||
if (i < DTZ_ENTRIES) {
|
||||
struct DTZTableEntry table_entry = DTZ_table[i];
|
||||
DTZTableEntry table_entry = DTZ_table[i];
|
||||
|
||||
for (; i > 0; i--)
|
||||
DTZ_table[i] = DTZ_table[i - 1];
|
||||
|
||||
DTZ_table[0] = table_entry;
|
||||
} else {
|
||||
struct TBHashEntry *ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
|
||||
TBHashEntry *ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
|
||||
|
||||
for (i = 0; i < HSHMAX; i++)
|
||||
if (ptr2[i].key == key) break;
|
||||
if (ptr2[i].key == key)
|
||||
break;
|
||||
|
||||
if (i == HSHMAX) {
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr = ptr2[i].ptr;
|
||||
char str[16];
|
||||
int mirror = (ptr->key != key);
|
||||
prt_str(pos, str, mirror);
|
||||
bool mirror = (ptr->key != key);
|
||||
std::string s = prt_str(pos, mirror);
|
||||
|
||||
if (DTZ_table[DTZ_ENTRIES - 1].entry)
|
||||
free_dtz_entry(DTZ_table[DTZ_ENTRIES-1].entry);
|
||||
|
||||
for (i = DTZ_ENTRIES - 1; i > 0; i--)
|
||||
DTZ_table[i] = DTZ_table[i - 1];
|
||||
load_dtz_table(str, calc_key(pos, mirror), calc_key(pos, !mirror));
|
||||
|
||||
load_dtz_table(s, calc_key(pos, mirror), calc_key(pos, !mirror));
|
||||
}
|
||||
}
|
||||
|
||||
ptr = DTZ_table[0].entry;
|
||||
|
||||
if (!ptr) {
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bside, mirror, cmirror;
|
||||
|
||||
if (!ptr->symmetric) {
|
||||
if (key != ptr->key) {
|
||||
cmirror = 8;
|
||||
|
@ -273,20 +300,25 @@ static int probe_dtz_table(Position& pos, int wdl, int *success)
|
|||
}
|
||||
|
||||
if (!ptr->has_pawns) {
|
||||
struct DTZEntry_piece *entry = (struct DTZEntry_piece *)ptr;
|
||||
DTZEntry_piece *entry = (DTZEntry_piece *)ptr;
|
||||
|
||||
if ((entry->flags & 1) != bside && !entry->symmetric) {
|
||||
*success = -1;
|
||||
return 0;
|
||||
}
|
||||
ubyte *pc = entry->pieces;
|
||||
|
||||
uint8_t *pc = entry->pieces;
|
||||
|
||||
for (i = 0; i < entry->num;) {
|
||||
Bitboard bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
|
||||
(PieceType)(pc[i] & 0x07));
|
||||
|
||||
do {
|
||||
p[i++] = pop_lsb(&bb);
|
||||
} while (bb);
|
||||
}
|
||||
idx = encode_piece((struct TBEntry_piece *)entry, entry->norm, p, entry->factor);
|
||||
|
||||
idx = encode_piece((TBEntry_piece *)entry, entry->norm, p, entry->factor);
|
||||
res = decompress_pairs(entry->precomp, idx);
|
||||
|
||||
if (entry->flags & 2)
|
||||
|
@ -295,27 +327,34 @@ static int probe_dtz_table(Position& pos, int wdl, int *success)
|
|||
if (!(entry->flags & pa_flags[wdl + 2]) || (wdl & 1))
|
||||
res *= 2;
|
||||
} else {
|
||||
struct DTZEntry_pawn *entry = (struct DTZEntry_pawn *)ptr;
|
||||
DTZEntry_pawn *entry = (DTZEntry_pawn *)ptr;
|
||||
int k = entry->file[0].pieces[0] ^ cmirror;
|
||||
Bitboard bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07));
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
p[i++] = pop_lsb(&bb) ^ mirror;
|
||||
} while (bb);
|
||||
int f = pawn_file((struct TBEntry_pawn *)entry, p);
|
||||
|
||||
int f = pawn_file((TBEntry_pawn *)entry, p);
|
||||
|
||||
if ((entry->flags[f] & 1) != bside) {
|
||||
*success = -1;
|
||||
return 0;
|
||||
}
|
||||
ubyte *pc = entry->file[f].pieces;
|
||||
|
||||
uint8_t *pc = entry->file[f].pieces;
|
||||
|
||||
for (; i < entry->num;) {
|
||||
bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
|
||||
(PieceType)(pc[i] & 0x07));
|
||||
|
||||
do {
|
||||
p[i++] = pop_lsb(&bb) ^ mirror;
|
||||
} while (bb);
|
||||
}
|
||||
idx = encode_pawn((struct TBEntry_pawn *)entry, entry->file[f].norm, p, entry->file[f].factor);
|
||||
|
||||
idx = encode_pawn((TBEntry_pawn *)entry, entry->file[f].norm, p, entry->file[f].factor);
|
||||
res = decompress_pairs(entry->file[f].precomp, idx);
|
||||
|
||||
if (entry->flags[f] & 2)
|
||||
|
@ -335,6 +374,7 @@ static ExtMove *add_underprom_caps(Position& pos, ExtMove *stack, ExtMove *end)
|
|||
|
||||
for (moves = stack; moves < end; moves++) {
|
||||
Move move = moves->move;
|
||||
|
||||
if (type_of(move) == PROMOTION && !pos.empty(to_sq(move))) {
|
||||
(*extra++).move = (Move)(move - (1 << 12));
|
||||
(*extra++).move = (Move)(move - (2 << 12));
|
||||
|
@ -365,24 +405,33 @@ static int probe_ab(Position& pos, int alpha, int beta, int *success)
|
|||
|
||||
for (moves = stack; moves < end; moves++) {
|
||||
Move capture = moves->move;
|
||||
|
||||
if (!pos.capture(capture) || type_of(capture) == ENPASSANT
|
||||
|| !pos.legal(capture, ci.pinned))
|
||||
continue;
|
||||
|
||||
pos.do_move(capture, st, pos.gives_check(capture, ci));
|
||||
v = -probe_ab(pos, -beta, -alpha, success);
|
||||
pos.undo_move(capture);
|
||||
if (*success == 0) return 0;
|
||||
|
||||
if (*success == 0)
|
||||
return 0;
|
||||
|
||||
if (v > alpha) {
|
||||
if (v >= beta) {
|
||||
*success = 2;
|
||||
return v;
|
||||
}
|
||||
|
||||
alpha = v;
|
||||
}
|
||||
}
|
||||
|
||||
v = probe_wdl_table(pos, success);
|
||||
if (*success == 0) return 0;
|
||||
|
||||
if (*success == 0)
|
||||
return 0;
|
||||
|
||||
if (alpha >= v) {
|
||||
*success = 1 + (alpha > 0);
|
||||
return alpha;
|
||||
|
@ -410,12 +459,14 @@ int Tablebases::probe_wdl(Position& pos, int *success)
|
|||
// If en passant is not possible, we are done.
|
||||
if (pos.ep_square() == SQ_NONE)
|
||||
return v;
|
||||
if (!(*success)) return 0;
|
||||
|
||||
if (*success == 0)
|
||||
return 0;
|
||||
|
||||
// Now handle en passant.
|
||||
int v1 = -3;
|
||||
// Generate (at least) all legal en passant captures.
|
||||
ExtMove stack[192];
|
||||
ExtMove stack[MAX_MOVES];
|
||||
ExtMove *moves, *end;
|
||||
StateInfo st;
|
||||
|
||||
|
@ -428,32 +479,45 @@ int Tablebases::probe_wdl(Position& pos, int *success)
|
|||
|
||||
for (moves = stack; moves < end; moves++) {
|
||||
Move capture = moves->move;
|
||||
|
||||
if (type_of(capture) != ENPASSANT
|
||||
|| !pos.legal(capture, ci.pinned))
|
||||
continue;
|
||||
|
||||
pos.do_move(capture, st, pos.gives_check(capture, ci));
|
||||
int v0 = -probe_ab(pos, -2, 2, success);
|
||||
pos.undo_move(capture);
|
||||
if (*success == 0) return 0;
|
||||
|
||||
if (*success == 0)
|
||||
return 0;
|
||||
|
||||
if (v0 > v1) v1 = v0;
|
||||
}
|
||||
|
||||
if (v1 > -3) {
|
||||
if (v1 >= v) v = v1;
|
||||
else if (v == 0) {
|
||||
// Check whether there is at least one legal non-ep move.
|
||||
for (moves = stack; moves < end; moves++) {
|
||||
Move capture = moves->move;
|
||||
|
||||
if (type_of(capture) == ENPASSANT) continue;
|
||||
if (pos.legal(capture, ci.pinned)) break;
|
||||
|
||||
if (pos.legal(capture, ci.pinned))
|
||||
break;
|
||||
}
|
||||
|
||||
if (moves == end && !pos.checkers()) {
|
||||
end = generate<QUIETS>(pos, end);
|
||||
|
||||
for (; moves < end; moves++) {
|
||||
Move move = moves->move;
|
||||
|
||||
if (pos.legal(move, ci.pinned))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If not, then we are forced to play the losing ep capture.
|
||||
if (moves == end)
|
||||
v = v1;
|
||||
|
@ -469,6 +533,7 @@ static int probe_dtz_no_ep(Position& pos, int *success)
|
|||
int wdl, dtz;
|
||||
|
||||
wdl = probe_ab(pos, -2, 2, success);
|
||||
|
||||
if (*success == 0) return 0;
|
||||
|
||||
if (wdl == 0) return 0;
|
||||
|
@ -476,7 +541,7 @@ static int probe_dtz_no_ep(Position& pos, int *success)
|
|||
if (*success == 2)
|
||||
return wdl == 2 ? 1 : 101;
|
||||
|
||||
ExtMove stack[192];
|
||||
ExtMove stack[MAX_MOVES];
|
||||
ExtMove *moves, *end = NULL;
|
||||
StateInfo st;
|
||||
CheckInfo ci(pos);
|
||||
|
@ -491,51 +556,69 @@ static int probe_dtz_no_ep(Position& pos, int *success)
|
|||
|
||||
for (moves = stack; moves < end; moves++) {
|
||||
Move move = moves->move;
|
||||
|
||||
if (type_of(pos.moved_piece(move)) != PAWN || pos.capture(move)
|
||||
|| !pos.legal(move, ci.pinned))
|
||||
continue;
|
||||
|
||||
pos.do_move(move, st, pos.gives_check(move, ci));
|
||||
int v = -probe_ab(pos, -2, -wdl + 1, success);
|
||||
pos.undo_move(move);
|
||||
|
||||
if (*success == 0) return 0;
|
||||
|
||||
if (v == wdl)
|
||||
return v == 2 ? 1 : 101;
|
||||
}
|
||||
}
|
||||
|
||||
dtz = 1 + probe_dtz_table(pos, wdl, success);
|
||||
|
||||
if (*success >= 0) {
|
||||
if (wdl & 1) dtz += 100;
|
||||
|
||||
return wdl >= 0 ? dtz : -dtz;
|
||||
}
|
||||
|
||||
if (wdl > 0) {
|
||||
int best = 0xffff;
|
||||
|
||||
for (moves = stack; moves < end; moves++) {
|
||||
Move move = moves->move;
|
||||
|
||||
if (pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN
|
||||
|| !pos.legal(move, ci.pinned))
|
||||
continue;
|
||||
|
||||
pos.do_move(move, st, pos.gives_check(move, ci));
|
||||
int v = -Tablebases::probe_dtz(pos, success);
|
||||
pos.undo_move(move);
|
||||
if (*success == 0) return 0;
|
||||
|
||||
if (*success == 0)
|
||||
return 0;
|
||||
|
||||
if (v > 0 && v + 1 < best)
|
||||
best = v + 1;
|
||||
}
|
||||
|
||||
return best;
|
||||
} else {
|
||||
int best = -1;
|
||||
|
||||
if (!pos.checkers())
|
||||
end = generate<NON_EVASIONS>(pos, stack);
|
||||
else
|
||||
end = generate<EVASIONS>(pos, stack);
|
||||
|
||||
for (moves = stack; moves < end; moves++) {
|
||||
int v;
|
||||
Move move = moves->move;
|
||||
|
||||
if (!pos.legal(move, ci.pinned))
|
||||
continue;
|
||||
|
||||
pos.do_move(move, st, pos.gives_check(move, ci));
|
||||
|
||||
if (st.rule50 == 0) {
|
||||
if (wdl == -2) v = -1;
|
||||
else {
|
||||
|
@ -545,11 +628,16 @@ static int probe_dtz_no_ep(Position& pos, int *success)
|
|||
} else {
|
||||
v = -Tablebases::probe_dtz(pos, success) - 1;
|
||||
}
|
||||
|
||||
pos.undo_move(move);
|
||||
if (*success == 0) return 0;
|
||||
|
||||
if (*success == 0)
|
||||
return 0;
|
||||
|
||||
if (v < best)
|
||||
best = v;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
}
|
||||
|
@ -591,12 +679,14 @@ int Tablebases::probe_dtz(Position& pos, int *success)
|
|||
|
||||
if (pos.ep_square() == SQ_NONE)
|
||||
return v;
|
||||
if (*success == 0) return 0;
|
||||
|
||||
if (*success == 0)
|
||||
return 0;
|
||||
|
||||
// Now handle en passant.
|
||||
int v1 = -3;
|
||||
|
||||
ExtMove stack[192];
|
||||
ExtMove stack[MAX_MOVES];
|
||||
ExtMove *moves, *end;
|
||||
StateInfo st;
|
||||
|
||||
|
@ -604,21 +694,29 @@ int Tablebases::probe_dtz(Position& pos, int *success)
|
|||
end = generate<CAPTURES>(pos, stack);
|
||||
else
|
||||
end = generate<EVASIONS>(pos, stack);
|
||||
|
||||
CheckInfo ci(pos);
|
||||
|
||||
for (moves = stack; moves < end; moves++) {
|
||||
Move capture = moves->move;
|
||||
|
||||
if (type_of(capture) != ENPASSANT
|
||||
|| !pos.legal(capture, ci.pinned))
|
||||
continue;
|
||||
|
||||
pos.do_move(capture, st, pos.gives_check(capture, ci));
|
||||
int v0 = -probe_ab(pos, -2, 2, success);
|
||||
pos.undo_move(capture);
|
||||
if (*success == 0) return 0;
|
||||
|
||||
if (*success == 0)
|
||||
return 0;
|
||||
|
||||
if (v0 > v1) v1 = v0;
|
||||
}
|
||||
|
||||
if (v1 > -3) {
|
||||
v1 = wdl_to_dtz[v1 + 2];
|
||||
|
||||
if (v < -100) {
|
||||
if (v1 >= 0)
|
||||
v = v1;
|
||||
|
@ -636,17 +734,24 @@ int Tablebases::probe_dtz(Position& pos, int *success)
|
|||
} else {
|
||||
for (moves = stack; moves < end; moves++) {
|
||||
Move move = moves->move;
|
||||
|
||||
if (type_of(move) == ENPASSANT) continue;
|
||||
if (pos.legal(move, ci.pinned)) break;
|
||||
|
||||
if (pos.legal(move, ci.pinned))
|
||||
break;
|
||||
}
|
||||
|
||||
if (moves == end && !pos.checkers()) {
|
||||
end = generate<QUIETS>(pos, end);
|
||||
|
||||
for (; moves < end; moves++) {
|
||||
Move move = moves->move;
|
||||
|
||||
if (pos.legal(move, ci.pinned))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (moves == end)
|
||||
v = v1;
|
||||
}
|
||||
|
@ -661,15 +766,21 @@ static int has_repeated(StateInfo *st)
|
|||
{
|
||||
while (1) {
|
||||
int i = 4, e = std::min(st->rule50, st->pliesFromNull);
|
||||
|
||||
if (e < i)
|
||||
return 0;
|
||||
|
||||
StateInfo *stp = st->previous->previous;
|
||||
|
||||
do {
|
||||
stp = stp->previous->previous;
|
||||
|
||||
if (stp->key == st->key)
|
||||
return 1;
|
||||
|
||||
i += 2;
|
||||
} while (i <= e);
|
||||
|
||||
st = st->previous;
|
||||
}
|
||||
}
|
||||
|
@ -693,7 +804,9 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Va
|
|||
int success;
|
||||
|
||||
int dtz = probe_dtz(pos, &success);
|
||||
if (!success) return false;
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
StateInfo st;
|
||||
CheckInfo ci(pos);
|
||||
|
@ -703,14 +816,18 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Va
|
|||
Move move = rootMoves[i].pv[0];
|
||||
pos.do_move(move, st, pos.gives_check(move, ci));
|
||||
int v = 0;
|
||||
|
||||
if (pos.checkers() && dtz > 0) {
|
||||
ExtMove s[192];
|
||||
ExtMove s[MAX_MOVES];
|
||||
|
||||
if (generate<LEGAL>(pos, s) == s)
|
||||
v = 1;
|
||||
}
|
||||
|
||||
if (!v) {
|
||||
if (st.rule50 != 0) {
|
||||
v = -Tablebases::probe_dtz(pos, &success);
|
||||
|
||||
if (v > 0) v++;
|
||||
else if (v < 0) v--;
|
||||
} else {
|
||||
|
@ -718,8 +835,12 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Va
|
|||
v = wdl_to_dtz[v + 2];
|
||||
}
|
||||
}
|
||||
|
||||
pos.undo_move(move);
|
||||
if (!success) return false;
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
rootMoves[i].score = (Value)v;
|
||||
}
|
||||
|
||||
|
@ -730,6 +851,7 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Va
|
|||
// Use 50-move counter to determine whether the root position is
|
||||
// won, lost or drawn.
|
||||
int wdl = 0;
|
||||
|
||||
if (dtz > 0)
|
||||
wdl = (dtz + cnt50 <= 100) ? 2 : 1;
|
||||
else if (dtz < 0)
|
||||
|
@ -737,6 +859,7 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Va
|
|||
|
||||
// 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().
|
||||
|
@ -747,33 +870,44 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Va
|
|||
|
||||
// Now be a bit smart about filtering out moves.
|
||||
size_t j = 0;
|
||||
|
||||
if (dtz > 0) { // winning (or 50-move rule draw)
|
||||
int best = 0xffff;
|
||||
|
||||
for (size_t i = 0; i < rootMoves.size(); i++) {
|
||||
int v = rootMoves[i].score;
|
||||
|
||||
if (v > 0 && v < best)
|
||||
best = v;
|
||||
}
|
||||
|
||||
int max = best;
|
||||
|
||||
// If the current phase has not seen repetitions, then try all moves
|
||||
// that stay safely within the 50-move budget, if there are any.
|
||||
if (!has_repeated(st.previous) && best + cnt50 <= 99)
|
||||
max = 99 - cnt50;
|
||||
|
||||
for (size_t i = 0; i < rootMoves.size(); i++) {
|
||||
int v = rootMoves[i].score;
|
||||
|
||||
if (v > 0 && v <= max)
|
||||
rootMoves[j++] = rootMoves[i];
|
||||
}
|
||||
} else if (dtz < 0) { // losing (or 50-move rule draw)
|
||||
int best = 0;
|
||||
|
||||
for (size_t i = 0; i < rootMoves.size(); i++) {
|
||||
int v = rootMoves[i].score;
|
||||
|
||||
if (v < best)
|
||||
best = v;
|
||||
}
|
||||
|
||||
// Try all moves, unless we approach or have a 50-move rule draw.
|
||||
if (-best * 2 + cnt50 < 100)
|
||||
return true;
|
||||
|
||||
for (size_t i = 0; i < rootMoves.size(); i++) {
|
||||
if (rootMoves[i].score == best)
|
||||
rootMoves[j++] = rootMoves[i];
|
||||
|
@ -785,6 +919,7 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Va
|
|||
rootMoves[j++] = rootMoves[i];
|
||||
}
|
||||
}
|
||||
|
||||
rootMoves.resize(j, Search::RootMove(MOVE_NONE));
|
||||
|
||||
return true;
|
||||
|
@ -800,7 +935,10 @@ bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoveVector& rootMoves
|
|||
int success;
|
||||
|
||||
int wdl = Tablebases::probe_wdl(pos, &success);
|
||||
if (!success) return false;
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
score = wdl_to_Value[wdl + 2];
|
||||
|
||||
StateInfo st;
|
||||
|
@ -814,17 +952,23 @@ bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoveVector& rootMoves
|
|||
pos.do_move(move, st, pos.gives_check(move, ci));
|
||||
int v = -Tablebases::probe_wdl(pos, &success);
|
||||
pos.undo_move(move);
|
||||
if (!success) return false;
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
rootMoves[i].score = (Value)v;
|
||||
|
||||
if (v > best)
|
||||
best = v;
|
||||
}
|
||||
|
||||
size_t j = 0;
|
||||
|
||||
for (size_t i = 0; i < rootMoves.size(); i++) {
|
||||
if (rootMoves[i].score == best)
|
||||
rootMoves[j++] = rootMoves[i];
|
||||
}
|
||||
|
||||
rootMoves.resize(j, Search::RootMove(MOVE_NONE));
|
||||
|
||||
return true;
|
||||
|
|
Loading…
Add table
Reference in a new issue