Source for Usenix Tournament GO Referee
Peter Langston
psl at petrus.UUCP
Fri Apr 25 16:37:07 AEST 1986
# To unbundle, sh this file
echo READ_ME 1>&2
sed 's/.//' >READ_ME <<'//GO.SYSIN DD READ_ME'
-GO Referee distribution 4/86
-
-These are the components of the GO referee used for the Usenix GO Tournaments.
-Since these are sources they should work on almost any system.
-The one system-specific module is "SUBS/utime.c"; it's set up for BSD systems.
-If you have a non-BSD system you'll have to hack it (good luck).
-
-There are two subdirectories;
- SUBS contains source files to build the archive "gosub.a"
- GREF contains source files for the referee itself
-
-After unbundling the files, cd into SUBS and say "make". This will create
-the "gosub.a" archive used by the referee (and also potentially useful for
-your own programs).
-
-Then cd into GREF and say "make". This will make "gref", the referee,
-"gotst", a random GO player for testing the referee, and will ry to print
-the gref document (check the Makefile to be sure it's saying the right
-things for your system; note that it uses PIC).
-
-Note also that gref must be able to read /dev/kmem to do program timings;
-if it can't it will go ahead, but show no timings.
-
-Good luck. Let me know of any bugs, as always.
-
-Peter Langston
-bellcore!psl
//GO.SYSIN DD READ_ME
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
echo GREF/Makefile 1>&2
sed 's/.//' >GREF/Makefile <<'//GO.SYSIN DD GREF/Makefile'
-CFLAGS = -O -I..
-GOSUB = ../gosub.a
-
-default: gref
-
-all: gref gotst doc
-
-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 $@
-
-doc: gref.n
- pic gref.n | ditroff -ms
//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);
- }
- 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 if (mv == RESIGN)
- mp = "resign";
- 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
-Lucasfilm Ltd.
-.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
-.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).
-.LP
-Data paths from invoking \fIgref\fR
-("gref go1.5 gobelle" for example)
-are as shown in figure 1.
-.PS
- down
- ellipse "CRT" "terminal"
- line <-> down
-Grefbox:
- box wid 1i ht 0.75i "go referee" "program" "``gref''"
- arrow right from Grefbox.e; circle diam 0.85i "file" "``gref.trans''"
- line <-> down left from Grefbox.sw
- down; box wid 0.85i ht 0.6i "go" "program" "``go1.5''"
- arrow down from last box.s; circle diam 0.75i "file" "``log.black''"
- line <-> down right from Grefbox.se
- down; box wid 0.85i ht 0.6i "go" "program" "``gobelle''"
- arrow down from last box.s; circle diam 0.75i "file" "``log.white''"
-.PE
-.ce
-figure 1: Data Paths
-.LP
-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 which is 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 board on which the game is played 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 CW
-.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
-.ft R
-.B2
-.ce
-figure 2: The CRT Display
-.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'' are 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.
//GO.SYSIN DD GREF/gref.n
echo GREF/utime.c 1>&2
sed 's/.//' >GREF/utime.c <<'//GO.SYSIN DD GREF/utime.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/utime.c
echo SUBS/Makefile 1>&2
sed 's/.//' >SUBS/Makefile <<'//GO.SYSIN DD SUBS/Makefile'
-CFLAGS = -O -I..
-DOTOS = bdinit.o clearflg.o copy.o glb.o groups.o grpop.o gsize.o holes.o \
- legality.o lfs.o liberties.o makemove.o numcap.o stoc.o
-DOTCS = bdinit.c clearflg.c copy.c glb.c groups.c grpop.c gsize.c holes.c \
- legality.c lfs.c liberties.c makemove.c numcap.c stoc.c
-LIB = ../gosub.a
-
-default: $(LIB)
- ranlib $(LIB)
- @echo "$(LIB) is up to date unless there were diagnostics."
-
-$(LIB):: $(DOTCS)
- -$(CC) $(CFLAGS) -c $?
- -ar uv $(LIB) *.o
- -rm -f *.o
//GO.SYSIN DD SUBS/Makefile
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/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);
- c &= ~0x20; /* make upper case */
- for (i = 1; letters[i] && letters[i] != c; i++);
- return(i);
-}
//GO.SYSIN DD SUBS/stoc.c
More information about the Comp.sources.unix
mailing list