[net.sources] Kriegspiel game

wolfe@ernie.Berkeley.EDU (David Wolfe) (05/07/86)

*****************************************************************
*       		                        		*
*              K   R   I   E   G   S   P   I   E   L            *
*                       A Game Of Inference                     *
*                              	       	                        *
*       Kriegspiel is a chess variant in which each player	*
*       cannot see his opponents pieces.  Here, the computer	*
*       acts as a judge for two players, similar to the		*
*       arcade game `Encounter'.  (If you have never seen	*
*       this game in arcades, you are not alone.)  The game	*
*       is surprisingly fun, even for the non-chess		*
*       enthusiast (although enthusiasm helps).  The program	*
*       uses 4.2 IPC protocols, and the `curses' graphics	*
*       library.  It looks prettiest on a VT100 or VT220 type	*
*       terminal.						*
*       							*
*****************************************************************
------------------------------ CUT HERE -----------------------------------
# To unbundle, sh this file
cat >help <<'//GO.SYSIN DD *'

NAME
     kriegspiel - A Chess Variant

SYNOPSIS
     kriegspiel [-bwcaprsdh] user[@machine]

DESCRIPTION
     _K_r_i_e_g_s_p_i_e_l is a chess variant in which each player cannot
     see his opponents pieces.  The computer acts as a judge for
     two players. The rules of Kriegspiel are discussed at the
     end of this document.

     The game must be invoked separately by two users.  Various
     options may be chosen in the command line; conflicting
     options (such as if both players choose white) are resolved
     with a flip of a coin.

     Moves may be specified in either algebraic or descriptive
     notation.  Most standard methods will work.  For example,
     all of the following are legal (and equivalent) for white's
     first move:  p-k4, p/k2-k4, e2-e4, e4, pe4.  In descriptive
     notation, use an 'x' for pawn takes (such as pxkb4), but do
     not use an 'x' when taking using other pieces.  Castling can
     be done with o-o (king side) and o-o-o (queen side), or by
     moving the king two squares.

     The other commands available are:

     resign         I resign.
     draw           Offer a draw.
     help           Give examples of legal commands.
     any            Can I take with any of my pawns?
     say _s_t_r_i_n_g     Send message to opponent.
     _C_o_n_t_r_o_l-_L      Redraw the screen (when typed at any time).

     Under the default options, you will be informed of the fol-
     lowing information when applicable:
     (1) your opponent tries an illegal move
     (2) you or your opponent is in check from the appropriate direction
     (3) your piece is taken (but not your opponent's piece is taken)
     (4) your opponent asks `any', and the response

     The game ends if either player is checkmated or stalemated,
     if both players have insufficient material, if either player
     resigns, if both players agree on a draw, or the game can
     end due to hardware error.  (But not if the same position
     comes up three times or if the game goes 50 consecutive
     moves without a piece take or pawn capture, as in ordinary
     chess).






Printed 5/6/86             2 May 1986                           1






KRIEGSPIEL(1)       UNIX Programmer's Manual        KRIEGSPIEL(1)



OPTIONS
     Options preceded by a `-' turn the option off.  If the
     players choose conflicting option, then the option will be
     chosen by a flip of a coin.

     w              I wish to be white.  Negated by opponent
                    choosing options `c' or `w'
     b              I wish to be black.  Negated by opponent
                    choosing options `c' or `b'
     c              Force color to be chosen randomly.  This is
                    the default if neither person chooses a
                    color.
     a              Announce to both players when a piece is
                    taken, revealing also whether it was a pawn
                    or a major piece that was taken.  Also
                    announce if a pawn ever promotes.
     p              Announce to both players how many possible
                    ways the player to move can take with his
                    pawns (if he can at all).  The player to move
                    can only try three moves which take with his
                    pawns.  If, after exhausting these three
                    tries, the player's only legal move is to
                    take with his pawn, then the player is check-
                    mated or stalemated as appropriate.  If the
                    player tries the same take twice, this will
                    not be counted against him.  The `any' com-
                    mand is ignored under this option.
     r              Reverse the direction from which algebraic
                    moves are accepted if I am black.  (Thus,
                    e2-e4 on black's first move would move the
                    pawn in front of your king up two squares.
                    Without this option set, the move would be
                    entered as d7-d5 in algebaic)
     d              Dumb terminal:  Use this option if the graph-
                    ics don't seem to be working well.  This may
                    help.
     h              Print out this help file.
     s              Make me the server.  This option should only
                    be used as a last resort.  Invisibly to the
                    user, one player is the server, and one is
                    the client.  These are usually chosen by the
                    program by a protocol.  If you're having
                    troubles connecting with your opponent, then
                    try the following:  One player invoke the
                    program with the `s' option, and one with the
                    `-s' option.
     _n              A number between one and a thousand to be
                    used as the port.  This option should only be
                    used if you are having troubles connecting.
                    Both players should select the same number
                    between 1 and 1000 to be used to compute the
                    port on which they communicate.



Printed 5/6/86             2 May 1986                           2






KRIEGSPIEL(1)       UNIX Programmer's Manual        KRIEGSPIEL(1)



RULES
     Kriegspiel is a chess variation dating back at least before
     WWII.  It requires three people: two players and a judge.
     The players sit back to back, each with a board with only
     their own pieces.  The judge has a board between the
     players, with the entire position.  Each player in his turn
     tries different moves.  For each illegal move tried, the
     judge says `illegal' aloud.  If a player is put into check,
     this fact is said out loud, along with the direction from
     which he/she is in check: Check along the file, rank, short
     diagonal, long diagonal (from the point of view of the
     king), and knight.  When the player makes a legal move, that
     is the move he must play.

     Beyond this, the ammount of information the judge should
     reveal is controversial.  The author prefers the following.
     If a piece is taken, the judge (quietly) removes the piece
     from the injured party's board.  On her/his turn, a person
     may ask `any?', meaning `Are there any ways of taking any of
     my opponent's pieces with any of my pawns?'  The judge
     answers aloud `yes' or `no', as appropriate.  The reason
     this rule is included is to speed up the game;  otherwise
     each player would try all possible pawn takes at the start
     of each turn.  The disadvantage with asking `any?' is that
     the opponent also finds out the answer; the advantage is
     that the player is under no obligation to actually take a
     piece with one of his pawns, even if the answer is yes.
     (Thus, he has gained information for free.)

     Some people prefer to play that takes are announced out
     loud, along with whether the piece taken was a pawn or not,
     allowing the players to have an idea how well their doing.
     Furthermore, that it should be announced not only whether a
     person has any available pawn tries, but also how many on
     every move.  This extra information, it is said, makes the
     game less chaotic and random, and keeps it from becoming
     like Battleship.  However, the extra information is somewhat
     tempered by the fact that a person may only try to take in
     three different ways with his pawns, after which a pawn take
     becomes illegal.

AUTHOR
     David Wolfe

BUGS
     There is no way of saving a game in progress.  This is par-
     ticularly frustrating if you are playing on an unreliable
     network:  If the network goes down, give it up...

     Other bugs, unknown.  Please notify me:
     wolfe@ernie.berkeley.edu




Printed 5/6/86             2 May 1986                           3



//GO.SYSIN DD *
cat >Makefile <<'//GO.SYSIN DD *'
# Kriegspiel written by David Wolfe based on a program by Bert Enderton
#  May 5, 1986
#
# on machines without alloca () `#define alloca malloc' in externs.h

# CFLAGS = -g
OBJ = check.o init.o input.o list.o mate.o makemove.o movecycle.o output.o pawntries.o piecemoves.o output.o legalmove.o main.o connect.o error.o review.o traps.o

ks: $(OBJ) makefile
	cc -o ks $(OBJ) -lcurses -ltermcap

check.o: externs.h constants.h
debugger.o: externs.h constants.h
externs.h: constants.h
init.o: externs.h constants.h
input.o: externs.h constants.h
legalmove.o: externs.h constants.h
list.o: constants.h
makemove.o: externs.h constants.h
mate.o: externs.h constants.h
movecycle.o: externs.h constants.h
output.o: externs.h constants.h
pawntries.o: externs.h constants.h
piecemoves.o: externs.h constants.h
main.o: externs.h constants.h
connect.o: externs.h constants.h
error.o:
review.o: externs.h constants.h
traps.o: externs.h constants.h
//GO.SYSIN DD *
cat >README <<'//GO.SYSIN DD *'

Kriegspiel written by David Wolfe based on a program by Bert Enderton
    May 5, 1986

1) First adjust the first to constants in constants.h
2) If your machine does not have malloc (), then see comment in externs.h
3) type 'make'
//GO.SYSIN DD *
cat >check.c <<'//GO.SYSIN DD *'
/* check.c */

#include "externs.h"

moveintocheck (from, to)
	int from, to;
{
	int victim, intocheck, color;
	LIST check ();

	color = whose [from];			/* make move on board */
	victim = findvictim (from, to);
	if (victim)
		whose [victim] = EMPTY;
	whose [to] = color;
	whose [from] = EMPTY;
	if (occupant [from] == KING)
		kingloc [color] = to;
	intocheck = (check (color) != NIL);	/* see if now in check */
	if (occupant [from] == KING)		/* restore board position */
		kingloc [color] = from;
	whose [from] = color;
	whose [to] = EMPTY;
	if (victim)
		whose [victim] = 1 - color;
	return intocheck;
}

LIST
check (color)
	int color;
{
	LIST l, checkdirs, lmember (), linsert ();
	int direction, spot, dist, side;

	checkdirs = NIL;
	l = dirlist [QUEEN];
	while (l != NIL) {
		direction = l->i;
		l = l->n;
		spot = kingloc [color];
		for (dist = 1; TRUE; dist++) {
			spot += direction;
			if ((whose [spot] == 1 - color)
			&& (lmember (-direction, dirlist [occupant [spot]])
			    && !(occupant [spot] == KING && dist > 1)))
				checkdirs = linsert (checkdirs, direction);
			if (whose [spot] != EMPTY)
				break;
		}
	}
	l = dirlist [KNIGHT];
	while (l != NIL) {
		direction = l->i;
		l = l->n;
		spot = kingloc [color] + direction;
		if (whose [spot] == 1 - color && occupant [spot] == KNIGHT)
			checkdirs = linsert (checkdirs, direction);
	}
	for (side = -1; side <= 1; side += 2) {
		spot = kingloc [color] + pawndir [color] + side;
		if (whose [spot] == 1 - color && occupant [spot] == PAWN)
			checkdirs = linsert(checkdirs, pawndir [color] + side);
	}

	return checkdirs;
}
//GO.SYSIN DD *
cat >connect.c <<'//GO.SYSIN DD *'
/* connect.c */

#include "externs.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pwd.h>

connectport (opponent, port)
	char *opponent;
	int port;
{
	struct sockaddr_in addr;
	struct hostent *hishost;
	struct passwd *mypasswd, *getpwuid();
	char *hishostname, *myhostname, *myname, *index(), *getpw(), *malloc();
	uid_t getuid();
	int i;

	if (hishostname = index (opponent, '@')) {
		hishostname [0] = '\0';        /* separate user and host */
		hishostname++;
	} else {
		hishostname = malloc (MAXBUFF);
		if (gethostname (hishostname, MAXBUFF) < 0)
			error ("gethostname in connectport");
	}
	myhostname = malloc (MAXBUFF);
	if (gethostname (myhostname, MAXBUFF) < 0)
		error ("gethostname in connectport");
	if ((hishost = (struct hostent *) gethostbyname(hishostname))
	    == (struct hostent *) NIL)
		error ("gethostname in connectport");
	mypasswd = getpwuid ((int) getuid());
	myname = mypasswd -> pw_name;
	if (iamserver == UNSET)
		if (i = strcmp (myname, opponent))
			iamserver = (i < 0);
		else if (i = strcmp (myhostname, hishost -> h_name))
			iamserver = (i < 0);
	if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
		error ("socket in connectport");
	bzero ((char *) &addr, sizeof (addr));
	if (port != 0) {
		if (port < 0 || port > 1000)
			error ("bad port number");
	} else if (iamserver) {
		hashport (myhostname, &port);
		hashport (hishost -> h_name, &port);
		hashport (myname, &port);
		hashport (opponent, &port);
	} else {
		hashport (hishost -> h_name, &port);
		hashport (myhostname, &port);
		hashport (opponent, &port);
		hashport (myname, &port);
	}
	port += 3000;
	addr.sin_family = AF_INET;
	addr.sin_port = htons ((u_short) port);
	if (iamserver) {
		if (bind (sock, /*(char *)*/ &addr, sizeof (addr)) < 0)
			if ((errno == EADDRINUSE || errno == ENOTCONN)
			&& iamserver == UNSET) {
				/* hope other player is server */
				iamserver = FALSE;
				close (sock);
				if ((sock = socket (AF_INET, SOCK_STREAM, 0))
				    < 0)
					error ("socket in connectport");
			} else
				error ("bind in connectport");
		if (iamserver && listen (sock, 1) < 0)
			error ("listen in connectport");
		while (iamserver
		&& (sock = accept (sock, (struct sockaddr_in *) NULL,
				   (int *) NULL)) < 0)
			if (errno != EINTR && errno != EBADF)
				error ("accept in connectport");
	}
	if (!iamserver) {
		bcopy (hishost->h_addr, (char *) &addr.sin_addr,
		       hishost->h_length);
		while (connect (sock, /*(char *)*/ &addr, sizeof (addr)) < 0)
			if ( errno == EINTR || errno == ECONNREFUSED) {
				close (sock);
				if ((sock = socket (AF_INET, SOCK_STREAM, 0))
				    < 0)
					error ("socket in connectport");
			} else
				error ("connect in connectport");
	}
}

hashport (s, port)
	char *s;
	int *port;
{
	while (*s)
		*port = ((*port < 0) | (*port << 1)) + *s++;
	*port &= ~0x80000000;	/* make *port nonnegative */
}
//GO.SYSIN DD *
cat >constants.h <<'//GO.SYSIN DD *'

/* constants.h */

/* These next two constants are system dependent */

/* file used for printing a file to the terminal (try /bin/pr) */
#define		PRINT_FILE	"/usr/ucb/more"
/* file where help will be kept */
#define		HELP_FILE	"/vd/gsf85/wolfe/code/kriegspiel/help"


/*		FALSE		0 */
/*		TRUE		1 */
#define		ILLEGAL_PIECE	-1
#define		ILLEGAL		-1
#define		NOWAY		-2
#define		AMBIGUOUS	-3
#define		NOMOREPAWNTRIES	-4

#define		UNSET		2
#define		RANDOM		3
#define		NIL		0
#define		MAXBUFF		100

#define		OFFBOARD	-1
#define		WHITE		0
#define		BLACK		1
#define		EMPTY		2

#define		PAWN		1
#define		KING		2
#define		KNIGHT		3
#define		BISHOP		4
#define		ROOK		5
#define		QUEEN		6

#define		MYCOLOR		0
#define		TOMOVE		1
#define		CLOCK		2
#define		CAPTURE		3
#define		PAWNTRIES	4
#define		CHECK		5
#define		PROMPT		6
#define		LEGAL		7
#define		INPUT		8
#define		MESSAGE		9
#define		OPPONENT	10

#define		NOPTIONS	4
#define		COLOR		0
#define		ANNOUNCETAKES	1
#define		ANNOUNCEPAWNS	2
#define		REVERSE		3
//GO.SYSIN DD *
cat >error.c <<'//GO.SYSIN DD *'
/* error.c */
#include "externs.h"
#include <signal.h>

error (s)
	char *s;
{
	clear ();
	refresh ();
	endwin ();
	if (errno == EPIPE)
		dead = TRUE;
	else {
		if (s != (char *) NULL) {
			send (sock, "very dead\3\0", 10, 0);
			perror (s);
			fflush (stdout);
			fflush (stderr);
		}
		shutdown (sock, 2);
		close (sock);
		exit (0);
	}
}
//GO.SYSIN DD *
cat >externs.h <<'//GO.SYSIN DD *'
/* externs.h */

#include "constants.h"
#include <stdio.h>
#include <curses.h>
#include <errno.h>
/* on machines without alloca () */
/* #define alloca malloc         */

struct IN
{
	int i;
	struct IN *n;
};
typedef struct IN *LIST;

struct MOVE
{
	int from;
	int to;
	struct MOVE *n;
};
typedef struct MOVE *MOVELIST;

extern	int	occupant [100];		/* what piece occupies square	*/
extern	int	whose [100];		/* which color occupies square	*/
extern	char	symbol [7];		/* symbols for printing pieces	*/
extern	LIST	dirlist [7];		/* directions a piece moves	*/
extern		pawndir	[2];		/* direction pawns of move	*/
extern	LIST	piecelocs [2];		/* locations of pieces		*/
extern	int	kingloc [2];		/* location of king		*/
extern	MOVELIST movelist;		/* record of game		*/
extern	int	ourcolor;
extern	char	*colorname [2];
extern	int	lastmovefrom;
extern	int	lastmoveto;
extern	int	virgin [100]; 		/* pieces not moved or captured	*/
extern	int	drawok [2];		/* side has agreed to draw	*/
extern	int	resign;			/* somebody resigned		*/
extern	int	dead;			/* somebody died		*/
extern	int	option [NOPTIONS];	/* options players must agree on*/
extern	WINDOW	*blanksq [89];		/* blank chessboard squares	*/
extern	WINDOW	*square [89];		/* contents of chessboard	*/
extern	WINDOW	*win [23];		/* message window areas		*/
extern	WINDOW	*backupwin [23];	/* for switching screens	*/
extern	WINDOW	*backupscreen;		/* used for redrawing vt220	*/
extern	WINDOW	*blankscreen;		/* used for redrawing vt220	*/
extern	char	sqcolor [2];		/* character used for square	*/
extern	int	vtterm;			/* is this a vt220?		*/
extern	int	dumbterm;		/* are we dumb?			*/
extern	int	reversescr;		/* can terminal inverse video?	*/
extern	int	sqheight;		/* height of a square		*/
extern	int	sqwidth;		/* width of a square		*/
extern	int	iamserver;		/* am I the server player?	*/
extern	int	sock;			/* socket for opponent		*/
extern	int	errno;			/* system error numbers		*/
//GO.SYSIN DD *
cat >help.nroff <<'//GO.SYSIN DD *'

.TH KRIEGSPIEL 1 "2 May 1986"
.UC 4
.SH NAME
kriegspiel \- A Chess Variant
.SH SYNOPSIS
.B kriegspiel
[-bwcaprsdh] user[@machine]
.br
.SH DESCRIPTION
.I Kriegspiel
is a chess variant in which each player cannot see his opponents
pieces.  The computer acts as a judge for two players. The rules of
Kriegspiel are discussed at the end of this document.
.PP
The game must be invoked separately by two users.  Various options may be
chosen in the command line; conflicting options (such as if both players
choose white) are resolved with a flip of a coin.
.PP
Moves may be specified in either algebraic or descriptive notation.  Most
standard methods will work.  For example, all of the following are legal
(and equivalent) for white's first move:  p-k4, p/k2-k4, e2-e4, e4, pe4.
In descriptive notation, use an 'x' for pawn takes (such as pxkb4), but do
not use an 'x' when taking using other pieces.  Castling can be done with
o-o (king side) and o-o-o (queen side), or by moving the king two squares.
.PP
The other commands available are:
.PP
.br
.ns
.TP 15
resign
I resign.
.br
.ns
.TP
draw
Offer a draw.
.br
.ns
.TP
help
Give examples of legal commands.
.br
.ns
.TP
any
Can I take with any of my pawns?
.br
.ns
.TP
.RI say \ string
Send message to opponent.
.br
.ns
.TP
.I Control-L
Redraw the screen (when typed at any time).
.PP
Under the default options, you will be informed of the following
information when applicable:
.nf
(1) your opponent tries an illegal move
(2) you or your opponent is in check from the appropriate direction
(3) your piece is taken (but not your opponent's piece is taken)
(4) your opponent asks `any', and the response
.fi
.PP
The game ends if either player is checkmated or stalemated, if both players
have insufficient material, if either player resigns, if both players
agree on a draw, or the game can end due to hardware error.  (But not if
the same position comes up three times or if the game goes 50 consecutive
moves without a piece take or pawn capture, as in ordinary chess).

.SH OPTIONS
.PP
Options preceded by a `-' turn the option off.  If the players choose
conflicting option, then the option will be chosen by a flip of a coin.
.PP
.br
.ns
.TP 15
w
I wish to be white.  Negated by opponent choosing options `c' or
`w'
.br
.ns
.TP
b
I wish to be black.  Negated by opponent choosing options `c' or
`b'
.br
.ns
.TP
c
Force color to be chosen randomly.  This is the default if neither person
chooses a color.
.br
.ns
.TP
a
Announce to both players when a piece is taken, revealing also
whether it was a pawn or a major piece that was taken.  Also
announce if a pawn ever promotes.
.br
.ns
.TP
p
Announce to both players how many possible ways the player to move
can take with his pawns (if he can at all).  The player to move can
only try three moves which take with his pawns.  If, after exhausting these
three tries, the player's
only legal move is to take with his pawn, then the player is
checkmated or stalemated as appropriate.  If the player tries the
same take twice, this will not be counted against him.  The `any'
command is ignored under this option.
.br
.ns
.TP
r
Reverse the direction from which algebraic moves are accepted if I
am black.  (Thus, e2-e4 on black's first move would move the pawn
in front of your king up two squares.  Without this option set, the
move would be entered as d7-d5 in algebaic)
.br
.ns
.TP
d
Dumb terminal:  Use this option if the graphics don't seem to be
working well.  This may help.
.br
.ns
.TP
h
Print out this help file.
.br
.ns
.TP
s
Make me the server.  This option should only be used as a last
resort.  Invisibly to the user, one player is the
server, and one is the client.  These are usually chosen by the
program by a protocol.  If you're having troubles connecting with
your opponent, then try the following:  One player invoke the
program with the `s' option, and one with the `-s' option.
.br
.ns
.TP
.I n
A number between one and a thousand to be used as the port.  This option
should only be used if you are having troubles connecting.  Both players
should select the same number between 1 and 1000 to be used to compute
the port on which they communicate.
.SH RULES
Kriegspiel is a chess variation dating back at least before WWII.
It requires three people: two players and a judge.  The players sit back to
back, each with a board with only their own pieces.  The judge has a board
between the players, with the entire position.  Each player in his turn
tries different moves.  For each illegal move tried, the judge says
`illegal' aloud.  If a player is put into check, this fact is said out
loud, along with the direction from which he/she is in check: Check along
the file, rank, short diagonal, long diagonal (from the point of view of
the king), and knight.  When the player makes a legal move, that is the
move he must play.
.PP
Beyond this, the ammount of information the judge should reveal is
controversial.  The author prefers the following.  If a piece is taken, the
judge (quietly) removes the piece from the injured party's board.  On
her/his turn, a person may ask `any?', meaning `Are there any ways of
taking any of my opponent's pieces with any of my pawns?'  The judge
answers aloud `yes' or `no', as appropriate.  The reason this rule is
included is to speed up the game;  otherwise each player would try all
possible pawn takes at the start of each turn.  The disadvantage with
asking `any?' is that the opponent also finds out the answer; the advantage
is that the player is under no obligation to actually take a piece with one
of his pawns, even if the answer is yes.  (Thus, he has gained information
for free.)
.PP
Some people prefer to play that takes are announced out loud,
along with whether the piece taken was a pawn or not, allowing the players
to have an idea how well their doing.  Furthermore, that it should be
announced not only whether a person has any available pawn tries, but also
how many on every move.  This extra information, it is said, makes the game
less chaotic and random, and keeps it from becoming like Battleship.
However, the extra information is somewhat tempered by the fact that a
person may only try to take in three different ways with his pawns, after
which a pawn take becomes illegal.
.SH AUTHOR
David Wolfe
.SH BUGS
There is no way of saving a game in progress.  This is particularly
frustrating if you are playing on an unreliable network:  If the network
goes down, give it up...
.PP
Other bugs, unknown.  Please notify me:  wolfe@ernie.berkeley.edu
//GO.SYSIN DD *
cat >init.c <<'//GO.SYSIN DD *'
/* init.c */
#include "externs.h"
#include <ctype.h>

initdirlists ()
{
	LIST linsert ();
	dirlist [PAWN] = (LIST) NIL;
	dirlist [KING] = linsert (linsert (linsert (linsert (linsert (linsert
         (linsert (linsert ((LIST) NIL, -10), -9), 1), 11), 10), 9), -1), -11);
	dirlist [KNIGHT] = linsert (linsert (linsert (linsert (linsert (linsert
	 (linsert (linsert ((LIST)NIL, -19),-8), 12), 21), 19), 8), -12), -21);
	dirlist [BISHOP] = linsert (linsert (linsert (linsert
            ((LIST) NIL, -9), 11), 9), -11);
	dirlist [ROOK] = linsert (linsert (linsert (linsert
            ((LIST) NIL, -10), 1), 10), -1);
	dirlist [QUEEN] = linsert (linsert (linsert (linsert (linsert (linsert
          (linsert (linsert ((LIST) NIL, -10),-9), 1), 11), 10), 9), -1), -11);
}

initpiecelocs ()
{
	piecelocs [BLACK] = linsert (linsert (linsert (linsert (linsert
            (linsert (linsert (linsert (linsert (linsert (linsert (linsert
	    (linsert (linsert (linsert (linsert ((LIST) NIL, 11), 12), 13), 14)
            , 15), 16), 17), 18), 21), 22), 23), 24), 25), 26), 27), 28);
        piecelocs [WHITE] = linsert (linsert (linsert (linsert (linsert
            (linsert (linsert (linsert (linsert (linsert (linsert (linsert
            (linsert (linsert (linsert (linsert ((LIST) NIL, 71), 72), 73), 74)
            , 75), 76), 77), 78), 81), 82), 83), 84), 85), 86), 87), 88);
	kingloc [WHITE] = 85;
	kingloc [BLACK] = 15;
}


initscreen ()
{
	int ww, ws1, ws2, ws3, ws;
	char *termtype, *getenv();

	termtype = getenv("TERM");
	vtterm = (!strncmp(termtype, "vt", 2) && !dumbterm);
	if (vtterm)
		COLS = 40;
	if (dumbterm)
		LINES = 10;
	initscr();
	noecho();
	crmode();
	if (SO == NIL || dumbterm)
		reversescr = FALSE;
	else
		reversescr = TRUE;
	if (vtterm) {
		sqheight = 3;
		sqwidth = 3;
		sqcolor [WHITE] = ' ';
		sqcolor [BLACK] = ' ';
		backupscreen = newwin (LINES, COLS, 0, 0);
		blankscreen = newwin (LINES, COLS, 0, 0);
	} else if (reversescr) {
		sqheight = 3;
		sqwidth = 5;
		sqcolor [WHITE] = ' ';
		sqcolor [BLACK] = ' ';
	} else {
		sqheight = 1;
		sqwidth = 2;
		sqcolor [WHITE] = '.';
		sqcolor [BLACK] = '*';
	}
	if (vtterm)
		ws = sqwidth * 8 + 1;
	else if (dumbterm)
		ws = sqwidth * 8 + 4;
	else
		ws = sqwidth * 8 + 10;
	ww = COLS - ws;
	if (dumbterm) {
		ww = ww / 3 - 1;
		ws1 = ws + 1;
		ws2 = ws1 + ww + 1;
		ws3 = ws2 + ww + 1;
		win [MYCOLOR] = subwin   (stdscr, 1, 15    ,  9,   3);
		win [TOMOVE] = subwin    (stdscr, 1, ww    ,  1, ws3);
		win [CLOCK] = newwin     (/*none*/1,  1    ,  1,   1);
		win [CAPTURE] = subwin   (stdscr, 1, ww    ,  3, ws3);
		win [PAWNTRIES] = subwin (stdscr, 1, ww    ,  4, ws3);
		win [CHECK] = subwin     (stdscr, 3, ww    ,  5, ws3);
		win [PROMPT] = subwin    (stdscr, 1, ww    ,  1, ws1);
		win [INPUT] = subwin     (stdscr, 3, ww    ,  2, ws1);
		win [LEGAL] = subwin     (stdscr, 1, ww    ,  5, ws1);
		win [MESSAGE] = subwin   (stdscr, 4, ww    ,  1, ws2);
		win [OPPONENT] = subwin  (stdscr, 5, ww    ,  5, ws2);
		backupwin [PROMPT] = subwin    (stdscr, 1, ww    ,  1, ws1);
		backupwin [MESSAGE] = subwin   (stdscr, 4, ww    ,  1, ws2);
		backupwin [INPUT] = subwin     (stdscr, 3, ww    ,  2, ws1);
	} else {
		win [MYCOLOR] = subwin   (stdscr, 1, ww    ,  1, ws);
		win [TOMOVE] = subwin    (stdscr, 1, ww - 1,  3, ws);
		win [CLOCK] = subwin     (stdscr, 1,          1,  3, COLS-1);
		win [CAPTURE] = subwin   (stdscr, 1, ww    ,  5, ws);
		win [PAWNTRIES] = subwin (stdscr, 1, ww    ,  6, ws);
		win [CHECK] = subwin     (stdscr, 3, ww    ,  7, ws);
		win [PROMPT] = subwin    (stdscr, 1, ww    , 10, ws);
		win [INPUT] = subwin     (stdscr, 3, ww    , 11, ws);
		win [LEGAL] = subwin     (stdscr, 1, ww    , 14, ws);
		win [MESSAGE] = subwin   (stdscr, 4, ww    , 15, ws);
		win [OPPONENT] = subwin  (stdscr, 5, ww    , 19, ws);
		scrollok (win [MESSAGE], TRUE);
		scrollok (win [INPUT], TRUE);
		backupwin [PROMPT] = subwin    (stdscr, 1, ww    , 10, ws);
		backupwin [MESSAGE] = subwin   (stdscr, 4, ww    , 15, ws);
		backupwin [INPUT] = subwin     (stdscr, 3, ww    , 11, ws);
	}
}

initboard(allpieces)
	int allpieces;
{
	int row, col, spot, i, j;
	static int initwhose [100] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
				       -1, 1, 1, 1, 1, 1, 1, 1, 1,-1,
				       -1, 1, 1, 1, 1, 1, 1, 1, 1,-1,
				       -1, 2, 2, 2, 2, 2, 2, 2, 2,-1,
				       -1, 2, 2, 2, 2, 2, 2, 2, 2,-1,
				       -1, 2, 2, 2, 2, 2, 2, 2, 2,-1,
				       -1, 2, 2, 2, 2, 2, 2, 2, 2,-1,
				       -1, 0, 0, 0, 0, 0, 0, 0, 0,-1,
				       -1, 0, 0, 0, 0, 0, 0, 0, 0,-1,
				       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };

	static int initoccupant [100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
					  0, 5, 3, 4, 6, 2, 4, 3, 5, 0,
					  0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
					  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
					  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
					  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
					  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
					  0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
					  0, 5, 3, 4, 6, 2, 4, 3, 5, 0,
					  0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

	for (i = 0; i < 100; i++) {
		whose [i] = initwhose [i];
		occupant [i] = initoccupant [i];
	}

	for (row = 0; row <= 7; row++)
		for (col = 0; col <= 7; col ++) {
			if (ourcolor == WHITE) {
				i = row;
				j = col;
			} else {
				i = 7 - row;
				j = 7 - col;
			}
			spot = 10 * (row + 1) + (col + 1);
			blanksq [spot] = subwin (stdscr, sqheight, sqwidth,
						 sqheight * i, sqwidth * j);
			square [spot] = subwin (stdscr, 1, 1,
					  (sqheight * i) + (sqheight / 2),
					  (sqwidth * j) + (sqwidth / 2));
			if (reversescr && (row + col) % 2 == 0) {
				wstandout (blanksq [spot]);
				wstandout (square [spot]);
			}
			for (i = 1; i <= sqwidth; i++)
				for (j = 1; j <= sqheight; j++)
					waddch (blanksq [spot], ' ');
			waddch (square [spot], sqcolor [(row + col) % 2]);
		}
	for (row = 1; row <= 2; row++)
		for (col = 1; col <= 8; col++) {
			if (ourcolor == WHITE)
				spot = 10 * (9 - row) + col;
			else
				spot = 10 * row + col;
			waddch (square [spot], symbol [occupant [spot]]);
			if (allpieces)
				waddch (square [99 - spot], tolower
					(symbol [occupant [99 - spot]]));
		}
}

//GO.SYSIN DD *
cat >input.c <<'//GO.SYSIN DD *'
/* input.c */

#include "externs.h"
#include <ctype.h>
#include <strings.h>
#include <sys/time.h>

char instr [MAXBUFF];

entermove (pstart, pend, color, pawntries)
	int *pstart, *pend, color, pawntries;
{
	int i, readfds;
	int counter = 0;
	struct timeval timeout;
	char c;

	timeout.tv_sec = (long int) 1;
	timeout.tv_usec = (long int) 0;
	wclear (win [OPPONENT]);
	while (TRUE) {
		drawok [color] = FALSE;
		if (color == ourcolor) {
			printf ("\007");    /* ring bell */
			if (drawok [1 - color]) {
				waddstr (win [MESSAGE], "draw offered");
				wclear (win [MESSAGE]);
			}
			wclear (win [INPUT]);
			waddstr (win [INPUT], ": ");
			waddstr (win [PROMPT], "your move");
			i = 0;
			while (TRUE) {
				move (win [INPUT]->_cury + win [INPUT]->_begy,
				      win [INPUT]->_curx + win [INPUT]->_begx);
				refresh ();
				instr [i] = getchar ();
				if (instr [i] == '\n'
				||  instr [i] == '\r')
					break;
				else if (instr [i] == '\f') {	/* ^L */
					redraw();
					continue;
				} else if (instr [i] == '\b'	/* ^H */
				|| instr [i] == '\177') {	/* delete */
					if (i > 0) {
						--i;
						wmove( win [INPUT],
						       win [INPUT]->_cury,
						       win [INPUT]->_curx - 1);
						wdelch (win [INPUT]);
					}
					continue;
				} else if (instr [i] == '\030'	/* ^X */
				|| instr [i] == '\025') {	/* ^U */
					wclear (win [INPUT]);
					waddstr (win [INPUT], ": ");
					i = 0;
					continue;
				} else if (isupper (instr [i]))
					tolower (instr [i]);
				wclear (win [LEGAL]);
				if (isprint (instr [i]))
					waddch (win [INPUT], instr [i++]);
			}
			instr [i] = '\000';
			wclear (win [INPUT]);
			if (send (sock, instr, strlen (instr) + 1, 0) < 0)
				error ("send in entermove");
		} else {
			i = 0;
			wclear (win [MESSAGE]);
			waddstr (win [MESSAGE],
				 "waiting for\nopponent's\nmove");
			refresh ();
			while (TRUE) {
				readfds = 1 + (1 << sock);
				while (select (sock + 1, &readfds, (int *)
					       NULL, (int *) NULL,
					       &timeout) < 0)
					if (errno != EINTR)
						error ("select in entermove");
				if (! (readfds & (1 << sock))) {
					wclear (win [CLOCK]);
					if (counter++ % 2 == 1)
						waddch (win [CLOCK],'/');
					else
						waddch (win [CLOCK],'\\');
					move (win [CLOCK]->_begy,
					      win [CLOCK]->_begx);
					refresh();
					if (readfds & 1) {
						c = getch();
						if (c == '\f'	/* ^L */)
							redraw();
					}
				}
				else
					break;
				wclear (win [LEGAL]);
			}
			wclear (win [LEGAL]);
			while (recv (sock, instr, MAXBUFF, 0) < 0)
				if (errno != EINTR)
					error ("recv in entermove");
		}
		wclear (win [PROMPT]);
		if (!strcmp (instr, "draw")) {
			drawok [color] = TRUE;
			break;
		} else if (!strcmp (instr, "resign")) {
			resign = TRUE;
			break;
		} else if (!strcmp (instr, "very dead\3")) {
			dead = TRUE;
			break;
		} else if (drawok [1 - color]) {
			if (!strcmp (instr, "yes")) {
				drawok [color] = TRUE;
				break;
			} else if (!strcmp (instr, "no")) {
				if (ourcolor != color)
					waddstr (win[MESSAGE], "draw refused");
				break;
			} else {
				wclear (win [MESSAGE]);
				waddstr (win [MESSAGE],
					 "draw offered\ntype yes or no\n");
			}
		} else if (!strcmp (instr, "o-o-o")
		&& kingloc [color] % 10 == 5) {
			*pstart = kingloc [color];
			*pend = kingloc [color] - 2;
			break;
		} else if (!strcmp (instr, "o-o")
		&& kingloc [color] % 10 == 5) {
			*pstart = kingloc [color];
			*pend = kingloc [color] + 2;
			break;
		} else if ((!strncmp (instr, "help", 4) || !strcmp (instr,""))
		&& color == ourcolor) {
			wclear (win [MESSAGE]);
			waddstr (win [MESSAGE],
				 "eg. qe4, p-k4\npxkb3, o-o-o\n");
			waddstr (win [MESSAGE],
				 "draw, resign\nsay you'll lose");
		} else if (!strncmp (instr, "say", 3)) {
			if (color != ourcolor) {
				wclear (win [OPPONENT]);
				waddstr (win [OPPONENT], "message:\n");
				waddstr (win [OPPONENT], instr + 3);
				waddch (win [OPPONENT], '\n');
			}
		} else if ((!option [ANNOUNCEPAWNS])
		&& (!strcmp (instr, "any")))
			if (pawntries)
				waddstr (win [PAWNTRIES], "pawntries\r");
			else
				waddstr (win [PAWNTRIES], "no pawntries\r");
		else {
			if ((i = parse_algebraic_move(pstart,pend,color))
			    == NOWAY)
				i = parse_descriptive_move (pstart,pend,color);
			if (i == TRUE)
				break;
			else
				illegal (i, color);
		}
	}
}

#define boardpos(col, row)  ((9 - (row)) * 10 + (col))
#define RIGHT_SIDE 2
#define RIGHT_FILE 1

/* parse an algebraic move (e2-e4), and return TRUE for non error */
parse_algebraic_move (pstart, pend, color)
	int *pstart, *pend, color;
{
	int foundpiece = FALSE, i, j, piece, spot;
	LIST piecemoves (), lmember ();

	if (strlen (instr) == 5)
		if (instr [0] >= 'a' && instr [0] <= 'h'
		&&  instr [1] >= '1' && instr [1] <= '8'
		&&  instr [3] >= 'a' && instr [3] <= 'h'
		&&  instr [4] >= '1' && instr [4] <= '8') {
			*pstart = boardpos (instr[0]-'a'+1, instr[1]-'0');
			*pend   = boardpos (instr[3]-'a'+1, instr[4]-'0');
			if (option [REVERSE] && color == BLACK) {
				*pstart = 99 - *pstart;
				*pend   = 99 - *pend;
			}
			return TRUE;
		} else

			return NOWAY;
	else if (strlen (instr) == 4)
		if (instr [0] >= 'a' && instr [0] <= 'h'
		&&  instr [1] >= '1' && instr [1] <= '8'
		&&  instr [2] >= 'a' && instr [2] <= 'h'
		&&  instr [3] >= '1' && instr [3] <= '8') {
			*pstart = boardpos (instr[0]-'a'+1, instr[1]-'0');
			*pend   = boardpos (instr[2]-'a'+1, instr[3]-'0');
			if (option [REVERSE] && color == BLACK) {
				*pstart = 99 - *pstart;
				*pend   = 99 - *pend;
			}
			return TRUE;
		} else

			return NOWAY;
	else if (strlen (instr) == 2) {
		if (instr [0] < 'a' || instr [0] > 'h')
			return NOWAY;
		else if (instr [1] >= 'a' && instr [1] <= 'h') {
			/* pawn take */
			for (i = 2; i <= 7 ; i++) {
				spot = boardpos (instr[0]-'a'+1, i);
				if (option [REVERSE] && color == BLACK)
					spot = 99 - spot;
				if (whose [spot] == color
				&& occupant [spot] == PAWN)
					if (foundpiece)
						return AMBIGUOUS;
					else
						foundpiece = spot;
			}
			if (foundpiece) {
				*pstart = foundpiece;
				if (option [REVERSE] && color == BLACK)
					*pend = boardpos ('i'-instr[1],
							  9 - foundpiece / 10)
						+ pawndir [color];
				else
					*pend = boardpos (instr[1]-'a'+1,
							  9 - foundpiece / 10)
						+ pawndir [color];
				return TRUE;
			} else
				return NOWAY;
		} else if (instr [1] >= '1' && instr [1] <= '8') {
			/* pawn move */
			*pend = boardpos (instr[0]-'a'+1, instr[1]-'0');
			if (option [REVERSE] && color == BLACK)
				*pend = 99 - *pend;
			if (((ourcolor == BLACK) && (*pend <= 28))
			||  ((ourcolor == WHITE) && (*pend >= 71)))
			    return NOWAY;
			if ((whose [*pstart= *pend - pawndir [color]] == color
			     && occupant [*pstart] == PAWN)
			|| (whose [*pstart= *pstart - pawndir [color]] == color
			    && occupant [*pstart] == PAWN))
				return TRUE;
			else
				return NOWAY;
		} else
			return NOWAY;
	} else if (strlen (instr) == 3) {    /* eg. nc6 */
		if ((piece = piecetype(instr [0])) == ILLEGAL_PIECE)
			return NOWAY;
		if (instr [1] < 'a' || instr [1] > 'h'
		|| instr [2] < '0' || instr [2] >'h')
			return NOWAY;
		*pend = boardpos (instr [1] - 'a' + 1, instr [2] - '0');
		if (option [REVERSE] && color == BLACK)
			*pend = 99 - *pend;
		for (i = 1; i <= 8; i++) {
			for (j = 1; j <= 8; j++) {
				*pstart = boardpos (i, j);
				if (whose [*pstart] != color
				|| occupant [*pstart] != piece
				|| !lmember (*pend, piecemoves(*pstart,TRUE)))
					continue;
				if (foundpiece)
					return AMBIGUOUS;
				foundpiece = *pstart;
			}
		}
		if (*pstart = foundpiece)
			return TRUE;
		else
			return NOWAY;
	}
	return NOWAY;   /* shoud never be reached */
}

/* parse a descriptive move (n-kb3), return TRUE for non error */
parse_descriptive_move (pstart, pend, color)
	int *pstart, *pend, color;
{
	char *sfrom, *sto, *alloca(), *index(), *afterslash;
	int nlegalbyfile = 0, nlegalbyside = 0, fromlegal = 0, frombyfile
		, frombyside, pawntake = FALSE, piece;
	LIST tryto, targets, piecemoves ();
	int i, j, spot, tobyfile, tobyside;
	struct {
		int row;
		int col;
		int goodness;
	} xfrom[100];

	/* sfrom is from string, sto is to string */
	sfrom = alloca (strlen (instr) + 1);
	strcpy(sfrom, instr);
	if ((sto = index (sfrom, '-')) == NULL)
		if ((sto = index (sfrom, 'x')) != NULL)
			pawntake = TRUE;
		else
			return NOWAY;
	*sto++ = '\0';
	if ((afterslash = index (sfrom, '/')) != NULL)
		*afterslash++ = '\0';
	if ((piece = piecetype(sfrom [strlen (sfrom) - 1])) == ILLEGAL_PIECE)
		return NOWAY;
	pawntake = pawntake && piece == PAWN;
	sfrom [strlen (sfrom) - 1] = '\0';

	/* build a list of legal from moves */
	for (i = 1; i <= 8; i++) {
		for (j = 1; j <= 8; j++) {
			spot = (9 - i) * 10 + j;
			if (whose [spot] != color)
				continue;
			if (occupant [spot] != piece)
				continue;
			xfrom [fromlegal].goodness = RIGHT_FILE;
			if (afterslash) {
				switch (xfrom [fromlegal].goodness
					= matchpos(afterslash, spot, color)) {
				case FALSE:
					continue;
				case ILLEGAL:
					return NOWAY;
				case RIGHT_SIDE:
				case RIGHT_FILE:
					break;
				}
			}
			if (*sfrom) {
				switch (xfrom [fromlegal].goodness
					= matchpos(sfrom, spot, color)) {
				case FALSE:
					continue;
				case ILLEGAL:
					return NOWAY;
				case RIGHT_SIDE:
				case RIGHT_FILE:
					break;
				}
			}
			xfrom[fromlegal].row = i;
			xfrom[fromlegal].col = j;
			fromlegal++;
		}
	}

	/* find all the consistent 'to' moves for those 'from' moves */
	for (i = 0; i < fromlegal; i++) {
		spot = (9 - xfrom [i].row) * 10 + xfrom [i].col;
		targets = piecemoves (spot, TRUE);
		for (tryto = targets; tryto != NULL; tryto = tryto->n) {
			switch (matchpos(sto, tryto->i, color)) {
			case RIGHT_FILE:
				if (xfrom [i].goodness == RIGHT_FILE) {
					if (piece == PAWN
					&& pawntake == ((tryto->i % 10)
							== (xfrom[i].col)))
						continue;
					frombyfile = i;
					tobyfile = tryto -> i;
					nlegalbyfile++;
				}
				/* fall through */
			case RIGHT_SIDE:
				if (piece == PAWN
				&& pawntake
				    == ((tryto->i % 10) == (xfrom[i].col)))
					continue;
				frombyside = i;
				tobyside = tryto -> i;
				nlegalbyside++;
				break;
			case FALSE:
				continue;
			case ILLEGAL:
				return NOWAY;
			}
		}
	}

	/* complain if there are too many or if there are none */
	if (nlegalbyside != 1 && nlegalbyfile != 1) {
		if (nlegalbyside > 1)
			return AMBIGUOUS;
		else
			return NOWAY;
	}

	if (nlegalbyside == 1) {
		/* frombyside and tobyside now define the unique legal move */
		*pstart = (9 - xfrom[frombyside].row) * 10
			+ xfrom[frombyside].col;
		*pend = tobyside;
	} else if (nlegalbyfile == 1) {
		/* frombyfile and tobyfile now define the unique legal move */
		*pstart = (9 - xfrom[frombyfile].row) * 10
			+ xfrom[frombyfile].col;
		*pend = tobyfile;
	}
	return TRUE;
}

/* matchpos -- tells whether a square number matches the description
   desc is of the form b4 or qb4 or just b or 4 */
static
matchpos(desc, squareno, color)
	char *desc;
	int squareno, color;
{
	static char *piececol = "rnbqkbnr";
	char side = FALSE, piece, rownum;
	int row, col;

	/* get row and col with player's king on (4,1)	*/
	/* (black's board is reflected)			*/
	row = 9 - squareno / 10;
	col = squareno % 10;
	if (color == BLACK)
		row = 9 - row;

	if (desc [0] == 'k' || desc [0] == 'q') {
		side = desc [0];
		if (!isdigit(desc[1]))
			desc++;
	}
	if (isalpha (desc [0])) {
		piece = desc [0];
		desc++;
	} else
		piece = side;
	if (rownum = isdigit (desc [0]))
		rownum = desc++ [0];
	if (( piece && index(piececol, piece) == NULL)
	|| ( rownum && index("12345678", rownum) == NULL)
	|| desc [0] != '\0')
		return ILLEGAL;
	else if ((side == 'k' && col <= 4) || (side == 'q' && col >= 5)
	|| (rownum && row != rownum - '0')
	|| (piece && piececol [col - 1] != piece))
		return FALSE;
	else if (side && !piece && piececol [col - 1] != side)
		return RIGHT_SIDE;   /* eg. b/q-n2 when b is on queen side */
	else
		return RIGHT_FILE;   /* eg. b/q-n2 when b is in queen file */
}

static piecetype(letter)
	char letter;
{
	switch (letter) {
	case 'p':
		return PAWN;
	case 'r':
		return ROOK;
	case 'n':
		return KNIGHT;
	case 'b':
		return BISHOP;
	case 'q':
		return QUEEN;
	case 'k':
		return KING;
	default:
		return ILLEGAL_PIECE;
	}
}

//GO.SYSIN DD *
cat >legalmove.c <<'//GO.SYSIN DD *'
/* legalmove.c */

#include "externs.h"

legalmove(pawntries, pawnattempts, checkdirs, from, to, color)
	int from, to, color;
	int pawntries, *pawnattempts;
	LIST checkdirs;
{
	LIST lmember(), piecemoves();
	int i;
	static struct {
		int from;
		int to;
	} pawnstried [3];

	if (whose [from] != color)
		return NOWAY;
	else if (occupant [from] == KING && to == from + 2) {
		if (!virgin [from]			/* castle king side */
		|| !virgin [from + 3]
		|| whose [from + 1] == color
		|| whose [from + 2] == color)
			return NOWAY;
		else if (checkdirs
		|| whose [from + 1] != EMPTY
		|| whose [from + 2] != EMPTY
		|| moveintocheck (from, from + 1)
		|| moveintocheck (from, from + 2))
			return ILLEGAL;
		else
			return TRUE;
	} else if (occupant [from] == KING && to == from - 2) {
		if (!virgin [from]			/* castle queen side */
		|| !virgin [from - 4]
		|| whose [from - 1] == color
		|| whose [from - 2] == color
		|| whose [from - 3] == color)
			return NOWAY;
		else if (checkdirs
		|| whose [from - 1] != EMPTY
		|| whose [from - 2] != EMPTY
		|| whose [from - 3] != EMPTY
		|| moveintocheck (from, from - 1)
		|| moveintocheck (from, from - 2))
			return ILLEGAL;
		else
			return TRUE;
	} else if (!lmember (to, piecemoves (from, TRUE)))
		return NOWAY;
	else if (option [ANNOUNCEPAWNS] == TRUE
	&& from % 10 != to % 10
	&& occupant [from] == PAWN) {
		if (pawntries == 0)
			return NOWAY;
		for (i = 0; i < *pawnattempts; i++)
			if (pawnstried [i].from == from
			&&  pawnstried [i].to   == to)
				return ILLEGAL;
		if (*pawnattempts == 3)
			return NOMOREPAWNTRIES;
		pawnstried [*pawnattempts].from = from;
		pawnstried [++*pawnattempts].to = to;
		if (*pawnattempts == 1)
			wprintw (win [MESSAGE], "1 attempt\n");
		else
			wprintw (win [MESSAGE], "%d attempts", pawnattempts);
		return ILLEGAL;
	} else if (!lmember (to, piecemoves (from, FALSE)))
		return ILLEGAL;
	else if (moveintocheck (from, to))
		return ILLEGAL;
	else
		return TRUE;
}
//GO.SYSIN DD *
cat >list.c <<'//GO.SYSIN DD *'
/* list.c */

#include "constants.h"
#include <curses.h>

struct IN
{
	int i;
	struct IN *n;
};
typedef struct IN *LIST;

LIST
linsert (list, number)
	LIST list;
	int number;
{
	LIST cell;

	char *malloc ();
	cell = (LIST) malloc (sizeof (struct IN));
	cell->i = number;
	cell->n = list;
	return cell;
}

LIST
lmember (number, list)
	int number;
	LIST list;
{
	while (list != NIL) {
		if (list->i == number)
			return list;
		list = list->n;
	}
	return FALSE;
}

llength (list)
	LIST list;
{
	int i;

	i = 0;
	while (list != NIL) {
		i++;
		list = list->n;
	}
	return i;
}

lfront (sublist, list)
	LIST sublist, list; /* both must be non-NIL */
	/* Allows easy deletion, when combined with lmember.  Violent. */
{
	int n;

	n = list->i;
	list->i  = sublist->i;
	sublist->i = n;
}
//GO.SYSIN DD *
cat >main.c <<'//GO.SYSIN DD *'
/* Kriegspiel written by David Wolfe based on a program by Bert Enderton
    May 5, 1986
*/

/* main.c */
#include "externs.h"
#include <ctype.h>
#include <signal.h>

char symbol [7] = { '-', 'P', 'K', 'N', 'B', 'R', 'Q' };
int whose [100];
int occupant [100];
char *colorname [2] = { "white", "black" };
int pawndir [2] = { -10, 10 };

LIST		dirlist [7];
LIST		piecelocs [2];
int		kingloc [2];
MOVELIST	movelist = (MOVELIST) NULL;
int		ourcolor = UNSET;
int		lastmovefrom = 0;
int		lastmoveto = 0;
int		virgin [100];
int		drawok [2] = { FALSE, FALSE};
int		resign = FALSE;
int		dead = FALSE;
int		option [NOPTIONS];
WINDOW		*blanksq [89];
WINDOW		*square [89];
WINDOW		*win [23];
WINDOW		*backupwin [23];
WINDOW		*backupscreen;
WINDOW		*blankscreen;
char		sqcolor [2];
int		vtterm;
int		dumbterm = FALSE;
int		reversescr;
int		sqheight;
int		sqwidth;
int		iamserver = UNSET;
int		sock;
long		random();

main (argc, argv, envp)
	int argc;
	char **argv, **envp;
{
	int i, j, port = 0, trap_sigint();
	char *p, *malloc ();
	long time ();

	signal (SIGINT, SIG_IGN);
	signal (SIGPIPE, SIG_IGN);
	srandom (time((long *) NULL));
	if (!strcmp (argv [1], "help")) {
		execle(PRINT_FILE, PRINT_FILE,
		       HELP_FILE, 0, envp);
		perror ("execle");
		exit (1);
	}
	if (argc <= 1) {
		printf ("Usage: %s [-bwcaprsdh] user\n", argv[0]);
		printf ("Or for help: %s help\n", argv[0]);
		exit (0);
	}
	for (i = 0; i < NOPTIONS; i++)
		option [i] = UNSET;
	j = 0;
	for (i = 1; i < argc - 1; i++) {
		j = TRUE;
		for (p = argv [i]; *p != '\000'; p++) {
			if isupper (*p)
				*p = tolower (*p);
			if (*p == '-')
				j = FALSE;
			else if (*p == 'b')
				option [COLOR] = BLACK;
			else if (*p == 'w')
				option [COLOR] = WHITE;
			else if (*p == 'c')
				option [COLOR] = RANDOM;
			else if (*p == 'a')
				option [ANNOUNCETAKES] = j;
			else if (*p == 'p')
				option [ANNOUNCEPAWNS] = j;
			else if (*p == 'r')
				option [REVERSE] = j;
			else if (*p == 's')
				iamserver = j;
			else if (*p == 'd')
				dumbterm = j;
			else if (isdigit (*p))
				port = port * 10 + (*p - '0');
			else if (*p == 'h') {
				execle(PRINT_FILE, PRINT_FILE,
				       HELP_FILE, 0, envp);
				perror ("execle");
				exit (1);
			}
		}
	}
	initdirlists ();
	initpiecelocs ();
	initscreen ();
	refresh();
	redraw();
	signal (SIGINT, trap_sigint);
	p = argv [argc - 1];
	waddstr (win [MESSAGE], "(connecting)");
	refresh ();
	connectport (p, port);
	wclear (win [MESSAGE]);
	waddstr (win [MESSAGE], "type help for\nsample commands");
	refresh ();
	p = malloc (MAXBUFF);
	if (iamserver) {
		while (recv (sock, p, NOPTIONS, 0) < 0)
			if (errno != EINTR)
				error ("recv in main");
		for (i = 0; i < NOPTIONS; i++) {
			if (i == REVERSE)
				p [i] = option [i] = (option [COLOR] == BLACK
						      && option [i] == TRUE)
						  || (option [COLOR] == WHITE
						      && p [i] == TRUE);
			if (option [i] == UNSET || p [i] == UNSET)
				p [i] = option [i] = option[i] + p[i] - UNSET;
			if (option [i] == UNSET)
				if (i == COLOR)
					option [i] = p [i] = RANDOM;
				else
					option [i] = p [i] = FALSE;
			else if (option [i] != p [i])
				option [i] = p [i] = RANDOM;
			if (option [i] == RANDOM)
				option [i] = p [i] = random () & 01;
		}
		if (send (sock, p, NOPTIONS, 0) < 0)
			error ("send in main");
	} else {
		for (i = 0; i < NOPTIONS; i++)
			p [i] = option [i];
	        if (p [COLOR] == WHITE || p [COLOR] == BLACK)
			p [COLOR] = ! option [COLOR];
		if (send (sock, p, NOPTIONS, 0) < 0)
			error ("send in main");
		while (recv (sock, p, NOPTIONS, 0) < 0)
			if (errno != EINTR)
				error ("recv in main");
		for (i = 0; i < NOPTIONS; i++)
			option [i] = p [i];
		option [COLOR] = ! p [COLOR];
	}
	ourcolor = option [COLOR];
	if (ourcolor == WHITE)
		waddstr(win [MYCOLOR], "--- WHITE ---");
	else
		waddstr(win [MYCOLOR], "--- BLACK ---");
	initboard (FALSE);
	for (i = 0; i < 100; i++)
		virgin [i] = TRUE;
	movecycle ();
}
//GO.SYSIN DD *
cat >makemove.c <<'//GO.SYSIN DD *'
/* makemove.c */

#include "externs.h"

makemove (from, to, color)
	int from, to, color;
{
	int victim;
	LIST l, lmember ();
	MOVELIST newmove;
	static MOVELIST lastmove;
	char *malloc ();

	newmove = (MOVELIST) malloc (sizeof (struct MOVE));
	newmove -> from = from;
	newmove -> to = to;
	newmove -> n = NULL;
	if (!movelist)
		movelist = newmove;
	else
		lastmove -> n = newmove;
	lastmove = newmove;
	victim = findvictim (from, to);
	if (victim) {
		if (option [ANNOUNCETAKES] || whose [victim] == ourcolor) {
			if (occupant [victim] == PAWN)
				waddstr (win [CAPTURE], "pawn ");
			else
				waddstr (win [CAPTURE], "piece ");
			if (ourcolor == BLACK && option [REVERSE])
				wprintw (win [CAPTURE], "take: %1c%1d\r",
					 (9 - victim % 10) + 'a' - 1,
					 victim / 10);
			else
				wprintw (win [CAPTURE], "take: %1c%1d\r",
					 victim % 10 + 'a' - 1,
					 9 - victim / 10);
		}
		virgin [victim] = FALSE;
		whose [victim] = EMPTY;
		waddch (square [victim], sqcolor[(victim + victim / 10) % 2]);
		lfront (lmember (victim, piecelocs [1 - color]),
			piecelocs [1 - color]);
		piecelocs [1 - color] = (piecelocs [1 - color])->n;
	}
	l = lmember (from, piecelocs [color]);
	l->i = to;
	if (occupant [from] == KING)
		kingloc [color] = to;
	virgin [from] = FALSE;
	whose [to] = color;
	occupant [to] = occupant [from];
	whose [from] = EMPTY;
	occupant [from] = 0;
	if (occupant [to] == PAWN
	&& ((to / 10 == 1 && color == WHITE)
	||  (to / 10 == 8 && color == BLACK))) {
		if (option [ANNOUNCETAKES])
			waddstr (win [MESSAGE], "pawn promoted\n");
		occupant [to] = QUEEN;
	}
	if (whose [to] == ourcolor) {
		waddch (square [from], sqcolor[(from + from / 10) % 2]);
		waddch (square [to], symbol [occupant [to]]);
	}
}
//GO.SYSIN DD *
cat >mate.c <<'//GO.SYSIN DD *'
/* mate.c */

#include "externs.h"

mate (pawnattempts, color)
	int pawnattempts, color;
{
	LIST l, tos, piecemoves ();
	int from, to;

	l = piecelocs [color];
	while (l != NIL) {
		from = l->i;
		l = l->n;
		tos = piecemoves (from, FALSE);
		while (tos != NIL) {
			to = tos->i;
			tos = tos->n;
			if (moveintocheck (from, to))
				continue;
			if (occupant [from] == PAWN
			&& from % 10 != to % 10
			&& pawnattempts > 3
			&& option [ANNOUNCEPAWNS] == TRUE)
				continue;
			return FALSE;
		}
	}
	return TRUE;
}

insufficient ()
{
	int i, p, minorpieces = 0;
	LIST l;

	for (i = 0; i < 2; i++) {
		l = piecelocs [i];
		while (l != NIL) {
			p = occupant [l->i];
			if (p == QUEEN || p == ROOK || p == PAWN)
				return FALSE;
			if (p == KNIGHT || p == BISHOP)
				minorpieces++;
			l = l->n;
		}
	}
	return (minorpieces <= 2);
}
//GO.SYSIN DD *
cat >movecycle.c <<'//GO.SYSIN DD *'
/* movecycle.c */

#include "externs.h"

movecycle ()
{
	int from, to, color, pawntries, pawnattempts, l;
	LIST check (), checkdirs;

	color = WHITE;
	while (TRUE) {
		wclear (win [CLOCK]);
		wclear (win [PROMPT]);
		pawnattempts = 0;
		wprintw (win [TOMOVE], "%s to move\r", colorname [color]);
		pawntries = countpawntries (color);
		if (option [ANNOUNCEPAWNS] && pawntries && pawnattempts < 3)
			if (pawntries == 1)
				wprintw (win [PAWNTRIES], "1 pawntry");
			else
				wprintw (win [PAWNTRIES], "%d pawntries",
					 pawntries);
		checkdirs = check (color);
		reportchecks (checkdirs, kingloc [color]);
		if (mate (pawnattempts, color)) {
			wclear (win [CHECK]);
			if (checkdirs != NIL)
				waddstr (win [CHECK], "CHECKMATE !");
			else
				waddstr (win [CHECK], "STALEMATE");
			break;
		}
		if (insufficient () || (drawok [WHITE] && drawok [BLACK])) {
			wclear (win [CHECK]);
			waddstr (win [CHECK], "DRAW");
			break;
		}
		if (resign) {
			wclear (win [CHECK]);
			waddstr (win [CHECK], "RESIGNS");
			break;
		}
		if (dead) {
			wclear (win [CHECK]);
			waddstr (win [CHECK], "DEAD");
			wclear (win [MESSAGE]);
			waddstr (win[MESSAGE], "lost your\nopponent\n(sorry)");
		}
		entermove (&from, &to, color, pawntries);
		while ((l = legalmove (pawntries, &pawnattempts, checkdirs,
				       from, to, color)) != TRUE
		&& !drawok [color] && !drawok [1 - color]
		&& !resign && !dead) {
			illegal (l, color);
			entermove (&from, &to, color, pawntries);
		}
		wclear (win [CAPTURE]);
		wclear (win [PAWNTRIES]);
		wclear (win [CHECK]);
		if (!drawok [1 - color] && !drawok [color]
		&& !resign && !dead) {
			makemove (from, to, color);
			if (occupant [to] == KING && to == from + 2)
				makemove (from + 3, from + 1, color);
			if (occupant [to] == KING && to == from - 2)
				makemove (from - 4, from - 1, color);
			lastmovefrom = from;
			lastmoveto = to;
		}
		if (drawok [1 - color] && !drawok [color])
			drawok [color] = FALSE;
		color = 1 - color;
		wclear (win [MESSAGE]);
	}
	wclear (win [TOMOVE]);
	wclear (win [CLOCK]);
	wclear (win [CAPTURE]);
	wclear (win [PAWNTRIES]);
	while (TRUE) {
		waddstr (win [PROMPT], "\rreview game?");
		wclear (win [MESSAGE]);
		waddstr (win [MESSAGE], "type y or n");
		wclear (win [INPUT]);
		waddstr (win [INPUT], ": ");
		move (win [INPUT]->_cury + win [INPUT]->_begy,
		      win [INPUT]->_curx + win [INPUT]->_begx);
		refresh ();
		wclear (win [CHECK]);
		switch (getchar ()) {
		case 'y':
			wclear (win [PROMPT]);
			wclear (win [MESSAGE]);
			review();
			break;
		case 'n':
			error ((char *) NULL);
		default:
			printf ("\007");
		}
	}
}
//GO.SYSIN DD *
cat >output.c <<'//GO.SYSIN DD *'
/* output.c */

#include "externs.h"
#include <strings.h>

redraw ()
{
	int i;

	if (vtterm) {
		/* make characters double-width on a vt100 type terminal */
		overwrite (stdscr, backupscreen);
		overwrite (blankscreen, stdscr);
		refresh ();
		printf("\0337\033[0;0H\033#6"); /* save cursor, home,
						   and widen first line */
		for (i = 1; i <= LINES - 1; i++)
			printf("\n\033#6");	/* wide next line */
		printf("\0338");		/* restore cursor */
		overwrite (backupscreen, stdscr);
		refresh();
	} else
		wrefresh(curscr);
}

reportchecks (checkdirs, kingloc)
	LIST checkdirs;
	int kingloc;
{
	LIST l, lmember ();
	int quadrant, n;
	char str [2] [40];

	n = 0;
	quadrant = ((kingloc % 10 > 4) == (kingloc/10 < 5));
	if (lmember (-9, checkdirs) || lmember (9, checkdirs))
		if (quadrant == 1)
			strcpy (str[n++], "long diagonal\n");
		else
			strcpy (str[n++], "short diagonal\n");
	if (lmember (-11, checkdirs) || lmember (11, checkdirs))
		if (quadrant == 0)
			strcpy (str[n++], "long diagonal\n");
		else
			strcpy (str[n++], "short diagonal\n");
	if (lmember (-10, checkdirs) || lmember (10, checkdirs))
		strcpy (str[n++], "file\n");
	if (lmember (-1, checkdirs) || lmember (1, checkdirs))
		strcpy (str[n++], "rank\n");
	l = dirlist [KNIGHT];
	while (l != NIL) {
		if (lmember (l->i, checkdirs))
			strcpy (str[n++], "knight\n");
		l = l->n;
	}
	if (n > 0) {
		waddstr (win [CHECK], "check by the\n");
		waddstr (win [CHECK], str[0]);
	}
	if (n == 2) {
		waddstr (win [CHECK], "and ");
		waddstr (win [CHECK], str[1]);
	}
	refresh();
}

illegal (why, color)
	int color, why;
{
	wclear (win [LEGAL]);
	if (why == ILLEGAL)
		waddstr (win [LEGAL], "illegal");
	else if (color == ourcolor) {
		if (why == NOMOREPAWNTRIES)
		    waddstr (win [LEGAL], "3 pawns tried");
		else if (why == NOWAY)
			waddstr (win [LEGAL], "no way");
		else if (why == AMBIGUOUS)
			waddstr (win [LEGAL], "ambiguous");
	} else
		waddstr (win [LEGAL], "nope");
}
//GO.SYSIN DD *
cat >pawntries.c <<'//GO.SYSIN DD *'
/* "pawntries.c */

#include "externs.h"

countpawntries (color)
	int color;
{
	LIST l, moves, piecemoves ();
	int tries, /* move,*/ start, end;

	tries = 0;
	l = piecelocs [color];
	while (l != NIL) {
		start = l->i;
		l = l->n;
		if (occupant [start] != PAWN)
			continue;
		moves = piecemoves (start, FALSE);
		while (moves != NIL) {
			end = moves->i;
			moves = moves->n;
			if (start % 10 == end % 10)
				continue;
			if (moveintocheck (start, end))
				continue;
			tries++;
		}
	}
	return tries;
}


findvictim (from, to)
	int from, to;
{
	if (occupant [from] == PAWN) {
		if (from % 10 == to % 10)
			return FALSE;
		if (whose [to] == 1 - whose [from])
			return to;
		else
			return (to - pawndir [whose [from]]);  /* en passent */
	} else {
		if (whose [to] == 1 - whose[from])
			return to;
		else
			return FALSE;
	}
}
//GO.SYSIN DD *
cat >piecemoves.c <<'//GO.SYSIN DD *'
/* piecemoves.c */

#include "externs.h"

LIST
piecemoves (from, ignoreenemy)
	/* doesn't include castling */
	int from, ignoreenemy;
{
	int piece, color, front, spot, side, addend, to;
	LIST dirs, moves, linsert ();

	piece = occupant [from];
	color = whose [from];
	moves = NIL;
	if (piece == PAWN) {
		front = from + pawndir [color];
		if (whose [front] != color
		&& (ignoreenemy || whose [front] == EMPTY)) {
			moves = linsert (moves, front);
			if (from / 10 == 7 - 5 * color) { /* pawn can move 2 */
				spot = front + pawndir [color];
				if (whose [spot] != color
				&& (ignoreenemy || whose [spot] == EMPTY))
					moves = linsert (moves, spot);
			}
		}
		for (side = -1; side <= 1; side += 2) {
			spot = front + side;
			if (whose [spot] != color
			&& whose [spot] != OFFBOARD
			&& (ignoreenemy || whose [spot] == 1 - color
			|| (from / 10 == 4 + color	/* en passent */
			    && occupant [from + side] == PAWN
			    && lastmovefrom == spot + pawndir [color]
			    && lastmoveto == from + side)))
				moves = linsert (moves, spot);
		}
	} else {
		dirs = dirlist [piece];
		while (dirs != NIL) {
			addend = dirs->i;
			dirs = dirs->n;
			to = from;
			while (TRUE) {
				to += addend;
				if (to < 0 || to > 99)
					break;
				if (whose [to] == OFFBOARD
				||  whose [to] == color)
					break;
				moves = linsert (moves, to);
				if (ignoreenemy == FALSE
				&& whose [to] == 1 - color)
					break;
				if (piece == KING || piece == KNIGHT)
					break;
			}
		}
	}
	return moves;
}
//GO.SYSIN DD *
cat >review.c <<'//GO.SYSIN DD *'
/* review.c */

#include "externs.h"
#include <ctype.h>
#define STEPTIME 3	/* time between moves in seconds */

review ()
{
	int color = BLACK;
	MOVELIST m;

	initdirlists ();
	initpiecelocs ();
	initboard (TRUE);
	touchwin (stdscr);
	redraw ();
	m = movelist;
	while (m) {
		if (occupant [m -> from] != KING
		|| ((m->to - m->from) %4) != 2) {	/* not castling */
			color = 1 - color;
			sleep (STEPTIME);
		}
		makereviewmove (m -> from, m -> to, color);
		refresh();
		m = m -> n;
	}
}

makereviewmove (from, to, color)
	int from, to, color;
{
	int victim;

	wclear (win [INPUT]);
	waddstr (win [INPUT], ": ");
	if (victim = findvictim (from, to)) {
		whose [victim] = EMPTY;
		waddch (square [victim], sqcolor[(victim + victim / 10) % 2]);
	}
	if (occupant [from] == KING)
		kingloc [color] = to;
	whose [to] = color;
	occupant [to] = occupant [from];
	whose [from] = EMPTY;
	occupant [from] = 0;
	if (occupant [to] == PAWN
	&& ((to / 10 == 1 && color == WHITE)
	||  (to / 10 == 8 && color == BLACK)))
		occupant [to] = QUEEN;
	waddch (square [from], sqcolor [(from + from / 10) % 2]);
	if (whose [to] == ourcolor)
		waddch (square [to], symbol [occupant [to]]);
	else
		waddch (square [to], tolower (symbol [occupant [to]]));
	if (option [REVERSE] && ourcolor == BLACK) {
		from = 99 - from;
		to = 99 - to;
	}
	waddch (win [INPUT], 'a' + (9 - from % 10) - 1);
	waddch (win [INPUT], '0' + (9 - from / 10));
	waddch (win [INPUT], '-');
	waddch (win [INPUT], 'a' + (9 - to % 10) - 1);
	waddch (win [INPUT], '0' + (9 - to / 10));
}
//GO.SYSIN DD *
cat >traps.c <<'//GO.SYSIN DD *'
/* traps.c */

#include "externs.h"
#include <signal.h>

trap_sigint ()
{
	int y, x;
	char c;

	signal (SIGINT, SIG_IGN);
	getyx (stdscr, y, x);
	overwrite (stdscr, backupscreen);
	overwrite (win [PROMPT], backupwin[PROMPT]);
	overwrite (win [MESSAGE], backupwin[MESSAGE]);
	overwrite (win [INPUT], backupwin[INPUT]);
	overwrite (blankscreen, stdscr);
	wclear (win [PROMPT]);
	wclear (win [MESSAGE]);
	wclear (win [INPUT]);
	waddstr (win [PROMPT], "Quit?");
	waddstr (win [MESSAGE], "type y or n");
	waddstr (win [INPUT], ": ");
	move (win [INPUT]->_cury + win [INPUT]->_begy,
	      win [INPUT]->_curx + win [INPUT]->_begx);
	refresh ();
	c = getchar();
	while (c!='n' && c!='N' && c!='y' && c!='Y') {
		if (c == '\f')  /*  ^L */
			refresh ();
		c = getchar();
	}
	if (c == 'y') {
		send (sock, "resign\0", 7, 0);
		error ((char *) NULL);
	}
	overwrite (backupscreen, stdscr);
	overwrite (backupwin [PROMPT], win [PROMPT]);
	overwrite (backupwin [MESSAGE], win [MESSAGE]);
	overwrite (backupwin [INPUT], win [INPUT]);
	move (y, x);
	touchwin (stdscr);
	redraw ();
	signal (SIGINT, trap_sigint);
}
//GO.SYSIN DD *