I'm considering to use Nalimov tablebases in
my program. Is there any guide that would help
in implementation? Also it would help if there
would be some statistics about the percentages of
won game if specific sort of endgames.
Tommi
Using EGTB
Moderators: hgm, Rebel, chrisw
Re: Using EGTB
There was supposed to be an article called probe.txt about this subject on Robert Hyatts home pages, but I didn't find it. Perhaps some one else has this article or could at least post a link.
-
- Posts: 3533
- Joined: Tue Jan 09, 2007 8:33 pm
- Location: Antalya, Turkey
Re: Using EGTB
Do you mean probe.c?
If yes, you can check the source of Crafty 19.20.
Best,
If yes, you can check the source of Crafty 19.20.
Best,
hi, merhaba, hallo HT
-
- Posts: 287
- Joined: Sat Mar 11, 2006 3:19 am
- Location: Atlanta, GA
Re: Using EGTB
I likewise cannot find it. I have a copy of the old 5-men Nalimov files (PM me your email and I can send it to you) but I cannot find the new 6-men ones with the new readmes.Tommi wrote:There was supposed to be an article called probe.txt about this subject on Robert Hyatts home pages, but I didn't find it. Perhaps some one else has this article or could at least post a link.
-
- Posts: 12542
- Joined: Wed Mar 08, 2006 8:57 pm
- Location: Redmond, WA USA
Re: Using EGTB
Dieter Buerssner wrote a really nice article on how to interface with Nalimov endgame tablebase files.
It's not hard to do that part. The really, really hard part is to get ahold of Eugene Nalimov and get permission to use them. I know people who have tried for years unsuccessfully to get permission.
It's not hard to do that part. The really, really hard part is to get ahold of Eugene Nalimov and get permission to use them. I know people who have tried for years unsuccessfully to get permission.
-
- Posts: 287
- Joined: Sat Mar 11, 2006 3:19 am
- Location: Atlanta, GA
Re: Using EGTB
I think he started giving out permission a while ago. I got permission two years after I sent the email. Do you have a link to the article by Buerssner? Is the article also valid for probing the new 6-men Nalimov tablebases?Dann Corbit wrote:Dieter Buerssner wrote a really nice article on how to interface with Nalimov endgame tablebase files.
It's not hard to do that part. The really, really hard part is to get ahold of Eugene Nalimov and get permission to use them. I know people who have tried for years unsuccessfully to get permission.
Re: Using EGTB
I have that permission already. If you know where that document is, please post a link.
-
- Posts: 12542
- Joined: Wed Mar 08, 2006 8:57 pm
- Location: Redmond, WA USA
Re: Using EGTB
Here is Dieter's article:
http://www.open-aurec.com/wbforum/viewt ... 4158&t=931
http://www.open-aurec.com/wbforum/viewt ... 4158&t=931
-
- Posts: 12542
- Joined: Wed Mar 08, 2006 8:57 pm
- Location: Redmond, WA USA
Re: Using EGTB
Here is also a code sample Dieter sent to me:
Code: Select all
/* Anybody can use this. Originally written by
Dieter Buerssner, 2004. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* We use the same here as Nalimov */
enum piece_type {nothing, pawn, knight, bishop, rook, queen, king};
enum color {white, black, empty};
#define SHORT_CASTLE_WHITE 1
#define LONG_CASTLE_WHITE 2
#define SHORT_CASTLE_BLACK 4
#define LONG_CASTLE_BLACK 8
#define TO64(r,c) (8*(r)+(c))
typedef struct {
int board[8][8];
int cboard[8][8];
int stm;
unsigned castling_state;
int eps;
} POSITION;
#if 0
#define MM_DEBUG(string) my_print(DEBUG_INFO, "%s\n", string)
#else
#define MM_DEBUG(string)
#endif
/* Nasty macro, with side effects and assuming the variable names. */
#define SET_PIECE(c, p) \
do { \
if (col > 7) { \
printf("ERROR setboard c = %c, column outside of board\n", c); \
return 1; \
} \
pos->cboard[row][col]=c;pos->board[row][col]=p;col++;} while(0)
int setboard(const char *str, char **ep, POSITION *pos)
{
int col, row, c, c2, i, j, sawwk, sawbk, board_done;
for (i=0; i<8; i++)
for (j=0; j<8; j++)
{
pos->board[i][j] = nothing;
pos->cboard[i][j] = empty;
}
pos->castling_state = 0;
pos->eps = -1;
/* trim spaces */
while (isspace(*str))
str++;
sawwk = sawbk = 0; /* didn't find kings yet */
col = 0;
row = 7;
board_done = 0;
while ((c = *str) != '\0' && !board_done)
{
MM_DEBUG(str);
switch (c)
{
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7': case '8':
col += c - '0'; break;
case '/': /* We support missing number before / */
if (--row < 0) /* Swallow additional / sometimes found at the end
of wrong FENs */
board_done = 1; /* Actually incorrect FEN */
col = 0;
break;
case 'p': SET_PIECE(black,pawn); break; /* Should check for 1st/8th row */
case 'P': SET_PIECE(white,pawn); break;
case 'n': SET_PIECE(black,knight); break;
case 'N': SET_PIECE(white,knight); break;
case 'b': SET_PIECE(black,bishop); break;
case 'B': SET_PIECE(white,bishop); break;
case 'r': SET_PIECE(black,rook); break;
case 'R': SET_PIECE(white,rook); break;
case 'q': SET_PIECE(black,queen); break;
case 'Q': SET_PIECE(white,queen); break;
case 'k': SET_PIECE(black,king); sawbk++; break;
case 'K': SET_PIECE(white,king); sawwk++; break;
case ' ': case '\t': /* We support all sorts of abbrev. */
board_done = 1;
break;
default:
{
printf("ERROR setboard c = %c, unknown piece letter\n", c);
return 1;
}
}
str++;
}
MM_DEBUG("after pos");
if (sawwk != 1 || sawbk != 1)
{
printf("ERROR setboard kings are not correct\n");
return 1;
}
while (isspace(*str)) /* Actually only spaces allowed */
str++;
MM_DEBUG("trimmed spaces");
if (*str == 'w' || *str == 'W')
{
pos->stm = 0;
str++;
}
else if (*str == 'b' || *str == 'B')
{
pos->stm = 1;
str++;
}
else
return 1; /* report stm missing */
MM_DEBUG("after color");
/* We support short FENs without castling ep etc. */
/* get castling status */
while (isspace(*str)) /* Actually no spaces allowed */
str++;
switch (*str)
{
case 'K': pos->castling_state |= SHORT_CASTLE_WHITE; str++; break;
case 'Q': pos->castling_state |= LONG_CASTLE_WHITE; str++; break;
case 'k': pos->castling_state |= SHORT_CASTLE_BLACK; str++; break;
case 'q': pos->castling_state |= LONG_CASTLE_BLACK;; str++; break;
case '-': case 'n': str++; goto no_castling;
}
MM_DEBUG("after castling 1");
while (isspace(*str)) /* Actually no spaces allowed */
str++;
switch (*str)
{
case 'K': pos->castling_state |= SHORT_CASTLE_WHITE; str++; break;
case 'Q': pos->castling_state |= LONG_CASTLE_WHITE; str++; break;
case 'k': pos->castling_state |= SHORT_CASTLE_BLACK; str++; break;
case 'q': pos->castling_state |= LONG_CASTLE_BLACK;; str++; break;
}
MM_DEBUG("after castling 2");
while (isspace(*str)) /* Actually no spaces allowed */
str++;
switch (*str)
{
case 'K': pos->castling_state |= SHORT_CASTLE_WHITE; str++; break;
case 'Q': pos->castling_state |= LONG_CASTLE_WHITE; str++; break;
case 'k': pos->castling_state |= SHORT_CASTLE_BLACK; str++; break;
case 'q': pos->castling_state |= LONG_CASTLE_BLACK;; str++; break;
}
MM_DEBUG("after castling 3");
while (isspace(*str)) /* Actually no spaces allowed */
str++;
switch (*str)
{
case 'K': pos->castling_state |= SHORT_CASTLE_WHITE; str++; break;
case 'Q': pos->castling_state |= LONG_CASTLE_WHITE; str++; break;
case 'k': pos->castling_state |= SHORT_CASTLE_BLACK; str++; break;
case 'q': pos->castling_state |= LONG_CASTLE_BLACK;; str++; break;
}
MM_DEBUG("after castling 4");
no_castling:
/* Check that castling state is in accordance with placement
of kings/rooks. */
/* Caution, Omitted here */
/* e.p. field */
while (isspace(*str))
str++;
c = *str;
MM_DEBUG("trimmed spaces for ep");
if (c == 'n' || c == '-') /* support bogos "n" in some FENs */
str++;
else
{
if (isupper(c)) /* Some compilers have broken tolower in case of
none uppercase letter */
c = tolower(c);
if (c >= 'a' && c <= 'h')
{
c2 = *++str;
str++;
if ((c2 == '3' && pos->stm == black) || (c2 == '6' && pos->stm == white))
pos->eps = (c2 - '1') * 8 + c - 'a'; /* Assumes ASCII */
}
}
MM_DEBUG("after ep");
if (isspace(*str)) /* Actually only spaces allowed */
{
while (isspace(*str)) /* Actually only spaces allowed */
str++;
/* 50 moves counter, ignore it */
while (isdigit(*str))
str++;
if (isspace(*str)) /* Actually only spaces allowed */
{
while (isspace(*str)) /* Actually only spaces allowed */
str++;
/* Move number, ignore it */
while (isdigit(*str))
str++;
}
}
if (ep) /* set end of string */
*ep = (char *)str;
MM_DEBUG("assignement ep");
/* Caution, Omitted here */
/* Check, that we have a consistent ep square. All of it omitted.
Only one check actually done, and correct FEN assumed otherwise.
Note that this check really is needed here, because the Standard
for FEN wants a set ep target, even when ep is not possible.
Nalimov code however will do strange things sometimes when ep
is set, but an epmove is not possible.
So, without changes, this code will not correct even with
correct FENs in some cases. User should not give the ep-flag,
in case ep is not possible.
*/
/* Do all sort of checks on the position, all omitted here */
/* if (verify_position(pos, &etext) == 0) ... */
return 0;
}
/* From start of tbindex.cpp. */
#define pageL 65536 /* 256 */
/* tablebase byte entry semispan length */
#define tbbe_ssL ((pageL - 4) / 2)
/* tablebase signed byte entry values */
#define bev_broken (tbbe_ssL + 1) /* illegal or busted */
#if defined (_MSC_VER)
#define TB_FASTCALL __fastcall
#else
#define TB_FASTCALL
#endif
#define T_INDEX64
#define XX 127
#define C_PIECES 3 /* Maximum # of pieces of one color OTB */
#if defined (T_INDEX64) && defined (_MSC_VER)
typedef unsigned __int64 INDEX;
#elif defined (T_INDEX64)
typedef unsigned long long INDEX;
#else
typedef unsigned long INDEX;
#endif
typedef unsigned int square;
typedef INDEX (TB_FASTCALL * PfnCalcIndex)
(square*, square*, square, int fInverse);
extern int IDescFindFromCounters (int*);
extern int FRegisteredFun (int, /*color*/int);
#define FRegistered FRegisteredFun
extern PfnCalcIndex PfnIndCalcFun (int, /*color*/int);
#define PfnIndCalc PfnIndCalcFun
extern int TB_FASTCALL L_TbtProbeTable (int, /*color*/int, INDEX);
extern int IInitializeTb(char *);
extern int FTbSetCacheSize(void *, unsigned long);
extern int cbEGTBCompBytes;
size_t egtb_cache_size = 2L*1024L*1024L;
int table_pieces=0;
static void *cache_buf = 0;
void set_egtb_cache(long siz)
{
egtb_cache_size = siz;
if(table_pieces > 0)
{
if (cache_buf)
{
free(cache_buf);
cache_buf = 0;
}
cache_buf = malloc(egtb_cache_size);
if (cache_buf && FTbSetCacheSize(cache_buf, egtb_cache_size))
printf("Using %.3f MB cache for TBs\n", egtb_cache_size/(1024. * 1024.));
else
{
table_pieces = 0;
if (cache_buf)
{
free(cache_buf);
cache_buf = 0;
}
}
}
}
/* Should use const char *, but Eugene does not ... */
void init_egtb(char *path)
{
if (cache_buf)
{
free(cache_buf);
cache_buf = 0;
}
table_pieces = IInitializeTb(path);
if(table_pieces != 0)
{
printf("%d-men endgame table bases found, %.3f MB used for decompression tables\n",
table_pieces, cbEGTBCompBytes/(1024. * 1024.));
set_egtb_cache(egtb_cache_size);
}
else
printf("No endgame tables found\n");
}
#define MYPIECE_TO_NALIMOV(p) (p) /* We use the same internal piece type */
#define ROWCOL_TO_64(r,c) ((r)*8+(c)) /* Nalimov uses a1=0, b1=1, ... h8=63 */
int probe_egtb(POSITION *pos, int *score)
{
int piece_count[10];
square white_squares[5*C_PIECES+1], black_squares[5*C_PIECES+1];
int idx_tb, side, invert, value, ep, i, j, pc, sq, nwp, nbp;
INDEX idx;
square *wp, *bp;
if (pos->castling_state)
return 0;
/* Setup arrays white_pieces and black_pieces, so that they will
work with original (=Crafty) SqFind...() macros. Set also up
piece_counts */
/* Note, that a real chess engine would probably have a piece list,
and the following code would be more efficiently done.
Also number of white and black pieces will already be known. */
for (i=0; i<10; i++)
piece_count[i] = 0;
for (i=0; i<=5*C_PIECES; i++)
white_squares[i] = black_squares[i] = 0;
nwp = nbp = 0;
for (i=0; i<8; i++)
{
for (j=0; j<8; j++)
{
if (pos->cboard[i][j] == white)
{
nwp++;
if (nwp > C_PIECES+1) /* Avoid out of bounds index */
return 0;
pc = MYPIECE_TO_NALIMOV(pos->board[i][j]);
sq = ROWCOL_TO_64(i,j);
pc = pos->board[i][j];
if (pc == king)
white_squares[5*C_PIECES] = sq;
else
white_squares[(pc-1) * C_PIECES + piece_count[pc-1]++] = sq;
}
else if (pos->cboard[i][j] == black)
{
nbp++;
if (nbp > C_PIECES+1) /* Avoid out of bounds index */
return 0;
pc = MYPIECE_TO_NALIMOV(pos->board[i][j]);
sq = ROWCOL_TO_64(i,j);
pc = pos->board[i][j];
if (pc == king)
black_squares[5*C_PIECES] = sq;
else
black_squares[(pc-1) * C_PIECES + piece_count[pc-1+5]++] = sq;
}
}
}
if (nwp + nbp > table_pieces) /* We have more pieces on the board,
than found in any TB */
return 0;
/* Everything is setup here, now call the Nalimov functions
to do the real work for the actual probing. */
idx_tb = IDescFindFromCounters(piece_count);
if (idx_tb == 0)
return 0;
else if (idx_tb > 0)
{
side = pos->stm;
invert = 0;
wp = white_squares;
bp = black_squares;
}
else
{
side = pos->stm^1;
invert = 1;
wp = black_squares;
bp = white_squares;
idx_tb = -idx_tb;
}
if(!FRegisteredFun(idx_tb, side))
return 0;
ep = (pos->eps > 0) ? pos->eps : XX; /* Careful, see comment in setboard
Note that pos uses "Nalimov squares" for
ep already */
idx = PfnIndCalcFun(idx_tb, side)(wp, bp, ep, invert);
value = L_TbtProbeTable(idx_tb, side, idx);
if(value == bev_broken)
return 0;
*score = value;
return 1;
}
/* 0 = draw; 1 = mate in one; -1 = mated; -2 = mated in 1; -3 = mated in 2 */
#define MATE_FROM_TB_SCORE(score) \
(((score) > 0) ? 32767-(score) : ((score) == 0 ? 0 : -((score)+32766)-1))
int main(void)
{
char buf[256];
POSITION pos;
int v;
init_egtb("c:/tb;c:/6men"); /* Hardcoded ... */
while(fgets(buf, sizeof buf, stdin))
{
if (setboard(buf, NULL, &pos) != 0)
break; /* for example quit ... */
if (probe_egtb(&pos, &v) == 0)
printf("pos not found in TB\n");
else
{
printf("TB returned %d which means ", v);
v = MATE_FROM_TB_SCORE(v);
if (v == 0)
printf("draw\n");
else if (v > 0)
printf("mate in %d\n", v);
else
printf("mated in %d\n", -v-1);
}
}
return 0;
}
-
- Posts: 287
- Joined: Sat Mar 11, 2006 3:19 am
- Location: Atlanta, GA
Re: Using EGTB
This is an example of how to use Nalimov's probing code. I'm looking for the original 6-man Nalimov code (I have the 5-man). I'm looking for a set of these original files for 6-man:Dann Corbit wrote:Here is Dieter's article:
http://www.open-aurec.com/wbforum/viewt ... 4158&t=931
Code: Select all
tbcmp.cpp
tbgen.cpp
tbstat.cpp
tbdecode.h
tbindex.cpp
probe.txt
readme.txt