[comp.sources.games] v02i091: nchess - network chess game for Suns, Part01/04

games-request@tekred.UUCP (11/19/87)

Submitted by: (Tom Anderson) toma@tc.fluke.com
Comp.sources.games: Volume 2, Issue 91
Archive-name: nchess/Part01

	[This was originally posted to net.sources.games, but I had
	 a request to repost it here so it could be archived.  I
	 checked with Tom (the author) and he had no objections to
	 posting and had not made any significant changes to the source
	 since it was first posted.   -br]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 4)."
# Contents:  README MANIFEST Icons boardsw.c nchess.6 nchess.h
# Wrapped by billr@tekred on Thu Nov 19 10:49:19 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(904 characters\)
sed "s/^X//" >README <<'END_OF_README'
XThis is a five-part distribution of "nchess", a network chess game I wrote
Xa few months ago during a chess fad at work.  It runs on Sun Microsystems'
Xworkstations, and would be quite difficult to port to other machines due
Xto heavy reliance on Sun's window libraries.  It bears no relation to the
Xexisting chesstool program; i.e., it was written from scratch without any
Xknowledge of how chesstool is implemented (since we don't have the source).
X
XSince the manual page is included in the following shell archives, no more
Xneed be said.  Please mail any comments, bugs, etc. directly to me, since
XI very rarely read net news.
X
XAny commercial use of this software is strictly prohibited, INCLUDING usage
Xas a demo vehicle for Sun workstations.
X
XEnjoy!
X
XTom Anderson, (206) 356-5895
XJohn Fluke Mfg. Co., Inc.,  P.O. Box C9090 M/S 245F, Everett, Wa. 98206
X{ hplsla, microsoft, uw-beaver, sun }!fluke!toma
X
X
END_OF_README
if test 904 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f MANIFEST -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"MANIFEST\"
else
echo shar: Extracting \"MANIFEST\" \(1086 characters\)
sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X Icons                     1	
X Icons/bishop.icon         4	
X Icons/bishopStencil.icon  3	
X Icons/blackSquare.icon    4	
X Icons/king.icon           4	
X Icons/kingStencil.icon    4	
X Icons/knight.icon         4	
X Icons/knightStencil.icon  3	
X Icons/nchess.icon         4	
X Icons/pawn.icon           4	
X Icons/pawnStencil.icon    4	
X Icons/queen.icon          4	
X Icons/queenStencil.icon   3	
X Icons/rook.icon           4	
X Icons/rookStencil.icon    3	
X Icons/whiteSquare.icon    4	
X MANIFEST                  1	
X Makefile                  4	
X README                    1	
X board.c                   2	
X boardsw.c                 1	
X chessprocess.c            3	
X controlsw.c               3	
X daemon.c                  3	
X decls.h                   3	
X ipc.c                     3	
X main.c                    3	
X msgsw.c                   3	
X nchess.6                  1	
X nchess.h                  1	
X talksw.c                  4	
X tool.c                    3	
X xdr.c                     4	
END_OF_MANIFEST
if test 1086 -ne `wc -c <MANIFEST`; then
    echo shar: \"MANIFEST\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test ! -d Icons ; then
    echo shar: Creating directory \"Icons\"
    mkdir Icons
fi
if test -f boardsw.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"boardsw.c\"
else
echo shar: Extracting \"boardsw.c\" \(34145 characters\)
sed "s/^X//" >boardsw.c <<'END_OF_boardsw.c'
X/*
X * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
X * Stanwood, WA  98282.   All rights reserved.
X */
X
X/*
X * handle the board subwindow (as well as fielding RPC and chess game
X * process selects)
X */
X
X#include <stdio.h>
X#include <suntool/tool_hs.h>
X#include <suntool/panel.h>
X#include <suntool/gfxsw.h>
X#include <suntool/icon_load.h>
X#include <sys/resource.h>
X#include <sys/ioctl.h>
X#include <strings.h>
X
X#include "nchess.h"
X
X#define	MOVE_PR_WIDTH	(SQUARE_WIDTH * 2)
X#define	MOVE_PR_HEIGHT	(SQUARE_HEIGHT * 2)
X#define	MOVE_X_OFFSET	(MOVE_PR_WIDTH/2 - SQUARE_WIDTH/2)
X#define	MOVE_Y_OFFSET	(MOVE_PR_HEIGHT/2 - SQUARE_HEIGHT/2)
X
Xextern int svc_fds;			/* RPC service file descriptor(s) */
Xint BoardSWMask;			/* board gfx sw file des. */
XBOOL Flashing = FALSE;			/* tool icon is flashing */
X
Xenum {					/* confirmation state using mouse */
X    CONFIRM_WANTED,
X    CONFIRM_SETUP_END,
X    CONFIRM_WHOSE_TURN,
X    CONFIRM_UNDO,
X    CONFIRM_RESIGNATION,
X} confirmState;
X
XMouseState Mouse = IDLE;
X
Xchar * PieceIconFileNames[] = {
X    "pawn.icon",
X    "knight.icon",
X    "bishop.icon",
X    "rook.icon",
X    "queen.icon",
X    "king.icon",
X};
X
Xchar * PieceStencilFileNames[] = {
X    "pawnStencil.icon",
X    "knightStencil.icon",
X    "bishopStencil.icon",
X    "rookStencil.icon",
X    "queenStencil.icon",
X    "kingStencil.icon",
X};
X
X/*
X * piece icons and stencils
X */
Xunsigned short RookBlackImage[] = {
X#include "Icons/rook.icon"
X};
Xunsigned short RookWhiteImage[] = {
X#include "Icons/rook.icon"
X};
Xunsigned short RookStencilImage[] = {
X#include "Icons/rookStencil.icon"
X};
Xmpr_static(RookBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, RookBlackImage);
Xmpr_static(RookWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, RookWhiteImage);
Xmpr_static(RookStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, RookStencilImage);
X
Xunsigned short KnightBlackImage[] = {
X#include "Icons/knight.icon"
X};
Xunsigned short KnightWhiteImage[] = {
X#include "Icons/knight.icon"
X};
Xunsigned short KnightStencilImage[] = {
X#include "Icons/knightStencil.icon"
X};
Xmpr_static(KnightBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KnightBlackImage);
Xmpr_static(KnightWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KnightWhiteImage);
Xmpr_static(KnightStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KnightStencilImage);
X
Xunsigned short BishopBlackImage[] = {
X#include "Icons/bishop.icon"
X};
Xunsigned short BishopWhiteImage[] = {
X#include "Icons/bishop.icon"
X};
Xunsigned short BishopStencilImage[] = {
X#include "Icons/bishopStencil.icon"
X};
Xmpr_static(BishopBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BishopBlackImage);
Xmpr_static(BishopWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BishopWhiteImage);
Xmpr_static(BishopStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BishopStencilImage);
X
Xunsigned short KingBlackImage[] = {
X#include "Icons/king.icon"
X};
Xunsigned short KingWhiteImage[] = {
X#include "Icons/king.icon"
X};
Xunsigned short KingStencilImage[] = {
X#include "Icons/kingStencil.icon"
X};
Xmpr_static(KingBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KingBlackImage);
Xmpr_static(KingWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KingWhiteImage);
Xmpr_static(KingStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KingStencilImage);
X
Xunsigned short QueenBlackImage[] = {
X#include "Icons/queen.icon"
X};
Xunsigned short QueenWhiteImage[] = {
X#include "Icons/queen.icon"
X};
Xunsigned short QueenStencilImage[] = {
X#include "Icons/queenStencil.icon"
X};
Xmpr_static(QueenBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, QueenBlackImage);
Xmpr_static(QueenWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, QueenWhiteImage);
Xmpr_static(QueenStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, QueenStencilImage);
X
Xunsigned short PawnBlackImage[] = {
X#include "Icons/pawn.icon"
X};
Xunsigned short PawnWhiteImage[] = {
X#include "Icons/pawn.icon"
X};
Xunsigned short PawnStencilImage[] = {
X#include "Icons/pawnStencil.icon"
X};
Xmpr_static(PawnBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, PawnBlackImage);
Xmpr_static(PawnWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, PawnWhiteImage);
Xmpr_static(PawnStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, PawnStencilImage);
X
Xstruct pixrect * PieceStencils[6] = {
X    &PawnStencilPR,
X    &KnightStencilPR,
X    &BishopStencilPR,
X    &RookStencilPR,
X    &QueenStencilPR,
X    &KingStencilPR,
X};
X
Xstruct pixrect * PieceIcons[6][2] = {
X    &PawnBlackPR,	&PawnWhitePR,
X    &KnightBlackPR,	&KnightWhitePR,
X    &BishopBlackPR,	&BishopWhitePR,
X    &RookBlackPR,	&RookWhitePR,
X    &QueenBlackPR,	&QueenWhitePR,
X    &KingBlackPR,	&KingWhitePR,
X};
X
X/*
X * blank square pixrects
X */
Xunsigned short WhiteSquareImage[] = {
X#include "Icons/whiteSquare.icon"
X};
Xmpr_static(WhiteSquarePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, WhiteSquareImage);
X
Xunsigned short BlackSquareImage[] = {
X#include "Icons/blackSquare.icon"
X};
Xmpr_static(BlackSquarePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BlackSquareImage);
X
X/* board subwindow handles */
Xstruct toolsw * BoardSW;
Xstruct gfxsubwindow * Board;
X
X/* pixrects used for piece animation */
Xstruct pixrect * MoveFromPR, * MoveToPR;
X
X/* pixrect used for victim drawing */
Xstruct pixrect * VictimPR;
X
X/*
X * board sigwinch handler 
X */
X/*ARGSUSED*/
XboardSigwinch(sw)
X    caddr_t sw;
X{
X    gfxsw_interpretesigwinch(Board);
X    gfxsw_handlesigwinch(Board);
X    if (Board->gfx_flags & GFX_RESTART) {
X	Board->gfx_flags &= ~ GFX_RESTART;
X	DrawBoard();
X    }
X}
X
X/*
X * map a mouse coordinate to a board coordinate
X */
Xvoid
XmapMouseToBoard(mlocp, blocp)
X    struct pr_pos * mlocp;
X    BoardCoordinate * blocp;
X{
X    if (MyColor == WHITE) {
X	blocp->x = mlocp->x / (SQUARE_WIDTH-1);
X	blocp->y = mlocp->y / (SQUARE_HEIGHT-1);
X    } else {
X	blocp->x = (8 * (SQUARE_WIDTH-1) - mlocp->x)/(SQUARE_WIDTH-1);
X	blocp->y = (8 * (SQUARE_HEIGHT-1) - mlocp->y)/(SQUARE_HEIGHT-1);
X    }
X}
X
X/* 
X * map a board coordinate to a mouse coordinate
X */
Xvoid
XmapBoardToMouse(blocp, mlocp)
X    BoardCoordinate * blocp;
X    struct pr_pos * mlocp;
X{
X    if (MyColor == WHITE) {
X	mlocp->x = blocp->x * (SQUARE_WIDTH-1) - 1;
X	mlocp->y = blocp->y * (SQUARE_HEIGHT-1) - 1;
X    } else {
X	mlocp->x = (7 - blocp->x) * (SQUARE_WIDTH-1) - 1;
X	mlocp->y = (7 - blocp->y) * (SQUARE_WIDTH-1) - 1;
X    }
X}
X
X/*
X * put a piece back where we got it (used to abort piece animation for 
X * various reasons)
X */
Xvoid
XputPieceBack(from, stencil, icon)
X    BoardCoordinate * from;
X    struct pixrect * stencil, * icon;
X{
X    struct pr_pos loc;
X
X    mapBoardToMouse(from, &loc);
X    pw_stencil(Board->gfx_pixwin, 
X	loc.x, loc.y,
X	SQUARE_WIDTH, SQUARE_HEIGHT,
X	PIX_SRC, stencil, 0, 0, icon, 0, 0);
X}
X
X/*
X * parameters which belong in boardSelected(), but which are shared
X * with RequestUndo() so that we can abort piece animation if the 
X * klutz at the other end panics (via an undo request or a resignation).  
X * all of them need to be static, anyway.
X */
X
XBoardCoordinate from, to;
Xstruct pixrect * pieceIcon, * pieceStencil;
Xstruct pr_pos lastMouseLoc;
X
X/*
X * abort any mouse activity - this really only means aborting piece 
X * animation.
X */
Xvoid
XKillMouseActivity()
X{
X    switch (Mouse) {
X    case PROMOTING_PAWN:
X	UnDoMove();
X	break;
X    case MOVING_PIECE:
X	/* repaint the background */
X	pw_rop(Board->gfx_pixwin,
X	    lastMouseLoc.x - MOVE_X_OFFSET,
X	    lastMouseLoc.y - MOVE_Y_OFFSET,
X	    MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X	    PIX_SRC, MoveFromPR, 0, 0);
X	putPieceBack(&from, pieceStencil, pieceIcon);
X	break;
X    }
X}
X
X/*
X * relay a request for an undo by the opponent.
X *
X * this has the side-effect of aborting any mouse activity that the 
X * user had going at the time.  however, setups will not be interrupted 
X * by undo requests since the (spurious) undo request will be prevented 
X * when the opponent's program detects that he hasn't moved yet.
X */
Xvoid
XRequestUndo()
X{
X    Message("Your opponent wants to undo - left OK, other not OK");
X    KillMouseActivity();
X    Mouse = CONFIRMING;
X    confirmState = CONFIRM_UNDO;
X}
X
X/*
X * confirm a wish to resign
X */
Xvoid
XConfirmResignation()
X{
X
X    Message("Sure you want to resign? - left yes, other no");
X    Mouse = CONFIRMING;
X    confirmState = CONFIRM_RESIGNATION;
X}
X
X/*
X * board select() handler 
X */
X/*ARGSUSED*/
XboardSelected(nullsw, ibits, obits, ebits, timer)
X    caddr_t * nullsw;
X    int * ibits, * obits, * ebits;
X    struct timeval ** timer;
X{
X    static tickCount = 0;
X    static Move move;
X    static SetupChange setup;
X    struct inputevent ie;
X    struct pr_pos newMouseLoc;
X    Square * sqp;
X    long nbytes;
X    BOOL clamped;
X    int color, i;
X    struct pixrect * pr;
X
X    /*
X     * 1-second ticker.  this cannot use SIGALRM, since the RPC
X     * package already has dibs on that signal for implementing timeouts.
X     * hence, it uses the subwindow select timeout mechanism.
X     * the ticker is used to flash the window every 5 seconds if 
X     * there is some event the user hasn't seen yet (opening the 
X     * tool window turns the flasher off).
X     *
X     * note - timeouts render the file descriptor masks undefined, 
X     * so we clean up and return w/o checking them.
X     */
X    if ((*timer)->tv_sec == 0L && (*timer)->tv_usec == 0L) {
X	if (Flashing) {
X	    if (wmgr_iswindowopen(NchessTool->tl_windowfd)) {
X		tickCount = 0;
X		Flashing = FALSE;
X	    } else if (tickCount-- <= 0
X	    && (pr = (struct pixrect *) tool_get_attribute(NchessTool, 
X		WIN_ICON_IMAGE)) != (struct pixrect *) -1)
X	    {
X		tickCount = 5;
X		pr_rop(pr, 0, 0, pr->pr_size.x, pr->pr_size.x, 
X		    PIX_NOT(PIX_SRC), pr, 0, 0);
X		tool_set_attributes(NchessTool, WIN_ICON_IMAGE, pr, 0);
X		pr_rop(pr, 0, 0, pr->pr_size.x, pr->pr_size.x, 
X		    PIX_NOT(PIX_SRC), pr, 0, 0);
X		tool_set_attributes(NchessTool, WIN_ICON_IMAGE, pr, 0);
X		tool_free_attribute(WIN_ICON_IMAGE, pr);
X	    }
X	}
X	/* reset the timer and the file des. masks */
X	(*timer)->tv_sec = 1L;
X	(*timer)->tv_usec = 0L;
X	* ibits = svc_fds | BoardSWMask 
X	    | ChessProcessFDs[BLACK] | ChessProcessFDs[WHITE];
X	* obits = * ebits = 0;
X	return;
X    }
X    /* 
X     * check for RPC service required 
X     */
X    if (*ibits & svc_fds) {
X	svc_getreq(*ibits & svc_fds);
X    } 
X    /*
X     * check for machine move received
X     *
X     * note: it is possible in some circumstances to receive a move
X     * from a machine player after the game is over (for example, 
X     * the opponent of the machine which is on move dies).
X     * in that event, we simply throw the move away.
X     */
X    for (color = BLACK , i = 0  ; i < 2 ; color = WHITE , i++) {
X	if ((*ibits & ChessProcessFDs[color]) 
X	&& GetMachineMove(&move, color)
X	&& ! GameOver) {
X	    BOOL updateMsgWindow = TRUE;
X
X	    Flashing = TRUE;
X	    DoMove(&move, TRUE);
X	    Turn = OTHERCOLOR(Turn);
X	    /* 
X	     * if we are trying to save a game of machine vs. machine,
X	     * hold up sending the move until both machine states 
X	     * have been saved.  when subsequently restoring the 
X	     * game, this move will be resubmitted.
X	     */
X	    if (SaveWanted) {
X		SaveGame(SaveFileName);
X		SaveWanted = FALSE;
X		updateMsgWindow = FALSE;
X	    }
X	    /* 
X	     * if the player not moving is a machine, send the move 
X	     */
X	    if (IsMachine[OTHERCOLOR(color)]) {
X		SendMove(&move, OTHERCOLOR(color));
X	    /*
X	     * else if the player not moving is a human that wants an
X	     * undo, back it out
X	     */
X	    } else if (UndoWanted) {
X		MachineUndo(color);
X		UndoWanted = FALSE;
X		Mouse = IDLE;
X	    }
X	    if (updateMsgWindow)
X		WhoseMoveMessage((char *) 0);
X	}
X    }
X    /*
X     * check for board subwindow service required
X     */
X    if (*ibits & BoardSWMask) {
X	if (input_readevent(BoardSW->ts_windowfd, &ie) == -1) {
X	    perror("input failed");
X	    abort();
X	}
X	switch (Mouse) {
X	/*
X	 * locked: ignore all mouse activity
X	 */
X	case LOCKED:
X	    break;
X	/* 
X	 * we are using the mouse to confirm something 
X	 */
X	case CONFIRMING:
X	    if (win_inputposevent(&ie) 
X	    && ie.ie_code >= BUT_FIRST
X	    && ie.ie_code <= BUT_LAST) {
X		Mouse = IDLE;
X		switch(confirmState) {
X		case CONFIRM_RESIGNATION:
X		    if (ie.ie_code == MS_LEFT) {
X			SendResignation(PeerColor);
X			Mouse = LOCKED;		/* game is over */
X			DoResignation(MyColor);
X			Message("Resigned");
X		    } else {
X			WhoseMoveMessage((char *) 0);
X		    }
X		    break;
X		case CONFIRM_SETUP_END:
X		    if (ie.ie_code == MS_LEFT) {
X			/* 
X			 * if either player is a machine, white always moves
X			 * first following a setup (another brain-damaged
X			 * attribute of the unix chess program).
X			 */
X			if (IsMachine[WHITE] || IsMachine[BLACK]) {
X			    BOOL legalSetup = TRUE;
X
X			    Turn = WHITE;
X			    if (IsMachine[BLACK]) {
X				legalSetup = MachineSetup(BLACK);
X			    }
X			    if (legalSetup && IsMachine[WHITE]) {
X				if (legalSetup = MachineSetup(WHITE))
X				    MachineFirst(WHITE);
X			    }
X			    if ( ! legalSetup) {
X				Message("Illegal setup - try again");
X				Mouse = SETUP;
X			    } else {
X				/*
X				 * if both players are machines, the human part
X				 * is over.
X				 */
X				if (IsMachine[BLACK] && IsMachine[WHITE]) 
X				    Mouse = LOCKED;
X				/*
X				 * else we get to play
X				 */
X				else 
X				    InitialTurn = WHITE;
X				WhoseMoveMessage((char *) 0);
X				SetupMode = FALSE;
X			    }
X			/*
X			 * else the opponent is a human, and we can specify
X			 * who moves first.
X			 */
X			} else {
X			    Message("Left button to move first, other to move second");
X			    Mouse = CONFIRMING;
X			    confirmState = CONFIRM_WHOSE_TURN;
X			    SetupMode = FALSE;
X			}
X		    } else {
X			Message("Setup: left - source, middle - delete, right - end");
X			Mouse = SETUP;
X		    }
X		    break;
X		case CONFIRM_WHOSE_TURN:
X		    Turn = InitialTurn = (ie.ie_code == MS_LEFT ? 
X			MyColor : 
X			OTHERCOLOR(MyColor));
X		    WhoseMoveMessage((char *) 0);
X		    SendEndRestore();
X		    break;
X		case CONFIRM_UNDO:
X		    SendUndoAcknowledgement(ie.ie_code == MS_LEFT);
X		    break;
X		}
X	    }
X	    break;
X	/*
X	 * we are setting up an initial board layout
X	 */
X	case SETUP:
X	    switch (ie.ie_code) {
X	    /*
X	     * generate and pick up a source piece
X	     */
X	    case MS_LEFT:
X		if (win_inputposevent(&ie)) {
X		    newMouseLoc.x = ie.ie_locx;
X		    newMouseLoc.y = ie.ie_locy;
X		    mapMouseToBoard(&newMouseLoc, &from);
X		    /* if this a source square */
X		    if (IsSrcPieceAt(&from)) {
X			Mouse = MOVING_PIECE;
X			sqp = GetSrcSquare(from.x, from.y);
X			setup.type = sqp->type;
X			setup.color = sqp->color;
X			/*
X			 * create the first background pixrect,
X			 * centered on the selected board square
X			 */
X			mapBoardToMouse(&from, &lastMouseLoc);
X			/* grab the currently displayed image */
X			pw_read(MoveFromPR, 
X			    0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X			    PIX_SRC,
X			    Board->gfx_pixwin,
X			    lastMouseLoc.x - MOVE_X_OFFSET,
X			    lastMouseLoc.y - MOVE_Y_OFFSET);
X			/* repaint the blank square */
X			pr_rop(MoveFromPR,
X			    MOVE_X_OFFSET,
X			    MOVE_Y_OFFSET,
X			    SQUARE_WIDTH, SQUARE_HEIGHT,
X			    PIX_SRC,
X			    ((from.x + from.y) & 0x01) ? 
X				&BlackSquarePR :
X				&WhiteSquarePR,
X			    0, 0);
X			/* 
X			 * remember the pixrect used to paint the piece 
X			 * being moved 
X			 */
X			pieceIcon = PieceIcons[(int) sqp->type][sqp->color];
X			pieceStencil = PieceStencils[(int) sqp->type];
X			/* 
X			 * if there is a piece at the source square, repaint 
X			 * the piece on the background pixrect 
X			 */
X			sqp = GetSquare(from.x, from.y);
X			if (sqp->type != NULLPC) {
X			    pr_stencil(MoveFromPR,
X				MOVE_X_OFFSET,
X				MOVE_Y_OFFSET,
X				SQUARE_WIDTH, SQUARE_HEIGHT,
X				PIX_SRC, 
X				PieceStencils[(int)sqp->type], 0, 0, 
X				PieceIcons[(int) sqp->type][sqp->color], 0, 0);
X			}
X		    }
X		}
X		break;
X	    /*
X	     * delete a piece 
X	     */
X	    case MS_MIDDLE:
X		if (win_inputposevent(&ie)) {
X		    newMouseLoc.x = ie.ie_locx;
X		    newMouseLoc.y = ie.ie_locy;
X		    mapMouseToBoard(&newMouseLoc, &from);
X		    setup.x = from.x;
X		    setup.y = from.y;
X		    setup.type = NULLPC;
X		    DoSetupChange(&setup);
X		    SendSetupChange(&setup, PeerColor);
X		}
X		break;
X	    /*
X	     * exit setup
X	     */
X	    case MS_RIGHT:
X		if (win_inputposevent(&ie)) {
X		    Message("Sure you want to end setup? left - yes, other - no");
X		    Mouse = CONFIRMING;
X		    confirmState = CONFIRM_SETUP_END;
X		}
X		break;
X	    }
X	    break;
X	/*
X	 * we are promoting a pawn
X	 */
X	case PROMOTING_PAWN:
X	    switch(ie.ie_code) {
X	    /*
X	     * select the next pawn morph
X	     */
X	    case MS_LEFT:
X		if (win_inputposevent(&ie))
X		    move.newPieceType = PromotePawn(&to);
X		break;
X	    /*
X	     * go for the current morph
X	     */
X	    case MS_MIDDLE:
X		if (win_inputposevent(&ie) && SendMove(&move, PeerColor)) {
X		    Turn = OTHERCOLOR(Turn);
X		    WhoseMoveMessage((char *) 0);
X		    Mouse = IDLE;
X		}
X		break;
X	    /*
X	     * we exited the window - back out the pawn move 
X	     */
X	    case LOC_WINEXIT:
X		UnDoMove();
X		Mouse = IDLE;
X		break;
X	    }
X	    break;
X	/* 
X	 * we aren't currently doing anything
X	 */
X	case IDLE:
X	    switch(ie.ie_code) {
X	    case MS_LEFT:
X		/*
X		 * if this a left button press 
X		 * and it is our turn
X		 * and we aren't waiting for an undo acknowledgement
X		 */
X		if (win_inputposevent(&ie) && Turn == MyColor && ! UndoWanted) {
X		    newMouseLoc.x = ie.ie_locx;
X		    newMouseLoc.y = ie.ie_locy;
X		    mapMouseToBoard(&newMouseLoc, &from);
X		    /* 
X		     * if there is one of our pieces on this square 
X		     */
X		    if (IsOurPieceAt(&from)) {
X			Mouse = MOVING_PIECE;
X			sqp = GetSquare(from.x, from.y);
X			/*
X			 * create the first background pixrect,
X			 * centered on the selected board square
X			 */
X			mapBoardToMouse(&from, &lastMouseLoc);
X			/* grab the currently displayed image */
X			pw_read(MoveFromPR, 
X			    0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X			    PIX_SRC,
X			    Board->gfx_pixwin,
X			    lastMouseLoc.x - MOVE_X_OFFSET,
X			    lastMouseLoc.y - MOVE_Y_OFFSET);
X			/* repaint the blank square */
X			pr_rop(MoveFromPR,
X			    MOVE_X_OFFSET,
X			    MOVE_Y_OFFSET,
X			    SQUARE_WIDTH, SQUARE_HEIGHT,
X			    PIX_SRC,
X			    ((from.x + from.y) & 0x01) ? 
X				&BlackSquarePR :
X				&WhiteSquarePR,
X			    0, 0);
X			/* 
X			 * remember the pixrect used to paint the piece 
X			 * being moved 
X			 */
X			pieceIcon = PieceIcons[(int) sqp->type][sqp->color];
X			pieceStencil = PieceStencils[(int) sqp->type];
X			/*
X			 * a bit un-structured, but we are forced to do this
X			 * if we want the piece to "jump" to the cursor when
X			 * the button is initially depressed ("forced" in the
X			 * sense that we are inside a switch statement).
X			 */
X			goto moveIt;
X		    }
X		}
X		break;
X	    }
X	    break;
X	/*
X	 * we are animating a piece 
X	 */
X	case MOVING_PIECE:
X	    switch(ie.ie_code) {
X	    case MS_LEFT:
X		/*
X		 * if we are putting down a piece
X		 */
X		if (win_inputnegevent(&ie)) {
X		    BOOL legal;
X
X		    Mouse = IDLE;
X		    newMouseLoc.x = ie.ie_locx;
X		    newMouseLoc.y = ie.ie_locy;
X		    mapMouseToBoard(&newMouseLoc, &to);
X		    legal = TRUE;
X		    move.x1 = from.x; move.y1 = from.y;
X		    move.x2 = to.x; move.y2 = to.y;
X		    if (SetupMode) {
X			/* repaint the background */
X			pw_rop(Board->gfx_pixwin,
X			    lastMouseLoc.x - MOVE_X_OFFSET,
X			    lastMouseLoc.y - MOVE_Y_OFFSET,
X			    MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X			    PIX_SRC, MoveFromPR, 0, 0);
X			/* put the piece down no matter what */
X			setup.x = to.x;
X			setup.y = to.y;
X			DoSetupChange(&setup);
X			SendSetupChange(&setup, PeerColor);
X			Mouse = SETUP;
X		    } else if ( ! (from.x == to.x && from.y == to.y) 
X		    && Turn == MyColor 
X		    && (legal = IsMoveLegal(&from, &to))) {
X			/* if this is a pawn promotion */
X			if (GetSquare(from.x, from.y)->type == PAWN
X			&& (to.y == 0 || to.y == 7)) {
X			    /* repaint the background */
X			    pw_rop(Board->gfx_pixwin,
X				lastMouseLoc.x - MOVE_X_OFFSET,
X				lastMouseLoc.y - MOVE_Y_OFFSET,
X				MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X				PIX_SRC, MoveFromPR, 0, 0);
X			    move.newPieceType = (int) QUEEN;
X			    DoMove(&move, TRUE);
X			    /* if we are playing the brain-damaged unix chess
X			     * program, can only promote to queens */
X			    if (IsMachine[OTHERCOLOR(MyColor)]) {
X				Turn = OTHERCOLOR(Turn);
X				SendMove(&move, PeerColor);
X				WhoseMoveMessage((char *) 0);
X			    /* else need to have the user select the promoted 
X			     * piece type */
X			    } else {
X				Message("Left button: select piece type, middle: send move.");
X				Mouse = PROMOTING_PAWN;
X			    }
X			/* else if we can send the move */
X			} else if (SendMove(&move, PeerColor)) {
X			    /* repaint the background */
X			    pw_rop(Board->gfx_pixwin,
X				lastMouseLoc.x - MOVE_X_OFFSET,
X				lastMouseLoc.y - MOVE_Y_OFFSET,
X				MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X				PIX_SRC, MoveFromPR, 0, 0);
X			    DoMove(&move, TRUE);
X			    Turn = OTHERCOLOR(Turn);
X			    WhoseMoveMessage((char *) 0);
X			/* else the peer is dead */
X			} else {
X			    /* repaint the background */
X			    pw_rop(Board->gfx_pixwin,
X				lastMouseLoc.x - MOVE_X_OFFSET,
X				lastMouseLoc.y - MOVE_Y_OFFSET,
X				MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X				PIX_SRC, MoveFromPR, 0, 0);
X			    putPieceBack(&from, pieceStencil, pieceIcon);
X			}
X		    } else {
X			/* repaint the background */
X			pw_rop(Board->gfx_pixwin,
X			    lastMouseLoc.x - MOVE_X_OFFSET,
X			    lastMouseLoc.y - MOVE_Y_OFFSET,
X			    MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X			    PIX_SRC, MoveFromPR, 0, 0);
X			putPieceBack(&from, pieceStencil, pieceIcon);
X			if ( ! legal)
X			    Message("Illegal move");
X		    }
X		}
X		break;
X	    /*
X	     * exited the window - clean it up.
X	     */
X	    case LOC_WINEXIT:
X		/* repaint the background */
X		pw_rop(Board->gfx_pixwin,
X		    lastMouseLoc.x - MOVE_X_OFFSET,
X		    lastMouseLoc.y - MOVE_Y_OFFSET,
X		    MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X		    PIX_SRC, MoveFromPR, 0, 0);
X		if (SetupMode) {
X		    Mouse = SETUP;
X		} else {
X		    putPieceBack(&from, pieceStencil, pieceIcon);
X		    Mouse = IDLE;
X		}
X		break;
X	    /* 
X	     * animate the piece
X	     */
X	    case LOC_MOVEWHILEBUTDOWN:
X	moveIt:
X		/* ignore old motion events */
X		ioctl(Board->gfx_windowfd, (int) FIONREAD, (char *) &nbytes);
X		if (nbytes/sizeof(struct inputevent) <= 3) {
X		    do {
X			newMouseLoc.x = ie.ie_locx - SQUARE_WIDTH/2;
X			newMouseLoc.y = ie.ie_locy - SQUARE_HEIGHT/2;
X			clamped = FALSE;
X			/*
X			 * clamp motion if necessary
X			 */
X			if (newMouseLoc.x - lastMouseLoc.x >= MOVE_X_OFFSET) {
X			    newMouseLoc.x = lastMouseLoc.x + (MOVE_X_OFFSET-1);
X			    clamped = TRUE;
X			} else if (newMouseLoc.x - lastMouseLoc.x <= - MOVE_X_OFFSET) {
X			    newMouseLoc.x = lastMouseLoc.x - (MOVE_X_OFFSET-1);
X			    clamped = TRUE;
X			} 
X			if (newMouseLoc.y - lastMouseLoc.y >= MOVE_Y_OFFSET) {
X			    newMouseLoc.y = lastMouseLoc.y + (MOVE_Y_OFFSET-1);
X			    clamped = TRUE;
X			} else if (newMouseLoc.y - lastMouseLoc.y <= - MOVE_Y_OFFSET) {
X			    newMouseLoc.y = lastMouseLoc.y - (MOVE_Y_OFFSET-1);
X			    clamped = TRUE;
X			}
X			/* grab the new area */
X			pw_read(MoveToPR, 
X			    0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X			    PIX_SRC, Board->gfx_pixwin,
X			    newMouseLoc.x - MOVE_X_OFFSET,
X			    newMouseLoc.y - MOVE_Y_OFFSET);
X			/* paste the old background over the new area */
X			pr_rop(MoveToPR,
X			    lastMouseLoc.x - newMouseLoc.x,
X			    lastMouseLoc.y - newMouseLoc.y,
X			    MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X			    PIX_SRC, MoveFromPR, 0, 0);
X			/* save the new background */
X			pr_rop(MoveFromPR, 0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X			    PIX_SRC, MoveToPR, 0, 0);
X			/* paint the piece on the new area */
X			pr_stencil(MoveToPR, 
X			    MOVE_X_OFFSET, MOVE_Y_OFFSET,
X			    SQUARE_WIDTH, SQUARE_HEIGHT,
X			    PIX_SRC, pieceStencil, 0, 0, pieceIcon, 0, 0);
X			/* now paint the new area on the screen */
X			pw_rop(Board->gfx_pixwin,
X			    newMouseLoc.x - MOVE_X_OFFSET,
X			    newMouseLoc.y - MOVE_Y_OFFSET,
X			    MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
X			    PIX_SRC, MoveToPR, 0, 0);
X			lastMouseLoc.x = newMouseLoc.x;
X			lastMouseLoc.y = newMouseLoc.y;
X		    } while (clamped);
X		}
X		break;
X	    }
X	    break;
X	}
X    }
X    * ibits = svc_fds | BoardSWMask | ChessProcessFDs[BLACK] | ChessProcessFDs[WHITE];
X    * obits = * ebits = 0;
X}
X
X/*
X * initialize the board subwindow
X */
Xvoid
XInitBoardSW(useRetained, iconDirectory)
X    BOOL useRetained;			/* use a retained pixrect */
X    char * iconDirectory;		/* custom piece icon directory */
X{
X    static struct timeval tickValue;
X    struct inputmask mask;
X    register unsigned int i;
X    int height = (SQUARE_HEIGHT-1) * 8 + ((7 * SQUARE_HEIGHT)/4) + 10;
X
X    /*
X     * initialize the subwindow
X     */
X    if ((BoardSW = gfxsw_createtoolsubwindow(NchessTool, "",
X	TOOL_SWEXTENDTOEDGE, 
X	/* playing surface    +  victim area */
X/*	(SQUARE_HEIGHT-1) * 8 + ((7 * SQUARE_HEIGHT)/4) + 10,  */
X	height,
X	NULL)) == NULL) 
X    {
X	fprintf(stderr, "Can't create board subwindow\n");
X	exit(1);
X    }
X    Board = (struct gfxsubwindow *) BoardSW->ts_data;
X    if (useRetained)
X	gfxsw_getretained(Board); 
X    BoardSW->ts_io.tio_handlesigwinch = boardSigwinch;
X    BoardSW->ts_io.tio_selected = boardSelected;
X    input_imnull(&mask);
X    win_setinputcodebit(&mask, MS_LEFT);
X    win_setinputcodebit(&mask, MS_MIDDLE);
X    win_setinputcodebit(&mask, MS_RIGHT);
X    win_setinputcodebit(&mask, LOC_MOVEWHILEBUTDOWN);
X    win_setinputcodebit(&mask, LOC_WINEXIT);
X    mask.im_flags |= IM_NEGEVENT;
X    win_setinputmask(BoardSW->ts_windowfd, &mask, NULL, WIN_NULLLINK);
X    /* 
X     * add the RPC service and chess process file descriptor select
X     * masks to this subwindow.
X     */
X    BoardSW->ts_io.tio_inputmask = svc_fds 
X	| (BoardSWMask = 1 << BoardSW->ts_windowfd) 
X	| ChessProcessFDs[BLACK] 
X	| ChessProcessFDs[WHITE] ;
X    /*
X     * set the timeout to 1 second 
X     */
X    tickValue.tv_sec = 1L;
X    tickValue.tv_usec = 0L;
X    BoardSW->ts_io.tio_timer = &tickValue;
X    /*
X     * create the white pieces by inverting the black pieces, using custom
X     * pieces where appropriate.
X     */
X    for ( i = 0 ; i < 6 ; i++ ) {
X	if (iconDirectory != (char *) 0) {
X	    FILE * iconFile, * stencilFile;
X	    icon_header_object iconHeader, stencilHeader;
X	    char fileName[512], errorMsg[IL_ERRORMSG_SIZE + 2];
X
X	    strcpy(fileName, iconDirectory);
X	    strcat(fileName, "/");
X	    strcat(fileName, PieceIconFileNames[i]);
X	    if ((iconFile = icon_open_header(fileName, errorMsg, 
X		&iconHeader)) != (FILE *) 0) 
X	    {
X		if (iconHeader.width != SQUARE_WIDTH 
X		|| iconHeader.height != SQUARE_HEIGHT
X		|| iconHeader.depth != 1) {
X		    fprintf(stderr, "warning: bogus icon (ignored): %s\n", fileName);
X		} else {
X		    strcpy(fileName, iconDirectory);
X		    strcat(fileName, "/");
X		    strcat(fileName, PieceStencilFileNames[i]);
X		    if ((stencilFile = icon_open_header(fileName, errorMsg, 
X			&stencilHeader)) != (FILE *) 0) 
X		    {
X			if (stencilHeader.width != SQUARE_WIDTH 
X			|| stencilHeader.height != SQUARE_HEIGHT
X			|| stencilHeader.depth != 1) {
X			    fprintf(stderr, "warning: bogus icon (ignored): %s\n", fileName);
X			} else {
X			    icon_read_pr(iconFile, &iconHeader, PieceIcons[i][BLACK]);
X			    icon_read_pr(stencilFile, &stencilHeader, PieceStencils[i]);
X			}
X			fclose(stencilFile);
X		    }
X		}
X		fclose(iconFile);
X	    }
X	}
X	pr_rop(PieceIcons[i][WHITE], 0, 0, SQUARE_WIDTH, SQUARE_HEIGHT,
X	    PIX_NOT(PIX_SRC),
X	    PieceIcons[i][BLACK], 0, 0);
X    }
X    /* 
X     * create the pixrects used for piece animation and victim drawing
X     */
X    if ((MoveFromPR = mem_create(MOVE_PR_WIDTH, MOVE_PR_HEIGHT, 1)) == (struct pixrect *) 0
X    || (MoveToPR = mem_create(MOVE_PR_WIDTH, MOVE_PR_HEIGHT, 1)) == (struct pixrect *) 0
X    || (VictimPR = mem_create(SQUARE_WIDTH, SQUARE_HEIGHT, 1)) == (struct pixrect *) 0) {
X	fprintf(stderr, "can't create the animation pixrects\n");
X	exit(1);
X    }
X}
X
X/*
X * draw a square, including the piece (if any)
X */
Xvoid
XDrawSquare(x, y, sqp)
X    int x, y;
X    register Square * sqp;
X{
X    BoardCoordinate bloc;
X    struct pr_pos mloc;
X
X    bloc.x = x; bloc.y = y;
X    mapBoardToMouse(&bloc, &mloc);
X    /* paint the blank square */
X    pw_rop(Board->gfx_pixwin, 
X	mloc.x, mloc.y,
X	SQUARE_WIDTH, SQUARE_HEIGHT,
X	PIX_SRC, 
X	(((x + y) & 0x01) ? &BlackSquarePR : &WhiteSquarePR), 
X	0, 0);
X    /* paint the piece, if there is one */
X    if (sqp->type != NULLPC) {
X	pw_stencil(Board->gfx_pixwin, mloc.x, mloc.y,
X	    SQUARE_WIDTH, SQUARE_HEIGHT,
X	    PIX_SRC,
X	    PieceStencils[(int) sqp->type], 0, 0,
X	    PieceIcons[(int) sqp->type][sqp->color], 0, 0);
X    }
X}
X
X/*
X * draw the playing surface and victim area
X */
Xvoid
XDrawBoard()
X{
X    register int x, y;
X    register Square * sqp;
X
X    /* clear the board area */
X    pw_rop(Board->gfx_pixwin,
X	0, 0, Board->gfx_rect.r_width, Board->gfx_rect.r_height,
X	PIX_CLR, (struct pixrect *) 0, 0, 0);
X    /* draw the playing area */
X    for (x = 0 ; x < 8 ; x++) {
X	for (y = 0 ; y < 8 ; y++) {
X	    sqp = GetSquare(x, y);
X	    DrawSquare(x, y, sqp);
X	}
X    }
X    /* draw the victims */
X    drawVictims();
X}
X
X/*
X * your basic victim 
X */
Xtypedef struct {
X    PieceType type;			/* victim type */
X    BOOL active;			/* victim slot state */
X    int count;				/* victim overflow count */
X} Victim;
X
X#define	NUM_VICTIM_SLOTS 8
X
XVictim victims[2 /* pawns(1) vs. pieces(0) */][2 /* color */ ][NUM_VICTIM_SLOTS /* victim slot # */];
X
X/*
X * map the victim specified by the triple 
X * [ isPawn { 0, 1 }, color { BLACK, WHITE }, slot { 0 .. NUM_VICTIM_SLOTS-1 } ]
X * to a mouse coordinate (relative to the board subwindow)
X */
Xvoid
XmapVictimToMouse(isPawn, color, slot, mlocp)
X    BOOL isPawn;
X    int color, slot;
X    struct pr_pos * mlocp;
X{
X    mlocp->x = slot * (3 * SQUARE_WIDTH/4) + color * (3 * SQUARE_WIDTH/8);
X    mlocp->y = 8 * (SQUARE_HEIGHT-1) + isPawn * (SQUARE_HEIGHT/2) + color * (SQUARE_HEIGHT/4) + 5;
X}
X
X/* 
X * draw the victims
X */
XdrawVictims()
X{
X    register int i, j, k;
X    register Victim * victim;
X    struct pr_pos victimOrigin;
X
X    for (i = 0 ; i < 2 ; i++) {
X	for (j = 0 ; j < 2 ; j++) {
X	    for (k = 0 ; k < NUM_VICTIM_SLOTS ; k++) {
X		victim = &victims[i][j][k];
X		if (victim->active) {
X		    mapVictimToMouse(i, j, k, &victimOrigin);
X		    pw_stencil(Board->gfx_pixwin, 
X			victimOrigin.x, victimOrigin.y,
X			SQUARE_WIDTH, SQUARE_HEIGHT,
X			PIX_SRC,
X			PieceStencils[(int) victim->type], 0, 0,
X			PieceIcons[(int) victim->type][j], 0, 0);
X		}
X	    }
X	}
X    }
X}
X
X/* 
X * add a piece to the set of victims 
X */
Xvoid
XAddVictim(type, color, drawIt) 
X    PieceType type;
X    int color;
X    BOOL drawIt;
X{
X    register int i, j, k;
X    int empty, lastMatch, extras;
X    register Victim * victim;
X    BOOL isPawn = (type == PAWN);
X    struct pr_pos victimOrigin, othersOrigin;
X
X    /* 
X     * look for the first empty slot and the last slot which 
X     * contains a piece of the same type
X     */
X    for (lastMatch = empty = -1 , i = 0 ; i < NUM_VICTIM_SLOTS ; i++) {
X	victim = &victims[isPawn][color][i];
X	if (empty < 0 && ! victim->active)
X	    empty = i;
X	if (victim->active && victim->type == type)
X	    lastMatch = i;
X    }
X    /*
X     * if there were no empty slots 
X     */
X    if (empty == -1) {
X	/* 
X	 * if there was one or more pieces of the same type, update
X	 * the last instance's overflow count (includes coalescing
X	 * all overflows of that type at the last instance)
X	 */
X	if (lastMatch >= 0) {
X	    for (extras = i = 0 ; i < lastMatch ; i++) {
X		victim = &victims[isPawn][color][i];
X		if (victim->active && victim->type == type && victim->count > 1) {
X		    extras += victim->count - 1;
X		    victim->count = 1;
X		}
X	    }
X	    victims[isPawn][color][lastMatch].count += extras;
X	}
X    /*
X     * else install the victim in the empty slot 
X     */
X    } else {
X	victim = &victims[isPawn][color][empty];
X	victim->type = type;
X	victim->active = TRUE;
X	victim->count = 1;
X	if (drawIt) {
X	    /*
X	     * re-draw all the pieces in the victim's slot 
X	     */
X	    mapVictimToMouse(isPawn, color, empty, &victimOrigin);
X	    pr_rop(VictimPR, 0, 0, SQUARE_WIDTH, SQUARE_HEIGHT,
X		PIX_CLR, (struct pixrect *) 0, 0, 0);
X	    for (i = 0 ; i < 2 ; i++) {
X		for (j = 0 ; j < 2 ; j++) {
X		    for (k = 0 ; k < NUM_VICTIM_SLOTS ; k++) {
X			victim = &victims[i][j][k];
X			if (victim->active) {
X			    mapVictimToMouse(i, j, k, &othersOrigin);
X			    pr_stencil(VictimPR,
X				othersOrigin.x - victimOrigin.x,
X				othersOrigin.y - victimOrigin.y,
X				SQUARE_WIDTH, SQUARE_HEIGHT,
X				PIX_SRC,
X				PieceStencils[(int) victim->type], 0, 0,
X				PieceIcons[(int) victim->type][j], 0, 0);
X			}
X		    }
X		}
X	    }
X	    /*
X	     * now re-draw the slot 
X	     */
X	    pw_rop(Board->gfx_pixwin,
X		victimOrigin.x, victimOrigin.y, 
X		SQUARE_WIDTH, SQUARE_HEIGHT,
X		PIX_SRC, VictimPR, 0, 0);
X	}
X    }
X}
X
X/*
X * reincarnate a victim (via an undo)
X */
Xvoid
XDeleteVictim(type, color)
X    PieceType type;
X    int color;
X{
X    register int i, j, k;
X    int lastMatch, extras;
X    register Victim * victim;
X    BOOL isPawn = (type == PAWN);
X    struct pr_pos victimOrigin, othersOrigin;
X
X    /* 
X     * look for the last slot which contains a piece of this type
X     */
X    for (lastMatch = -1 , i = 0 ; i < NUM_VICTIM_SLOTS ; i++) {
X	victim = &victims[isPawn][color][i];
X	if (victim->active && victim->type == type)
X	    lastMatch = i;
X    }
X    /*
X     * if there were no matches, don't do anything
X     */
X    if (lastMatch == -1) {
X	/* do nothing */
X    /*
X     * else if the last match slot contains overflows, simply 
X     * decrement the overflow count
X     */
X    } else if ((victim = &victims[isPawn][color][lastMatch])->count > 1) {
X	victim->count--;
X    /*
X     * else zero out the slot and re-draw it as empty
X     */
X    } else {
X	victim->active = FALSE;
X	/*
X	 * re-draw all the remaining pieces in the victim's slot 
X	 */
X	mapVictimToMouse(isPawn, color, lastMatch, &victimOrigin);
X	pr_rop(VictimPR, 0, 0, SQUARE_WIDTH, SQUARE_HEIGHT,
X	    PIX_CLR, (struct pixrect *) 0, 0, 0);
X	for (i = 0 ; i < 2 ; i++) {
X	    for (j = 0 ; j < 2 ; j++) {
X		for (k = 0 ; k < NUM_VICTIM_SLOTS ; k++) {
X		    victim = &victims[i][j][k];
X		    if (victim->active) {
X			mapVictimToMouse(i, j, k, &othersOrigin);
X			pr_stencil(VictimPR,
X			    othersOrigin.x - victimOrigin.x,
X			    othersOrigin.y - victimOrigin.y,
X			    SQUARE_WIDTH, SQUARE_HEIGHT,
X			    PIX_SRC,
X			    PieceStencils[(int) victim->type], 0, 0,
X			    PieceIcons[(int) victim->type][j], 0, 0);
X		    }
X		}
X	    }
X	}
X	/*
X	 * now re-draw the slot 
X	 */
X	pw_rop(Board->gfx_pixwin,
X	    victimOrigin.x, victimOrigin.y, 
X	    SQUARE_WIDTH, SQUARE_HEIGHT,
X	    PIX_SRC, VictimPR, 0, 0);
X    }
X}
X
END_OF_boardsw.c
if test 34145 -ne `wc -c <boardsw.c`; then
    echo shar: \"boardsw.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f nchess.6 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"nchess.6\"
else
echo shar: Extracting \"nchess.6\" \(16236 characters\)
sed "s/^X//" >nchess.6 <<'END_OF_nchess.6'
X.TH NCHESS 6 "14 October 1986"
X.SH NAME
Xnchess \- general-purpose chess tool
X.SH SYNOPSIS
X.B nchess
X[\fB-c\fP]
X.br
X	[\fB-e\fP | \fB-r\fP\fIrestoreFileName\fP]
X.br
X	[\fB-s\fP\fIsaveFileName\fP]
X.br
X	[\fB-d\fP\fIpieceIconDirectory\fP]
X.br
X	[\fB-t\fP\fItranscriptFileName\fP]
X.br
X	[\fB-x\fP\fIn\fP]
X.br
X
X	\fB-m\fP\fIchessProgram\fP [\fB-m\fP\fIarg\fP ...] | \fB-n\fP\fIchessProgram\fP [\fB-n\fP\fIarg\fP ...]
X.br
X	or
X.br
X	\fB-m\fP\fIchessProgram\fP [\fB-m\fP\fIarg\fP ...] \fB-n\fP\fIchessProgram\fP [\fB-n\fP\fIarg\fP ...]
X.br	
X	or
X.br
X	[\fB-b | -w\fP] \fIuser@host\fP
X.SH DESCRIPTION
X.I Nchess
Xis a general-purpose chess interface suitable for playing any 
Xcombination of { human, machine } vs. { human, machine }.
XSome of the more notable features of nchess 
Xare facilities for generating transcript files
Xin various formats,
Xfor saving and restoring games,
Xand for setting up initial board situations.
X.SH "INVOCATION"
X.LP
XNchess accepts numerous command line arguments:
X.IP "\fB-c\fP"
Xdon't keep an internal copy of the board's display image
X(the default is to keep one)
X.IP "\fB-b\fP"
Xask to play the black pieces
X.IP "\fB-w\fP"
Xask to play the white pieces
X.IP "\fB-e\fI"
Xedit the board (i.e., set up a non-standard board configuration)
Xprior to starting the game
X.IP "\fB-r\fP \fIrestoreFileName\fP"
Xresume a game from the game saved in \fIrestoreFileName\fP
X.IP "\fB-s\fP \fIsaveFileName\fP"
Xuse \fIsaveFileName\fP for saving games instead of the 
Xdefault \fB"nchess.save"\fP.
X.IP "\fB-t\fP \fItranscriptFileName\fP"
Xuse \fItranscriptFileName\fP for writing transcripts instead of the 
Xdefault \fB"nchess.transcript"\fP.
X.IP "\fB-x\fP\fIn\fP"
Xgenerate transcripts in format \fIn\fP, where \fIn\fP is one of:
X.nf
X
X		0	formal; e.g., P/K2-K4, R/KB3xP
X		1	minimal; e.g., P-K4, RxP (the default)
X		2	algebraic; e.g., E2E4, F3F5
X.fi
X.IP "\fB-d\fP \fIpieceIconDirectory\fP"
Xlook in \fIpieceIconDirectory\fP for piece icons to use instead
Xof the default ones supplied by \fInchess\fP.
X.IP "\fB-m\fP \fIchessProgram\fP"
Xstart up \fIchessProgram\fP playing the white pieces
X.IP "\fB-n\fP \fIchessProgram\fP"
Xstart up \fIchessProgram\fP playing the black pieces
X.LP
XSpecifying \fB-c\fP forces \fInchess\fP to recompute the board
Ximage whenever any portion of it must be made visible again.
XHowever, the memory savings it entails may justify its use 
Xfor systems which are running a bit short.
X.LP
XThe \fB-m\fP and \fB-n\fP arguments are cumulative.
XThe first of either is interpreted as the name of an 
Xexecutable chess program;
Xsubsequent instances are collected and passed as arguments 
Xto the chess program.
X.SH "HUMAN VS. HUMAN"
X.LP
XHuman vs. human games are started by
Xinvoking \fInchess\fP with an argument of
Xthe form "\fIuser@host\fP" and
Xneither of the \fB-m\fP, \fB-n\fP arguments.
XBoth the local machine and the host specified by the \fIhost\fP
Xargument must be running \fInchessd(6)\fP (hereafter referred
Xto as the daemon).
X\fINchess\fP first checks the local daemon for an invitation 
Xregistered by \fIuser\fP at \fIhost\fP.
XIf none is found, \fInchess\fP sends an invitation to the 
Xdaemon running on \fIhost\fP,
Xprints something like "Waiting for \fIuser\fP to respond...",
Xthen idles waiting for a message from a 
Xresponding \fInchess\fP process.
XIn turn, the remote daemon prints something useful 
Xand sufficiently distracting on the remote console.
X.LP
XIf an invitation was found waiting in the local daemon,
X\fInchess\fP sends a response message to the 
Xpeer \fInchess\fP process.
XSubsequent communication is peer-to-peer; 
Xi.e., the daemon is no longer consulted for anything.
XIf either user specified \fB-b\fP or \fB-w\fP,
Xthe two peers attempt to satisfy color preferences;
Xif both users requested the same color,
Xa single round of arbitration results.
XIf this arbitration fails, 
Xboth \fInchess\fP processes exit, 
Xawaiting a less contentious session.
X.SH "HUMAN VS. MACHINE"
X.LP
XHuman vs. machine games are started by 
Xinvoking \fInchess\fP with one of 
Xthe \fI-m\fP or \fI-n\fP arguments.
XThe existence of the daemon is not required.
XThe chess program used is expected to conform to 
Xthe interface protocol described below.
X.SH "MACHINE VS. MACHINE"
X.LP
XMachine vs. machine games are started by 
Xinvoking \fInchess\fP with both of 
Xthe \fI-m\fP and \fI-n\fP arguments.
XThe existence of the daemon is not required.
XBoth chess programs used are expected to conform to 
Xthe interface protocol described below.
X.SH "MESSAGE SUBWINDOW"
X.LP
XDuring the course of the game, 
Xvarious messages appear in a one-line subwindow
Xdirectly over the button panel.
XThese messages may direct you to press certain buttons
Xto confirm various actions (e.g., resigning, allowing an undo).
XThe cursor must be positioned in the board subwindow
Xwhen buttons are pressed in response to a message.
X.SH "NORMAL PLAY"
X.LP
XIn normal play, pieces are moved by positioning the cursor
Xover the square a piece resides on,
Xdepressing the left mouse button,
Xmoving the piece to the desired square,
Xand releasing the button.
XAfter moving, activity in the board subwindow is 
Xsuppressed until a move is made by the opponent.
X.LP
XCertain move types deserve special mention.
XEn passant pawn captures are performed by moving the 
Xcapturing pawn to the third rank square;
Xi.e., the square it will reside on after the move.
X\fINchess\fP enforces the restriction that en passant
Xcapturing rights expire after the move immediately 
Xfollowing the pawn advance.
XCastling to either side is performed by moving the
Xking two squares in the appropriate direction.
XFinally, pawn "queening" is a three-step process:
XFirst, the pawn is moved to the eighth rank, where
Xit is initially polymorphed to a queen.
XSecond, the pawn is rotated through the set of legal
Xpawn morphs for every left mouse button click (the legal
Xpawn morphs are queen, bishop, knight, and rook).
XFinally, the move is sent to the opponent when the middle 
Xbutton is pressed.
X(Note: If the opponent is a machine,
Xpawns may only be promoted to queens
Xand step two is skipped.)
X.LP
XAt any time during the game,
Xclicking the left mouse button on one of
Xseveral buttons above the board subwindow 
Xwill have the following effects:
X.IP "(Resign)"
XResignation is final; and after confirming
Xthat you really wanted to resign,
Xit's curtains...
X.IP "(Undo)"
XAgainst a human opponent, this button causes \fInchess\fP
Xto forward a request to your opponent to undo your last move.
XAssuming your opponent agrees, your last move will no longer
Xhaunt you and it will be your turn again.
XIf it was your turn to play, 
Xyour opponent's last move will be undone as well.
XAgainst a machine opponent, 
Xacquiescence is implicit.
XUndos can be repeated,
Xconstrained only by reaching the initial game state and
Xthe limits of your opponent's compassion.
X.IP "(Last Play)"
XThe last play made by either side will be illustrated by
Xbriefly undoing the move in the board subwindow.
X.IP "(Transcript)"
XA transcript of the game is written to the transcript file
Xspecified on the command line; if no file was specified,
X"nchess.transcript" is used.
X.IP "(Save)"
XThe game state (including the move history) is saved in the
Xfile specified on the command line; if no file was specified,
X"nchess.save" is used.
X.LP
XWhen both players are machines, the "Resign" and "Undo"
Xbuttons are omitted from the window.
X.SH "EDITING THE BOARD"
X.LP
XWhen \fInchess\fP is invoked with the \fB-e\fP flag,
Xthe tool starts up as a board editor with initial play suspended.
XPieces are deleted by positioning the cursor over the 
Xsquare the piece resides on and clicking the middle button.
XPieces are created by positioning the mouse over the square
Xa piece of the desired type and color would reside on at the 
Xbeginning of a normal game, 
Xdepressing the left button, 
Xmoving the piece to the destination square,
Xand releasing the button.
XWhen editing is complete and play is about to commence, 
Xthe right button is clicked,
Xfollowed by another mouse click
Xto confirm exiting the board editor (once the board editor is
Xexited, it cannot be re-entered).
XIf this is a human vs. human game, the user is then asked
Xto specify which side moves first (via yet another mouse click).
XFollowing that, the game is afoot.
X.LP
XBoards can be edited for any of the { human, machine } combinations
Xdescribed above.
XAfter setting up a board for a machine vs. machine session, 
Xthe human is reduced to being a mere spectator.
XAlso, in any combination involving machines the white pieces
Xalways move first, due to a deficiency in the existing 
XUnix chess program.
X.SH "BADGERING YOUR OPPONENT"
X.LP
X\fINchess\fP provides a one-line talk subwindow in human vs. human
Xgames for sending pithy messages to your opponent.
XTo send a message, position the cursor to the right of the "\fBSend:\fP"
Xfield, type the message, and hit carriage return.
XThe message will not be sent until you've typed the carriage return,
Xallowing you to use the normal Unix line editing features.
X.SH "CREATING YOUR OWN PIECES"
X.LP 
X\fINchess\fP allows you to supplant any or all of the pictorial piece 
Xrepresentations (icons) with pieces of your own design.
XA few guidelines concerning icon creation are outlined below.
XFor starters, you might want to take a look at the 
Xicons used by \fInchess\fP.
X.LP
XAll icons used by \fInchess\fP are drawn using \fIicontool(1)\fP,
Xand are (\fIicontool\fP's default) 64 pixels wide, 64 pixels high,
Xand 1 pixel deep.
XOnly the black pieces are drawn - the white pieces are created
Xby \fInchess\fP by inverting the black pieces.
XYou must leave a blank border of at 
Xleast three pixels around the piece,
Xand the piece should be centered in \fIicontool's\fP drawing subwindow.
X.LP
XAfter you have drawn the piece, you need to create the 
Xcorresponding "stencil" image.
XThe stencil is used by \fInchess\fP to limit drawing the piece on
Xthe board to only those areas within the 64 by 64 square that
Xactually represent the piece image.
XAlso, in order to create the white pieces correctly, the stencil
Xborder needs to be grown one pixel past the piece image border - this
Xgives the white piece a thin black line border.
XAn easy way to create the stencil is to use the
Xfollowing procedure:
X.IP
XLoad the piece image
X.IP
XSelect "Fill: black" and "Fill: xor" modes.
X.IP
XFill the entire drawing subwindow.  You should now have a reverse
Xvideo image of the piece.
X.IP
XSelect "Fill: white" and "Fill: src" modes, and get rid of all 
Xblack pixels except for a one-line border 
Xaround the white piece image.
X.IP
XSelect "Fill: black" mode and fill inside the border.
X.LP
XYou should now have a solid black image of the piece which is one
Xpixel bigger in all directions than the image you drew earlier.  
XStore this image as the stencil.
XIf you want any parts of the piece to be transparent 
X(e.g., windows in the rook),
Xsimply leave those parts white in the stencil.
X.LP
XThe file names to use for the various pieces and stencils are listed
Xbelow in the "FILES" section.
XBoth the piece and stencil images must be accessible in the 
Xspecified icon directory before \fInchess\fP will attempt to use them.
X.LP
XIn case you are concerned,
Xusing your own pieces does not cause \fInchess\fP to use any more
Xmemory than it already does.
X.SH "CHESS PROGRAM INTERFACE PROTOCOL"
X.LP
XThe protocol for communication with chess programs is derived
Xin bottom-up fashion from the syntax and semantics
Xused by the existing Unix chess program.
XWhen the program starts up, 
Xit is expected to make a short one-line announcement (e.g., "Chess"),
Xwhich \fInchess\fP simply throws away.
XNext, \fInchess\fP sends a single line consisting of the keyword "alg",
Xwhich informs the chess program that algebraic notation is desired.
X.LP
XIf \fInchess\fP was invoked with the \fB-e\fP flag,
Xthe next communication with the chess program is to deliver the 
Xsetup information.
XThis is done by sending a single line consisting 
Xof the keyword "setup",
Xfollowed by eight lines of eight characters each.
XEach character represents the piece on a square, 
Xwith space characters representing empty squares.
XFor the white pieces, 
Xthe characters used are { p, n, b, r, q, k } for 
Xpawn, knight, bishop, rook, queen, and king, respectively.
XBlack pieces are represented by the upper case equivalent.
XLines are transmitted starting with the eighth rank (i.e., a8-h8).
XAfter receiving the eighth setup line (a1-h1),
Xthe chess program is expected to respond with a single line 
Xconsisting of either the key 
Xphrase "Setup successful" or "Illegal setup".
X.LP
XNext, the chess program will be sent either the first move by
Xits opponent (which will be white), 
Xor a single line consisting of the keyword "first",
Xwhich it should interpret to mean that it should play the white pieces
Xand that it should make the first move.
XMoves sent to the chess program will always be in the format
Ximplied by the printf string "%c%d%c%d\\n",
Xwhere the character specifications describe the file [a-h]
Xand the decimal digit specifications describe the rank [1-8].
XEn passant captures are encoded as a horizontal move; e.g., d5e5.
XCastling moves are encoded as the king move; e.g., e1g1.
XPawns implicitly turn into queens; thus, d7d8 implies P-Q8(Q).
X.LP
XAfter receiving a move, the chess program must echo a single line.
XThe standard Unix chess program uses this line to re-format and 
Xecho the move it received; 
Xhowever, \fInchess\fP does not interpret the echo and thus 
Xplaces no restrictions on its format.
X
X.SH "FILES"
X.br
Xbishop.icon
X.br
XbishopStencil.icon
X.br
Xking.icon
X.br
XkingStencil.icon
X.br
Xknight.icon
X.br
XknightStencil.icon
X.br
Xpawn.icon
X.br
XpawnStencil.icon
X.br
Xqueen.icon
X.br
XqueenStencil.icon
X.br
Xrook.icon
X.br
XrookStencil.icon
X.br
X.SH "SEE ALSO"
Xchess(6), chesstool(6), nchessd(6)
X.SH "BUGS"
X.LP
XThere aren't any clocks (yet).
X.LP
XThe board editor cannot be re-entered.  This is intentional, in order
Xto keep the middle of the game orderly.  However, some of the author's
Xcohorts think it is a bad idea.
X.LP
XTranscript files do not show the initial board state, which makes
Xit necessary to separately document non-standard initial positions.
XThis will be corrected in a future release.
X.LP
XThe algebraic notation used for transcripts is not really what you
Xmight expect.
X.LP
XWhen either player is a machine, pawns may be promoted only to queens.
XThis bug is inherited from the existing Unix chess program.
X.LP
XWhen either player is a machine, the white pieces must always make 
Xthe first move in a game.
XThis is another bug inherited from the existing Unix chess program.
X.LP
XSaved games must be re-started with the same configuration of human
Xand machine players.
XThis bug is due to the unknown format of the existing Unix chess
Xprogram's save files and to the lack of any known standard for 
Xthe format of such files.
X.LP
XThe talk subwindow has no facility for queueing lines for paced
Xreview by the receiver (as in games like rogue and hack).
XAlso, there is no way to shut the door if the opponent's messages
Xare a source of irritation instead of amusement or enlightenment.
X.LP
XThe rules for offering, accepting, and detecting draws are not
Ximplemented.  These apparently have ramifications with regard to 
Xhandling clocks, and are the principal reason clocks are not 
Ximplemented yet.  All this will be implemented in a future release.
XFor now, the talk subwindow is expected to suffice.
X.LP
XCheckmate and stalemate are not explicitly detected 
Xby \fInchess\fP, since it doesn't have an internal 
Xlegal move generator.
XAgain, the talk subwindow is expected to suffice.
X.LP
XThere is currently no way to play Blitz chess rules (e.g., don't 
Xannounce check, not forced to alleviate check, etc.).
X.LP
XMultiple kings are allowed in human vs. human setups; however,
Xonly the first one found is examined for being in check.
X.LP
XIn order to guarantee the ability to write background
Xchess process save files,
X\fInchess\fP changes its working directory to /tmp following
Xthe call to fork() and before the call to execvp().
XThus, chess programs in the former working directory
Xwhich were executable only via the '.'
Xcomponent in the PATH environment variable 
Xwill not be found by execvp().
XThis bug can be traced to the Unix chess program, which (apparently)
Xdoes not allow one to specify an alternative file name for its
Xsave file.
X
END_OF_nchess.6
if test 16236 -ne `wc -c <nchess.6`; then
    echo shar: \"nchess.6\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f nchess.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"nchess.h\"
else
echo shar: Extracting \"nchess.h\" \(3546 characters\)
sed "s/^X//" >nchess.h <<'END_OF_nchess.h'
X/*
X * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
X * Stanwood, WA  98282.   All rights reserved.
X */
X
X/*
X * network chess header
X */
X
X#define BOOL 			int
X#ifndef TRUE
X#define TRUE			1
X#endif
X#ifndef FALSE
X#define FALSE			0
X#endif
X
X#define	SERVERPROGNUM	((u_long) 0x31233216)	/* RPC daemon program number */
X#define VERSNUM			((u_long) 1)	/* RPC version number */
X
X/*
X * daemon procedure numbers
X */
X#define	REQPROCNUM		((u_long) 1)	/* game request */
X#define	ACKPROCNUM		((u_long) 2)	/* game acknowledge */
X#define	CANCELPROCNUM		((u_long) 3)	/* cancel a game request */
X
X/*
X * peer procedure numbers 
X */
X#define	ACCEPTPROCNUM		((u_long) 1)	/* game accepted */
X#define	MOVEPROCNUM		((u_long) 2)	/* chess move */
X#define	COLORFAILPROCNUM	((u_long) 3)	/* color arbitration failure */
X#define	UNDOPROCNUM		((u_long) 4)	/* undo request */
X#define	RESIGNPROCNUM		((u_long) 5)	/* resignation */
X#define	UNDOACKPROCNUM		((u_long) 6)	/* undo request response */
X#define	MSGPROCNUM		((u_long) 7)	/* one-liner antagonism */
X#define	RESTOREMOVEPROCNUM	((u_long) 8)	/* move during game restoration */
X#define	ENDRESTOREPROCNUM	((u_long) 9)	/* restoration/setup complete */
X#define	SETUPPROCNUM		((u_long) 10)	/* board setup change */
X#define	GOODBYEPROCNUM		((u_long) 11)	/* player killed his tool */
X
X/*
X * color arbitration values - the values are important, as the 
X * game can proceed when the sum of the two players' colors is 
X * WANTSWHITE+WANTSBLACK; also, the values are used as indices 
X * into arrays.
X */
X#define	WANTSBLACK		0		/* user wants black */
X#define	BLACK			WANTSBLACK	/* user has black */
X#define	WANTSWHITE		1		/* user wants white */
X#define	WHITE			WANTSWHITE	/* user has white */
X#define	EITHERCOLOR		2		/* user doesn't care */
X
X#define	OTHERCOLOR(a)	((a) == WHITE ? BLACK : WHITE)
X/*
X * rendezvous information 
X */
Xtypedef struct {
X    unsigned long progNum;			/* RPC program number of requester */
X    int color;					/* requested color */
X    int resumeGame;				/* boolean: wants to resume a game */
X    char hostName[256];				/* host name of requester */
X    char userName[256];				/* name of requesting user */
X} GameRequest;
X
X/*
X * piece move information 
X */
Xtypedef struct {
X    int x1;					/* origin square */
X    int y1;
X    int x2; 					/* destination square */
X    int y2;
X    int newPieceType;				/* new piece type for 8th rank pawns */
X} Move;
X
X/*
X * board square dimensions
X */
X#define	SQUARE_WIDTH	64
X#define	SQUARE_HEIGHT	SQUARE_WIDTH
X
X/*
X * board coordinates
X */
Xtypedef struct {
X    int x;
X    int y;
X} BoardCoordinate;
X
X/*
X * piece types
X */
Xtypedef enum {
X    PAWN = 0,
X    KNIGHT,
X    BISHOP,
X    ROOK,
X    QUEEN,
X    KING,
X    NULLPC,
X} PieceType;
X
X/*
X * square state
X */
Xtypedef struct {
X    PieceType type;
X    int color;
X} Square;
X
X/*
X * setup change information 
X */
Xtypedef struct {
X    int x;
X    int y;
X    PieceType type;
X    int color;
X} SetupChange;
X
X/*
X * mouse (in the board subwindow) activity states
X */
Xtypedef enum {
X    IDLE,		/* nada */
X    MOVING_PIECE,	/* animating a piece with the left button down */
X    PROMOTING_PAWN,	/* selecting a piece type for a pawn promotion */
X    CONFIRMING,		/* borrowed for confirmation of something */
X    LOCKED,		/* locked (ignored until unlocked) */
X    SETUP,		/* setting up a board */
X} MouseState;
X
X/*
X * transcript types
X */
X#define	TR_MIN_TYPE		0
X#define	TR_FORMAL_NORMAL	0	/* P/K2-K4, R/KB3xP/KB5, etc. */
X#define	TR_MIN_NORMAL		1	/* P-K4, RxP, etc. */
X#define	TR_ALGEBRAIC		2	/* D2D4, etc. */
X#define	TR_MAX_TYPE		2
X
X#include "decls.h"
X
END_OF_nchess.h
if test 3546 -ne `wc -c <nchess.h`; then
    echo shar: \"nchess.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 4\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0