[net.sources] Source for Usenix Tournament GO Referee

psl@petrus.UUCP (Peter Langston) (04/25/86)

# 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

mark@tove.UUCP (Mark Weiser) (04/30/86)

Peter's go referee doesn't run on 2.x Suns because of his child timing
hack (for which he he predicts a day in hell for himself, of which this
posting is possibly the first minute).

(The second minute is the following: you must mkdir SUBS and GREF
before sh'ing his file.)

Here is the contextual diff that makes the program run on Suns, while
unfortunately breaking the child forking cheating check.
-------------------------------------------------------------
*** utime.c	Sun Apr 27 23:01:23 1986
--- utime.c.new	Sun Apr 27 22:54:34 1986
***************
*** 115,121
  	}
  	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);

--- 115,121 -----
  	}
  	if (i >= nproc)		/* did we find the proc table entry? */
  	    return(0);
! 	ycptp = 0;
  	if (readusr(&p) == 0)
  	    return(0);
  	return(usr.u_ru.ru_utime.tv_sec);
-------------------------------------------------------------
-mark
-- 
Spoken: Mark Weiser 	ARPA:	mark@maryland	Phone: +1-301-454-7817
CSNet:	mark@umcp-cs 	UUCP:	{seismo,allegra}!umcp-cs!mark
USPS: Computer Science Dept., University of Maryland, College Park, MD 20742