Re: Current world's smallest chess program
Posted: Sun Feb 22, 2009 8:16 am
Unfortunaly the adapter still had problems, as on Toledo the indication of a promotion piece is mandatory (while uMax assumes Q if it is not given). I fixed the adapter so that it now correctly handles promotions both ways (Toleo can underpromote!). The new source is given below. (Not thoroughly tested, as promotions are rare, and Toledo plays slowly.)
Do you have any idea what causes the 'memory leak' in Toledo? Is it that 'main' reserves space for buffers, each time it is called? (And because 'main' is used as Search() in Toledo it is called really often!) Not having a separate routine for Search() might save some charcters, but this effect is quickly undone if you need all the buffer stuff to prevent it from crashing! (Which probaby forces you to include stdio.h as well...)
Can you also compile a blitz version of Toledo? You can make this by changing the '5' on the last line (3rd character) into '4'.
Note that Toledo tends to hang after a game, using full CPU. The adapter tries to kill it, but apparently this does not work.
The new Max2WB.c:
Do you have any idea what causes the 'memory leak' in Toledo? Is it that 'main' reserves space for buffers, each time it is called? (And because 'main' is used as Search() in Toledo it is called really often!) Not having a separate routine for Search() might save some charcters, but this effect is quickly undone if you need all the buffer stuff to prevent it from crashing! (Which probaby forces you to include stdio.h as well...)
Can you also compile a blitz version of Toledo? You can make this by changing the '5' on the last line (3rd character) into '4'.
Note that Toledo tends to hang after a game, using full CPU. The adapter tries to kill it, but apparently this does not work.
The new Max2WB.c:
Code: Select all
/**************************************************/
/* Max2WB adapter by H.G. Muller */
/* Allows micro-Max stand-alone versions, as well */
/* as Toledo_nanochess to play under WinBoard */
/* Use "Max2WB <egine> as WinBoard chess-program */
/* name, where <engine> is the name of the engine */
/* executable file. */
/**************************************************/
#include <stdio.h>
#include <signal.h>
char before[80], after[80];
FILE *f;
void ReadBoard(int inp, char *board)
{ // read 64 non-blank characters
int i;
char c, *oldBoard = board;
for(i=0; i<64; i++) {
do{ read(inp, &c, 1);
} while(c == '\n' || c == ' ' || c == '\t' || c == '\r');
*board++ = c;
}
fprintf(f, "E< '%s'\n", oldBoard); fflush(f);
}
void ProduceMove(int from, int to)
{
int ifrom=-1, ito=-1, i;
write(to, "\n", 1); // send thinking command (empty line)
ReadBoard(from, after); // should respond with board;
for(i=0; i<64; i++) {
if(before[i] == after[i]) continue;
if(after[i] == '.') {
// squre became empty: from-square
if(ifrom <= 0 || ifrom == 7 || ifrom == 070 || ifrom == 077)
ifrom = i; // first one, or overwrite corner Rook
else if(ifrom != 4 && ifrom != 074)
ifrom = 65; // two fromSqr, and not K or R: must be e.p.
} else {
// if not empty after move, must be to-square
if(ito < 0 || ito != 2 && ito != 072)
ito = i; // first one, or write King over Rook
}
if(ifrom == 65) ifrom = ito ^ 010; // calculate e.p. fromSqr
}
if(before[ifrom] != after[ito]) // piece changed: promotion
printf("move %c%c%c%c%c\n", 'a'+(ifrom&7), '8'-(ifrom>>3),
'a'+(ito&7), '8'-(ito>>3),
after[ito]|32);
else
printf("move %c%c%c%c\n", 'a'+(ifrom&7), '8'-(ifrom>>3),
'a'+(ito&7), '8'-(ito>>3));
fflush(stdout);
}
main(int argc, char **argv)
{
int toPipe[2], fromPipe[2], from_prog, to_prog, pid, pid2, i, j;
char c, buf[256], command[256], *name;
if(argc < 2)
exit(0); // first arg must be engine
name = argv[1]; while(*name) name++;
while(name-argv[1] > 0 && name[-1] != '\\' && name[-1] != '/') name--;
/* OK, so we now send through to_prog, receive through from_prog */
f = fopen("log", "w");
{ /* cmain loop ommunicates to WinBoard */
int forceMode = 0;
setbuf(stdin, NULL);
i = 0;
while((c=getchar()) != EOF) {
if(c == '\r') continue;
if(c != '\n') { buf[i++] = c; continue; }
buf[i] = 0;
fprintf(f, "WB> %s\n", buf); fflush(f);
sscanf(buf, "%s", command);
if(!strcmp(command, "quit")) // pass on & kill
close(to_prog),
close(from_prog),
kill(pid, SIGKILL),
fclose(f),
exit(0);
else if(!strcmp(command, "result")) // pass on & kill
close(to_prog),
close(from_prog),
kill(pid, SIGKILL);
else if(!strcmp(command, "protover"))
printf("feature myname=\"%s\" done=1\n", name),
fflush(stdout);
else if(!strcmp(command, "go")) // end force mode & think
forceMode=0,
ProduceMove(from_prog, to_prog);
else if(!strcmp(command, "force")) // remember
forceMode = 1;
else if(!strcmp(command, "new")) { // start new engine proc
/* close old pipes */
if(from_prog)close(from_prog);
if(to_prog)close(to_prog);
/* set up pipes */
pipe(toPipe);
pipe(fromPipe);
/* create engine */
if((pid = fork()) == 0)
{ /* child */
fclose(stderr);
close(toPipe[1]);
close(fromPipe[0]);
dup2(toPipe[0], 0);
dup2(fromPipe[1], 1);
if(toPipe[0] >= 2) close(toPipe[0]);
close(fromPipe[1]);
execv(argv[1], argv+1);
perror(argv[1]);
exit(1);
}
/* parent */
close(toPipe[0]);
close(fromPipe[1]);
from_prog = fromPipe[0];
to_prog = toPipe[1];
forceMode = 0;
ReadBoard(from_prog, before);
} else if((buf[4] == 0 || buf[5] == 0) &&
command[0] >= 'a' && command[0] <= 'h' &&
command[2] >= 'a' && command[2] <= 'h' &&
command[1] >= '1' && command[1] <= '8' &&
command[3] >= '1' && command[3] <= '8' ) // pass on
{ /* move */ char c; int k;
if(c = buf[4]) {
k = buf[0]-'a'+('8'-buf[1])*8;
if(after[k]=='+' || after[k] == '*') // uMax
k = c=='q'?0:c=='r'?1:c=='b'?2:c=='n'?3:4;
else k = c=='q'?6:c=='r'?5:c=='b'?4:c=='n'?3:2;
sprintf(command, "%c%c%c%c%d\n",
buf[0], buf[1], buf[2], buf[3], k);
write(to_prog, command, 6);
} else { sprintf(command, "%c%c%c%c\n",
buf[0], buf[1], buf[2], buf[3]);
write(to_prog, command, 5);
}
ReadBoard(from_prog, before); // read board after forced move
if(!forceMode) // go thinking if not in force mode
ProduceMove(from_prog, to_prog);
}
i = 0;
}
}
}