#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  README Makefile debug.c disp.c go.c go.h
# Wrapped by jdr@hebe.weh.andrew.cmu.edu on Wed Dec 12 14:49:51 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(846 characters\)
sed "s/^X//" >README <<'END_OF_README'
X
XThe four files included with the current README comprise the go skeleton
Xprogram written by Jeff Rosenfeld at Carnegie Mellon University in
XSeptember of 1988. It is hereby placed in the public domain.
X
XThe code includes some termcap/curses dependencies that would be trivial
Xto remove were anyone so inclined. It should build and run easily on any
Xsystem that supports curses.
X
XThe commands are single-characters, as follows:
X
X	h,j,k,l: move the cursor left, down, up, or right, respectively.
X	y,u,b,n: move the cursor NW, NE, SW, SE, respectively.
X	s: set SKIP mode.
X	p: pass your turn and turn off SKIP mode.
X	.: enter your move at the current cursor location.
X	^L: redraw the board.
X	(space): continues after a debug message.
X
XSKIP mode allows you to set multiple stones down in the current color.
X
XEnjoy,
X		- Jeff,
X		  (jdr@andrew.cmu.edu).
END_OF_README
if test 846 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(93 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
XCFLAGS = -g -O
X
XOBJS = go.o disp.o debug.o
X
Xgo: $(OBJS)
X	cc -o go $(OBJS) -lcurses -ltermcap
END_OF_Makefile
if test 93 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f debug.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"debug.c\"
else
echo shar: Extracting \"debug.c\" \(753 characters\)
sed "s/^X//" >debug.c <<'END_OF_debug.c'
X#include <curses.h>
X#include "go.h"
X
X/* highlight a group on the board and display a message
X   concerning that group until the space bar is pressed */
Xshow(pgrp,str)
X struct group *pgrp;
X char *str;
X{
X	register struct elem *spot;
X	int x,y;
X	getyx(stdscr,y,x);
X	standout();
X	mvaddstr(1,15,str);
X	standend();
X	for (spot=pgrp->head; spot; spot=spot->next) spot->color |= 0x80;
X	draw();
X	while (getch() != ' ') beep();
X	for (spot=pgrp->head; spot; spot=spot->next) spot->color &= 0x7F;
X	move(1,15);
X	clrtoeol();
X	move(y,x);
X	draw();
X}
X
X/* display a message near the bottom of the screen */
Xcomment(fmt,a,b,c,d,e,f)
X char *fmt;
X int a,b,c,d,e,f;
X{
X	int x,y;
X	getyx(stdscr,y,x);
X	move(23,15);
X	printw(fmt,a,b,c,d,e,f);
X	clrtoeol();
X	move(y,x);
X	refresh();
X}
END_OF_debug.c
if test 753 -ne `wc -c <debug.c`; then
    echo shar: \"debug.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f disp.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"disp.c\"
else
echo shar: Extracting \"disp.c\" \(2159 characters\)
sed "s/^X//" >disp.c <<'END_OF_disp.c'
X#include <curses.h>
X#include "go.h"
X
X/* initialize the curses package and display mode */
Xsetup()
X{
X    initscr();
X    crmode();
X    noecho();
X    move(3,7);
X}
X
X/* draws the current game board
X   the debug package might set the high bit on some stones to indicate
X   that those spots should be highlighted */
Xdraw()
X{
X    register int i,j;
X    int x,y;
X    getyx(stdscr,y,x);
X    mvaddstr(2,5,"|---------------------------------------|");
X    for (i=0; i<19; ++i) {
X	mvaddch(3+i,5,'|');
X	for (j=0; j<19; ++j) {
X	    addch(' ');
X	    if (Board[j][i].color & 0x80) standout();
X	    switch(Board[j][i].color & 0x7F) {
X	      case NONE: addch('+'); break;
X	      case BLACK: addch('@'); break;
X	      case WHITE: addch('O'); break;
X	      default: addch('!'); break; /* ERROR! */
X	    }
X	    if ((Board[j][i].color & 0x80) &&
X		j+1<19 && !(Board[j+1][i].color & 0x80)) standend();
X	}
X	addch(' '); addch('|');
X    }
X    mvaddstr(3+i,5,"|---------------------------------------|");
X    move(y,x);
X    refresh();
X}
X
X/* relative cursor motion on a flat board with bounds-checking */
Xrup(dy,dx)
X int dy,dx;
X{
X	int x,y;
X	getyx(stdscr,y,x);
X	x += dx; y += dy;
X	if (x < 7 || x >= 45) x -= dx;
X	if (y < 3 || y >= 22) y -= dy;
X	move(y,x);
X	refresh();
X}
X
Xfetchmove(ploc)
X struct location *ploc;
X{
X	static int setmode = 0;
X	int done = 0;
X	while (!done) switch (getch()) {
X	  case 'j': rup(1,0); break;
X	  case 'k': rup(-1,0); break;
X	  case 'h': rup(0,-2); break;
X	  case 'l': rup(0,2); break;
X	  case 'y': rup(-1,-2); break;
X	  case 'u': rup(-1,2); break;
X	  case 'b': rup(1,-2); break;
X	  case 'n': rup(1,2); break;
X	  case 's': setmode=1; break;
X	  case 'p': setmode=0; return PASS;
X	  case 'L'&0x1F: draw(); break;
X	  case '.': done=1; break;
X	  default: beep(); break;
X	}
X	getyx(stdscr,ploc->y,ploc->x);
X	ploc->x -= 7; ploc->y -= 3;
X	ploc->x /= 2;
X	return setmode?SKIP:MOVE;
X}
X
Xbeep()
X{
X	static int inited = 0;
X	static char *str = NULL;
X	if (!inited) {
X		str = getcap("bl");
X		if (str == NULL) str = getcap("vb");
X		if (str == NULL) str = "";
X		inited = 1;
X	}
X	write(2,str,strlen(str));
X}
X
X/* the opposite of setup() */
Xcleanup()
X{
X	move(23,0);
X	refresh();
X	endwin();
X}
END_OF_disp.c
if test 2159 -ne `wc -c <disp.c`; then
    echo shar: \"disp.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f go.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"go.c\"
else
echo shar: Extracting \"go.c\" \(5069 characters\)
sed "s/^X//" >go.c <<'END_OF_go.c'
X#include <sys/signal.h>
X#include "go.h"
X
X/* offsets for pointer arithmetic in a 19x19 2-space;
X   the first four correspond to N,S,W,E, next are the diagonals, and last is
X   the no-movement offset - this facilitates restricting motion to the
X   taxicab directions without using two arrays */
Xint Dir[9] = { -19,19,-1,1, -20,-18,18,20, 0 };
X
Xstruct elem Board[19][19];
Xstruct group Groups[50];	/* static limit of 50 groups - ick! */
X
X/* there is only ever one spot on the board that cannot be played despite
X   that it will have liberties after the play - this marks that spot */
Xstruct elem *KoSpot;
X
X/* number of consecutive passes */
Xint Pass;
X
X/* bounds-checking */
X#define onboard(a) ((a) >= &Board[0][0] && (a) <= &Board[19][19])
X
X/* runs code for each taxicab direction about the center */
X#define LOOPAROUND(center,ptr,code) \
X	{ register int _i; \
X	  for (ptr=(center)+Dir[_i=0]; _i<4; ptr=(center)+Dir[++_i]) \
X	      if (onboard(ptr) && adjacent(ptr,(center))) \
X	          { code } }
X
Xsigexit()
X{
X    cleanup();
X    exit(1);
X}
X
Xmain()
X{
X    register int i,j;
X    for (j=0; j<19; ++j) for (i=0; i<19; ++i) {
X	Board[i][j].loc.x = i;
X	Board[i][j].loc.y = j;
X    }
X    setup();
X    signal(SIGINT,sigexit);
X    draw();
X    Pass = 0;
X    do {
X        doturn(BLACK);
X        doturn(WHITE);
X    } while(Pass != 2);
X    cleanup();
X}
X
Xdoturn(whose)
Xcolor_t whose;
X{
X    struct location loc;
X    while (1) {
X	comment("%s's turn.",whose==BLACK?"BLACK":"WHITE");
X	switch (fetchmove(&loc)) {
X	  case PASS:
X	    ++Pass;
X	    return;
X	  case MOVE:
X	    if (checkmove(whose,&loc)) { beep(); continue; }
X	    domove(whose,&loc);
X	    break;
X	  case SKIP:
X	    domove(whose,&loc);
X	    continue;
X	}
X	break;
X    }
X    Pass = 0;			/* if move was not PASS, reset Pass */
X    draw();
X}
X
X/* check the validity of a move - 0 indicates validity, 1 does not.
X   the kospot may be occupied only when a snapback occurs - this is
X   when one of the opponent's groups touching the kospot has only
X   one liberty and more than one element */
Xcheckmove(turn,loc)
Xcolor_t turn;
Xregister struct location *loc;
X{
X    register int i;
X    struct elem *targ;
X    struct elem *spot = &Board[loc->x][loc->y];
X    if (spot->color != EMPTY) return 1;
X    if (spot == KoSpot) {
X	LOOPAROUND(spot,targ,	/* check for snapback */
X		   if (targ->color != turn &&
X		       targ->group->liberties == 1 &
X		       targ->group->head->next != NULL)
X		     return 0;	/* snapback! */
X		   );
X	return 1;		/* catch `ko's */
X    }
X    return 0;
X}
X
X/* perform a valid move.
X   this includes updating the group list, possibly joining two or more
X   groups together or creating a new group. we also update liberty counts,
X   killing groups with zero liberties. */
Xdomove(turn,loc)
X color_t turn;
X register struct location *loc;
X{
X    register int i;
X    int tmp;
X    struct elem *targ;
X    struct elem *spot = &Board[loc->x][loc->y];
X    KoSpot = NULL;
X    mkgroup(spot);
X    spot->group->owner = spot->color = turn;
X    LOOPAROUND(spot,targ,
X	       if (targ->color == turn) {
X		   if (spot->group != targ->group)
X		       nattach(targ->group,spot->group);
X	       }
X	       else if (targ->color != EMPTY) {
X		   tmp = countlibs(targ->group);
X		   if (tmp == 0) kill(targ->group);
X		   else targ->group->liberties = tmp;
X	       }
X	       );
X    if ((spot->group->liberties = countlibs(spot->group)) == 0) {
X	kill(spot->group);
X	KoSpot = NULL;
X    }
X    return 0;
X}
X
Xmkgroup(spot)
Xstruct elem *spot;
X{
X    register struct group *pgrp;
X    for (pgrp = &Groups[0]; pgrp < &Groups[50]; ++pgrp)
X        if (pgrp->head == NULL) {
X            pgrp->head = spot;
X            pgrp->owner = spot->color;
X	    pgrp->flags = 0;
X	    spot->group = pgrp;
X	    spot->next = NULL;
X            return 0;
X        }
X    return 1;
X}
X
Xkill(grp)
Xstruct group *grp;
X{
X    register struct elem *spot;
X    show(grp,"killing");
X    if (grp->head->next == NULL) KoSpot = grp->head;
X    for (spot=grp->head; spot; spot=spot->next)
X        spot->color = EMPTY;
X    grp->head = NULL;
X}
X
X/* attach two groups together without counting liberties */
Xnattach(dst,grp)
Xstruct group *dst, *grp;
X{
X    register struct elem *spot, *tmp;
X    show(grp,"attaching this...");
X    show(dst,"...to this.");
X    for (spot=grp->head; spot; tmp=spot,spot=spot->next)
X        spot->group = dst;
X    tmp->next = dst->head;
X    dst->head = grp->head;
X    grp->head = NULL;
X    return 0;
X}
X
X/* attach two groups, returning the number of liberties in the
X   resulting group */
Xattach(dst,grp)
Xstruct group *dst, *grp;
X{
X    nattach(dst,grp);
X    return (dst->liberties = countlibs(dst));
X}
X
Xcountlibs(grp)
Xstruct group *grp;
X{
X    register struct elem *elem, *spot;
X    int count = 0;
X    show(grp,"counting liberties");
X    for (elem=grp->head; elem; elem=elem->next)
X	LOOPAROUND(elem,spot,
X		   if (!spot->mark) {
X		       spot->mark = 1;
X		       if (spot->color == EMPTY)
X			   ++count;
X		   }
X		   );
X    for (elem=grp->head; elem; elem=elem->next)
X	LOOPAROUND(elem,spot,
X		   spot->mark = 0;
X		   );
X    comment("counted %d liberties",count);
X    return count;
X}
END_OF_go.c
if test 5069 -ne `wc -c <go.c`; then
    echo shar: \"go.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f go.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"go.h\"
else
echo shar: Extracting \"go.h\" \(1523 characters\)
sed "s/^X//" >go.h <<'END_OF_go.h'
Xtypedef unsigned short color_t;
Xtypedef unsigned long bits_t;
X
Xstruct location {
X    char x,y;			/* assumes chars are SIGNED */
X};
X
X#define EMPTY 0
X#define NONE EMPTY
X#define BLACK 1
X#define WHITE 2
X
Xstruct elem {
X    struct elem *next;		/* ptr to next stone in group */
X    struct group *group;	/* ptr to group descriptor */
X    int mark;			/* temp. marker - must always be reset to 0 */
X    struct location loc;	/* coordinates of this stone */
X    color_t color;		/* color of this stone */
X};
X
Xstruct group {
X    struct elem *head;		/* some stone in the group */
X    color_t owner;		/* head->color */
X    short liberties;		/* how many liberties this group has */
X    bits_t flags;		/* group-specific flags */
X};
X
X#define GR_EYE		0x01	/* group has at least one eye */
X#define GR_LIVE		0x02	/* group is alive */
X
X#define setf(bit,place) (place |= (bit))
X#define clrf(bit,place) (place &= ~(bit))
X#define getf(bit,place) ((place) & (bit))
X
X#define abs(a) ((a)>0 ? (a) : -(a))
X#define adjacent(a,b) ((abs((a)->loc.x - (b)->loc.x) +    \
X                        abs((a)->loc.y - (b)->loc.y)) == 1)
X
X#define PASS 0			/* player passes */
X#define MOVE 1			/* player attempts to make a move */
X#define SKIP 2			/* player enters setup mode */
X
X#define UP	0
X#define DOWN	1
X#define LEFT	2
X#define RIGHT	3
X#define UPLEFT	4
X#define UPRIGHT	5
X#define DNLEFT	6
X#define DNRIGHT	7
X
X#ifndef NULL
X#define NULL 0
X#endif
X
Xextern struct elem Board[19][19]; /* the game board */
Xextern int Dir[];		/* offsets for relative motion on the board */
END_OF_go.h
if test 1523 -ne `wc -c <go.h`; then
    echo shar: \"go.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 1 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0


