Moderator: Andres Valverde
I guess there isn't a generic one but I follow TSCP's way of handling the WB protocol:H.G.Muller wrote:Is there some generic main() available (in C) for a Winboard-compatible engine? I mean something that implements the interpreter loop for all the Winboard commands, including setting, starting and stopping the various clocks and variables describing the search-limiting parameters (MaxDepth, TimeLeft, MovesLeft), to which I only have to supply routines Init(), InitBoard(), ThinkAndMove(), PrintMove(), ParseAndMove() to build a Winboard-compatible engine?
while(fgets(line,LINE_SIZE,stdin))
{
char command[LINE_SIZE];
sscanf(line,"%s",command);
if(!strcmp(command,"go"))
{
...
}
else if(!strcmp(command,"new"))
{
...
}
}
H.G.Muller wrote:I was indeed tempted to steal the TSCP code, but I am not sure how I should handle time control. This part of the protocol seems quite confusing. There are two clocks, and one of them measures the time that the computer is thinking, and the other starts running when the computer gives of the move and stops when a move is entered or one of the commands that stops the clock? And if I change colors by a black, white or go command, the clocks are not affected? (i.e. the clock that used to measure time for white might now measure time for black?)
How about setting the clock with the time or otime command? Should this be time used or time left??? Do the clocks count down? If I use the level or st command, does it affect the clocks, or are the clocks only affected by the new command, based on the last level or st command given before it, and do such commands have no effect on a game being in progress?
If the depth is limited by sd, should the engine still pay attention to time?
H.G.Muller wrote:1) is this correct or not?
2) When the computer starts playing again with the other color as before, should I swap the time on the clocks or not?
3) OK. Time left is then to the next time control? So if I set the level to, say, 40 moves per hour, and white (the computer) just did its 40th move, and both sides have used 59 minutes, I should expect Winboard to send time 366000 and otime 6000?
4) Does the clock measure elapsed time since the beginning or time left to the next time control.
5) OK. So these commands are only issued immediately after new, and if the engine recieves them it should immediately set TimeLeft for both clocks to the given time, and MovesLeft for both sides to the given number of moves. Is that correct? Like TimeLeft, MovesLeft is also not swapped when the computer gets to play the other side.
6) OK. This seemed to follow from the protocol description, but it is not what TSCP does (it does change time per move on receiving the sd command), which confused me.
setbuf(stdout, NULL);
setbuf(stdin, NULL);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
int ReadMove(char *s)
{
/* make sure the string looks like a move */
if (s[0] < 'a' || s[0] > 'h' ||
s[1] < '0' || s[1] > '9' ||
s[2] < 'a' || s[2] > 'h' ||
s[3] < '0' || s[3] > '9')
return -1;
/* syntax OK, bring in engine representation */
READ_MOVE;
return 0;
}
/* Generic main() for Winboard-compatible engine */
/* (Inspired by TSCP) */
/* Author: H.G. Muller */
/* The engine is invoked through the following */
/* subroutines, that can draw on the global vaiables */
/* that are maintained by the interface: */
/* Side side to move */
/* Move move input to or output from engine */
/* PromPiece requested piece on promotion move */
/* TimeLeft ms left to next time control */
/* MovesLeft nr of moves to play within TimeLeft */
/* MaxDepth search-depth limit in ply */
/* Post boolean to invite engine babble */
/* InitEngine() progran start-up initialization */
/* InitGame() initialization to start new game */
/* (sets Side, but not time control) */
/* Think() think up move from current position */
/* (leaves move in Move, can be invalid */
/* if position is check- or stalemate) */
/* DoMove() perform the move in Move */
/* (togglese Side) */
/* ReadMove() convert input move to engine format */
/* PrintMove() print Move on standard output */
/* Legal() check Move for legality */
/* ClearBoard() make board empty */
/* PutPiece() put a piece on the board */
/* define this to the codes used in your engine, */
/* if the engine hasn't defined it already. */
#define EMPTY
#define WHITE
#define BLACK
/* make unique integer from engine move representation */
#define PACK_MOVE ...
/* convert intger argument back to engine move representation */
#define UNPACK_MOVE(A) ...
/* Global variables visible to engine. Normally they */
/* would be replaced by the names under which these */
/* are known to your engine, so that they can be */
/* manipulated directly by the interface. */
int Side;
int Move;
int PromPiece;
int Result;
int TimeLeft;
int MovesLeft;
int MaxDepth;
int Post;
int GameHistory[1024];
int GamePtr;
int main()
{
int Computer, MaxTime, MaxMoves, TimeInc, sec;
char line[256], command[256];
int m, nr;
clock_t t;
signal(SIGINT, SIG_IGN);
printf("\n");
InitEngine();
InitGame();
Computer = EMPTY;
MaxTime = 10000; /* 10 sec */
MaxDepth = MAXPLY; /* maximum depth of your search */
for (;;) {
fflush(stdout);
if (Side == Computer) {
/* think up & do move, measure time used */
/* it is the responsibility of the engine */
/* to control its search time based on */
/* MovesLeft, TimeLeft, MaxMoves, TimeInc */
/* Next 'MovesLeft' moves have to be done */
/* within TimeLeft+(MovesLeft-1)*TimeInc */
/* If MovesLeft<0 all remaining moves of */
/* the game have to be done in this time. */
/* If MaxMoves=1 any leftover time is lost*/
t = clock();
Think();
if (!Legal()) {
Computer = EMPTY;
continue;
}
DoMove();
printf("move ");
PrintMove();
printf("\n");
m = (clock() - t)*1000/CLOCKS_PER_SEC;
GameHistory[GamePtr++] = PACK_MOVE;
PrintResult();
/* time-control accounting */
TimeLeft -= m;
TimeLeft += TimeInc;
if(--MovesLeft == 0) {
MovesLeft = MaxMoves;
if(MaxMoves == 1)
TimeLeft = MaxTime;
else TimeLeft += MaxTime;
}
continue;
}
if (!fgets(line, 256, stdin))
return;
if (line[0] == '\n')
continue;
sscanf(line, "%s", command);
if (!strcmp(command, "xboard"))
continue;
if (!strcmp(command, "new")) {
/* start new game */
InitGame();
GamePtr = 0;
Computer = BLACK;
TimeLeft = MaxTime;
MovesLeft = MaxMoves;
continue;
}
if (!strcmp(command, "quit"))
/* exit engine */
return;
if (!strcmp(command, "force")) {
/* computer plays neither */
Computer = EMPTY;
continue;
}
if (!strcmp(command, "white")) {
/* set white to move in current position */
Side = WHITE;
Computer = BLACK;
continue;
}
if (!strcmp(command, "black")) {
/* set blck to move in current position */
Side = BLACK;
Computer = WHITE;
continue;
}
if (!strcmp(command, "st")) {
/* move-on-the-bell mode */
/* indicated by MaxMoves = 1 */
sscanf(line, "st %d", &MaxTime);
MovesLeft = MaxMoves = 1;
TimeLeft = MaxTime *= 1000;
TimeInc = 0;
continue;
}
if (!strcmp(command, "sd")) {
/* set depth limit (remains in force */
/* until next 'sd n' command) */
sscanf(line, "sd %d", &MaxDepth);
continue;
}
if (!strcmp(command, "level")) {
/* normal or blitz time control */
sec = 0;
if(sscanf(line, "level %d %d %d",
&MaxMoves, &MaxTime, &TimeInc)!=3 &&
sscanf(line, "level %d %d:%d %d",
&MaxMoves, &MaxTime, &sec, &TimeInc)!=4)
continue;
MovesLeft = MaxMoves;
TimeLeft = MaxTime = 60000*MaxTime + 1000*sec;
TimeInc *= 1000;
continue;
}
if (!strcmp(command, "time")) {
/* set time left on clock */
sscanf(line, "time %d", &TimeLeft);
TimeLeft *= 10; /* centi-sec to ms */
continue;
}
if (!strcmp(command, "otim")) {
/* opponent's time (not kept, so ignore) */
continue;
}
if (!strcmp(command, "go")) {
/* set computer to play current side to move */
Computer = Side;
continue;
}
if (!strcmp(command, "hint")) {
Think();
if (!Legal())
continue;
printf("Hint: ");
PrintMove();
printf("\n");
continue;
}
if (!strcmp(command, "undo") && (nr=1) ||
!strcmp(command, "remove") && (nr=2) ) {
/* 'take back' moves by replaying game */
/* from history until desired ply */
if (GamePtr < nr)
continue;
GamePtr -= nr;
InitGame();
for(nr=0; nr<GamePtr; nr++) {
UNPACK_MOVE(GameHistory[nr]);
DoMove();
}
continue;
}
if (!strcmp(command, "post")) {
Post = 1;
continue;
}
if (!strcmp(command, "nopost")) {
Post = 0;
continue;
}
if (!strcmp(command, "edit")) {
int color = WHITE;
while(fgets(line, 256, stdin)) {
m = line[0];
if(m=='.') break;
if(m=='#') {
ClearBoard();
continue;
}
if(m=='c') {
color = WHITE+BLACK - color;
continue;
}
if((m=='P' || m=='N' || m=='B' ||
m=='R' || m=='Q' || m=='K')
&& line[1] >= 'a' && line[1] <= 'h'
&& line[2] >= '1' && line[2] <= '8') {
PutPiece(color);
continue;
}
}
continue;
}
/* command not recoognized, assume input move */
m = ReadMove(line);
if (m == -1)
/* doesn't have move syntax */
printf("Error (unknown command): %s\n", command);
else if(!Legal())
/* did have move syntax, but illegal move */
printf("Illegal move:%s\n", line);
else { /* legal move, perform it */
GameHistory[GamePtr++] = PACK_MOVE;
DoMove();
PrintResult();
}
}
}
if (!strcmp(command, "white")) {
/* set white to move in current position */
Side = WHITE;
Computer = BLACK;
continue;
}
if (!strcmp(command, "black")) {
/* set blck to move in current position */
Side = BLACK;
Computer = WHITE;
continue;
}
if (!strcmp(command, "white")) {
/* set white to move in current position */
Side = WHITE;
Computer = SIDE;
Opponent = BLACK;
continue;
}
if (!strcmp(command, "black")) {
/* set blck to move in current position */
Side = BLACK;
Computer = SIDE;
Opponent = WHITE;
continue;
}
So what is a 'winboard debug'? Is there a way to monitor the communication between Winboard and the engine?
if (!strcmp(command, "white")) {
/* set white to move in current position */
Side = WHITE;
Computer = SIDE;
Opponent = BLACK;
continue;
}
if (!strcmp(command, "black")) {
/* set blck to move in current position */
Side = BLACK;
Computer = SIDE;
Opponent = WHITE;
continue;
}
if (!strcmp(command, "white")) {
/* set white to move in current position */
Side = WHITE;
Computer = SIDE;
Opponent = BLACK;
continue;
}
if (!strcmp(command, "black")) {
/* set blck to move in current position */
Side = BLACK;
Computer = SIDE;
Opponent = WHITE;
continue;
}
/* white (WB)
*
* Set White on move. Set the engine to play Black. Stop clocks.
*/
if (!strcmp(command, "white"))
{
......
}
H.G.Muller wrote:After clearing the hash table also before taking an input move, the winboard-compatible micro-Max runs fine. So it seems the generic xboard driver above is OK.
Return to Winboard and related Topics
Users browsing this forum: No registered users and 24 guests