This is a simple C program that launches two uci engines to play a simple game. I tested that it compiles and runs under linux.
Incidentally, my xboard cannot work anymore (arch linux +kde; something about... Failed to start 1st chess engine... ) so my chess program has to stop for a while; there is so far no good-enough replacement linux chess interface for uci engines meant for programmers.
Code: Select all
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/timeb.h>
#include <sys/time.h>
#include <assert.h>
/* This program launches two uci engines and have them play a simple game. */
#define WHITE 0
#define BLACK 1
static FILE * filein[2], * fileout[2];
void sendmsg(const char *msg, const int bw) {
fprintf(fileout[bw], "%s", msg);
}
void myfatal(const char *msg) {
char buf[1024];
sprintf(buf, "Program aborting, %s", msg);
perror(buf);
printf("%s", fgets(buf, 1023, stderr));
sendmsg("quit\n", WHITE);
sendmsg("quit\n", BLACK);
exit(EXIT_FAILURE);
}
void getmsg(char * line, int nbyte, const int bw) {
if (fgets(line, nbyte, filein[bw]) == NULL) {
char buf[256];
sprintf(buf, "side %d getmsg - fgets failed", bw);
myfatal(buf);
}
}
struct timeval tv_start;
unsigned int msecfrom(struct timeval *start) {
struct timeval now;
if (!gettimeofday(&now, NULL));
else {
myfatal("gettimeofday failed");
}
return (now.tv_sec - start->tv_sec) * 1000
+ (now.tv_usec - start->tv_usec) / 1000;
}
int main(int argc, char *argv[]) {
char line[65536];
char command[1024];
pid_t pid[2];
int pipe_i[2][2];
int pipe_o[2][2];
/* Create the white pipes, fork white child process */
if (pipe(pipe_i[WHITE])) {
myfatal("create pipe_i failed");
}
if (pipe(pipe_o[WHITE])) {
myfatal("create pipe_o failed");
}
/* Create white child process. */
pid[WHITE] = fork();
if (pid[WHITE] < (pid_t) 0) {
myfatal("fork failed");
}
if (pid[WHITE] == (pid_t) 0) {
/* This is the child process. Close other end first. */
// replace standard input with input part of pipe
printf("white child process\n");
if (dup2(pipe_i[WHITE][0], 0) != -1);
else {
myfatal("dup2 pipe_i[WHITE][0] failed");
}
close(pipe_i[WHITE][1]);
// replace standard output with output part of pipe
if (dup2(pipe_o[WHITE][1], 1) != -1);
else {
myfatal("dup2 pipe_o[1] failed");
}
close(pipe_o[WHITE][0]);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
execlp("/home/rasjid/chess/fruit/fruit_22", "fruit_22", NULL);
//execlp("/home/rasjid/chess/texel/texel-101-64-ja", "texel", NULL);
//execl returns only on error
exit(EXIT_FAILURE);
} else {
//parent process
printf("parent process\n");
close(pipe_i[WHITE][0]);
close(pipe_o[WHITE][1]);
if ((filein[WHITE] = fdopen(pipe_o[WHITE][0], "r")) == NULL) {
myfatal("parent open pipe_o[0] failed");
}
if ((fileout[WHITE] = fdopen(pipe_i[WHITE][1], "w")) == NULL) {
myfatal("parent open pipe_i[1] failed");
}
setvbuf(filein[WHITE], NULL, _IONBF, 0);
setvbuf(fileout[WHITE], NULL, _IONBF, 0);
}
/* Create the black pipes, fork black child process */
if (pipe(pipe_i[BLACK])) {
myfatal("create pipe_i failed");
}
if (pipe(pipe_o[BLACK])) {
myfatal("create pipe_o failed");
}
/* Create black child process. */
pid[BLACK] = fork();
if (pid[BLACK] < (pid_t) 0) {
myfatal("fork failed");
}
if (pid[BLACK] == (pid_t) 0) {
/* This is the child process. Close other end first. */
// replace standard input with input part of pipe
printf("black child process\n");
//white pipes are also inherited, child end must be closed
close(pipe_i[WHITE][1]);
close(pipe_o[WHITE][0]);
if (dup2(pipe_i[BLACK][0], 0) != -1);
else {
myfatal("dup2 pipe_i[BLACK][0] failed");
}
close(pipe_i[BLACK][1]);
// replace standard output with output part of pipe
if (dup2(pipe_o[BLACK][1], 1) != -1);
else {
myfatal("dup2 pipe_o[1] failed");
}
close(pipe_o[BLACK][0]);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
//execlp("/home/rasjid/chess/fruit/fruit_22", "fruit_22", NULL);
execlp("/home/rasjid/chess/texel/texel-101-64-ja", "texel", NULL);
//execl returns only on error
exit(EXIT_FAILURE);
} else {
//parent process
printf("parent process\n");
close(pipe_i[BLACK][0]);
close(pipe_o[BLACK][1]);
if ((filein[BLACK] = fdopen(pipe_o[BLACK][0], "r")) == NULL) {
myfatal("parent open pipe_o[0] failed");
}
if ((fileout[BLACK] = fdopen(pipe_i[BLACK][1], "w")) == NULL) {
myfatal("parent open pipe_i[1] failed");
}
setvbuf(filein[BLACK], NULL, _IONBF, 0);
setvbuf(fileout[BLACK], NULL, _IONBF, 0);
}
sendmsg("uci\n", WHITE);
while (1) {
getmsg(line, 65536, WHITE);
sscanf(line, "%s", command);
if (!strcmp(command, "uciok")) {
sendmsg("setoption name Hash value 64", WHITE);
break;
}
}
printf("white uci ok\n");
sendmsg("uci\n", BLACK);
while (1) {
getmsg(line, 65536, BLACK);
sscanf(line, "%s", command);
if (!strcmp(command, "uciok")) {
sendmsg("setoption name Hash value 64", BLACK);
break;
}
}
printf("black uci ok\n");
//postion command
//sendmsg("isready\n", WHITE);
int side, nummove;
unsigned int ms;
int clockms[2] = {60000, 60000};
char init_position[1024]; // = "position startpos";
char moves[1024][8];
char buf[2048 * 8], *pmove;
moves[0][0] = 0;
sprintf(init_position, "position startpos");
side = WHITE;
while (1) {
sprintf(buf, "%s", init_position);
nummove = 0;
pmove = &moves[0][0];
while (*pmove != 0) {
if (nummove == 0) {
strcat(buf, " moves ");
} else {
strcat(buf, " ");
}
strcat(buf, pmove);
pmove += 8;
++nummove;
}
strcat(buf, "\n");
//send position command
printf("sent %s\n", buf);
sendmsg(buf, side);
sendmsg("isready\n", side);
while (1) {
getmsg(line, 65536, side);
sscanf(line, "%s", command);
if (!strcmp(command, "readyok")) {
sprintf(buf, "go wtime %d btime %d\n", clockms[0], clockms[1]);
//send go command
sendmsg(buf, side);
if (!gettimeofday(&tv_start, NULL));
else {
myfatal("W gettimeofday error");
}
printf("sent %s\n", buf);
// wait for move
while (1) {
getmsg(line, 65536, side);
ms = msecfrom(&tv_start);
sscanf(line, "%s", command);
if (!strcmp(command, "bestmove")) {
if (sscanf(line, "%*s %s", command) == 1) {
// bestmove
strcpy(pmove, command);
*(pmove + 8) = 0;
clockms[side] -= ms;
if (!strcmp(pmove, "0000")) {
//side mated
goto GAME_OVER;
}
if (clockms[side] < 0) {
goto LOST_ON_TIME;
}
printf("%4d %s\n", nummove + 1, command);
side ^= 1;
break;
} else {
myfatal("sscanf bestmove error 1");
}
}
}
break;
}
}
assert(side == BLACK);
sprintf(buf, "%s", init_position);
nummove = 0;
pmove = &moves[0][0];
while (*pmove != 0) {
if (nummove == 0) {
strcat(buf, " moves ");
} else {
strcat(buf, " ");
}
strcat(buf, pmove);
pmove += 8;
++nummove;
}
strcat(buf, "\n");
//send position command
printf("sent %s\n", buf);
sendmsg(buf, side);
sendmsg("isready\n", side);
while (1) {
getmsg(line, 65536, side);
sscanf(line, "%s", command);
if (!strcmp(command, "readyok")) {
sprintf(buf, "go wtime %d btime %d\n", clockms[0], clockms[1]);
//send go command
sendmsg(buf, side);
if (!gettimeofday(&tv_start, NULL));
else {
myfatal("B gettimeofday error");
}
printf("sent %s\n", buf);
// wait for move
while (1) {
getmsg(line, 65536, side);
ms = msecfrom(&tv_start);
sscanf(line, "%s", command);
if (!strcmp(command, "bestmove")) {
if (sscanf(line, "%*s %s", command) == 1) {
strcpy(pmove, command);
// bestmove
*(pmove + 8) = 0;
clockms[side] -= ms;
if (!strcmp(pmove, "0000")) {
//side mated
goto GAME_OVER;
}
if (clockms[side] < 0) {
goto LOST_ON_TIME;
}
printf("%4d %s\n", nummove + 1, command);
side ^= 1;
break;
} else {
myfatal("sscanf bestmove error 1");
}
}
}
break;
}
}
}
LOST_ON_TIME:
;
printf("%s lost on time\n", side ? "Black" : "White");
sendmsg("quit\n", WHITE);
sendmsg("quit\n", BLACK);
return EXIT_SUCCESS;
GAME_OVER:
;
printf("%s mated\n", side ? "Black" : "White");
sendmsg("quit\n", WHITE);
sendmsg("quit\n", BLACK);
return EXIT_SUCCESS;
}