psl@petrus.UUCP (Peter Langston) (04/26/86)
# To unbundle, sh this file echo GREF/Makefile 1>&2 sed 's/.//' >GREF/Makefile <<'//GO.SYSIN DD GREF/Makefile' -CFLAGS = -O -I.. -GOSUB = ../gosub.a - -all: gref - -fgo: fgo.o $(GOSUB) - $(CC) $(CFLAGS) $@.o $(GOSUB) -o $@ - -gotst: gotst.o $(GOSUB) - $(CC) $(CFLAGS) $@.o $(GOSUB) -o $@ - -gref: gref.o utime.o bdisp.o $(GOSUB) - $(CC) $(CFLAGS) $@.o utime.o bdisp.o $(GOSUB) -lcurses -ltermcap -o $@ - -jgref: gref.o utime.o jbdisp.o $(GOSUB) - $(CC) $(CFLAGS) gref.o utime.o jbdisp.o $(GOSUB) -o $@ - -grev: grev.o bdisp.o $(GOSUB) - $(CC) $(CFLAGS) $@.o bdisp.o $(GOSUB) -lcurses -ltermcap -o $@ - -jgrev: grev.o bdisp.o $(GOSUB) - $(CC) $(CFLAGS) grev.o jbdisp.o $(GOSUB) -o $@ - -doc: gref.n - pic gref.n | ditroff -ms - -lpq - -tst: tst.o - $(CC) $(CFLAGS) tst.o -o $@ //GO.SYSIN DD GREF/Makefile echo GREF/bdisp.c 1>&2 sed 's/.//' >GREF/bdisp.c <<'//GO.SYSIN DD GREF/bdisp.c' -#include "godef.h" -#include <curses.h> -/* -** BDISP -- board graphics for gref, GO referee program -** CURSINIT -- One-time initialization for bdisp() -** CURSFINI -- One-time cleanup -** BDREDRAW -- Re-draw the screen if messed up -** DISLOG -- display a log entry -** psl 6/84 -*/ - -#define SCRNH 24 /* assume 24-lines for the moment */ - -extern char *letters; /* from stoc.c */ - -extern char *copy(); - -cursinit() -{ - register char *cp; - register int i, j; - - initscr(); - leaveok(stdscr, TRUE); - /* top border */ - for (i = 1; i < BSZ1; i++) { - move(0, 2 * i + 1); - addch(letters[i]); - } - /* left and right edges */ - for (j = BSZ1; --j > 0; ) { - move(20 - j, 0); - printw("%2d ", j); - move(20 - j, 2 * BSZ1 + 1); - printw("%d ", j); - } - /* bottom border */ - for (i = 1; i < BSZ1; i++) { - move(20, 2 * i + 1); - addch(letters[i]); - } - move(0, 47); - addstr("# black white time"); - cp = copy(p[BLACK].p_plyr, fmtbuf); - i = 6 - (cp - fmtbuf) / 2; - move(21, i > 0? i : 0); - printw("BLACK/%s", p[BLACK].p_plyr); - cp = copy(p[WHITE].p_plyr, fmtbuf); - i = 30 - (cp - fmtbuf) / 2; - move(21, i); - printw("WHITE/%s", p[WHITE].p_plyr); - move(21, 19); - addstr(" vs. "); -} - -/* Update board display -*/ -bdisp() -{ - register int i, j; - - move(22, 7); - printw("%3d PRISONERS %3d", - p[BLACK].p_captures, p[WHITE].p_captures); - move(23, 5); - printw("%2d:%02d:%02d USER TIME %3d:%02d:%02d", - (int) (p[BLACK].p_utime / 3600), - (int) ((p[BLACK].p_utime % 3600) / 60), - (int) (p[BLACK].p_utime % 60), - (int) (p[WHITE].p_utime / 3600), - (int) ((p[WHITE].p_utime % 3600) / 60), - (int) (p[WHITE].p_utime % 60)); - for (j = BSZ1; --j > 0; ) { - for (i = 1; i < BSZ1; i++) { - move(BSZ1 - j, 2 * i + 1); - addch(".*O?"[b.b_spot[i + j * BSZ2].s_occ]); - } - } - refresh(); -} - -cursfini() -{ - leaveok(stdscr, FALSE); - move(22, 70); - refresh(); - endwin(); -} - -bdredraw() -{ - wrefresh(curscr); -} - -update() -{ - refresh(); -} - -/* Display a transcript entry -*/ -dislog(str) -char *str; -{ - static int lastline; - - if (++lastline >= SCRNH - 1) { - /* move 'em up */ - lastline = 1; - } - move(lastline, 46); - addstr(str); - move(lastline + 1, 46); - clrtoeol(); -} //GO.SYSIN DD GREF/bdisp.c echo GREF/gotst.c 1>&2 sed 's/.//' >GREF/gotst.c <<'//GO.SYSIN DD GREF/gotst.c' -/* -** GOTST -- Random GO player (for testing referee) -*/ -#include <stdio.h> -#include "godef.h" - -main() -{ - char buf[128]; - int omove, tmove; - int ocolor, tcolor; - - setbuf(stdout, 0); - srand((int) time(0)); - fgets(buf, sizeof buf, stdin); - if (strcmp(buf, "black\n") == 0) { - ocolor = BLACK; - tcolor = WHITE; - } else if (strcmp(buf, "white\n") == 0) { - ocolor = WHITE; - tcolor = BLACK; - } else { - fprintf(stderr, "Huh? Expected `black' or `white', got `%s'\n", - buf); - fputs("resign\n", stdout); - exit(1); - } - bdinit(&b); /* initialize board contents */ - omove = tmove = 0; - switch (ocolor) { - case WHITE: - for (;;) { - fgets(buf, sizeof buf, stdin); - tmove = ctos(buf); - if (tmove == RESIGN || (tmove == PASS && omove == PASS)) - break; - makemove(tcolor, tmove); - case BLACK: - omove = pickmove(ocolor); - printf("%s\n", stoc(omove)); - if (omove == RESIGN || (tmove == PASS && omove == PASS)) - break; - makemove(ocolor, omove); - } - } -} - -pickmove(ocolor) -{ - register int i, x, y, omove; - char buf[128], oc; - - for (i = 100; --i > 0; ) { - x = (rand() % BSZ) + 1; - y = (rand() % BSZ) + 1; - omove = x * BSZ2 + y; - if (legality(ocolor, omove) == LEGAL) - return(omove); - } - return(PASS); -} - -log(str) -char *str; -{ - fputs(str, stderr); -} //GO.SYSIN DD GREF/gotst.c echo GREF/gref.c 1>&2 sed 's/.//' >GREF/gref.c <<'//GO.SYSIN DD GREF/gref.c' -#include "godef.h" -#include <stdio.h> -#include <signal.h> -/* -** GREF -- GO referee program -** psl 5/84 -*/ - -char transfile[32]; /* transcript of this game */ -int movenum; -int iflg = 0; /* used by cursinit() for 5620 */ -int quiet = 0; /* > 0 ==> no board display */ -int sflg = 0; /* "stop mode", pause after each white move */ -int trace = 0; /* verbose */ -int tlimit = 60*60; /* in seconds, normally 60 * 60 */ -int stlimit = 10; /* in seconds, normally 10 */ - -struct plyrstr *lpw; /* to whom last pipe write was directed */ - -FILE *tfp; /* transcript file handle */ - -extern char *letters; /* from stoc.c */ -extern int ycptp; /* from utime.c */ -extern struct gstr g[MAXGRPS]; /* from groups.o in gosub.a */ -extern struct hstr h[MAXGRPS]; /* from holes.o in gosub.a */ - -int plumber(), whatsup(); -FILE *opentrans(); -extern char *stoc(), *copy(), *lfs(); -extern char *ctime(); -extern FILE *fopen(); - -main(argc, argv) -char *argv[]; -{ - char buf[128]; - int bmv, wmv, secs; - long now; - - setbuf(stdout, 0); - while (--argc > 0) { - if (argv[argc][0] == '-') { - switch (argv[argc][1]) { - case 'i': /* initialization flag for bdisp() */ - iflg++; - break; - case 'l': /* time limit */ - tlimit = atoi(&argv[argc][2]); - break; - case 'q': /* quiet (no board) */ - quiet++; - break; - case 's': /* stop mode */ - sflg++; - break; - case 't': /* trace */ - trace++; - break; - default: - goto oops; - } - } else { - if (access(argv[argc], 1) != 0) { - perror(argv[argc]); - goto oops; - } - if (p[WHITE].p_plyr == 0) - p[WHITE].p_plyr = argv[argc]; - else if (p[BLACK].p_plyr == 0) - p[BLACK].p_plyr = argv[argc]; - else - goto oops; - } - } - if (p[BLACK].p_plyr == 0) { -oops: - fprintf(stderr, - "Usage: %s [-quiet] [-trace] black-program white-program\n", - argv[0]); - exit(2); - } - tfp = opentrans(p[BLACK].p_plyr, p[WHITE].p_plyr); - utiminit(); /* set up for timing */ - time(&now); - fprintf(tfp, "%20.20s`%s' vs. `%s'\n", - ctime(&now), p[BLACK].p_plyr, p[WHITE].p_plyr); - bdinit(&b); /* initialize board contents */ - if (!quiet) - cursinit(); /* initialize display of board */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, whatsup); - signal(SIGPIPE, plumber); - forkplyr(BLACK); /* set up pipes & fork black */ - forkplyr(WHITE); /* set up pipes & fork white */ - send(&p[BLACK], bmv = BEBLACK); /* send "go first" to black */ - send(&p[WHITE], wmv = BEWHITE); /* send "go second" to white */ - if (!quiet) - bdisp(); /* show board */ - for (movenum = 0; ; ) { - movenum++; - bmv = rec(&p[BLACK]); /* read black player's move */ - trans(BLACK, bmv); /* update transcript */ - if (p[BLACK].p_utime >= tlimit) { /* check for short limit */ - secs = utime(p[BLACK].p_pid) - p[BLACK].p_utime; - if (secs > stlimit) - overtime(BLACK, secs); - } - if (makemove(BLACK, bmv) == ILLEGAL) /* carry out move */ - illmove(BLACK, bmv); - secs = utime(p[WHITE].p_pid); - if (p[WHITE].p_utime < tlimit && secs >= tlimit) { - send(&p[WHITE], BYOROMI); - log("White byo-romi"); - } - p[WHITE].p_utime = secs; - if (ycptp != p[WHITE].p_lycptp) { - p[WHITE].p_lycptp = ycptp; - log("White fork?"); - } - send(&p[WHITE], bmv); /* white starts thinking */ - if (bmv == PASS && wmv == PASS) - break; - p[BLACK].p_ko = 0; - if (!quiet) - bdisp(); /* show board */ - - movenum++; - wmv = rec(&p[WHITE]); /* read white player's move */ - trans(WHITE, wmv); /* update transcript */ - if (p[WHITE].p_utime >= tlimit) { /* check for short limit */ - secs = utime(p[WHITE].p_pid) - p[WHITE].p_utime; - if (secs > stlimit) - overtime(WHITE, secs); - } - if (makemove(WHITE, wmv) == ILLEGAL) /* carry out move */ - illmove(WHITE, wmv); - secs = utime(p[BLACK].p_pid); - if (p[BLACK].p_utime < tlimit && secs >= tlimit) { - send(&p[BLACK], BYOROMI); - log("Black byo-romi"); - } - p[BLACK].p_utime = secs; - if (ycptp != p[BLACK].p_lycptp) { - p[BLACK].p_lycptp = ycptp; - log("Black fork?"); - } - send(&p[BLACK], wmv); /* black starts thinking */ - if (bmv == PASS && wmv == PASS) - break; - p[WHITE].p_ko = 0; - if (!quiet) - bdisp(); /* show board */ - if (sflg) - read(0, buf, sizeof buf); - } - quit(0); -} - -FILE * -opentrans(bplyr, wplyr) -char *bplyr, *wplyr; -{ - register char *cp, *bp; - char bbuf[32], wbuf[32]; - - for (cp = bp = bplyr; *cp ; ) - if (*cp++ == '/') - bp = cp; - copy(bp, bbuf); - bbuf[6] = '\0'; - for (cp = bp = wplyr; *cp ; ) - if (*cp++ == '/') - bp = cp; - copy(bp, wbuf); - wbuf[6] = '\0'; - sprintf(transfile, "%s-%s", bbuf, wbuf); - if ((tfp = fopen(transfile, "a")) == (FILE *) NULL) { - perror(transfile); - exit(3); - } - return(tfp); -} - -quit(hurry) -{ - score(hurry); /* put board in transcript */ - if (!quiet) { - bdisp(); /* show final board */ - cursfini(); - } - exit(0); -} - -/* A player took too long for a move after exceeding the time limit -*/ -overtime(pn, secs) -{ - sprintf(fmtbuf, "%s took %d secs", color[pn], secs); - log(fmtbuf); - quit(0); -} - -/* Handle strange situations. -*/ -whatsup(signum) -{ - char buf[64]; - int i, pnum; - - signal(signum, whatsup); - if (!quiet) - update(); - fprintf(stderr, "\r Caught signal %d; what's up? \b\b", signum); - fgets(buf, sizeof buf, stdin); - switch (*buf) { - case 'Q': /* quick quit */ - quit(1); - case 'q': /* conservative quit */ - quit(0); - case 'r': /* redraw */ - break; - case 'm': /* send message */ - pnum = buf[1] - '0'; - if (pnum != BLACK && pnum != WHITE) - goto syntax; - i = copy(&buf[2], buf) - buf; - write(p[pnum].p_wpipe, buf, i); - break; - case 's': /* set stop mode move */ - sflg = atoi(&buf[1]); - fprintf(stderr, "Stop set to %d\n", sflg); - sleep(1); - break; - case 't': /* set trace level */ - trace = buf[1] - '0'; - fprintf(stderr, "Trace set to %d\n", trace); - sleep(1); - break; - default: -syntax: - fprintf(stderr, "Options are:\n"); - fprintf(stderr, " m#text - send msg to prog # (1 or 2)\n"); - fprintf(stderr, " q - kill progs & quit, update trans.\n"); - fprintf(stderr, " Q - kill progs & quit quickly\n"); - fprintf(stderr, " r - redraw the screen\n"); - fprintf(stderr, " s# - set stop mode after move #\n"); - fprintf(stderr, " t# - set trace level to #\n"); - sleep(3); - } - if (!quiet) - bdredraw(); -} - -/* Set up pipes, fork & exec a player's process. -*/ -forkplyr(us) -{ - register struct plyrstr *pp; - char buf[16], logbuf[128]; - int tpipe[2], fpipe[2], i; - - pp = &p[us]; - if (pipe(tpipe) == -1) { - perror("to pipe"); - exit(3); - } - if (pipe(fpipe) == -1) { - perror("from pipe"); - exit(3); - } - if (trace > 1) { - sprintf(fmtbuf, "EXEC: %s\n", pp->p_plyr); - log(fmtbuf); - } - switch (pp->p_pid = fork()) { - case -1: /* failure */ - perror("fork"); - exit(3); - case 0: /* child */ - close(0); - dup(tpipe[0]); - close(1); - dup(fpipe[1]); - close(2); - sprintf(logbuf, "log.%s", pp->p_plyr); - if (open(logbuf, 1) == 2) - lseek(2, (long) 0, 2); - else - creat(logbuf, 0644); - sprintf(logbuf, "%s vs. %s\n", p[BLACK].p_plyr, p[WHITE].p_plyr); - write(2, logbuf, strlen(logbuf)); - for (i = 16; --i > 2; close(i)); - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - sleep(5); /* to allow ycptp to be read */ - execl(pp->p_plyr, pp->p_plyr, 0); - perror(pp->p_plyr); - exit(3); - default: - utime(pp->p_pid); /* do this to set ycptp */ - pp->p_lycptp = ycptp; - pp->p_rpipe = fpipe[0]; - pp->p_wpipe = tpipe[1]; - close(fpipe[1]); - close(tpipe[0]); - } -} - -/* Send a move in the recipient's format -*/ -send(pp, mv) -struct plyrstr *pp; -{ - register char *mp; - - mp = stoc(mv); - if (trace > 1) { - sprintf(fmtbuf, "SEND(%s): %s\n", pp->p_plyr, mp); - log(fmtbuf); - } - lpw = pp; - write(pp->p_wpipe, mp, strlen(mp)); - write(pp->p_wpipe, "\n", 1); -} - -/* Catch broken pipe signals. -*/ -plumber() -{ - sprintf(fmtbuf, "%s has apparently died (broken pipe)\n", lpw->p_plyr); - fputs(fmtbuf, tfp); - fputs(fmtbuf, stdout); - signal(SIGPIPE, plumber); -} - -/* Read a move & convert from the sender's format to spot number -*/ -rec(pp) -struct plyrstr *pp; -{ - register char *bp; - register int i; - char buf[1024]; - extern int errno; - - if (trace > 1) { - sprintf(fmtbuf, "REC(%s):...", pp->p_plyr); - log(fmtbuf); - } - for (;;) { - bp = buf; - if (trace > 1) { - sprintf(fmtbuf, "About to read from %d", pp->p_rpipe); - log(fmtbuf); - } - while ((i = read(pp->p_rpipe, bp, 1)) == 1 && *bp != '\n') { - if (*bp != ' ' && *bp != '\t') - bp++; - if (trace > 2) { - sprintf(fmtbuf, "`%c'", bp[-1]); - log(fmtbuf); - } - if (bp - buf > 32) - --bp; - } - bp[1] = '\0'; - if (i <= 0) { - sprintf(fmtbuf, "Read on %s pipe returns %d, errno=%d\n", - pp->p_plyr, i, errno); - log(fmtbuf); - sprintf(fmtbuf, "Buffer had `%s'", buf); - log(fmtbuf); - update(); - sleep(3); - } - if (trace > 1) { - sprintf(fmtbuf, "REC got `%s'", lfs(buf)); - log(fmtbuf); - } - if (bp == &buf[1]) - continue; - i = ctos(buf); - if ((i > BSZ2 && i < BAREA - BSZ2) || i == PASS) - return(i); - } -} - -/* Somebody screwed up... -*/ -illmove(us, sn) -{ - illlog(us, sn); - sprintf(fmtbuf, "Game over; (%s's fault)", color[us]); - log(fmtbuf); - quit(0); -} - -/* Update the transcript file -*/ -trans(us, mv) -{ - char *cp, *mp; - long now; - - if (mv == PASS) - mp = "pass"; - else - mp = stoc(mv); - time(&now); - cp = ctime(&now); - cp = &cp[11]; - if (us == BLACK) - sprintf(fmtbuf, "%3d %-6s %8.8s", movenum, mp, cp); - else - sprintf(fmtbuf, "%3d %-6s %8.8s", movenum, mp, cp); - log(fmtbuf); -} - -/* Make an entry in the transcript -*/ -log(str) -char *str; -{ - static int lastline; - - fputs(str, tfp); - fputs("\n", tfp); - fflush(tfp); - if (!quiet) - dislog(str); -} - -illlog(us, sn) /* log the illegal move */ -{ - if (whyillegal == ILL_NOTEMPTY) { - sprintf(fmtbuf, "%s/%s plays in nonempty spot (%s)", - color[us], p[us].p_plyr, stoc(sn)); - log(fmtbuf); - } else if (whyillegal == ILL_INTOKO) { - sprintf(fmtbuf, "%s/%s plays back into a KO (%s)", - color[us], p[us].p_plyr, stoc(sn)); - log(fmtbuf); - } else if (whyillegal == ILL_SUICIDE) { - sprintf(fmtbuf, "%s/%s attempts suicide (%s)", - color[us], p[us].p_plyr, stoc(sn)); - log(fmtbuf); - } - update(); -} - -/* Collect time & score. Print them out. -*/ -score(hurry) -{ - if (!hurry) - sleep(3); /* pregnant pause (for programs to finish up) */ - if (p[BLACK].p_pid) - kill(p[BLACK].p_pid, 9); - if (p[WHITE].p_pid) - kill(p[WHITE].p_pid, 9); - if (hurry) - return; - while (timeone()); - fprintf(tfp, "\n* * * F I N A L B O A R D * * *\n"); - bdump(tfp); - fprintf(tfp, " Black/%-16.16s White/%-16.16s\n", - p[BLACK].p_plyr, p[WHITE].p_plyr); - fprintf(tfp, "CAPTURES %10d %24d\n", - p[BLACK].p_captures, p[WHITE].p_captures); - fprintf(tfp, "USER TIME %6d:%02d:%02d %18d:%02d:%02d\n", - (int) (p[BLACK].p_utime / 3600), - (int) ((p[BLACK].p_utime % 3600) / 60), - (int) (p[BLACK].p_utime % 60), - (int) (p[WHITE].p_utime / 3600), - (int) ((p[WHITE].p_utime % 3600) / 60), - (int) (p[WHITE].p_utime % 60)); - countem(tfp); -} - -countem(fp) -FILE *fp; -{ - register int gn, hn, i, j, k, wc, bc, sn; - int ngroups, nholes; - struct bdstr gb, hb; /* group & hole index boards */ - - ngroups = groups(&b, &gb); - nholes = holes(&b, &gb, &hb, 2); /* identify holes */ - /* (ignoring groups of size 2 or smaller in deciding eyes) */ - /* count eyes for all groups */ - for (gn = ngroups; --gn >= 0; ) - g[gn].g_eyes = 0; - for (hn = nholes; --hn >= 0; ) { - if (h[hn].h_grps == 1) { - gn = h[hn].h_g[0]; - i = g[gn].g_eyes++; - if (i < MAXEYES) - g[gn].g_h[i] = hn; - } - } - /* assign ownership of holes */ - for (hn = nholes; --hn >= 0; ) { - if (h[hn].h_who == (BLACK | WHITE)) { - k = 0; - if ((i = h[hn].h_grps) > MAXLIBS) - i = MAXLIBS; - while (--i >= 0) { - gn = h[hn].h_g[i]; - if (g[gn].g_eyes > 1) - k |= g[gn].g_who; - } - h[hn].h_who = k; - } - } - wc = bc = 0; - fprintf(fp, " "); - for (i = 1; i < BSZ1; i++) - fprintf(fp, " %c", letters[i]); - fprintf(fp, "\n"); - for (j = BSZ1; --j > 0; ) { - fprintf(fp, "%2d", j); - for (i = 1; i < BSZ1; i++) { - sn = i + j * BSZ2; - k = b.b_spot[sn].s_occ; - if (k != EMPTY) - fprintf(fp, " %c", ".*O?"[k]); - else { - k = h[hb.b_spot[sn].s_flg].h_who; - if (k == BLACK) { - bc++; - fprintf(fp, " +"); - } else if (k == WHITE) { - wc++; - fprintf(fp, " -"); - } else - fprintf(fp, " ."); - } - } - fprintf(fp, " %d\n", j); - } - fprintf(fp, " "); - for (i = 1; i < BSZ1; i++) - fprintf(fp, " %c", letters[i]); - fprintf(fp, "\n"); - fprintf(tfp, "TERRITORY Black:%d White:%d\n", bc, wc); -} - -bdump(fp) -FILE *fp; -{ - register int i, j; - - fprintf(fp, " "); - for (i = 1; i < BSZ1; i++) - fprintf(fp, " %c", letters[i]); - fprintf(fp, "\n"); - for (j = BSZ1; --j > 0; ) { - fprintf(fp, "%2d", j); - for (i = 1; i < BSZ1; i++) - fprintf(fp, " %c", ".*O?"[b.b_spot[i + j * BSZ2].s_occ]); - fprintf(fp, " %d\n", j); - } - fprintf(fp, " "); - for (i = 1; i < BSZ1; i++) - fprintf(fp, " %c", letters[i]); - fprintf(fp, "\n"); -} - -timeone() /* wait() and collect utime statistics */ -{ - int pid, exstat; - long before, after; - struct plyrstr *pp; - - before = kidutime(); - pid = wait(&exstat); - if (pid == -1) - return(0); - after = kidutime(); - if (pid == p[BLACK].p_pid) { - pp = &p[BLACK]; - p[BLACK].p_pid = 0; - } else if (pid == p[WHITE].p_pid) { - pp = &p[WHITE]; - p[WHITE].p_pid = 0; - } else { - fprintf(stderr, "Proc %d?\n", pid); - return(1); - } - pp->p_utime = after - before; - return(1); -} //GO.SYSIN DD GREF/gref.c echo GREF/gref.n 1>&2 sed 's/.//' >GREF/gref.n <<'//GO.SYSIN DD GREF/gref.n' -.TL -GREF \*- An Automated GO Referee -.AU -Peter S. Langston -.AI -Bell Communications Research -.AB -A program which acts as a referee between two competing -game programs is described. -The referee program appears to be a human player to each of the programs, -but merely forwards the moves from one program to the other while -maintaining a time clock, giving warnings of time limits, checking -legality of moves, and watching for other rule infringements. -.AE -.hy 15 -.LP -\fIGref\fR's primary function is to pass the moves back and forth between -two competing GO programs. It also records the sequence of moves, -maintains and displays the current configuration of the board, -checks moves for legality, -monitors the accumulated user time for each program, -and watches for any indication that either program -has forked another process, (and mentions it if so). -.in 1.1i -.ft B -.PS - down - ellipse "CRT" "terminal" - line <-> down -Grefbox: - box wid 1.5i ht 0.5i "go referee program" "``gref''" - arrow right from Grefbox.e; circle diam 0.9i "file" "``gref.trans''" - line <-> down left from Grefbox.sw - down; box wid 1i ht 0.5i "go program" "``go1.5''" - arrow down from last box.s; circle diam 0.85i "file" "``log.black''" - line <-> down right from Grefbox.se - down; box wid 1i ht 0.5i "go program" "``gobelle''" - arrow down from last box.s; circle diam 0.85i "file" "``log.white''" -.PE -.in -.ft B -.ce -figure 1: Data Paths -.ft R -.LP -Data paths from invoking \fIgref\fR -("gref go1.5 gobelle" for example) -are as shown in figure 1. -The three files involved are: -.IP \fBgref.trans\fR 10 -A transcript of the game, -including logging of events like ``byo-romi'' -being sent to either program or forking detected, -and final board. -.IP \fBlog.black\fR -All characters sent to the standard error -by the program playing black (``go1.5'' in our example). -.IP \fBlog.white\fR -All characters sent to the standard error -by the program playing white (``gobelle'' in our example). -.LP -One problem inherent in this arrangement is that some -I/O routines like to buffer output to pipes. -Several solutions are available: -.IP 1 -Include setbuf(stdout, NULL) in game programs that use <stdio.h>. -.IP 2 -Follow each printf() with an fflush(stdout). -.IP 3 -Use "write" system calls for all move output. -.LP -Another obvious problem with using the standard output for passing moves -to the referee is that many game programs print much more than -just the moves on the standard output. -In many cases this extra output will be ignored by \fIgref\fR, -but there are instances in which other output -will be incorrectly interpreted as a move. -Whenever possible it is recommended that diagnostic -or trace information be suppressable or be sent -to the standard error output. -.SH -NAMING CONVENTIONS -.LP -The game board is a square grid with -19 columns labeled ``A'' through ``T'' (excluding ``I'') left to right, and -19 rows labeled ``1'' through ``19'' bottom to top. -.SH -THE BOARD DISPLAY -.LP -\fIGref\fR uses the \fIcurses\fR screen management package -to maintain a display of the game in progress. -The board is displayed -along with a list of moves as in figure 2. - -.KS -.B1 -.ft lb -.nf - A B C D E F G H J K L M N O P Q R S T # black white time -19 + + + + + + + + + + + + + + + + + + + 19 122 S10 10:06:18 -18 + + + + + + + + + + + + + + + + + + + 18 123 C4 10:07:21 -17 + + + + + + + + + + + + + + X + + + + 17 124 T11 10:08:26 -16 + + + X O O O O + + + + + O X + + + + 16 125 Q11 10:09:30 -15 + + + X O X X O O + + + X O X O O + + 15 126 O12 10:10:34 -14 + + X X X O X X O + + + + O O X O O + 14 127 F4 10:11:37 -13 + + + + + O O X X O + + O O X X X O O 13 128 G3 10:12:41 -12 + + + + + + O X X O + + + O O O X X X 12 129 S5 10:13:44 -11 + + + + + + O X X O + + + + O X X O O 11 130 P11 10:14:49 -10 + + + + + O O X X O + + + + O X + O + 10 131 Q10 10:15:51 - 9 + + + X X X O X X O + + + + + X + + + 9 132 P10 10:16:55 - 8 + + O X + + + X X O + + + O + + + + + 8 133 Q9 10:17:58 - 7 + + O X O + O X X O + + + O X + + + + 7 134 B4 10:19:00 - 6 + + O X O O O O X O + X X O X O O + + 6 135 C3 10:20:03 - 5 + + O O X O X + X + + X O X X X + X + 5 136 C5 10:21:06 - 4 + O X O X X X + + + + + O + + + + + + 4 - 3 + + X O X O O + + + + X + X + X + + + 3 116 D4 09:59:56 - 2 + + + + X + + X + + + + + + + + + + + 2 117 E4 10:01:00 - 1 + + + + + + + + + + + + + + + + + + + 1 118 T11 10:02:03 - A B C D E F G H J K L M N O P Q R S T 119 T12 10:03:06 - BLACK/go1.5 vs. WHITE/gobelle 120 S11 10:04:10 - 0 PRISONERS 0 121 R11 10:05:13 - 0:48:53 USER TIME 0:40:12 -.fi -.B2 -.ft B -.ce -figure 2: The CRT Display -.ft R -.KE -.LP -The moves are presented as a circular list with -a blank line following the most recent move. -Otherwise the move list is identical to the contents -of the transcript file ``gref.trans''. -The count of captured stones (``PRISONERS'') is updated -on the receipt of each move as is the accumulated time used -(``USER TIME''). -.SH -COMMAND SYNTAX -.LP -Programs to compete under \fIgref\fR must interpret a standard set -of input commands and must generate output commands which meet -standard specifications for syntax and semantics. -.SH -Input Syntax -.RS -.LP -All input (from the referee) to the competing programs are -in the form of lines of text appearing at the standard -input and terminated by newline (linefeed). -.LP -The first line of input to each program will be either -``black'' or ``white'' to indicate which color -that program will be playing -(and thereby whether that program is to play first or second). -Note that neither ``black'' nor ``white'' is capitalized. -.LP -The placement of an opponent's stone will be expressed as -letter-number with the letter capitalized. -Examples are: A1, the lower left corner, -T19, the upper right corner, and K10, the center. -.LP -The opponent passing is expressed as ``pass'', (lower case). -.LP -When the initial time limit on accumulated ``user'' time -is exceeded the command ``byo-romi'' will be given by the -referee to the offending program. -All further moves must be generated within a shorter -(10 seconds by default) time limit. -.LP -The opponent resigning the game is expressed as ``resign'', -(lower case). -.RE -.SH -Output Syntax -.RS -.LP -All output from the competing programs is in the -form of lines of characters sent to the ``standard output'', -terminated by a newline, and flushed after every line. -.LP -The placement of a stone is expressed as letter-number (e.g. "G12"). -.LP -A pass is expressed as "pass" (lower case). -.LP -A resignation is expressed as "resign" (lower case). -.LP -Any other output lines that do not start with a syntactically -well-formed move will be considered garbage and ignored. -.RE -.SH -BAD MOVES -.LP -Any syntactically well-formed but illegal move -that is recognized by \fIgref\fR will be logged and -in some cases (noted below) will halt the game. -.LP -\fIGref\fR recognizes the following types of moves as illegal: -.IP \(bu -Playing on a non-empty spot. -.br -This includes playing off the edge of the board -(e.g. ``B0'' or ``M20'') -and playing on a spot which already contains a stone. -This is a fatal illegal move and will halt the game. -.IP \(bu -Suicide. -.br -This involves playing into a position with no ``liberties''. -This is a fatal illegal move and will halt the game. -.IP \(bu -Ko violation. -.br -This involves the usual illegal recapture in a ko -and is a fatal illegal move. -The line ``ko violation'' is logged and the game stops. -.SH -GAME END -.LP -Play continues until both programs pass in sequence or until -one of the fatal illegal moves mentioned above occurs. -.SH -TIME LIMIT -.LP -\fIGref\fR implements a limit on the amount of accumulated -``user time'' (as defined by UNIX systems) used by each program. -The default limit is 60 minutes, but it may be changed with -the \fB-l\fR argument (see ``Invoking Gref''). -Once a program has exceeded the initial limit it is allowed a -maximum of 10 seconds of user time for each move thereafter. -If a program exceeds the 10 second limit it is considered -a forfeit and the game halts. -.SH -INVOKING GREF -.LP -\fIGref\fR has several optional command line arguments. -Its syntax is: -.IP -\fBgref\fR [\fB-l\fR#] [\fB-q\fR] [\fB-t\fR] prog-to-play-black prog-to-play-white -.LP -The optional arguments are: -.RS -.IP \fB-l\fR# -Set the user time limit to ``#'' seconds. -The default value is 3600. -.IP \fB-q\fR -Run the games ``quietly'', i.e. without maintaining a display -of the game board on the CRT screen. -.IP \fB-t\fR -Turn on tracing information. If this argument is specified -more than once even more output will be produced. -.RE -.SH -SIGNALS -.LP -\fIGref\fR catches write-on-broken-pipe signals and comments on them, -but takes no other specific action. -.LP -\fIGref\fR ignores interrupts, (SIGINT), as do the game programs -unless they use signal() to do otherwise. -.LP -\fIGref\fR catches quits (SIGQUIT) and runs a little routine that asks why -you interrupted it. There are four requests you can make at that point: -.RS -.IP q 7 -Quit gracefully; update the transcript, log time statistics, etc. -.IP Q -Quit quickly; don't bother with logging anything. -.IP r -Redraw the screen. -Since \fIgref\fR will do this anyway after handling whatever -is requested, this is effectively a null request. -.IP s#msg -Send \fImsg\fR to player \fI#\fR. -\fI#\fR must be 1 (black) or 2 (white) and \fImsg\fR -will be sent exactly as typed. -.IP t# -Set trace level to \fI#\fR. -At the moment only 0 (no tracing), 1 (some tracing), -and 2 (all tracing) are meaningful. -.RE -.LP -The game programs ignore SIGQUIT unless they -use signal() to do otherwise. -.LP -All other signals, (e.g. SIGHUP), are left as they default. -.SH -BUGS -.LP -There is no ``nice'' way to find out the amount -of user time consumed by a non-terminated child -process in UNIX; I'm sure to spend an extra day -or two in Hell atoning for the sleazy hack that -\fIgref\fR uses to get around that shortcoming. -.SH -ACKNOWLEDGEMENT -.LP -The original version of the program described here -(and the original version of this document) -were written at Lucasfilm Ltd., San Rafael, California. //GO.SYSIN DD GREF/gref.n echo GREF/utimeBSD.c 1>&2 sed 's/.//' >GREF/utimeBSD.c <<'//GO.SYSIN DD GREF/utimeBSD.c' -#ifdef NOUTIME -utiminit() { return(0); } -utime() { return(0); } -kidutime() { return(0); } -int ycptp; /* set to proc.p_cptr (youngest child's proc table pointer) */ -#else -#include <sys/param.h> -#include <sys/dir.h> -#include <sys/user.h> -#include <sys/proc.h> -#include <sys/vm.h> -#include <machine/pte.h> -#include <nlist.h> -#include <stdio.h> -extern char fmtbuf[]; -/* -** UTIMINIT() -- Do one-time init stuff for ... -** UTIME(pid) -- Return the user time, in seconds, for process pid -** Also set global ycptp. -** KIDUTIME() -- Return the current total of terminated child process -** user times (seconds, ignoring microseconds). -** psl 5/84 -*/ - -#define UNIX "/vmunix" -#define KMEM "/dev/kmem" -#define MEM "/dev/mem" -#define SWAP "/dev/drum" - -static struct nlist nl[] = { -#define vproc (nl[0].n_value) - { "_proc" }, -#define vnproc (nl[1].n_value) - { "_nproc" }, -#define vUsrptmap (nl[2].n_value) - { "_Usrptmap" }, -#define vusrpt (nl[3].n_value) - { "_usrpt" }, - 0 -}; - -static int kfh, mfh, sfh, nproc; -static struct pte *Usrptma, *usrpt; -static struct proc *procp; -union { - struct user page; /* where the data really goes */ - char pad[NBPG][UPAGES]; /* to pad out to size read */ -} uzer; -#define usr uzer.page /* not as bad a hack as many to come */ - -int ycptp; /* set to proc.p_cptr (youngest child's proc table pointer) */ - -utiminit() -{ - nlist(UNIX, nl); - if ((kfh = vopen(KMEM)) < 0 - || (mfh = vopen(MEM)) < 0 - || (sfh = open(SWAP)) < 0) - return(-1); - procp = (struct proc *) kmemint(vproc); - nproc = kmemint(vnproc); - Usrptma = (struct pte *) vUsrptmap; - usrpt = (struct pte *) vusrpt; - return(0); -} - -static -vopen(file) -char *file; -{ - register int i; - - if ((i = open(file, 0)) < 0) - perror(file); - return(i); -} - -static -kmemint(addr) -unsigned long addr; -{ - long data; - - lseek(kfh, addr, 0); - if (read(kfh, &data, sizeof data) != sizeof data) - perror(KMEM); - return(data); -} - -int -utime(pid) -{ - register int i, s, n; - struct proc p; - extern int errno; - - for (i = 0; i < nproc; i++) { - s = (int) &procp[i]; - n = lseek(kfh, (long) s, 0); - if (n != s) { - sprintf(fmtbuf, "lseek(kmem, %x, 0) returns %d", s, n); - log(fmtbuf); - } - s = sizeof p; - n = read(kfh, &p, s); - if (n != s) { - sprintf(fmtbuf, "read(kmem, proc, %d) returns %d", s, n); - log(fmtbuf); - sprintf(fmtbuf, "errno=%d", errno); - log(fmtbuf); - return(0); - } - if (p.p_pid == pid) - break; - } - if (i >= nproc) /* did we find the proc table entry? */ - return(0); - ycptp = (int) p.p_cptr; - if (readusr(&p) == 0) - return(0); - return(usr.u_ru.ru_utime.tv_sec); -} - -static -readusr(pp) -struct proc *pp; -{ - register int i, n, s, ncl; - char *cp; - struct pte *pteaddr, apte; - struct pte arguutl[UPAGES+CLSIZE]; - extern int errno; - - if ((pp->p_flag & SLOAD) == 0) { - lseek(sfh, (long)dtob(pp->p_swaddr), 0); - s = sizeof usr; - n = read(sfh, &usr, s); - if (n == s) - return (1); - sprintf(fmtbuf, "read(swap, upage, %d) returns %d", s, n); -oops: - log(fmtbuf); - sprintf(fmtbuf, "errno=%d", errno); - log(fmtbuf); - return (0); - } - /* indirect pte from kmem */ - pteaddr = &Usrptma[btokmx(pp->p_p0br) + pp->p_szpt - 1]; - lseek(kfh, (long)pteaddr, 0); - s = sizeof apte; - n = read(kfh, (char *)&apte, s); - if (n != s) { - sprintf(fmtbuf, "read(kmem, apte, %d) returns %d", s, n); - goto oops; - } - s = (long)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte); - lseek(mfh, (long) s, 0); - s = sizeof arguutl; - n = read(mfh, (char *)arguutl, s); - if (n != s) { - sprintf(fmtbuf, "read(mem, arguutl, %d) returns %d", s, n); - goto oops; - } - ncl = (sizeof usr + NBPG*CLSIZE - 1) / (NBPG*CLSIZE); - cp = (char *) &usr; - for (i = 0; i < ncl * CLSIZE; i += CLSIZE) { - s = ctob(arguutl[CLSIZE+i].pg_pfnum); - lseek(mfh, (long) s, 0); - s = CLSIZE * NBPG; - n = read(mfh, cp, s); - if (n != s) { - sprintf(fmtbuf, "read(mem, upage, %d) returns %d", s, n); - goto oops; - } - cp += s; - } - return (1); -} - -kidutime() -{ - struct rusage ugh; - - getrusage(RUSAGE_CHILDREN, &ugh); - return(ugh.ru_utime.tv_sec); -} - -#endif NOUTIME //GO.SYSIN DD GREF/utimeBSD.c echo SUBS/bdinit.c 1>&2 sed 's/.//' >SUBS/bdinit.c <<'//GO.SYSIN DD SUBS/bdinit.c' -#include "../godef.h" -/* -** Initialize board & display -*/ -bdinit(bp) -struct bdstr *bp; -{ - register int i, j; - - /* fill entire board with EMPTY spots */ - for (i = BAREA; --i >= 0; ) { - bp->b_spot[i].s_occ = EMPTY; - bp->b_spot[i].s_flg = 0; - } - /* mark the borders as such */ - for (i = BSZ2; --i >= 0; ) { - j = i + BSZ2 * 0; - bp->b_spot[j].s_occ = BORDER; - j = i + BSZ2 * (BSZ2 - 1); - bp->b_spot[j].s_occ = BORDER; - j = 0 + BSZ2 * i; - bp->b_spot[j].s_occ = BORDER; - j = (BSZ2 - 1) + BSZ2 * i; - bp->b_spot[j].s_occ = BORDER; - } -} //GO.SYSIN DD SUBS/bdinit.c echo SUBS/clearflg.c 1>&2 sed 's/.//' >SUBS/clearflg.c <<'//GO.SYSIN DD SUBS/clearflg.c' -#include "../godef.h" -/* -** clear specified bit(s) in all flag words in specified board -** psl 5/84 -*/ - -clearflg(flg, bp) -struct bdstr *bp; -{ - register int i, mask; - - mask = ~flg; - for (i = BAREA; --i > 0; ) - bp->b_spot[i].s_flg &= mask; -} //GO.SYSIN DD SUBS/clearflg.c echo SUBS/copy.c 1>&2 sed 's/.//' >SUBS/copy.c <<'//GO.SYSIN DD SUBS/copy.c' -/* -** The old standby -*/ - -char * -copy(from, to) -register char *from, *to; -{ - while (*to++ = *from++); - return(--to); -} //GO.SYSIN DD SUBS/copy.c echo SUBS/glb.c 1>&2 sed 's/.//' >SUBS/glb.c <<'//GO.SYSIN DD SUBS/glb.c' -#include "../godef.h" -/* -** GLB -- globals for Go routines -** psl 5/84 -*/ - -char *color[] = { "oops!", "black", "white", "oops!!", }; -char fmtbuf[128]; - -int liblist[MAXLIBS], nlibs; -int dd[4] = { MUP, MRIGHT, MDOWN, MLEFT, }; - -struct plyrstr p[3]; -struct bdstr b; //GO.SYSIN DD SUBS/glb.c echo SUBS/groups.c 1>&2 sed 's/.//' >SUBS/groups.c <<'//GO.SYSIN DD SUBS/groups.c' -#include "../godef.h" - -/* -** groups(bp, gbp) based on data in bp generate groups and -** return group indices in gbp; -*/ - -extern char fmtbuf[]; -extern int dd[]; -extern struct bdstr *grpopbp; -#ifdef DEBUG -extern char *stoc(); -#endif DEBUG - -int numgrps = 0; /* how many groups exist */ - -struct gstr g[MAXGRPS]; -struct bdstr *gnbp; /* so grpadd() can use it */ - -groups(bp, gbp) -struct bdstr *bp, *gbp; -{ - register int i; - int grpadd(); - struct spotstr *sp; - -#ifdef DEBUG - sprintf(fmtbuf, "groups(0x%x, 0x%x)", bp, gbp); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - numgrps = 0; - clearflg(GRPFLG, bp); /* bp must not == gbp */ - for (i = BAREA; --i > 0; ) /* in bgp use flg to hold group num */ - gbp->b_spot[i].s_flg = 255; - grpopbp = bp; /* global used by grpop() & grpadd() */ - gnbp = gbp; /* global used by grpadd() */ - for (i = BAREA; --i > 0; ) { - sp = &bp->b_spot[i]; - if ((sp->s_occ == BLACK || sp->s_occ == WHITE) - && (sp->s_flg & GRPFLG) == 0) { - clearflg(LIBFLG, bp); /* get ready to count liberties */ - g[numgrps].g_who = sp->s_occ; - g[numgrps].g_spot = i; - g[numgrps].g_libs = 0; - g[numgrps].g_size = grpop(i, grpadd, GRPFLG); - numgrps++; - if (numgrps >= MAXGRPS) - break; /* should never happen, but */ - } - } - return(numgrps); -} - -grpadd(sn) -{ - register int ns, d, n; - - gnbp->b_spot[sn].s_flg = numgrps; - n = g[numgrps].g_libs; - for (d = 4; --d >= 0; ) { - ns = sn + dd[d]; - if (grpopbp->b_spot[ns].s_occ == EMPTY - && (grpopbp->b_spot[ns].s_flg & LIBFLG) == 0) { - if (n < MAXLIBS) - g[numgrps].g_l[n] = ns; - n++; - grpopbp->b_spot[ns].s_flg = LIBFLG; - } - } - g[numgrps].g_libs = n; -#ifdef DEBUG - sprintf(fmtbuf, "libcheck(%s) returns %d", stoc(sn), n); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - return(1); -} //GO.SYSIN DD SUBS/groups.c echo SUBS/groupsort.c 1>&2 sed 's/.//' >SUBS/groupsort.c <<'//GO.SYSIN DD SUBS/groupsort.c' -#include "../godef.h" - -/* -** groupsort(gbp) rearrange groups so biggest comes first -*/ - -#ifdef DEBUG -extern char fmtbuf[]; -extern char *stoc(); -#endif DEBUG - -extern int numgrps; /* how many groups exist */ - -extern struct gstr g[MAXGRPS]; - -groupsort(gbp) -struct bdstr *gbp; -{ - register int i, j, k; - struct spotstr *sp; - struct gstr gg; - -#ifdef DEBUG - sprintf(fmtbuf, "groupsort(0x%x)", gbp); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - for (i = numgrps; --i > 0; ) { - k = 0; - for (j = 1; j <= i; j++) { - if (g[j].g_size < g[k].g_size) - k = j; - } - if (k != i) { - gg = g[i]; g[i] = g[k]; g[k] = gg; - for (sp = &gbp->b_spot[BAREA]; --sp > gbp->b_spot; ) { - if (sp->s_flg == i) - sp->s_flg = k; - else if (sp->s_flg == k) - sp->s_flg = i; - } - } - } -} //GO.SYSIN DD SUBS/groupsort.c echo SUBS/grpop.c 1>&2 sed 's/.//' >SUBS/grpop.c <<'//GO.SYSIN DD SUBS/grpop.c' -#include "../godef.h" - -extern char fmtbuf[128]; -extern int dd[4]; -extern char *stoc(); - -struct bdstr *grpopbp; - -/* -** Call op() once on each member of the connected group. Use the board -** pointed at by global grpopbp; and the specified flag to avoid duplication. -** Return the sum of the returns from op() -*/ - -grpop(sn, op, flg) -int (*op)(); -{ - register int ns, d, n, same; - - same = grpopbp->b_spot[sn].s_occ; - grpopbp->b_spot[sn].s_flg |= flg; - n = 0; -#ifdef DEBUG - sprintf(fmtbuf, "grpop(%s, 0x%x, %d) same=%d", - stoc(sn), op, flg, same); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - for (d = 4; --d >= 0; ) { - ns = sn + dd[d]; -#ifdef DEBUG - sprintf(fmtbuf, "try %s; s_occ=%d, s_flg=%d", - stoc(ns), grpopbp->b_spot[ns].s_occ, grpopbp->b_spot[ns].s_flg); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - if (grpopbp->b_spot[ns].s_occ == same - && (grpopbp->b_spot[ns].s_flg & flg) == 0) - n += grpop(ns, op, flg); - } - return(n + (*op)(sn)); -} //GO.SYSIN DD SUBS/grpop.c echo SUBS/gsize.c 1>&2 sed 's/.//' >SUBS/gsize.c <<'//GO.SYSIN DD SUBS/gsize.c' -#include "../godef.h" - -/* -** GSIZE -- Return size of group containing specified spot. -*/ - -extern char fmtbuf[]; -extern struct bdstr *grpopbp; -#ifdef DEBUG -extern char *stoc(); -#endif DEBUG - -gsize(sn, bp) -struct bdstr *bp; -{ - int one(); - -#ifdef DEBUG - sprintf(fmtbuf, "gsize(%s)", stoc(sn)); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - clearflg(GRPFLG, bp); - grpopbp = bp; - return(grpop(sn, one, GRPFLG)); -} - -one() -{ - return(1); -} //GO.SYSIN DD SUBS/gsize.c echo SUBS/holes.c 1>&2 sed 's/.//' >SUBS/holes.c <<'//GO.SYSIN DD SUBS/holes.c' -#include "../godef.h" - -/* -** holes(bp, gbp, hbp, mgs) based on data in bp and gbp generate holes and -** return hole indices in hbp. mgs is minimum group size. -*/ - -extern char fmtbuf[]; -extern int dd[]; -extern struct bdstr *grpopbp, x; -#ifdef DEBUG -extern char *stoc(); -#endif DEBUG - -int numhls = 0; /* how many holes exist */ -extern int numgrps; /* how many groups exist (groups.c) */ -static char gr[MAXGRPS]; - -extern struct gstr g[]; /* we use the group info from groups() */ -struct hstr h[MAXGRPS]; /* here's where we leave the hole info */ -struct bdstr *hnbp, *gnbp; /* so hladd() can use them */ - -holes(bp, gbp, hbp, mgs) -struct bdstr *bp, *gbp, *hbp; -{ - register int i, j, n, q; - int hladd(); - struct spotstr *sp; - -#ifdef DEBUG - sprintf(fmtbuf, "holes(0x%x, 0x%x)", bp, hbp); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - numhls = 0; - clearflg(GRPFLG, bp); /* bp must not == hbp */ - for (i = BAREA; --i > 0; ) /* in hbp use flg to hold hole num */ - hbp->b_spot[i].s_flg = 255; - grpopbp = bp; /* global used by grpop() & hladd() */ - gnbp = gbp; /* global used by hladd() */ - hnbp = hbp; /* global used by hladd() */ - for (i = BAREA; --i > 0; ) { - sp = &bp->b_spot[i]; - if (sp->s_occ == EMPTY && (sp->s_flg & GRPFLG) == 0) { - for (j = numgrps; --j >= 0; gr[j] = 0); - h[numhls].h_spot = i; - h[numhls].h_size = grpop(i, hladd, GRPFLG); - for (n = j = q = 0; j < numgrps; j++) { - if (gr[j] && g[j].g_size > mgs) { - if (n < MAXLIBS) - h[numhls].h_g[n] = j; - q |= g[j].g_who; - n++; - } - } - h[numhls].h_grps = n; /* how many surrounding groups */ - h[numhls].h_who = q; /* who surrounds it */ - numhls++; - if (numhls >= MAXGRPS) - break; /* should never happen, but */ - } - } - return(numhls); -} - -hladd(sn) -{ - register int d, n; - - hnbp->b_spot[sn].s_flg = numhls; - for (d = 4; --d >= 0; ) { - n = gnbp->b_spot[sn + dd[d]].s_flg; - if (n < numgrps) - gr[n] = 1; - } - return(1); -} //GO.SYSIN DD SUBS/holes.c echo SUBS/legality.c 1>&2 sed 's/.//' >SUBS/legality.c <<'//GO.SYSIN DD SUBS/legality.c' -#include "../godef.h" - -extern char *color[]; -extern char fmtbuf[]; -extern struct plyrstr p[]; -extern int dd[]; -extern struct bdstr b; - -char whyillegal = 0; - -extern char *stoc(); - -/* check the spot sn for legality */ -legality(us, sn) -{ - register int i, them, d, ns; - char buf[80]; - -#ifdef DEBUG - sprintf(fmtbuf, "legality(%s, %s)?", color[us], stoc(sn)); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - whyillegal = 0; - if (sn < 0 || sn >= BAREA - || b.b_spot[sn].s_occ != EMPTY) { - whyillegal = ILL_NOTEMPTY; - return(ILLEGAL); - } - if (p[us].p_ko == sn && numcap(us, sn) == 1) { - whyillegal = ILL_INTOKO; - return(ILLEGAL); - } - b.b_spot[sn].s_occ = us; - them = (BLACK + WHITE) - us; - if (liberties(sn, &b) == 0) { /* need to capture to do this */ -#ifdef DEBUG - sprintf(fmtbuf, "in legality() liberties(%s, &b) is 0!", stoc(sn)); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - for (d = 4; --d >= 0; ) { - ns = sn + dd[d]; - if (b.b_spot[ns].s_occ == them && liberties(ns, &b) == 0) - break; /* ok, we capture >= 1 of them */ - } - if (d < 0) - whyillegal = ILL_SUICIDE; - } -#ifdef DEBUG - sprintf(fmtbuf, "legality(%s, %s) sets whyillegal to %d", - color[us], stoc(sn), whyillegal); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - b.b_spot[sn].s_occ = EMPTY; - if (whyillegal != 0) - return(ILLEGAL); - return(LEGAL); -} //GO.SYSIN DD SUBS/legality.c echo SUBS/lfs.c 1>&2 sed 's/.//' >SUBS/lfs.c <<'//GO.SYSIN DD SUBS/lfs.c' -/* -** strip line feeds of the argument -*/ - -char * -lfs(str) -char *str; -{ - register char *fp, *tp; - static char buf[128]; - - for (fp = str, tp = buf; *tp = *fp; ) - if (*fp++ != '\n') - tp++; - return(buf); -} //GO.SYSIN DD SUBS/lfs.c echo SUBS/liberties.c 1>&2 sed 's/.//' >SUBS/liberties.c <<'//GO.SYSIN DD SUBS/liberties.c' -#include "../godef.h" - -/* -** LIBERTIES -- Return number of liberties in group containing -** specified spot. -*/ - -extern char fmtbuf[]; -extern int dd[]; -extern struct bdstr b; -extern struct bdstr *grpopbp; -#ifdef DEBUG -extern char *stoc(); -#endif DEBUG - -liberties(sn, bp) -struct bdstr *bp; -{ - int libcheck(); - -#ifdef DEBUG - sprintf(fmtbuf, "liberties(%s)", stoc(sn)); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - clearflg(LIBFLG, bp); - grpopbp = bp; - return(grpop(sn, libcheck, LIBFLG)); -} - -libcheck(sn) -{ - register int ns, d, n; - - n = 0; - for (d = 4; --d >= 0; ) { - ns = sn + dd[d]; - if (grpopbp->b_spot[ns].s_occ == EMPTY - && (grpopbp->b_spot[ns].s_flg & LIBFLG) == 0) { - n++; - grpopbp->b_spot[ns].s_flg |= LIBFLG; - } - } -#ifdef DEBUG - sprintf(fmtbuf, "libcheck(%s) returns %d", stoc(sn), n); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - return(n); -} //GO.SYSIN DD SUBS/liberties.c echo SUBS/makemove.c 1>&2 sed 's/.//' >SUBS/makemove.c <<'//GO.SYSIN DD SUBS/makemove.c' -#include "../godef.h" - -extern char fmtbuf[128]; -extern char whyillegal; /* from legality.c */ -extern int dd[]; -extern struct plyrstr p[3]; -extern struct bdstr b; -extern struct bdstr *grpopbp; -extern char *stoc(); - -makemove(us, mv) /* Carry out player's move & update board */ -{ - register int caps, them, d, ns, i; - int capture(); - - if (mv == PASS || mv == RESIGN) - return(LEGAL); - if (legality(us, mv) == ILLEGAL) { - if (whyillegal == ILL_INTOKO) - log("ko violation!"); - else - return(ILLEGAL); - } - b.b_spot[mv].s_occ = us; - caps = 0; - them = (BLACK + WHITE) - us; - grpopbp = &b; - for (d = 4; --d >= 0; ) { - ns = mv + dd[d]; - if (b.b_spot[ns].s_occ == them && liberties(ns, &b) == 0) { -#ifdef DEBUG - sprintf(fmtbuf, "liberties(%s, &b) = 0", stoc(ns)); - log(fmtbuf); read(0, fmtbuf, 10); -#endif DEBUG - clearflg(GRPFLG, &b); - i = grpop(ns, capture, GRPFLG); - caps += i; - if (i == 1) - p[them].p_ko = ns; - } - } - if (caps != 1) - p[them].p_ko = 0; - p[us].p_captures += caps; - return(LEGAL); -} - -capture(sn) /* called by grpop() */ -{ - grpopbp->b_spot[sn].s_occ = EMPTY; - return(1); -} //GO.SYSIN DD SUBS/makemove.c echo SUBS/numcap.c 1>&2 sed 's/.//' >SUBS/numcap.c <<'//GO.SYSIN DD SUBS/numcap.c' -#include "../godef.h" - -extern int dd[]; -extern struct bdstr b; - -numcap(us, mv) /* How many does a move at mv capture? */ -{ - register int caps, them, d, ns, i; - int capture(); - - if (mv == PASS || mv == RESIGN) - return(0); - caps = 0; - them = (BLACK + WHITE) - us; - for (d = 4; --d >= 0; ) { - ns = mv + dd[d]; - if (b.b_spot[ns].s_occ == them && liberties(ns, &b) == 1) - caps += gsize(ns, &b); - } - return(caps); -} //GO.SYSIN DD SUBS/numcap.c echo SUBS/stoc.c 1>&2 sed 's/.//' >SUBS/stoc.c <<'//GO.SYSIN DD SUBS/stoc.c' -#include "../godef.h" - -/* -** STOC, CTOS, LTON -- Miscellaneous conversions -*/ - -char *letters = "?ABCDEFGHJKLMNOPQRST???"; - -extern char *lfs(); -struct mvstr { - int m_code; - char *m_text; -}; -static struct mvstr mv[] = { - PASS, "pass\n", - RESIGN, "resign\n", - BEBLACK, "black\n", - BEWHITE, "white\n", - BYOROMI, "byo-romi\n", - 0 -}; - -char * -stoc(s) /* Turn the spot number form of a move into the character form */ -{ - static char buf[32]; - register int i; - - for (i = 0; mv[i].m_code; i++) - if (s == mv[i].m_code) - return(lfs(mv[i].m_text)); - sprintf(buf, "%c%d", letters[s % BSZ2], s / BSZ2); - return(buf); -} - -ctos(mp) /* Turn the character form of a move into the spot number form */ -char *mp; -{ - register int i; - - for (i = 0; mv[i].m_code; i++) - if (strcmp(mp, mv[i].m_text) == 0) - return(mv[i].m_code); - return(lton(mp[0]) + BSZ2 * atoi(&mp[1])); -} - -lton(c) /* turn a letter into a number */ -char c; -{ - register int i; - - if (c < 'A') - return(0); - for (i = 1; letters[i] && letters[i] != c; i++); - return(i); -} //GO.SYSIN DD SUBS/stoc.c echo SUBS/timeleft.c 1>&2 sed 's/.//' >SUBS/timeleft.c <<'//GO.SYSIN DD SUBS/timeleft.c' - -/* -** SETIMELEFT -- set user time limit (seconds) -** TIMELEFT -- return amount of user time not yet used (seconds) -*/ -#ifndef BSD -#ifndef V8 -oops() { BSD = ~V8; } /* to generate an error message */ -#endif V* -#endif BSD - -#ifdef BSD - -#include <sys/time.h> -#include <sys/resource.h> - -static long stoptime; -static struct rusage ru; - -setimeleft(secs) -{ - getrusage(RUSAGE_SELF, &ru); - stoptime = ru.ru_utime.tv_sec + secs; -} - -timeleft() -{ - getrusage(RUSAGE_SELF, &ru); - return(stoptime - ru.ru_utime.tv_sec); -} - -#endif -#ifdef V8 - -#include <sys/types.h> -#include <sys/times.h> - -static time_t stoptime; -static struct tms t; - -setimeleft(secs) -{ - times(&t); - stoptime = t.tms_utime + secs * 60; -} - -timeleft() -{ - - times(&t); - return((stoptime - t.tms_utime) / 60); -} - -#endif //GO.SYSIN DD SUBS/timeleft.c echo godef.h 1>&2 sed 's/.//' >godef.h <<'//GO.SYSIN DD godef.h' -/* -** GODEF -- Definitions for go programs -** psl 5/84 -*/ - -#define LEGAL 0 -#define ILLEGAL 1 - -/* values for whyillegal */ -#define ILL_NOTEMPTY 1 -#define ILL_INTOKO 2 -#define ILL_SUICIDE 4 - -#define PASS (BAREA+1) -#define RESIGN (BAREA+2) -#define BEBLACK (BAREA+3) -#define BEWHITE (BAREA+4) -#define BYOROMI (BAREA+5) - -#define GRPFLG 1 -#define LIBFLG 2 - -#define BSZ 19 -#define BSZ1 (BSZ+1) -#define BSZ2 (BSZ+2) -#define BAREA (BSZ2*BSZ2) - -#define MUP (-BSZ2) -#define MDOWN (BSZ2) -#define MLEFT (-1) -#define MRIGHT (1) - -/* values for whyillegal */ -#define ILL_NOTEMPTY 1 -#define ILL_INTOKO 2 -#define ILL_SUICIDE 4 - -/* these macros for b_spot pointers */ -#define ABOVE(bsp) (bsp+UP) -#define BELOW(bsp) (bsp+DOWN) -#define LEFTOF(bsp) (bsp+LEFT) -#define RIGHTOF(bsp) (bsp+RIGHT) - -/* values for s_occ */ -#define EMPTY 0 -#define BLACK 1 -#define WHITE 2 -#define BORDER 3 - -#define MAXLIBS 24 -#define MAXEYES 2 -#define MAXGRPS 255 /* need to fit this in a char */ - -struct spotstr { - char s_occ; - char s_flg; -}; - -struct plyrstr { - char *p_plyr; /* program name */ - int p_pid; /* proc id for plyr */ - short p_rpipe; /* pipe from plyr */ - short p_wpipe; /* pipe to plyr */ - int p_captures; /* how many opponents captured */ - int p_ko; /* potential ko from previous move */ - int p_lycptp; /* last value of ycptp from utime.c */ - long p_utime; /* accumulated user time (seconds) */ -}; - -struct bdstr { - struct spotstr b_spot[BAREA]; -}; - -struct gstr { /* groups of stones (a.k.a. strings & blocks) */ - short g_who; /* who owns the group (BLACK | WHITE) */ - short g_size; /* how many stones are in the group */ - short g_spot; /* a representative stone in the group */ - short g_libs; /* how many liberties there are */ - short g_l[MAXLIBS]; /* the first few liberties */ - short g_eyes; /* how many eyes there are */ - short g_h[MAXEYES]; /* the first few eye hole numbers */ -}; - -struct hstr { /* holes between (among?) stones */ - short h_size; /* how many spots are in the hole */ - short h_spot; /* a representative spot in the hole */ - short h_grps; /* how many surrounding groups there are */ - short h_g[MAXLIBS]; /* the first few groups */ - short h_who; /* who "owns" (no one, BLACK, WHITE, both) */ -}; - - -extern char *passmove; -extern char *resignmove; -extern char *blackmove; -extern char *whitemove; -extern char *letters; -extern char *color[]; -extern char fmtbuf[]; -extern char whyillegal; - -extern int liblist[MAXLIBS], nlibs; -extern int dd[4]; -extern int movenum; -extern int lastflg; -extern struct plyrstr p[3]; -extern struct bdstr b; - -extern char *stoc(), *copy(); //GO.SYSIN DD godef.h