Kriegspiel game
David Wolfe
wolfe at ernie.Berkeley.EDU
Wed May 7 11:54:21 AEST 1986
*****************************************************************
* *
* 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 at 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 at 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 *
More information about the Comp.sources.unix
mailing list