Gaviota EGTBs, interface proposal for programmers

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
michiguel
Posts: 6401
Joined: Thu Mar 09, 2006 8:30 pm
Location: Chicago, Illinois, USA

Gaviota EGTBs, interface proposal for programmers

Post by michiguel »

Is there anything else that a tablebase interface should have?
Here you have the .h file and an example of how to probe the tablebases.
Before I release the code, I want to make sure that the interface has been chosen properly. Is there any potential problem I am missing? This is in C, is there anything that will inconvenience C++ programmers?

Miguel

This is the gtb.h file that should be included in the engine source. Each of the functions will be properly commented, but I think they have a name that are self-explanatory for now. Are they?

Code: Select all

#if !defined(H_GTB)
#define H_GTB
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

/* this includes a boolean type bool_t */
#include "bool_t.h"

/* this includes SQUARE and SQ_CONTENT types */
#include "tbtypes.h"


enum TB_return_values {	tb_DRAW = 0, tb_WMATE = 1, tb_BMATE = 2, tb_FORBID = 3, tb_UNKNOWN = 7};


extern void 	tb_init (void);
extern void		tb_done (void);


extern bool_t 	tb_probe 
						   (unsigned int stm, 
			 				SQUARE epsq,
			 				const SQUARE *inp_wSQ, 
			 				const SQUARE *inp_bSQ,
			 				const SQ_CONTENT *inp_wPC, 
			 				const SQ_CONTENT *inp_bPC,
			 				/*@out@*/ unsigned int *tbinfo, 
			 				/*@out@*/ unsigned int *plies);
							
/* tb cache routines */

extern bool_t	tbcache_init (size_t cache_mem, size_t block_mem);
extern void	tbcache_done (void);
extern void	tbcache_on();
extern void	tbcache_off();

/* for path */

extern bool_t 	tb_setpath (const char *path);
extern bool_t 	tb_addpath (const char *path);


/* building routines */

extern void	tb_set_build (int men);
extern bool_t	tb_set_validate (int men);
extern void	tb_individual_validate (const char *s);
extern void 	tb_set_cpu_usage (int cores);

/* testing routines */

extern bool_t 	tb_set_testlongest (int men);

/*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
#endif
This will be an example file showing how to probe the tablebases. It should compile and give a quick idea how to use them.

Code: Select all

#include <stdlib.h>

#include "gtb.h"
#include "tbtypes.h"
#include "bool_t.h"

/* The following are numbers the programmer should be aware of */

/*-------------------
   SQ_CONTENT Values
  -------------------*/

/* pieces definition */

#define NOPIECE 0u
#define PAWN    1u
#define KNIGHT  2u
#define BISHOP  3u
#define ROOK    4u
#define QUEEN   5u
#define KING    6u

/*-------------------
	SIDE Values
  -------------------*/

#define WHITE_TO_MOVE 0
#define BLACK_TO_MOVE 1

/*-------------------
       SQUARES
  -------------------*/

/* from A1=1 to H8=63, different squares posibles, NOSQUARE=64 */

enum SQUARES &#123;
	A1,B1,C1,D1,E1,F1,G1,H1,
	A2,B2,C2,D2,E2,F2,G2,H2,
	A3,B3,C3,D3,E3,F3,G3,H3,
	A4,B4,C4,D4,E4,F4,G4,H4,
	A5,B5,C5,D5,E5,F5,G5,H5,
	A6,B6,C6,D6,E6,F6,G6,H6,
	A7,B7,C7,D7,E7,F7,G7,H7,
	A8,B8,C8,D8,E8,F8,G8,H8,
	NOSQUARE
&#125;;

/*-------------------
      CASTLING
  -------------------*/

#define wOO  &#40;1<<3&#41;
#define wOOO &#40;1<<2&#41;
#define bOO  &#40;1<<1&#41;
#define bOOO &#40;1<<0&#41;

int main &#40;void&#41;
&#123;

		unsigned int	info = tb_UNKNOWN; /* default, no tbvalue */
		unsigned int	pliestomate;
		bool_t 			tb_available;

		/*----------------------------------*\
		|	Elements that define a position
		\*----------------------------------*/

		unsigned int	stm;			/* side to move */
		SQUARE 			ep_square;		/* target square for an en passant capture */ 
		unsigned int	castl; 			/* castling availability, 0 => no castles avail */
		SQUARE			ws&#91;17&#93;, bs&#91;17&#93;; /* list of squares for white and black */
		SQ_CONTENT		wp&#91;17&#93;, bp&#91;17&#93;; /* what pieces are on those squares */


		/*----------------------------------*\
		|	Initialization
		|
		|	Include somthing like this at 
		|	the beginning of the program.	
		\*----------------------------------*/

		tb_init&#40;);
		tb_setcompression &#40;1&#41;;
		tb_setpath ("/home/user/tb/");
		tb_addpath ("/media/bigdisk/tb/");
		tbcache_init &#40;64*1024*1024 /* cache size 64M */, 32*1024 /* block size 32k */);
		tbcache_on&#40;);
	
		/*--------------------------------------*\
		|
		|	ASSIGNING POSITIONAL VALUES for 
		|	one probing example
		|
		|	Position we try to probe&#58;
		|	
		|	1r6/6k1/8/8/8/8/1P6/1KR5 w - - 0 1 
		|	
		\*--------------------------------------*/

		stm =  WHITE_TO_MOVE; 	/* 0 = white to move, 1 = black to move */
		ep_square = NOSQUARE; 	/* no ep available */
		castl = 0; 				/* No castling available */

		ws&#91;0&#93; = B1;
		ws&#91;1&#93; = C1;
		ws&#91;2&#93; = B2;
		ws&#91;3&#93; = NOSQUARE;

		wp&#91;0&#93; = KING;
		wp&#91;1&#93; = ROOK;
		wp&#91;2&#93; = PAWN;
		wp&#91;3&#93; = NOPIECE;

		bs&#91;0&#93; = G7;
		bs&#91;1&#93; = B8;
		bs&#91;2&#93; = NOSQUARE;

		bp&#91;0&#93; = KING;
		bp&#91;1&#93; = ROOK;
		bp&#91;2&#93; = NOPIECE;


		/*----------------------------------*\
		|
		|		PROBING TBs
		|	
		\*----------------------------------*/

		tb_available = egtb_probe &#40;stm, ep_square, ws, bs, wp, bp, &info, &pliestomate&#41;;

		if &#40;tb_available&#41; &#123;

			if &#40;info == tb_DRAW&#41;
				printf ("Draw\n");
			else if &#40;info == tb_WMATE && stm == WHITE_TO_MOVE&#41;
 				printf ("White mates, plies=%d\n", pliestomate&#41;;
			else if &#40;info == tb_BMATE && stm == BLACK_TO_MOVE&#41;
 				printf ("Black mates, plies=%d\n", pliestomate&#41;;
			else if &#40;info == tb_WMATE && stm == BLACK_TO_MOVE&#41;
 				printf ("Black is mated, plies=%d\n", pliestomate&#41;;
			else if &#40;info == tb_BMATE && stm == WHITE_TO_MOVE&#41;
 				printf ("White is mated, plies=%d\n", pliestomate&#41;;			
			else &#123;
 				printf ("ERROR\n");	
			&#125;
		&#125; else &#123;
 				printf ("Tablebase not available\n");	
		&#125;


		/*----------------------------------*\
		|			Clean up
		\*----------------------------------*/

		tbcache_done&#40;);
		tb_done&#40;);

		/*----------------------------------*\
		|			Return
		\*----------------------------------*/

		if &#40;tb_available&#41;
			return EXIT_SUCCESS;
		else
			return EXIT_FAILURE;
&#125;
Aaron Becker
Posts: 292
Joined: Tue Jul 07, 2009 4:56 am

Re: Gaviota EGTBs, interface proposal for programmers

Post by Aaron Becker »

It looks very well designed to me. If you release it soon, I'll be sure to add support for Gaviota tablebases in the next version of Daydreamer. One point on C++ compatibility. If you wrap all the code in your header files with the following code:

Code: Select all

#ifdef __cplusplus
extern "C" &#123;
#endif

/* body of the C header goes here */

#ifdef __cplusplus
&#125;
#endif
Then any C++ files can include the headers directly and all functions will receive the appropriate linkage. It's a bit ugly, but it allows the same header to code to work correctly and integrate well in both C and C++ programs.
User avatar
michiguel
Posts: 6401
Joined: Thu Mar 09, 2006 8:30 pm
Location: Chicago, Illinois, USA

Re: Gaviota EGTBs, interface proposal for programmers

Post by michiguel »

Aaron Becker wrote:It looks very well designed to me. If you release it soon, I'll be sure to add support for Gaviota tablebases in the next version of Daydreamer. One point on C++ compatibility. If you wrap all the code in your header files with the following code:

Code: Select all

#ifdef __cplusplus
extern "C" &#123;
#endif

/* body of the C header goes here */

#ifdef __cplusplus
&#125;
#endif
Then any C++ files can include the headers directly and all functions will receive the appropriate linkage. It's a bit ugly, but it allows the same header to code to work correctly and integrate well in both C and C++ programs.
Thanks, I will do that.

I plan to release this very soon as "beta" to make sure that whoever supports it can sends me feedback. I want to be done with it this year.

As always, there are several things that can be optimized "behind the curtains", but if I wait for that, this will never get out the door. As they are now, the TBs are good enough (I think). Once we settle on the interface, I (or someone else since it will be open source) can keep improving it.

By the way, I found a couple of mistakes and I will correct them. I omitted the castling as a parameter and A1 is 0, not 1. Castling is not supported, but I want to have it as a parameter because I may support it in the future. The function will return FALSE if it sees that castles are available as if the file is absent. Of course this is not relevant for game play but I think that people who are interested in chess problems will appreciate it. I plant to have the castling supported in one file only, so it will not interfere with the rest of the files and people won't have to generate the files again. If the file is present, fine, if it is not, the function will return FALSE.

Miguel
User avatar
michiguel
Posts: 6401
Joined: Thu Mar 09, 2006 8:30 pm
Location: Chicago, Illinois, USA

Re: Gaviota EGTBs, interface proposal for programmers

Post by michiguel »

michiguel wrote:Is there anything else that a tablebase interface should have?
Here you have the .h file and an example of how to probe the tablebases.
Before I release the code, I want to make sure that the interface has been chosen properly. Is there any potential problem I am missing? This is in C, is there anything that will inconvenience C++ programmers?

Miguel

This is the gtb.h file that should be included in the engine source. Each of the functions will be properly commented, but I think they have a name that are self-explanatory for now. Are they?

Code: Select all

#ifdef __cplusplus
extern "C" &#123;
#endif

#if !defined&#40;H_GTB&#41;
#define H_GTB
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

/* this includes a boolean type bool_t */
#include "bool_t.h"

/* this includes SQUARE and SQ_CONTENT types */
#include "tbtypes.h"


enum TB_return_values &#123;	tb_DRAW = 0, tb_WMATE = 1, tb_BMATE = 2, tb_FORBID = 3, tb_UNKNOWN = 7&#125;;


extern void		tb_init &#40;void&#41;;
extern void		tb_done &#40;void&#41;;

extern bool_t 	tb_probe 
							&#40;unsigned int stm, 
							 unsigned int castles,
							 SQUARE epsq,
							 const SQUARE *inp_wSQ, 
							 const SQUARE *inp_bSQ,
							 const SQ_CONTENT *inp_wPC, 
							 const SQ_CONTENT *inp_bPC,
							 /*@out@*/ unsigned int *tbinfo, 
							 /*@out@*/ unsigned int *plies&#41;;
							
/* tb cache routines */

extern bool_t	tbcache_init &#40;size_t cache_mem, size_t block_mem&#41;;
extern void	tbcache_done &#40;void&#41;;
extern void	tbcache_on&#40;);
extern void	tbcache_off&#40;);

/* for path */

extern bool_t 	tb_setpath &#40;const char *path&#41;;
extern bool_t 	tb_addpath &#40;const char *path&#41;;


/* building routines */

extern void	tb_set_build &#40;int men&#41;;
extern bool_t	tb_set_validate &#40;int men&#41;;
extern void	tb_individual_validate &#40;const char *s&#41;;
extern void 	tb_set_cpu_usage &#40;int cores&#41;;

/* testing routines */

extern bool_t 	tb_set_testlongest &#40;int men&#41;;

/*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
#endif

#ifdef __cplusplus
&#125;
#endif 
This will be an example file showing how to probe the tablebases. It should compile and give a quick idea how to use them.

Code: Select all

#include <stdlib.h>

#include "gtb.h"
#include "tbtypes.h"
#include "bool_t.h"

/* The following are numbers the programmer should be aware of */

/*-------------------
   SQ_CONTENT Values
  -------------------*/

/* pieces definition */

#define NOPIECE 0u
#define PAWN    1u
#define KNIGHT  2u
#define BISHOP  3u
#define ROOK    4u
#define QUEEN   5u
#define KING    6u

/*-------------------
	SIDE Values
  -------------------*/

#define WHITE_TO_MOVE 0
#define BLACK_TO_MOVE 1

/*-------------------
       SQUARES
  -------------------*/

/* from A1=0 to H8=63, different squares posibles, NOSQUARE=64 */

enum SQUARES &#123;
	A1,B1,C1,D1,E1,F1,G1,H1,
	A2,B2,C2,D2,E2,F2,G2,H2,
	A3,B3,C3,D3,E3,F3,G3,H3,
	A4,B4,C4,D4,E4,F4,G4,H4,
	A5,B5,C5,D5,E5,F5,G5,H5,
	A6,B6,C6,D6,E6,F6,G6,H6,
	A7,B7,C7,D7,E7,F7,G7,H7,
	A8,B8,C8,D8,E8,F8,G8,H8,
	NOSQUARE
&#125;;

/*-------------------
      CASTLING
  -------------------*/

#define wOO  &#40;1<<3&#41;
#define wOOO &#40;1<<2&#41;
#define bOO  &#40;1<<1&#41;
#define bOOO &#40;1<<0&#41;

int main &#40;void&#41;
&#123;

		unsigned int	info = tb_UNKNOWN; /* default, no tbvalue */
		unsigned int	pliestomate;
		bool_t 			tb_available;

		/*----------------------------------*\
		|	Elements that define a position
		\*----------------------------------*/

		unsigned int	stm;			/* side to move */
		SQUARE 			ep_square;		/* target square for an en passant capture */ 
		unsigned int	castl; 			/* castling availability, 0 => no castles avail */
		SQUARE			ws&#91;17&#93;, bs&#91;17&#93;; /* list of squares for white and black */
		SQ_CONTENT		wp&#91;17&#93;, bp&#91;17&#93;; /* what pieces are on those squares */


		/*----------------------------------*\
		|	Initialization
		|
		|	Include somthing like this at 
		|	the beginning of the program.	
		\*----------------------------------*/

		tb_init&#40;);
		tb_setcompression &#40;1&#41;;
		tb_setpath ("/home/user/tb/");
		tb_addpath ("/media/bigdisk/tb/");
		tbcache_init &#40;64*1024*1024 /* cache size 64M */, 32*1024 /* block size 32k */);
		tbcache_on&#40;);
	
		/*--------------------------------------*\
		|
		|	ASSIGNING POSITIONAL VALUES for 
		|	one probing example
		|
		|	Position we try to probe&#58;
		|	
		|	1r6/6k1/8/8/8/8/1P6/1KR5 w - - 0 1 
		|	
		\*--------------------------------------*/

		stm =  WHITE_TO_MOVE; 	/* 0 = white to move, 1 = black to move */
		ep_square = NOSQUARE; 	/* no ep available */
		castl = 0; 				/* No castling available */

		ws&#91;0&#93; = B1;
		ws&#91;1&#93; = C1;
		ws&#91;2&#93; = B2;
		ws&#91;3&#93; = NOSQUARE;

		wp&#91;0&#93; = KING;
		wp&#91;1&#93; = ROOK;
		wp&#91;2&#93; = PAWN;
		wp&#91;3&#93; = NOPIECE;

		bs&#91;0&#93; = G7;
		bs&#91;1&#93; = B8;
		bs&#91;2&#93; = NOSQUARE;

		bp&#91;0&#93; = KING;
		bp&#91;1&#93; = ROOK;
		bp&#91;2&#93; = NOPIECE;


		/*----------------------------------*\
		|
		|		PROBING TBs
		|	
		\*----------------------------------*/

		tb_available = tb_probe &#40;stm, castl, ep_square, ws, bs, wp, bp, &info, &pliestomate&#41;;

		if &#40;tb_available&#41; &#123;

			if &#40;info == tb_DRAW&#41;
				printf ("Draw\n");
			else if &#40;info == tb_WMATE && stm == WHITE_TO_MOVE&#41;
 				printf ("White mates, plies=%d\n", pliestomate&#41;;
			else if &#40;info == tb_BMATE && stm == BLACK_TO_MOVE&#41;
 				printf ("Black mates, plies=%d\n", pliestomate&#41;;
			else if &#40;info == tb_WMATE && stm == BLACK_TO_MOVE&#41;
 				printf ("Black is mated, plies=%d\n", pliestomate&#41;;
			else if &#40;info == tb_BMATE && stm == WHITE_TO_MOVE&#41;
 				printf ("White is mated, plies=%d\n", pliestomate&#41;;			
			else &#123;
 				printf ("ERROR\n");	
			&#125;
		&#125; else &#123;
 				printf ("Tablebase not available\n");	
		&#125;


		/*----------------------------------*\
		|			Clean up
		\*----------------------------------*/

		tbcache_done&#40;);
		tb_done&#40;);

		/*----------------------------------*\
		|			Return
		\*----------------------------------*/

		if &#40;tb_available&#41;
			return EXIT_SUCCESS;
		else
			return EXIT_FAILURE;
&#125;
I corrected the code. Sorry that the tabs are not working perfectly.

Miguel
Aleks Peshkov
Posts: 892
Joined: Sun Nov 19, 2006 9:16 pm
Location: Russia

Re: Gaviota EGTBs, interface proposal for programmers

Post by Aleks Peshkov »

Not all programs have the same piece, square, castling, side to move encoding.
I think it make sense to have a plain FEN-string as input parameter.
Gian-Carlo Pascutto
Posts: 1243
Joined: Sat Dec 13, 2008 7:00 pm

Re: Gaviota EGTBs, interface proposal for programmers

Post by Gian-Carlo Pascutto »

Aleks Peshkov wrote:Not all programs have the same piece, square, castling, side to move encoding.
I think it make sense to have a plain FEN-string as input parameter.
Very dumb idea, requires both ends to do slow string processing.

Converting between square representations is trivial and fast.
Michel
Posts: 2272
Joined: Mon Sep 29, 2008 1:50 am

Re: Gaviota EGTBs, interface proposal for programmers

Post by Michel »

The only issue I have is that the table base object seems to be global.

For an api that is going to be widely used I would expect tb_init to return a pointer (i.e. object) which should then be passed as an argument to the other table base handling routines.
User avatar
rvida
Posts: 481
Joined: Thu Apr 16, 2009 12:00 pm
Location: Slovakia, EU

Re: Gaviota EGTBs, interface proposal for programmers

Post by rvida »

Michel wrote:The only issue I have is that the table base object seems to be global.
As long as it is thread safe, I have no problem with that.
zamar
Posts: 613
Joined: Sun Jan 18, 2009 7:03 am

Re: Gaviota EGTBs, interface proposal for programmers

Post by zamar »

Interface looks really nice and easy to use!!

I don't understand too well the internals of EGTB, so is there some reason why program using TBs should specify internal memory block size?
extern bool_t tbcache_init (size_t cache_mem, size_t block_mem);

Another thing is that for Nalimov TBs UCI specifies:

* NalimovPath, type string:
this is the path on the hard disk to the Nalimov compressed format.

* NalimovCache, type spin:
this is the size in MB for the cache for the nalimov table bases

I hope that when you release your EGTBs, you could give recommendations for the used UCI option names, so that we can get some standardization in here.
Joona Kiiski
Michel
Posts: 2272
Joined: Mon Sep 29, 2008 1:50 am

Re: Gaviota EGTBs, interface proposal for programmers

Post by Michel »

As long as it is thread safe, I have no problem with that.
Thread safety has nothing to do with it. An api should not contain global state because it dictates global state in all clients.