Moderator: Andres Valverde
*** ..\crafty\1912\egtb.cpp Tue Mar 30 13:27:14 2004
--- tbindex.cpp Sat May 15 21:41:06 2004
***************
*** 59,65 ****
--- 59,73 ----
#define SqFindSecond(psq, pi) (psq[C_PIECES*(pi-1)+1])
#define SqFindThird(psq, pi) (psq[C_PIECES*(pi-1)+2])
+ #if defined(SMP)
#include "lock.h"
+ #else
+ # define LockInit(p)
+ # define LockFree(p)
+ # define Lock(p)
+ # define Unlock(p)
+ #endif /* SMP code */
+
/*
All defined, now include probing code
***************
*** 168,174 ****
/* Directory delimiter */
! #if defined (_WIN32) || defined(_WIN64)
# define DELIMITER "\\"
#elif defined (__MWERKS__)
# define DELIMITER ":"
--- 176,182 ----
/* Directory delimiter */
! #if defined (_WIN32) || defined(_WIN64) || defined(__DJGPP__)
# define DELIMITER "\\"
#elif defined (__MWERKS__)
# define DELIMITER ":"
***************
*** 335,341 ****
pv = malloc(cb);
if (NULL == pv) {
! printf("*** Cannot allocate %d bytes of memory\n", cb);
exit(1);
}
cbAllocated += cb;
--- 343,349 ----
pv = malloc(cb);
if (NULL == pv) {
! printf("*** Cannot allocate %lu bytes of memory\n", (unsigned long)cb);
exit(1);
}
cbAllocated += cb;
***************
*** 5389,5394 ****
--- 5397,5404 ----
}
ptbd->m_rgfpFiles[side][iExtent] = fp;
}
+ else
+ goto ERROR_LABEL;
}
/* File opened. Now seek and read necessary chunk */
***************
*** 6000,6006 ****
iMaxTb = 0;
for (;;) {
for (i = 0; pszPath[i] != '\0' && pszPath[i] != ',' && pszPath[i] != ';'
! #if !defined (_WIN32) && !defined (__MWERKS__) && !defined(_WIN64)
&& pszPath[i] != ':'
#endif
; i++) {
--- 6010,6016 ----
iMaxTb = 0;
for (;;) {
for (i = 0; pszPath[i] != '\0' && pszPath[i] != ',' && pszPath[i] != ';'
! #if !defined (_WIN32) && !defined (__MWERKS__) && !defined(_WIN64) && !defined(__DJGPP__)
&& pszPath[i] != ':'
#endif
; i++) {
/* 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("g:/tb;g:/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;
}
Martin Giepmans wrote:I there information somewhere about the Nalimov TB's that enables me to write my own code in Delphi?
Jim Ablett wrote:Two Delphi engines I know of that use TBs >
Booot - (own TB format) source available
Ikarus - Private engine.
Jim
Dieter B?r?ner wrote:The code I showed, does not display correctly. For example line breaks are shown inside macros, where they are not allowed. Copying and pasting seems to yield correct code, however.
I see now, that Uri asked also in CCC, where there seem to be better answers, than mine.
Regards,
Dieter
Uri Blass wrote:If I understand correctly you suggest the following steps:
1)Copy Crafty19.12's lock.h and tbdecode.h(should cause no compilation errors)
2)Copy Crafty19.12 egtb.cpp and modify it based on what you posted
3)Copy your small program in a third file
Return to Programming and Technical Discussions
Users browsing this forum: No registered users and 14 guests