mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 20:57:10 +00:00
Currently Search::RootMoves is accessed and even modified by TB probing functions in a hidden and sneaky way. This is bad practice and makes the code tricky. Instead explicily pass the vector as function argument so to clarify that the vector is modified inside the functions. No functional change.
1379 lines
35 KiB
C++
1379 lines
35 KiB
C++
/*
|
|
Copyright (c) 2011-2013 Ronald de Man
|
|
This file may be redistributed and/or modified without restrictions.
|
|
|
|
tbcore.c contains engine-independent routines of the tablebase probing code.
|
|
This file should not need to much adaptation to add tablebase probing to
|
|
a particular engine, provided the engine is written in C or C++.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#ifndef __WIN32__
|
|
#include <sys/mman.h>
|
|
#endif
|
|
#include "tbcore.h"
|
|
|
|
#define TBMAX_PIECE 254
|
|
#define TBMAX_PAWN 256
|
|
#define HSHMAX 5
|
|
|
|
#define Swap(a,b) {int tmp=a;a=b;b=tmp;}
|
|
|
|
#define TB_PAWN 1
|
|
#define TB_KNIGHT 2
|
|
#define TB_BISHOP 3
|
|
#define TB_ROOK 4
|
|
#define TB_QUEEN 5
|
|
#define TB_KING 6
|
|
|
|
#define TB_WPAWN TB_PAWN
|
|
#define TB_BPAWN (TB_PAWN | 8)
|
|
|
|
static LOCK_T TB_mutex;
|
|
|
|
static bool initialized = false;
|
|
static int num_paths = 0;
|
|
static char *path_string = NULL;
|
|
static char **paths = NULL;
|
|
|
|
static int TBnum_piece, TBnum_pawn;
|
|
static struct TBEntry_piece TB_piece[TBMAX_PIECE];
|
|
static struct TBEntry_pawn TB_pawn[TBMAX_PAWN];
|
|
|
|
static struct TBHashEntry TB_hash[1 << TBHASHBITS][HSHMAX];
|
|
|
|
#define DTZ_ENTRIES 64
|
|
|
|
static struct DTZTableEntry DTZ_table[DTZ_ENTRIES];
|
|
|
|
static void init_indices(void);
|
|
static uint64 calc_key_from_pcs(int *pcs, int mirror);
|
|
static void free_wdl_entry(struct TBEntry *entry);
|
|
static void free_dtz_entry(struct TBEntry *entry);
|
|
|
|
static FD open_tb(const char *str, const char *suffix)
|
|
{
|
|
int i;
|
|
FD fd;
|
|
char file[256];
|
|
|
|
for (i = 0; i < num_paths; i++) {
|
|
strcpy(file, paths[i]);
|
|
strcat(file, "/");
|
|
strcat(file, str);
|
|
strcat(file, suffix);
|
|
#ifndef __WIN32__
|
|
fd = open(file, O_RDONLY);
|
|
#else
|
|
fd = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
#endif
|
|
if (fd != FD_ERR) return fd;
|
|
}
|
|
return FD_ERR;
|
|
}
|
|
|
|
static void close_tb(FD fd)
|
|
{
|
|
#ifndef __WIN32__
|
|
close(fd);
|
|
#else
|
|
CloseHandle(fd);
|
|
#endif
|
|
}
|
|
|
|
static char *map_file(const char *name, const char *suffix, uint64 *mapping)
|
|
{
|
|
FD fd = open_tb(name, suffix);
|
|
if (fd == FD_ERR)
|
|
return NULL;
|
|
#ifndef __WIN32__
|
|
struct stat statbuf;
|
|
fstat(fd, &statbuf);
|
|
*mapping = statbuf.st_size;
|
|
char *data = (char *)mmap(NULL, statbuf.st_size, PROT_READ,
|
|
MAP_SHARED, fd, 0);
|
|
if (data == (char *)(-1)) {
|
|
printf("Could not mmap() %s.\n", name);
|
|
exit(1);
|
|
}
|
|
#else
|
|
DWORD size_low, size_high;
|
|
size_low = GetFileSize(fd, &size_high);
|
|
// *size = ((uint64)size_high) << 32 | ((uint64)size_low);
|
|
HANDLE map = CreateFileMapping(fd, NULL, PAGE_READONLY, size_high, size_low,
|
|
NULL);
|
|
if (map == NULL) {
|
|
printf("CreateFileMapping() failed.\n");
|
|
exit(1);
|
|
}
|
|
*mapping = (uint64)map;
|
|
char *data = (char *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
|
|
if (data == NULL) {
|
|
printf("MapViewOfFile() failed, name = %s%s, error = %lu.\n", name, suffix, GetLastError());
|
|
exit(1);
|
|
}
|
|
#endif
|
|
close_tb(fd);
|
|
return data;
|
|
}
|
|
|
|
#ifndef __WIN32__
|
|
static void unmap_file(char *data, uint64 size)
|
|
{
|
|
if (!data) return;
|
|
munmap(data, size);
|
|
}
|
|
#else
|
|
static void unmap_file(char *data, uint64 mapping)
|
|
{
|
|
if (!data) return;
|
|
UnmapViewOfFile(data);
|
|
CloseHandle((HANDLE)mapping);
|
|
}
|
|
#endif
|
|
|
|
static void add_to_hash(struct TBEntry *ptr, uint64 key)
|
|
{
|
|
int i, hshidx;
|
|
|
|
hshidx = key >> (64 - TBHASHBITS);
|
|
i = 0;
|
|
while (i < HSHMAX && TB_hash[hshidx][i].ptr)
|
|
i++;
|
|
if (i == HSHMAX) {
|
|
printf("HSHMAX too low!\n");
|
|
exit(1);
|
|
} else {
|
|
TB_hash[hshidx][i].key = key;
|
|
TB_hash[hshidx][i].ptr = ptr;
|
|
}
|
|
}
|
|
|
|
static char pchr[] = {'K', 'Q', 'R', 'B', 'N', 'P'};
|
|
|
|
static void init_tb(char *str)
|
|
{
|
|
FD fd;
|
|
struct TBEntry *entry;
|
|
int i, j, pcs[16];
|
|
uint64 key, key2;
|
|
int color;
|
|
char *s;
|
|
|
|
fd = open_tb(str, WDLSUFFIX);
|
|
if (fd == FD_ERR) return;
|
|
close_tb(fd);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
pcs[i] = 0;
|
|
color = 0;
|
|
for (s = str; *s; s++)
|
|
switch (*s) {
|
|
case 'P':
|
|
pcs[TB_PAWN | color]++;
|
|
break;
|
|
case 'N':
|
|
pcs[TB_KNIGHT | color]++;
|
|
break;
|
|
case 'B':
|
|
pcs[TB_BISHOP | color]++;
|
|
break;
|
|
case 'R':
|
|
pcs[TB_ROOK | color]++;
|
|
break;
|
|
case 'Q':
|
|
pcs[TB_QUEEN | color]++;
|
|
break;
|
|
case 'K':
|
|
pcs[TB_KING | color]++;
|
|
break;
|
|
case 'v':
|
|
color = 0x08;
|
|
break;
|
|
}
|
|
for (i = 0; i < 8; i++)
|
|
if (pcs[i] != pcs[i+8])
|
|
break;
|
|
key = calc_key_from_pcs(pcs, 0);
|
|
key2 = calc_key_from_pcs(pcs, 1);
|
|
if (pcs[TB_WPAWN] + pcs[TB_BPAWN] == 0) {
|
|
if (TBnum_piece == TBMAX_PIECE) {
|
|
printf("TBMAX_PIECE limit too low!\n");
|
|
exit(1);
|
|
}
|
|
entry = (struct TBEntry *)&TB_piece[TBnum_piece++];
|
|
} else {
|
|
if (TBnum_pawn == TBMAX_PAWN) {
|
|
printf("TBMAX_PAWN limit too low!\n");
|
|
exit(1);
|
|
}
|
|
entry = (struct TBEntry *)&TB_pawn[TBnum_pawn++];
|
|
}
|
|
entry->key = key;
|
|
entry->ready = 0;
|
|
entry->num = 0;
|
|
for (i = 0; i < 16; i++)
|
|
entry->num += pcs[i];
|
|
entry->symmetric = (key == key2);
|
|
entry->has_pawns = (pcs[TB_WPAWN] + pcs[TB_BPAWN] > 0);
|
|
if (entry->num > Tablebases::MaxCardinality)
|
|
Tablebases::MaxCardinality = entry->num;
|
|
|
|
if (entry->has_pawns) {
|
|
struct TBEntry_pawn *ptr = (struct TBEntry_pawn *)entry;
|
|
ptr->pawns[0] = pcs[TB_WPAWN];
|
|
ptr->pawns[1] = pcs[TB_BPAWN];
|
|
if (pcs[TB_BPAWN] > 0
|
|
&& (pcs[TB_WPAWN] == 0 || pcs[TB_BPAWN] < pcs[TB_WPAWN])) {
|
|
ptr->pawns[0] = pcs[TB_BPAWN];
|
|
ptr->pawns[1] = pcs[TB_WPAWN];
|
|
}
|
|
} else {
|
|
struct TBEntry_piece *ptr = (struct TBEntry_piece *)entry;
|
|
for (i = 0, j = 0; i < 16; i++)
|
|
if (pcs[i] == 1) j++;
|
|
if (j >= 3) ptr->enc_type = 0;
|
|
else if (j == 2) ptr->enc_type = 2;
|
|
else { /* only for suicide */
|
|
j = 16;
|
|
for (i = 0; i < 16; i++) {
|
|
if (pcs[i] < j && pcs[i] > 1) j = pcs[i];
|
|
ptr->enc_type = 1 + j;
|
|
}
|
|
}
|
|
}
|
|
add_to_hash(entry, key);
|
|
if (key2 != key) add_to_hash(entry, key2);
|
|
}
|
|
|
|
void Tablebases::init(const std::string& path)
|
|
{
|
|
char str[16];
|
|
int i, j, k, l;
|
|
|
|
if (initialized) {
|
|
free(path_string);
|
|
free(paths);
|
|
struct TBEntry *entry;
|
|
for (i = 0; i < TBnum_piece; i++) {
|
|
entry = (struct TBEntry *)&TB_piece[i];
|
|
free_wdl_entry(entry);
|
|
}
|
|
for (i = 0; i < TBnum_pawn; i++) {
|
|
entry = (struct TBEntry *)&TB_pawn[i];
|
|
free_wdl_entry(entry);
|
|
}
|
|
for (i = 0; i < DTZ_ENTRIES; i++)
|
|
if (DTZ_table[i].entry)
|
|
free_dtz_entry(DTZ_table[i].entry);
|
|
} else {
|
|
init_indices();
|
|
initialized = true;
|
|
}
|
|
|
|
const char *p = path.c_str();
|
|
if (strlen(p) == 0 || !strcmp(p, "<empty>")) return;
|
|
path_string = (char *)malloc(strlen(p) + 1);
|
|
strcpy(path_string, p);
|
|
num_paths = 0;
|
|
for (i = 0;; i++) {
|
|
if (path_string[i] != SEP_CHAR)
|
|
num_paths++;
|
|
while (path_string[i] && path_string[i] != SEP_CHAR)
|
|
i++;
|
|
if (!path_string[i]) break;
|
|
path_string[i] = 0;
|
|
}
|
|
paths = (char **)malloc(num_paths * sizeof(char *));
|
|
for (i = j = 0; i < num_paths; i++) {
|
|
while (!path_string[j]) j++;
|
|
paths[i] = &path_string[j];
|
|
while (path_string[j]) j++;
|
|
}
|
|
|
|
LOCK_INIT(TB_mutex);
|
|
|
|
TBnum_piece = TBnum_pawn = 0;
|
|
MaxCardinality = 0;
|
|
|
|
for (i = 0; i < (1 << TBHASHBITS); i++)
|
|
for (j = 0; j < HSHMAX; j++) {
|
|
TB_hash[i][j].key = 0ULL;
|
|
TB_hash[i][j].ptr = NULL;
|
|
}
|
|
|
|
for (i = 0; i < DTZ_ENTRIES; i++)
|
|
DTZ_table[i].entry = NULL;
|
|
|
|
for (i = 1; i < 6; i++) {
|
|
sprintf(str, "K%cvK", pchr[i]);
|
|
init_tb(str);
|
|
}
|
|
|
|
for (i = 1; i < 6; i++)
|
|
for (j = i; j < 6; j++) {
|
|
sprintf(str, "K%cvK%c", pchr[i], pchr[j]);
|
|
init_tb(str);
|
|
}
|
|
|
|
for (i = 1; i < 6; i++)
|
|
for (j = i; j < 6; j++) {
|
|
sprintf(str, "K%c%cvK", pchr[i], pchr[j]);
|
|
init_tb(str);
|
|
}
|
|
|
|
for (i = 1; i < 6; i++)
|
|
for (j = i; j < 6; j++)
|
|
for (k = 1; k < 6; k++) {
|
|
sprintf(str, "K%c%cvK%c", pchr[i], pchr[j], pchr[k]);
|
|
init_tb(str);
|
|
}
|
|
|
|
for (i = 1; i < 6; i++)
|
|
for (j = i; j < 6; j++)
|
|
for (k = j; k < 6; k++) {
|
|
sprintf(str, "K%c%c%cvK", pchr[i], pchr[j], pchr[k]);
|
|
init_tb(str);
|
|
}
|
|
|
|
for (i = 1; i < 6; i++)
|
|
for (j = i; j < 6; j++)
|
|
for (k = i; k < 6; k++)
|
|
for (l = (i == k) ? j : k; l < 6; l++) {
|
|
sprintf(str, "K%c%cvK%c%c", pchr[i], pchr[j], pchr[k], pchr[l]);
|
|
init_tb(str);
|
|
}
|
|
|
|
for (i = 1; i < 6; i++)
|
|
for (j = i; j < 6; j++)
|
|
for (k = j; k < 6; k++)
|
|
for (l = 1; l < 6; l++) {
|
|
sprintf(str, "K%c%c%cvK%c", pchr[i], pchr[j], pchr[k], pchr[l]);
|
|
init_tb(str);
|
|
}
|
|
|
|
for (i = 1; i < 6; i++)
|
|
for (j = i; j < 6; j++)
|
|
for (k = j; k < 6; k++)
|
|
for (l = k; l < 6; l++) {
|
|
sprintf(str, "K%c%c%c%cvK", pchr[i], pchr[j], pchr[k], pchr[l]);
|
|
init_tb(str);
|
|
}
|
|
|
|
printf("info string Found %d tablebases.\n", TBnum_piece + TBnum_pawn);
|
|
}
|
|
|
|
static const char offdiag[] = {
|
|
0,-1,-1,-1,-1,-1,-1,-1,
|
|
1, 0,-1,-1,-1,-1,-1,-1,
|
|
1, 1, 0,-1,-1,-1,-1,-1,
|
|
1, 1, 1, 0,-1,-1,-1,-1,
|
|
1, 1, 1, 1, 0,-1,-1,-1,
|
|
1, 1, 1, 1, 1, 0,-1,-1,
|
|
1, 1, 1, 1, 1, 1, 0,-1,
|
|
1, 1, 1, 1, 1, 1, 1, 0
|
|
};
|
|
|
|
static const ubyte triangle[] = {
|
|
6, 0, 1, 2, 2, 1, 0, 6,
|
|
0, 7, 3, 4, 4, 3, 7, 0,
|
|
1, 3, 8, 5, 5, 8, 3, 1,
|
|
2, 4, 5, 9, 9, 5, 4, 2,
|
|
2, 4, 5, 9, 9, 5, 4, 2,
|
|
1, 3, 8, 5, 5, 8, 3, 1,
|
|
0, 7, 3, 4, 4, 3, 7, 0,
|
|
6, 0, 1, 2, 2, 1, 0, 6
|
|
};
|
|
|
|
static const ubyte invtriangle[] = {
|
|
1, 2, 3, 10, 11, 19, 0, 9, 18, 27
|
|
};
|
|
|
|
static const ubyte invdiag[] = {
|
|
0, 9, 18, 27, 36, 45, 54, 63,
|
|
7, 14, 21, 28, 35, 42, 49, 56
|
|
};
|
|
|
|
static const ubyte flipdiag[] = {
|
|
0, 8, 16, 24, 32, 40, 48, 56,
|
|
1, 9, 17, 25, 33, 41, 49, 57,
|
|
2, 10, 18, 26, 34, 42, 50, 58,
|
|
3, 11, 19, 27, 35, 43, 51, 59,
|
|
4, 12, 20, 28, 36, 44, 52, 60,
|
|
5, 13, 21, 29, 37, 45, 53, 61,
|
|
6, 14, 22, 30, 38, 46, 54, 62,
|
|
7, 15, 23, 31, 39, 47, 55, 63
|
|
};
|
|
|
|
static const ubyte lower[] = {
|
|
28, 0, 1, 2, 3, 4, 5, 6,
|
|
0, 29, 7, 8, 9, 10, 11, 12,
|
|
1, 7, 30, 13, 14, 15, 16, 17,
|
|
2, 8, 13, 31, 18, 19, 20, 21,
|
|
3, 9, 14, 18, 32, 22, 23, 24,
|
|
4, 10, 15, 19, 22, 33, 25, 26,
|
|
5, 11, 16, 20, 23, 25, 34, 27,
|
|
6, 12, 17, 21, 24, 26, 27, 35
|
|
};
|
|
|
|
static const ubyte diag[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 8,
|
|
0, 1, 0, 0, 0, 0, 9, 0,
|
|
0, 0, 2, 0, 0, 10, 0, 0,
|
|
0, 0, 0, 3, 11, 0, 0, 0,
|
|
0, 0, 0, 12, 4, 0, 0, 0,
|
|
0, 0, 13, 0, 0, 5, 0, 0,
|
|
0, 14, 0, 0, 0, 0, 6, 0,
|
|
15, 0, 0, 0, 0, 0, 0, 7
|
|
};
|
|
|
|
static const ubyte flap[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 6, 12, 18, 18, 12, 6, 0,
|
|
1, 7, 13, 19, 19, 13, 7, 1,
|
|
2, 8, 14, 20, 20, 14, 8, 2,
|
|
3, 9, 15, 21, 21, 15, 9, 3,
|
|
4, 10, 16, 22, 22, 16, 10, 4,
|
|
5, 11, 17, 23, 23, 17, 11, 5,
|
|
0, 0, 0, 0, 0, 0, 0, 0
|
|
};
|
|
|
|
static const ubyte ptwist[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
47, 35, 23, 11, 10, 22, 34, 46,
|
|
45, 33, 21, 9, 8, 20, 32, 44,
|
|
43, 31, 19, 7, 6, 18, 30, 42,
|
|
41, 29, 17, 5, 4, 16, 28, 40,
|
|
39, 27, 15, 3, 2, 14, 26, 38,
|
|
37, 25, 13, 1, 0, 12, 24, 36,
|
|
0, 0, 0, 0, 0, 0, 0, 0
|
|
};
|
|
|
|
static const ubyte invflap[] = {
|
|
8, 16, 24, 32, 40, 48,
|
|
9, 17, 25, 33, 41, 49,
|
|
10, 18, 26, 34, 42, 50,
|
|
11, 19, 27, 35, 43, 51
|
|
};
|
|
|
|
static const ubyte invptwist[] = {
|
|
52, 51, 44, 43, 36, 35, 28, 27, 20, 19, 12, 11,
|
|
53, 50, 45, 42, 37, 34, 29, 26, 21, 18, 13, 10,
|
|
54, 49, 46, 41, 38, 33, 30, 25, 22, 17, 14, 9,
|
|
55, 48, 47, 40, 39, 32, 31, 24, 23, 16, 15, 8
|
|
};
|
|
|
|
static const ubyte file_to_file[] = {
|
|
0, 1, 2, 3, 3, 2, 1, 0
|
|
};
|
|
|
|
static const short KK_idx[10][64] = {
|
|
{ -1, -1, -1, 0, 1, 2, 3, 4,
|
|
-1, -1, -1, 5, 6, 7, 8, 9,
|
|
10, 11, 12, 13, 14, 15, 16, 17,
|
|
18, 19, 20, 21, 22, 23, 24, 25,
|
|
26, 27, 28, 29, 30, 31, 32, 33,
|
|
34, 35, 36, 37, 38, 39, 40, 41,
|
|
42, 43, 44, 45, 46, 47, 48, 49,
|
|
50, 51, 52, 53, 54, 55, 56, 57 },
|
|
{ 58, -1, -1, -1, 59, 60, 61, 62,
|
|
63, -1, -1, -1, 64, 65, 66, 67,
|
|
68, 69, 70, 71, 72, 73, 74, 75,
|
|
76, 77, 78, 79, 80, 81, 82, 83,
|
|
84, 85, 86, 87, 88, 89, 90, 91,
|
|
92, 93, 94, 95, 96, 97, 98, 99,
|
|
100,101,102,103,104,105,106,107,
|
|
108,109,110,111,112,113,114,115},
|
|
{116,117, -1, -1, -1,118,119,120,
|
|
121,122, -1, -1, -1,123,124,125,
|
|
126,127,128,129,130,131,132,133,
|
|
134,135,136,137,138,139,140,141,
|
|
142,143,144,145,146,147,148,149,
|
|
150,151,152,153,154,155,156,157,
|
|
158,159,160,161,162,163,164,165,
|
|
166,167,168,169,170,171,172,173 },
|
|
{174, -1, -1, -1,175,176,177,178,
|
|
179, -1, -1, -1,180,181,182,183,
|
|
184, -1, -1, -1,185,186,187,188,
|
|
189,190,191,192,193,194,195,196,
|
|
197,198,199,200,201,202,203,204,
|
|
205,206,207,208,209,210,211,212,
|
|
213,214,215,216,217,218,219,220,
|
|
221,222,223,224,225,226,227,228 },
|
|
{229,230, -1, -1, -1,231,232,233,
|
|
234,235, -1, -1, -1,236,237,238,
|
|
239,240, -1, -1, -1,241,242,243,
|
|
244,245,246,247,248,249,250,251,
|
|
252,253,254,255,256,257,258,259,
|
|
260,261,262,263,264,265,266,267,
|
|
268,269,270,271,272,273,274,275,
|
|
276,277,278,279,280,281,282,283 },
|
|
{284,285,286,287,288,289,290,291,
|
|
292,293, -1, -1, -1,294,295,296,
|
|
297,298, -1, -1, -1,299,300,301,
|
|
302,303, -1, -1, -1,304,305,306,
|
|
307,308,309,310,311,312,313,314,
|
|
315,316,317,318,319,320,321,322,
|
|
323,324,325,326,327,328,329,330,
|
|
331,332,333,334,335,336,337,338 },
|
|
{ -1, -1,339,340,341,342,343,344,
|
|
-1, -1,345,346,347,348,349,350,
|
|
-1, -1,441,351,352,353,354,355,
|
|
-1, -1, -1,442,356,357,358,359,
|
|
-1, -1, -1, -1,443,360,361,362,
|
|
-1, -1, -1, -1, -1,444,363,364,
|
|
-1, -1, -1, -1, -1, -1,445,365,
|
|
-1, -1, -1, -1, -1, -1, -1,446 },
|
|
{ -1, -1, -1,366,367,368,369,370,
|
|
-1, -1, -1,371,372,373,374,375,
|
|
-1, -1, -1,376,377,378,379,380,
|
|
-1, -1, -1,447,381,382,383,384,
|
|
-1, -1, -1, -1,448,385,386,387,
|
|
-1, -1, -1, -1, -1,449,388,389,
|
|
-1, -1, -1, -1, -1, -1,450,390,
|
|
-1, -1, -1, -1, -1, -1, -1,451 },
|
|
{452,391,392,393,394,395,396,397,
|
|
-1, -1, -1, -1,398,399,400,401,
|
|
-1, -1, -1, -1,402,403,404,405,
|
|
-1, -1, -1, -1,406,407,408,409,
|
|
-1, -1, -1, -1,453,410,411,412,
|
|
-1, -1, -1, -1, -1,454,413,414,
|
|
-1, -1, -1, -1, -1, -1,455,415,
|
|
-1, -1, -1, -1, -1, -1, -1,456 },
|
|
{457,416,417,418,419,420,421,422,
|
|
-1,458,423,424,425,426,427,428,
|
|
-1, -1, -1, -1, -1,429,430,431,
|
|
-1, -1, -1, -1, -1,432,433,434,
|
|
-1, -1, -1, -1, -1,435,436,437,
|
|
-1, -1, -1, -1, -1,459,438,439,
|
|
-1, -1, -1, -1, -1, -1,460,440,
|
|
-1, -1, -1, -1, -1, -1, -1,461 }
|
|
};
|
|
|
|
static int binomial[5][64];
|
|
static int pawnidx[5][24];
|
|
static int pfactor[5][4];
|
|
|
|
static void init_indices(void)
|
|
{
|
|
int i, j, k;
|
|
|
|
// binomial[k-1][n] = Bin(n, k)
|
|
for (i = 0; i < 5; i++)
|
|
for (j = 0; j < 64; j++) {
|
|
int f = j;
|
|
int l = 1;
|
|
for (k = 1; k <= i; k++) {
|
|
f *= (j - k);
|
|
l *= (k + 1);
|
|
}
|
|
binomial[i][j] = f / l;
|
|
}
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
int s = 0;
|
|
for (j = 0; j < 6; j++) {
|
|
pawnidx[i][j] = s;
|
|
s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
|
|
}
|
|
pfactor[i][0] = s;
|
|
s = 0;
|
|
for (; j < 12; j++) {
|
|
pawnidx[i][j] = s;
|
|
s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
|
|
}
|
|
pfactor[i][1] = s;
|
|
s = 0;
|
|
for (; j < 18; j++) {
|
|
pawnidx[i][j] = s;
|
|
s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
|
|
}
|
|
pfactor[i][2] = s;
|
|
s = 0;
|
|
for (; j < 24; j++) {
|
|
pawnidx[i][j] = s;
|
|
s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
|
|
}
|
|
pfactor[i][3] = s;
|
|
}
|
|
}
|
|
|
|
static uint64 encode_piece(struct TBEntry_piece *ptr, ubyte *norm, int *pos, int *factor)
|
|
{
|
|
uint64 idx;
|
|
int i, j, k, m, l, p;
|
|
int n = ptr->num;
|
|
|
|
if (pos[0] & 0x04) {
|
|
for (i = 0; i < n; i++)
|
|
pos[i] ^= 0x07;
|
|
}
|
|
if (pos[0] & 0x20) {
|
|
for (i = 0; i < n; i++)
|
|
pos[i] ^= 0x38;
|
|
}
|
|
|
|
for (i = 0; i < n; i++)
|
|
if (offdiag[pos[i]]) break;
|
|
if (i < (ptr->enc_type == 0 ? 3 : 2) && offdiag[pos[i]] > 0)
|
|
for (i = 0; i < n; i++)
|
|
pos[i] = flipdiag[pos[i]];
|
|
|
|
switch (ptr->enc_type) {
|
|
|
|
case 0: /* 111 */
|
|
i = (pos[1] > pos[0]);
|
|
j = (pos[2] > pos[0]) + (pos[2] > pos[1]);
|
|
|
|
if (offdiag[pos[0]])
|
|
idx = triangle[pos[0]] * 63*62 + (pos[1] - i) * 62 + (pos[2] - j);
|
|
else if (offdiag[pos[1]])
|
|
idx = 6*63*62 + diag[pos[0]] * 28*62 + lower[pos[1]] * 62 + pos[2] - j;
|
|
else if (offdiag[pos[2]])
|
|
idx = 6*63*62 + 4*28*62 + (diag[pos[0]]) * 7*28 + (diag[pos[1]] - i) * 28 + lower[pos[2]];
|
|
else
|
|
idx = 6*63*62 + 4*28*62 + 4*7*28 + (diag[pos[0]] * 7*6) + (diag[pos[1]] - i) * 6 + (diag[pos[2]] - j);
|
|
i = 3;
|
|
break;
|
|
|
|
case 1: /* K3 */
|
|
j = (pos[2] > pos[0]) + (pos[2] > pos[1]);
|
|
|
|
idx = KK_idx[triangle[pos[0]]][pos[1]];
|
|
if (idx < 441)
|
|
idx = idx + 441 * (pos[2] - j);
|
|
else {
|
|
idx = 441*62 + (idx - 441) + 21 * lower[pos[2]];
|
|
if (!offdiag[pos[2]])
|
|
idx -= j * 21;
|
|
}
|
|
i = 3;
|
|
break;
|
|
|
|
default: /* K2 */
|
|
idx = KK_idx[triangle[pos[0]]][pos[1]];
|
|
i = 2;
|
|
break;
|
|
}
|
|
idx *= factor[0];
|
|
|
|
for (; i < n;) {
|
|
int t = norm[i];
|
|
for (j = i; j < i + t; j++)
|
|
for (k = j + 1; k < i + t; k++)
|
|
if (pos[j] > pos[k]) Swap(pos[j], pos[k]);
|
|
int s = 0;
|
|
for (m = i; m < i + t; m++) {
|
|
p = pos[m];
|
|
for (l = 0, j = 0; l < i; l++)
|
|
j += (p > pos[l]);
|
|
s += binomial[m - i][p - j];
|
|
}
|
|
idx += ((uint64)s) * ((uint64)factor[i]);
|
|
i += t;
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
// determine file of leftmost pawn and sort pawns
|
|
static int pawn_file(struct TBEntry_pawn *ptr, int *pos)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i < ptr->pawns[0]; i++)
|
|
if (flap[pos[0]] > flap[pos[i]])
|
|
Swap(pos[0], pos[i]);
|
|
|
|
return file_to_file[pos[0] & 0x07];
|
|
}
|
|
|
|
static uint64 encode_pawn(struct TBEntry_pawn *ptr, ubyte *norm, int *pos, int *factor)
|
|
{
|
|
uint64 idx;
|
|
int i, j, k, m, s, t;
|
|
int n = ptr->num;
|
|
|
|
if (pos[0] & 0x04)
|
|
for (i = 0; i < n; i++)
|
|
pos[i] ^= 0x07;
|
|
|
|
for (i = 1; i < ptr->pawns[0]; i++)
|
|
for (j = i + 1; j < ptr->pawns[0]; j++)
|
|
if (ptwist[pos[i]] < ptwist[pos[j]])
|
|
Swap(pos[i], pos[j]);
|
|
|
|
t = ptr->pawns[0] - 1;
|
|
idx = pawnidx[t][flap[pos[0]]];
|
|
for (i = t; i > 0; i--)
|
|
idx += binomial[t - i][ptwist[pos[i]]];
|
|
idx *= factor[0];
|
|
|
|
// remaining pawns
|
|
i = ptr->pawns[0];
|
|
t = i + ptr->pawns[1];
|
|
if (t > i) {
|
|
for (j = i; j < t; j++)
|
|
for (k = j + 1; k < t; k++)
|
|
if (pos[j] > pos[k]) Swap(pos[j], pos[k]);
|
|
s = 0;
|
|
for (m = i; m < t; m++) {
|
|
int p = pos[m];
|
|
for (k = 0, j = 0; k < i; k++)
|
|
j += (p > pos[k]);
|
|
s += binomial[m - i][p - j - 8];
|
|
}
|
|
idx += ((uint64)s) * ((uint64)factor[i]);
|
|
i = t;
|
|
}
|
|
|
|
for (; i < n;) {
|
|
t = norm[i];
|
|
for (j = i; j < i + t; j++)
|
|
for (k = j + 1; k < i + t; k++)
|
|
if (pos[j] > pos[k]) Swap(pos[j], pos[k]);
|
|
s = 0;
|
|
for (m = i; m < i + t; m++) {
|
|
int p = pos[m];
|
|
for (k = 0, j = 0; k < i; k++)
|
|
j += (p > pos[k]);
|
|
s += binomial[m - i][p - j];
|
|
}
|
|
idx += ((uint64)s) * ((uint64)factor[i]);
|
|
i += t;
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
// place k like pieces on n squares
|
|
static int subfactor(int k, int n)
|
|
{
|
|
int i, f, l;
|
|
|
|
f = n;
|
|
l = 1;
|
|
for (i = 1; i < k; i++) {
|
|
f *= n - i;
|
|
l *= i + 1;
|
|
}
|
|
|
|
return f / l;
|
|
}
|
|
|
|
static uint64 calc_factors_piece(int *factor, int num, int order, ubyte *norm, ubyte enc_type)
|
|
{
|
|
int i, k, n;
|
|
uint64 f;
|
|
static int pivfac[] = { 31332, 28056, 462 };
|
|
|
|
n = 64 - norm[0];
|
|
|
|
f = 1;
|
|
for (i = norm[0], k = 0; i < num || k == order; k++) {
|
|
if (k == order) {
|
|
factor[0] = f;
|
|
f *= pivfac[enc_type];
|
|
} else {
|
|
factor[i] = f;
|
|
f *= subfactor(norm[i], n);
|
|
n -= norm[i];
|
|
i += norm[i];
|
|
}
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
static uint64 calc_factors_pawn(int *factor, int num, int order, int order2, ubyte *norm, int file)
|
|
{
|
|
int i, k, n;
|
|
uint64 f;
|
|
|
|
i = norm[0];
|
|
if (order2 < 0x0f) i += norm[i];
|
|
n = 64 - i;
|
|
|
|
f = 1;
|
|
for (k = 0; i < num || k == order || k == order2; k++) {
|
|
if (k == order) {
|
|
factor[0] = f;
|
|
f *= pfactor[norm[0] - 1][file];
|
|
} else if (k == order2) {
|
|
factor[norm[0]] = f;
|
|
f *= subfactor(norm[norm[0]], 48 - norm[0]);
|
|
} else {
|
|
factor[i] = f;
|
|
f *= subfactor(norm[i], n);
|
|
n -= norm[i];
|
|
i += norm[i];
|
|
}
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
static void set_norm_piece(struct TBEntry_piece *ptr, ubyte *norm, ubyte *pieces)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < ptr->num; i++)
|
|
norm[i] = 0;
|
|
|
|
switch (ptr->enc_type) {
|
|
case 0:
|
|
norm[0] = 3;
|
|
break;
|
|
case 2:
|
|
norm[0] = 2;
|
|
break;
|
|
default:
|
|
norm[0] = ptr->enc_type - 1;
|
|
break;
|
|
}
|
|
|
|
for (i = norm[0]; i < ptr->num; i += norm[i])
|
|
for (j = i; j < ptr->num && pieces[j] == pieces[i]; j++)
|
|
norm[i]++;
|
|
}
|
|
|
|
static void set_norm_pawn(struct TBEntry_pawn *ptr, ubyte *norm, ubyte *pieces)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < ptr->num; i++)
|
|
norm[i] = 0;
|
|
|
|
norm[0] = ptr->pawns[0];
|
|
if (ptr->pawns[1]) norm[ptr->pawns[0]] = ptr->pawns[1];
|
|
|
|
for (i = ptr->pawns[0] + ptr->pawns[1]; i < ptr->num; i += norm[i])
|
|
for (j = i; j < ptr->num && pieces[j] == pieces[i]; j++)
|
|
norm[i]++;
|
|
}
|
|
|
|
static void setup_pieces_piece(struct TBEntry_piece *ptr, unsigned char *data, uint64 *tb_size)
|
|
{
|
|
int i;
|
|
int order;
|
|
|
|
for (i = 0; i < ptr->num; i++)
|
|
ptr->pieces[0][i] = data[i + 1] & 0x0f;
|
|
order = data[0] & 0x0f;
|
|
set_norm_piece(ptr, ptr->norm[0], ptr->pieces[0]);
|
|
tb_size[0] = calc_factors_piece(ptr->factor[0], ptr->num, order, ptr->norm[0], ptr->enc_type);
|
|
|
|
for (i = 0; i < ptr->num; i++)
|
|
ptr->pieces[1][i] = data[i + 1] >> 4;
|
|
order = data[0] >> 4;
|
|
set_norm_piece(ptr, ptr->norm[1], ptr->pieces[1]);
|
|
tb_size[1] = calc_factors_piece(ptr->factor[1], ptr->num, order, ptr->norm[1], ptr->enc_type);
|
|
}
|
|
|
|
static void setup_pieces_piece_dtz(struct DTZEntry_piece *ptr, unsigned char *data, uint64 *tb_size)
|
|
{
|
|
int i;
|
|
int order;
|
|
|
|
for (i = 0; i < ptr->num; i++)
|
|
ptr->pieces[i] = data[i + 1] & 0x0f;
|
|
order = data[0] & 0x0f;
|
|
set_norm_piece((struct TBEntry_piece *)ptr, ptr->norm, ptr->pieces);
|
|
tb_size[0] = calc_factors_piece(ptr->factor, ptr->num, order, ptr->norm, ptr->enc_type);
|
|
}
|
|
|
|
static void setup_pieces_pawn(struct TBEntry_pawn *ptr, unsigned char *data, uint64 *tb_size, int f)
|
|
{
|
|
int i, j;
|
|
int order, order2;
|
|
|
|
j = 1 + (ptr->pawns[1] > 0);
|
|
order = data[0] & 0x0f;
|
|
order2 = ptr->pawns[1] ? (data[1] & 0x0f) : 0x0f;
|
|
for (i = 0; i < ptr->num; i++)
|
|
ptr->file[f].pieces[0][i] = data[i + j] & 0x0f;
|
|
set_norm_pawn(ptr, ptr->file[f].norm[0], ptr->file[f].pieces[0]);
|
|
tb_size[0] = calc_factors_pawn(ptr->file[f].factor[0], ptr->num, order, order2, ptr->file[f].norm[0], f);
|
|
|
|
order = data[0] >> 4;
|
|
order2 = ptr->pawns[1] ? (data[1] >> 4) : 0x0f;
|
|
for (i = 0; i < ptr->num; i++)
|
|
ptr->file[f].pieces[1][i] = data[i + j] >> 4;
|
|
set_norm_pawn(ptr, ptr->file[f].norm[1], ptr->file[f].pieces[1]);
|
|
tb_size[1] = calc_factors_pawn(ptr->file[f].factor[1], ptr->num, order, order2, ptr->file[f].norm[1], f);
|
|
}
|
|
|
|
static void setup_pieces_pawn_dtz(struct DTZEntry_pawn *ptr, unsigned char *data, uint64 *tb_size, int f)
|
|
{
|
|
int i, j;
|
|
int order, order2;
|
|
|
|
j = 1 + (ptr->pawns[1] > 0);
|
|
order = data[0] & 0x0f;
|
|
order2 = ptr->pawns[1] ? (data[1] & 0x0f) : 0x0f;
|
|
for (i = 0; i < ptr->num; i++)
|
|
ptr->file[f].pieces[i] = data[i + j] & 0x0f;
|
|
set_norm_pawn((struct TBEntry_pawn *)ptr, ptr->file[f].norm, ptr->file[f].pieces);
|
|
tb_size[0] = calc_factors_pawn(ptr->file[f].factor, ptr->num, order, order2, ptr->file[f].norm, f);
|
|
}
|
|
|
|
static void calc_symlen(struct PairsData *d, int s, char *tmp)
|
|
{
|
|
int s1, s2;
|
|
|
|
ubyte* w = d->sympat + 3 * s;
|
|
s2 = (w[2] << 4) | (w[1] >> 4);
|
|
if (s2 == 0x0fff)
|
|
d->symlen[s] = 0;
|
|
else {
|
|
s1 = ((w[1] & 0xf) << 8) | w[0];
|
|
if (!tmp[s1]) calc_symlen(d, s1, tmp);
|
|
if (!tmp[s2]) calc_symlen(d, s2, tmp);
|
|
d->symlen[s] = d->symlen[s1] + d->symlen[s2] + 1;
|
|
}
|
|
tmp[s] = 1;
|
|
}
|
|
|
|
ushort ReadUshort(ubyte* d) {
|
|
return d[0] | (d[1] << 8);
|
|
}
|
|
|
|
uint32 ReadUint32(ubyte* d) {
|
|
return d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
|
|
}
|
|
|
|
static struct PairsData *setup_pairs(unsigned char *data, uint64 tb_size, uint64 *size, unsigned char **next, ubyte *flags, int wdl)
|
|
{
|
|
struct PairsData *d;
|
|
int i;
|
|
|
|
*flags = data[0];
|
|
if (data[0] & 0x80) {
|
|
d = (struct PairsData *)malloc(sizeof(struct PairsData));
|
|
d->idxbits = 0;
|
|
if (wdl)
|
|
d->min_len = data[1];
|
|
else
|
|
d->min_len = 0;
|
|
*next = data + 2;
|
|
size[0] = size[1] = size[2] = 0;
|
|
return d;
|
|
}
|
|
|
|
int blocksize = data[1];
|
|
int idxbits = data[2];
|
|
int real_num_blocks = ReadUint32(&data[4]);
|
|
int num_blocks = real_num_blocks + *(ubyte *)(&data[3]);
|
|
int max_len = data[8];
|
|
int min_len = data[9];
|
|
int h = max_len - min_len + 1;
|
|
int num_syms = ReadUshort(&data[10 + 2 * h]);
|
|
d = (struct PairsData *)malloc(sizeof(struct PairsData) + (h - 1) * sizeof(base_t) + num_syms);
|
|
d->blocksize = blocksize;
|
|
d->idxbits = idxbits;
|
|
d->offset = (ushort*)(&data[10]);
|
|
d->symlen = ((ubyte *)d) + sizeof(struct PairsData) + (h - 1) * sizeof(base_t);
|
|
d->sympat = &data[12 + 2 * h];
|
|
d->min_len = min_len;
|
|
*next = &data[12 + 2 * h + 3 * num_syms + (num_syms & 1)];
|
|
|
|
int num_indices = (tb_size + (1ULL << idxbits) - 1) >> idxbits;
|
|
size[0] = 6ULL * num_indices;
|
|
size[1] = 2ULL * num_blocks;
|
|
size[2] = (1ULL << blocksize) * real_num_blocks;
|
|
|
|
// char tmp[num_syms];
|
|
char tmp[4096];
|
|
for (i = 0; i < num_syms; i++)
|
|
tmp[i] = 0;
|
|
for (i = 0; i < num_syms; i++)
|
|
if (!tmp[i])
|
|
calc_symlen(d, i, tmp);
|
|
|
|
d->base[h - 1] = 0;
|
|
for (i = h - 2; i >= 0; i--)
|
|
d->base[i] = (d->base[i + 1] + ReadUshort((ubyte*)(d->offset + i)) - ReadUshort((ubyte*)(d->offset + i + 1))) / 2;
|
|
for (i = 0; i < h; i++)
|
|
d->base[i] <<= 64 - (min_len + i);
|
|
|
|
d->offset -= d->min_len;
|
|
|
|
return d;
|
|
}
|
|
|
|
static int init_table_wdl(struct TBEntry *entry, char *str)
|
|
{
|
|
ubyte *next;
|
|
int f, s;
|
|
uint64 tb_size[8];
|
|
uint64 size[8 * 3];
|
|
ubyte flags;
|
|
|
|
// first mmap the table into memory
|
|
|
|
entry->data = map_file(str, WDLSUFFIX, &entry->mapping);
|
|
if (!entry->data) {
|
|
printf("Could not find %s" WDLSUFFIX, str);
|
|
return 0;
|
|
}
|
|
|
|
ubyte *data = (ubyte *)entry->data;
|
|
if (data[0] != WDL_MAGIC[0] ||
|
|
data[1] != WDL_MAGIC[1] ||
|
|
data[2] != WDL_MAGIC[2] ||
|
|
data[3] != WDL_MAGIC[3]) {
|
|
printf("Corrupted table.\n");
|
|
unmap_file(entry->data, entry->mapping);
|
|
entry->data = 0;
|
|
return 0;
|
|
}
|
|
|
|
int split = data[4] & 0x01;
|
|
int files = data[4] & 0x02 ? 4 : 1;
|
|
|
|
data += 5;
|
|
|
|
if (!entry->has_pawns) {
|
|
struct TBEntry_piece *ptr = (struct TBEntry_piece *)entry;
|
|
setup_pieces_piece(ptr, data, &tb_size[0]);
|
|
data += ptr->num + 1;
|
|
data += ((uintptr_t)data) & 0x01;
|
|
|
|
ptr->precomp[0] = setup_pairs(data, tb_size[0], &size[0], &next, &flags, 1);
|
|
data = next;
|
|
if (split) {
|
|
ptr->precomp[1] = setup_pairs(data, tb_size[1], &size[3], &next, &flags, 1);
|
|
data = next;
|
|
} else
|
|
ptr->precomp[1] = NULL;
|
|
|
|
ptr->precomp[0]->indextable = (char *)data;
|
|
data += size[0];
|
|
if (split) {
|
|
ptr->precomp[1]->indextable = (char *)data;
|
|
data += size[3];
|
|
}
|
|
|
|
ptr->precomp[0]->sizetable = (ushort *)data;
|
|
data += size[1];
|
|
if (split) {
|
|
ptr->precomp[1]->sizetable = (ushort *)data;
|
|
data += size[4];
|
|
}
|
|
|
|
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
|
ptr->precomp[0]->data = data;
|
|
data += size[2];
|
|
if (split) {
|
|
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
|
ptr->precomp[1]->data = data;
|
|
}
|
|
} else {
|
|
struct TBEntry_pawn *ptr = (struct TBEntry_pawn *)entry;
|
|
s = 1 + (ptr->pawns[1] > 0);
|
|
for (f = 0; f < 4; f++) {
|
|
setup_pieces_pawn((struct TBEntry_pawn *)ptr, data, &tb_size[2 * f], f);
|
|
data += ptr->num + s;
|
|
}
|
|
data += ((uintptr_t)data) & 0x01;
|
|
|
|
for (f = 0; f < files; f++) {
|
|
ptr->file[f].precomp[0] = setup_pairs(data, tb_size[2 * f], &size[6 * f], &next, &flags, 1);
|
|
data = next;
|
|
if (split) {
|
|
ptr->file[f].precomp[1] = setup_pairs(data, tb_size[2 * f + 1], &size[6 * f + 3], &next, &flags, 1);
|
|
data = next;
|
|
} else
|
|
ptr->file[f].precomp[1] = NULL;
|
|
}
|
|
|
|
for (f = 0; f < files; f++) {
|
|
ptr->file[f].precomp[0]->indextable = (char *)data;
|
|
data += size[6 * f];
|
|
if (split) {
|
|
ptr->file[f].precomp[1]->indextable = (char *)data;
|
|
data += size[6 * f + 3];
|
|
}
|
|
}
|
|
|
|
for (f = 0; f < files; f++) {
|
|
ptr->file[f].precomp[0]->sizetable = (ushort *)data;
|
|
data += size[6 * f + 1];
|
|
if (split) {
|
|
ptr->file[f].precomp[1]->sizetable = (ushort *)data;
|
|
data += size[6 * f + 4];
|
|
}
|
|
}
|
|
|
|
for (f = 0; f < files; f++) {
|
|
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
|
ptr->file[f].precomp[0]->data = data;
|
|
data += size[6 * f + 2];
|
|
if (split) {
|
|
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
|
ptr->file[f].precomp[1]->data = data;
|
|
data += size[6 * f + 5];
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int init_table_dtz(struct TBEntry *entry)
|
|
{
|
|
ubyte *data = (ubyte *)entry->data;
|
|
ubyte *next;
|
|
int f, s;
|
|
uint64 tb_size[4];
|
|
uint64 size[4 * 3];
|
|
|
|
if (!data)
|
|
return 0;
|
|
|
|
if (data[0] != DTZ_MAGIC[0] ||
|
|
data[1] != DTZ_MAGIC[1] ||
|
|
data[2] != DTZ_MAGIC[2] ||
|
|
data[3] != DTZ_MAGIC[3]) {
|
|
printf("Corrupted table.\n");
|
|
return 0;
|
|
}
|
|
|
|
int files = data[4] & 0x02 ? 4 : 1;
|
|
|
|
data += 5;
|
|
|
|
if (!entry->has_pawns) {
|
|
struct DTZEntry_piece *ptr = (struct DTZEntry_piece *)entry;
|
|
setup_pieces_piece_dtz(ptr, data, &tb_size[0]);
|
|
data += ptr->num + 1;
|
|
data += ((uintptr_t)data) & 0x01;
|
|
|
|
ptr->precomp = setup_pairs(data, tb_size[0], &size[0], &next, &(ptr->flags), 0);
|
|
data = next;
|
|
|
|
ptr->map = data;
|
|
if (ptr->flags & 2) {
|
|
int i;
|
|
for (i = 0; i < 4; i++) {
|
|
ptr->map_idx[i] = (data + 1 - ptr->map);
|
|
data += 1 + data[0];
|
|
}
|
|
data += ((uintptr_t)data) & 0x01;
|
|
}
|
|
|
|
ptr->precomp->indextable = (char *)data;
|
|
data += size[0];
|
|
|
|
ptr->precomp->sizetable = (ushort *)data;
|
|
data += size[1];
|
|
|
|
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
|
ptr->precomp->data = data;
|
|
data += size[2];
|
|
} else {
|
|
struct DTZEntry_pawn *ptr = (struct DTZEntry_pawn *)entry;
|
|
s = 1 + (ptr->pawns[1] > 0);
|
|
for (f = 0; f < 4; f++) {
|
|
setup_pieces_pawn_dtz(ptr, data, &tb_size[f], f);
|
|
data += ptr->num + s;
|
|
}
|
|
data += ((uintptr_t)data) & 0x01;
|
|
|
|
for (f = 0; f < files; f++) {
|
|
ptr->file[f].precomp = setup_pairs(data, tb_size[f], &size[3 * f], &next, &(ptr->flags[f]), 0);
|
|
data = next;
|
|
}
|
|
|
|
ptr->map = data;
|
|
for (f = 0; f < files; f++) {
|
|
if (ptr->flags[f] & 2) {
|
|
int i;
|
|
for (i = 0; i < 4; i++) {
|
|
ptr->map_idx[f][i] = (data + 1 - ptr->map);
|
|
data += 1 + data[0];
|
|
}
|
|
}
|
|
}
|
|
data += ((uintptr_t)data) & 0x01;
|
|
|
|
for (f = 0; f < files; f++) {
|
|
ptr->file[f].precomp->indextable = (char *)data;
|
|
data += size[3 * f];
|
|
}
|
|
|
|
for (f = 0; f < files; f++) {
|
|
ptr->file[f].precomp->sizetable = (ushort *)data;
|
|
data += size[3 * f + 1];
|
|
}
|
|
|
|
for (f = 0; f < files; f++) {
|
|
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
|
ptr->file[f].precomp->data = data;
|
|
data += size[3 * f + 2];
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
template<bool LittleEndian>
|
|
static ubyte decompress_pairs(struct PairsData *d, uint64 idx)
|
|
{
|
|
if (!d->idxbits)
|
|
return d->min_len;
|
|
|
|
uint32 mainidx = idx >> d->idxbits;
|
|
int litidx = (idx & ((1 << d->idxbits) - 1)) - (1 << (d->idxbits - 1));
|
|
uint32 block = *(uint32 *)(d->indextable + 6 * mainidx);
|
|
if (!LittleEndian)
|
|
block = __builtin_bswap32(block);
|
|
|
|
ushort idxOffset = *(ushort *)(d->indextable + 6 * mainidx + 4);
|
|
if (!LittleEndian)
|
|
idxOffset = (idxOffset << 8) | (idxOffset >> 8);
|
|
litidx += idxOffset;
|
|
|
|
if (litidx < 0) {
|
|
do {
|
|
litidx += d->sizetable[--block] + 1;
|
|
} while (litidx < 0);
|
|
} else {
|
|
while (litidx > d->sizetable[block])
|
|
litidx -= d->sizetable[block++] + 1;
|
|
}
|
|
|
|
uint32 *ptr = (uint32 *)(d->data + (block << d->blocksize));
|
|
|
|
int m = d->min_len;
|
|
ushort *offset = d->offset;
|
|
base_t *base = d->base - m;
|
|
ubyte *symlen = d->symlen;
|
|
int sym, bitcnt;
|
|
|
|
uint64 code = *((uint64 *)ptr);
|
|
if (LittleEndian)
|
|
code = __builtin_bswap64(code);
|
|
|
|
ptr += 2;
|
|
bitcnt = 0; // number of "empty bits" in code
|
|
for (;;) {
|
|
int l = m;
|
|
while (code < base[l]) l++;
|
|
sym = offset[l];
|
|
if (!LittleEndian)
|
|
sym = ((sym & 0xff) << 8) | (sym >> 8);
|
|
sym += ((code - base[l]) >> (64 - l));
|
|
if (litidx < (int)symlen[sym] + 1) break;
|
|
litidx -= (int)symlen[sym] + 1;
|
|
code <<= l;
|
|
bitcnt += l;
|
|
if (bitcnt >= 32) {
|
|
bitcnt -= 32;
|
|
uint32 tmp = *ptr++;
|
|
if (LittleEndian)
|
|
tmp = __builtin_bswap32(tmp);
|
|
code |= ((uint64)tmp) << bitcnt;
|
|
}
|
|
}
|
|
|
|
ubyte *sympat = d->sympat;
|
|
while (symlen[sym] != 0) {
|
|
ubyte* w = sympat + (3 * sym);
|
|
int s1 = ((w[1] & 0xf) << 8) | w[0];
|
|
if (litidx < (int)symlen[s1] + 1)
|
|
sym = s1;
|
|
else {
|
|
litidx -= (int)symlen[s1] + 1;
|
|
sym = (w[2] << 4) | (w[1] >> 4);
|
|
}
|
|
}
|
|
|
|
return sympat[3 * sym];
|
|
}
|
|
|
|
void load_dtz_table(char *str, uint64 key1, uint64 key2)
|
|
{
|
|
int i;
|
|
struct TBEntry *ptr, *ptr3;
|
|
struct TBHashEntry *ptr2;
|
|
|
|
DTZ_table[0].key1 = key1;
|
|
DTZ_table[0].key2 = key2;
|
|
DTZ_table[0].entry = NULL;
|
|
|
|
// find corresponding WDL entry
|
|
ptr2 = TB_hash[key1 >> (64 - TBHASHBITS)];
|
|
for (i = 0; i < HSHMAX; i++)
|
|
if (ptr2[i].key == key1) break;
|
|
if (i == HSHMAX) return;
|
|
ptr = ptr2[i].ptr;
|
|
|
|
ptr3 = (struct TBEntry *)malloc(ptr->has_pawns
|
|
? sizeof(struct DTZEntry_pawn)
|
|
: sizeof(struct DTZEntry_piece));
|
|
|
|
ptr3->data = map_file(str, DTZSUFFIX, &ptr3->mapping);
|
|
ptr3->key = ptr->key;
|
|
ptr3->num = ptr->num;
|
|
ptr3->symmetric = ptr->symmetric;
|
|
ptr3->has_pawns = ptr->has_pawns;
|
|
if (ptr3->has_pawns) {
|
|
struct DTZEntry_pawn *entry = (struct DTZEntry_pawn *)ptr3;
|
|
entry->pawns[0] = ((struct TBEntry_pawn *)ptr)->pawns[0];
|
|
entry->pawns[1] = ((struct TBEntry_pawn *)ptr)->pawns[1];
|
|
} else {
|
|
struct DTZEntry_piece *entry = (struct DTZEntry_piece *)ptr3;
|
|
entry->enc_type = ((struct TBEntry_piece *)ptr)->enc_type;
|
|
}
|
|
if (!init_table_dtz(ptr3))
|
|
free(ptr3);
|
|
else
|
|
DTZ_table[0].entry = ptr3;
|
|
}
|
|
|
|
static void free_wdl_entry(struct TBEntry *entry)
|
|
{
|
|
unmap_file(entry->data, entry->mapping);
|
|
if (!entry->has_pawns) {
|
|
struct TBEntry_piece *ptr = (struct TBEntry_piece *)entry;
|
|
free(ptr->precomp[0]);
|
|
if (ptr->precomp[1])
|
|
free(ptr->precomp[1]);
|
|
} else {
|
|
struct TBEntry_pawn *ptr = (struct TBEntry_pawn *)entry;
|
|
int f;
|
|
for (f = 0; f < 4; f++) {
|
|
free(ptr->file[f].precomp[0]);
|
|
if (ptr->file[f].precomp[1])
|
|
free(ptr->file[f].precomp[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void free_dtz_entry(struct TBEntry *entry)
|
|
{
|
|
unmap_file(entry->data, entry->mapping);
|
|
if (!entry->has_pawns) {
|
|
struct DTZEntry_piece *ptr = (struct DTZEntry_piece *)entry;
|
|
free(ptr->precomp);
|
|
} else {
|
|
struct DTZEntry_pawn *ptr = (struct DTZEntry_pawn *)entry;
|
|
int f;
|
|
for (f = 0; f < 4; f++)
|
|
free(ptr->file[f].precomp);
|
|
}
|
|
free(entry);
|
|
}
|
|
|
|
static int wdl_to_map[5] = { 1, 3, 0, 2, 0 };
|
|
static ubyte pa_flags[5] = { 8, 0, 0, 0, 4 };
|
|
|