how to implement tablebases code?

Programming Topics (Computer Chess) and technical aspects as test techniques, book building, program tuning etc

Moderator: Andres Valverde

how to implement tablebases code?

Postby Uri Blass » 09 Dec 2004, 17:38

I think to implement tablebases in movei

I know that heiner posted the following code in
http://chessprogramming.org/cccsearch/c ... _id=192968

I also remember that Dieter said that it took him only few hours to implement tablebases from that code but the problem is that I do not understand it because I do not see step by step instructions in that post.

My question is what is the first step from that post to implement tablebases.

I guess that the first step is to copy and past some code but the question is what code exactly to copy and paste.

Note also that I do not understand the meaning of the functions that are described in that post because it is not clear to me if the function SqFindKing finds the white king or the black king and what is the reason that it needs to get a pointer.

I see no clear instructions in that post like:
1)copy code 1 and save it as egtbembed.cpp
2)copy code 2 and save is as egtbdefs.h
3)copy code 3 and save it as bastyp.h
4)copy code 4 and save it as basdef.h
5)copy code 5 and save it as lcltyp.h
6)copy code 6 and save it as tbindex.cpp
7)copy code 7 and save it as tbdecode.h
8)copy code 8 and save is as egtbembed.h
9)copy code 9 and save it as egtbif.c
10)copy code 10 and save it as egtbif.h
11)implement the following functions(of course I need explanation to understand the exact meaning of the functions and I have no problem to find the square of the white king when 0=a1, 1=b1 ... 63=h8)

a)SqFindKing (square *)
b)SqFindFirst (square *, piece),
c)SqFindSecond (square *, piece),
d)SqFindThird (square *, piece)
...


Uri
User avatar
Uri Blass
 
Posts: 727
Joined: 09 Oct 2004, 05:59
Location: Tel-Aviv

Re: how to implement tablebases code?

Postby José Carlos » 09 Dec 2004, 18:14

Hi Uri. That post is exactly what I used to implement EGTB's in Averno. It took me some time to get in context, but then everything is more or less easy.
_____________________________
José Carlos Martínez Galán
User avatar
José Carlos
 
Posts: 102
Joined: 26 Sep 2004, 03:22
Location: Murcia (Spain)

Re: how to implement tablebases code?

Postby Martin Giepmans » 10 Dec 2004, 20:49

I there information somewhere about the Nalimov TB's that enables me to write my own code in Delphi?

If possible, I don't want to use code from Crafty, which is difficult for me anyway because I'm not a C-programmer and can hardly read C.

I also would prefer not to use dll's written by others.
But maybe I have to. Or is there another way?
Martin
Martin Giepmans
 
Posts: 14
Joined: 26 Sep 2004, 23:47
Location: The Netherlands

Re: how to implement tablebases code?

Postby Uri Blass » 11 Dec 2004, 01:58

I need a map of what exactly to do because I do not like to add files to movei source before I have a complete design exactly what to do.

The problem is that when I try to make a design based on that post I do feel sure about the exact steps that I need to do so it discourage me to continue.

If I understand correctly the first steps are:

1)download egtb.cpp from Crafty18.10 and rename it to tbindex.cpp
(I already downloaded crafty18.10 source from Dan Corbit site)
2)delete the first 51 lines in "tbindex.cpp"
3)save them as egtbdefs.h
4)I do not understand added RCS comment at top
- (new) line 3193ff: make TB_CRC_CHECK a variable, again

I can see in Crafty18.10
#define TB_CRC_CHECK 0 at line 3239 and I do not understand the meaning of the comment of making TB_CRC_CHECK a variable(how can it be a variable when it is defined to be 0).

5)delete lines 79-82 from tbdecode.h(deleting terminating CNTL-M)
User avatar
Uri Blass
 
Posts: 727
Joined: 09 Oct 2004, 05:59
Location: Tel-Aviv

Re: how to implement tablebases code?

Postby Jim Ablett » 12 Dec 2004, 13:18

The GAFS project may be of interest to you (if you haven't come across it before.)

http://f11.parsimony.net/forum16635/messages/41884.htm


Jim.
___________________________
http://jimablett.net63.net/
Jim Ablett
 
Posts: 721
Joined: 27 Sep 2004, 10:39
Location: Essex, England

Re: how to implement tablebases code?

Postby Anonymous » 12 Dec 2004, 23:08

You might find the following almost complete program helpful. It should show, how to use the TBs. It will read FENs from stdin, and will show the TB result. For example:

6-men endgame table bases found, 45.787 MB used for decompression tables
Using 2.000 MB cache for TBs
6k1/5r2/6pp/R7/8/8/8/K7 w - -
TB returned -32741 which means mated in 25
6k1/5r2/6pp/R7/8/8/8/K7 b - -
TB returned 32746 which means mate in 21
quit
ERROR setboard c = u, unknown piece letter

Note. that the code is a bit of a hack in parts. Also some error checking is missing - especially in setboard(). egtb_probe() just assumes, that the pos is setup correctly. To compile it, use egtb.cpp and tbdecode.h from crafty. Here is the diff to Crafty 19.12. There is one semi serious error (the goto ...) fixed. I assume, it is also fixed in newer versions of Crafty. Also, that version needed lock.h, which really is Crafty specific. The other fix is to make it work better with the DJGPP compiler under DOS (I suggested the fix to Eugene, perhaps it is in later versions - most people won't be interested in compability to old DOS environments anyway):

Code: Select all
*** ..\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++) {


And now, my little sample program. Free to use to anybody (but not the Nalimov/Kadatch code, that gets called and is part of Crafty). This is really C code, not C++. For example with some compilers you can get a link error, when compiling it as C++ (some extern "C" is needed for called functions). Compile the Nalimov stuff as C++, of course. Link together, and the program should run.

Heiner's suggestions yield in "cleaner" code. For example, he uses a header file to avoid duplicate code. But that will mean, that each time Nalimov makes changes, you have to make rather many changes, while the not so clean solutions with the duplicate will need almost no changes (practically none, when one assumes that the reported bug got fixed, and hopefully the Crafty specific locking stuff, too).

In a practical program, what I show as one C source file here, would probably be in more than one files. (setboard and TB stuff in different files for example).

It might be needed to read probe.txt of Eugene. It is not available anymore from Hyatt's ftp, but can be found on another ftp (which I don't have handy. Renze??. Perhaps somebody else can give it).

It is a while ago, but perhaps Guido's library (GAFS) is easier to use and understand.

Good luck,
Dieter

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("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;
}
Anonymous
 

Re: how to implement tablebases code?

Postby Anonymous » 12 Dec 2004, 23:39

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
Anonymous
 

Re: how to implement tablebases code?

Postby Anonymous » 13 Dec 2004, 11:10

Martin Giepmans wrote:I there information somewhere about the Nalimov TB's that enables me to write my own code in Delphi?


Martin, while it is in theory of course possible, to write your own code to access the TBs, in practice it will be impossible, and you have to use Crafty code (nothing written by Bob, the stuff written by Eugene and Andrew). The layout of Nalimov TBs is documented in at least one paper, but only the general ideas about it, not the nasty details. To my knowledge, the compression method used is not documented (besides in the source). I am pretty sure, that it would be easier to write your own TB generator in your self baken format (that probably will not be as space efficient as the Nalimov format), than to write access code to Nalimov TBs.

Regards,
Dieter
Anonymous
 

Re: how to implement tablebases code?

Postby Jim Ablett » 13 Dec 2004, 11:48

Two Delphi engines I know of that use TBs >

Booot - (own TB format) source available
Ikarus - Private engine.

Jim
___________________________
http://jimablett.net63.net/
Jim Ablett
 
Posts: 721
Joined: 27 Sep 2004, 10:39
Location: Essex, England

Re: how to implement tablebases code?

Postby Alessandro Scotti » 13 Dec 2004, 13:26

Jim Ablett wrote:Two Delphi engines I know of that use TBs >

Booot - (own TB format) source available
Ikarus - Private engine.

Jim


I think also Delfi uses them (own format).
User avatar
Alessandro Scotti
 
Posts: 306
Joined: 20 Nov 2004, 00:10
Location: Rome, Italy

Re: how to implement tablebases code?

Postby Jim Ablett » 13 Dec 2004, 14:55

How could I have missed that one!
Out of interest, looking at Delfi's size, it's seems almost impossible for Delfi to support
4-man TBs internally in such a small program. (delfi.exe - 309kb/delfi.dat - 233kb)

Jim.
___________________________
http://jimablett.net63.net/
Jim Ablett
 
Posts: 721
Joined: 27 Sep 2004, 10:39
Location: Essex, England

Re: how to implement tablebases code?

Postby Alex Morozov » 13 Dec 2004, 16:43

Booot is Delphi engine. I had to write my own TB generator for it. Booot uses all 4men and some 5men DTM tablebases and some important 4men bitbases to access them from RAM. TB generator is on Leo site. I can share probing code and examples to everyone.
Alex Morozov
 
Posts: 5
Joined: 01 Oct 2004, 10:28
Location: Kiev, Ukraine

Re: how to implement tablebases code?

Postby Martin Giepmans » 13 Dec 2004, 19:06

Hi Alex,

Are others allowed to use your TB-generator?
If so I would be interested in your probing code, but perhaps I don't need it if I have enough infomation about the structure of the TB's that are generated.
Is that infomation available?
Martin
Martin Giepmans
 
Posts: 14
Joined: 26 Sep 2004, 23:47
Location: The Netherlands

Re: how to implement tablebases code?

Postby Alex Morozov » 13 Dec 2004, 20:12

Hi Martin!
I do not use compression of my egtb files. So, the structure of this files is quite simple.
Email me Booot@rambler.ru
Alex Morozov
 
Posts: 5
Joined: 01 Oct 2004, 10:28
Location: Kiev, Ukraine

Re: how to implement tablebases code?

Postby Uri Blass » 13 Dec 2004, 22:40

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


Hi dieter,

I am not sure about it.
The answers in CCC helped me to understand better what functions I need to write but did not explained exactly what I should do except writing the functions(what files to add).

I want to start even without working code by adding some files with no compilation errors in the files.

If I follow the old post in CCC it suggest me to start with steps that means that I have files with compilation errors because of missing files like lock.h that I need to add later.

I do not like to add many files to the project without being sure that it works so I guess that I will first start with a new project that only get fen and returns the expected result(I think that if I have that project then adding the information to movei may be an easy job and I do not need to check for correct fen there because the position in the board is always legal and always translated to correct fen).

The question is which files exactly I need to add to the project.

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

I do not like to start doing it now because I may understand not correctly and I prefer to work on other stuff and not to work on stuff that I am not sure about.

Uri
User avatar
Uri Blass
 
Posts: 727
Joined: 09 Oct 2004, 05:59
Location: Tel-Aviv

Re: how to implement tablebases code?

Postby Anonymous » 14 Dec 2004, 07:23

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


To 1) You don't need lock.h. In the first snippet I sent you will see somewhere close to the start:

[quote]
*** 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
***************
[quote]

*** 59,65 **** means: we are looking at line numbers 59 to 65 of original Crafty 19.12 egtb.cpp
--- 59,73 ---- means: we are looking at line numbers 59 to 73 of my changed egtb.cpp (which I renamed to tbindex.cpp, but it does not matter).

Lines that start with "+" are lines I added to the file from Crafty. Possibly I have written those lines myself, possible I have copied them from Crafty lock.h - I forgot. The purpose should be obvious. All the locking stuff that is done throughout the Nalimov Code is not needed for my engine, and I don't want to add Crafty lock.h (which might have more dependences on Crafty code, I don't want to have).

I suggest you use not Crafty 19.12 but rather a newer version. It most probably will have that one bug fixed (where you see in my post, that I added a line starting with goto).

If you are not interested in DJGPP, you don't need the other changes I had shown. BTW. Lines starting with ! means, that you will see them twice in the doutput of diff (that I posted), once how they looked in the original, once how I modified it.

I keep this diff output with my sources, so that I won't forget what I had to modify, when I last brought a Crafty egtb.cpp to my Yace source tree. So, when I am deciding to use a newer version from newer Crafty (which for example might support more TBs) I can add the same changes. For example I sent the __DJGPP__ (or similar for __MSDOS__) to Eugene, but he seems not interested. So, because I am using the DJGPP compiler, I always need to do this change. Actually, there is a program called patch, that can in a more or less intelligent way change the source code automatically, when it gets the output ot diff.

I am almost sure, that earlier I did not need the changes around l?ck.h. Perhaps newer versions won't need it either. You will see it immediately, when looking at egtb.cpp.

Say, you called my file tb.c and you have set up MSVC for commandline compiling (vcvars32.bat), you could just type:

cl -O tb.c egtb.cpp

and start tb.exe. I have no experience with MSVC projects (I use make), so I don't know if you have to add tbdecode.h to the project or not (I would guess, not).

Dieter
Anonymous
 

Re: how to implement tablebases code?

Postby Uri Blass » 14 Dec 2004, 20:04

Hi Dieter,

I tried with Crafty19.17 and the code does not compile

I documented every step that I did after copying the 2 files of Crafty
egtb.cpp that was renamed to tbindex.cpp and tbdecode.h that was copied with no changes.

I changed tbindex.cpp like you suggested and documented the changes and got errors and there is no point to add your file if the program does not compile.

Here are the steps that I did:



step 1:add in line 61 of tbindex.cpp

#if defined(SMP)

step 2:add lines 63-69
#else
# define LockInit(p)
# define LockFree(p)
# define Lock(p)
# define Unlock(p)
#endif /* SMP code */

step 3:
replace
#if defined (_WIN32) || defined(_WIN64) at line 175 by
#if defined (_WIN32) || defined(_WIN64) || defined(__DJGPP__)

step 4:
replace
printf("*** Cannot allocate %d bytes of memory\n", cb);
in line 356 by

printf("*** Cannot allocate %lu bytes of memory\n", (unsigned long)cb);

step 5:not needed
lines 5945-5946 already have else foto ERROR_LABEL

step 6:line 6681
replace #if !defined (_WIN32) && !defined (__MWERKS__) && !defined(_WIN64)
by
#if !defined (_WIN32) && !defined (__MWERKS__) && !defined(_WIN64) && !defined(__DJGPP__)

Compiling...
tbindex.cpp
D:\use\tablebases\tbindex.cpp(5635) : warning C4244: 'argument' : conversion from 'unsigned __int64' to 'unsigned int', possible loss of data
D:\use\tablebases\tbindex.cpp(5638) : warning C4244: 'argument' : conversion from 'unsigned __int64' to 'unsigned int', possible loss of data
D:\use\tablebases\tbindex.cpp(6326) : warning C4101: 'rgbBuffer' : unreferenced local variable
D:\use\tablebases\tbindex.cpp(6324) : warning C4101: 'fWasError' : unreferenced local variable
D:\use\tablebases\tbindex.cpp(6325) : warning C4101: 'block' : unreferenced local variable
D:\use\tablebases\tbindex.cpp(2735) : fatal error C1076: compiler limit : internal heap limit reached; use /Zm to specify a higher limit
D:\use\tablebases\tbindex.cpp(2694) : while compiling class-template member function 'unsigned __int64 __fastcall __fastcall T33<5,3,2,2>::IndCalcW(unsigned int *,unsigned int *,unsigned int,int)'
Error executing cl.exe.

tbindex.obj - 1 error(s), 5 warning(s)
User avatar
Uri Blass
 
Posts: 727
Joined: 09 Oct 2004, 05:59
Location: Tel-Aviv

Re: how to implement tablebases code?

Postby Uri Blass » 14 Dec 2004, 21:24

I decided to comment out the following lines because I do not think that I have place for big tablebases in my computer
//#define T41_INCLUDE
//#define T42_INCLUDE
//#define T33_INCLUDE

The results seem to be no error and only warnings.

still I get for
pb = (BYTE*) PvMalloc (cb);

warning C4244: 'argument' : conversion from 'unsigned __int64' to 'unsigned int', possible loss of data

I get the same warning for
if (cb != (INDEX) fread (pb, 1, cb, fp))

I also have 3 unreferensed local variables.

Uri
User avatar
Uri Blass
 
Posts: 727
Joined: 09 Oct 2004, 05:59
Location: Tel-Aviv

Re: how to implement tablebases code?

Postby Uri Blass » 14 Dec 2004, 23:19

I decided inspite of the warning to try it and the code seems to works so the question is why are the warning.

Maybe the code still has bug for more complex cases ans I tried only KB vs KN when one of them had mate in 1 and the code knew to tell me that it is mate in 1 and one was KB vs K draw when the code knew to tell me that it is a draw.

I needed to change g to the right directory but not more than it.

Uri
User avatar
Uri Blass
 
Posts: 727
Joined: 09 Oct 2004, 05:59
Location: Tel-Aviv

Re: how to implement tablebases code?

Postby Anonymous » 15 Dec 2004, 06:49

Uri, I think the warnings are harmless. For the error: the compiler gave you pretty good instructions:

> D:\use\tablebases\tbindex.cpp(2735) : fatal error C1076: compiler limit : internal heap limit reached; use /Zm to specify a higher limit

I don't know how to do it under the GUI, for the comman line, I just have to add Zm. For example to make tbindex.o from tbindex.cpp:

cl /O /Zm800 tbindex.cpp

I tried the free command line tools of MSVC. They seem to have a larger default now, and I did not get the error (which I remember from earlier, when I used MSVC version 6).

Note, that the code of tb.c is practically untested. While I did some copying and pasting of my original code, it is rather different from it (different data structures, for example, quite some editing to take out some error checking, which I could not do fast, because it would for example need an Incheck() routine, which I was too lazy to write for this data structure).

Dieter
Anonymous
 

Next

Return to Programming and Technical Discussions

Who is online

Users browsing this forum: No registered users and 42 guests