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 *