I'm enclosing a c file at the end of this. It makes a program
called metamachine. I have certain plans for this but that's a long
story I'll have to explain later. In a nutshell I want GNU Go to
be able to clone itself (hash, persistent cache and all) then
ask the clone questions.
At the moment, this program is working, or seems to work,
but there's a couple of problems I need help with.
It emulates a gtp engine by spawning a copy of gnugo and passing
commands from stdin to the engine, getting the response, then
passing them back to stdout. Though useless in itself, this could
be made useful with a bit of work: hack in gmp.c and get a
gtp/gmp translator.
I'm not a big unix hacker but wrote this after studying
Chapter 6 of Rochkind's "Advanced Unix Programming" and
the libc doc. As I said, it seems to work:
$ metamachine
boardsize 9
=
komi 5.5
=
showboard
A B C D E F G H J
9 . . . . . . . . . 9
8 . . . . . . . . . 8
7 . . + . . . + . . 7
6 . . . . . . . . . 6
5 . . . . + . . . . 5
4 . . . . . . . . . 4
3 . . + . . . + . . 3
2 . . . . . . . . . 2 WHITE has captured 0 stones
1 . . . . . . . . . 1 BLACK has captured 0 stones
A B C D E F G H J
=
genmove_black
= G7
PROBLEM 1: It doesn't kill the gnugo process when it exits.
(Run it a few times then ask yourself where all your memory
went.) What's the right way to do this?
PROBLEM 2: It hangs when called from twogtp. I can't figure
out why.
Dan
#include <stdio.h>
#include <unistd.h>
void error(const char *msg);
/* This program uses two pipes to communicate with the
* GNU Go client. To an external client it appears to
* be a gtp engine. It accomplishes this by intercepting
* gtp commands and passing them on to GNU Go.
*
* This program in and of itself is not useful but it
* can be the basis of useful programs. Example: hack
* in gmp.c and get a gtp / gmp translator.
*
* Bugs: the spawned process isn't killed when the
* program terminates. Hangs when called from twogtp. (Why?)
*
* Pipe a: client --> gnugo
* Pipe b: gnugo --> client
*/
int
main()
{
int pfd_a[2];
int pfd_b[2];
char gnugo_line[128], client_line[128];
int length = 0;
FILE *to_gnugo_stream, *from_gnugo_stream;
if (pipe(pfd_a) == -1)
error("can't open pipe a");
if (pipe(pfd_b) == -1)
error("can't open pipe b");
switch(fork()) {
case -1:
error("fork failed (try chopsticks)");
case 0:
/* Attach pipe a to stdin */
if (close(0) == -1)
error("close(0) failed");
if (dup(pfd_a[0]) != 0)
error("dup pfd_a[0] failed");
/* attach pipe b to stdout" */
if (close(1) == -1)
error("close(1) failed");
if (dup(pfd_b[1]) != 1)
error("dup pfd_b[1] failed");
execlp("gnugo", "gnugo", "--mode", "gtp", "--quiet", NULL);
error("execlp failed");
}
/* We use stderr to communicate with the client since stdout is needed. */
/* Attach pipe a to to_gnugo_stream */
to_gnugo_stream = fdopen(pfd_a[1], "w");
/* Attach pipe b to from_gnugo_stream */
from_gnugo_stream = fdopen(pfd_b[0], "r");
while (1) {
int length = 0;
if (!fgets(client_line, 128, stdin))
error("can't get command\n");
if (!strncmp(client_line, "quit", 4))
return 1;
if (fprintf(to_gnugo_stream, "%s", client_line) < 0)
error("can't write command to to_gnugo_stream");
fflush(to_gnugo_stream);
while (length != 1) {
if (!fgets(gnugo_line, 128, from_gnugo_stream))
error("can't get response");
length = strlen(gnugo_line);
printf(gnugo_line);
}
}
}
void
error(const char *msg)
{
fprintf(stderr, "metamachine: %s\n", msg);
abort();
}