Article View: net.sources.games
Article #762network chess (5 of 5)
From: Tom Anderson
Date: Thu, 08 Jan 1987 23:52
Date: Thu, 08 Jan 1987 23:52
1831 lines
50507 bytes
50507 bytes
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by spock!toma on Thu Jan 8 14:34:19 PST 1987
# Contents: boardsw.c msgsw.c talksw.c chessprocess.c
echo x - boardsw.c
sed 's/^@//' > "boardsw.c" <<'@//E*O*F boardsw.c//'
/*
* handle the board subwindow (as well as fielding RPC and chess game
* process selects)
*/
#include <stdio.h>
#include <suntool/tool_hs.h>
#include <suntool/panel.h>
#include <suntool/gfxsw.h>
#include <suntool/icon_load.h>
#include <sys/resource.h>
#include <sys/ioctl.h>
#include <strings.h>
#include "nchess.h"
#define MOVE_PR_WIDTH (SQUARE_WIDTH * 2)
#define MOVE_PR_HEIGHT (SQUARE_HEIGHT * 2)
#define MOVE_X_OFFSET (MOVE_PR_WIDTH/2 - SQUARE_WIDTH/2)
#define MOVE_Y_OFFSET (MOVE_PR_HEIGHT/2 - SQUARE_HEIGHT/2)
extern int svc_fds; /* RPC service file descriptor(s) */
int BoardSWMask; /* board gfx sw file des. */
BOOL Flashing = FALSE; /* tool icon is flashing */
enum { /* confirmation state using mouse */
CONFIRM_WANTED,
CONFIRM_SETUP_END,
CONFIRM_WHOSE_TURN,
CONFIRM_UNDO,
CONFIRM_RESIGNATION,
} confirmState;
MouseState Mouse = IDLE;
char * PieceIconFileNames[] = {
"pawn.icon",
"knight.icon",
"bishop.icon",
"rook.icon",
"queen.icon",
"king.icon",
};
char * PieceStencilFileNames[] = {
"pawnStencil.icon",
"knightStencil.icon",
"bishopStencil.icon",
"rookStencil.icon",
"queenStencil.icon",
"kingStencil.icon",
};
/*
* piece icons and stencils
*/
unsigned short RookBlackImage[] = {
#include "Icons/rook.icon"
};
unsigned short RookWhiteImage[] = {
#include "Icons/rook.icon"
};
unsigned short RookStencilImage[] = {
#include "Icons/rookStencil.icon"
};
mpr_static(RookBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, RookBlackImage);
mpr_static(RookWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, RookWhiteImage);
mpr_static(RookStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, RookStencilImage);
unsigned short KnightBlackImage[] = {
#include "Icons/knight.icon"
};
unsigned short KnightWhiteImage[] = {
#include "Icons/knight.icon"
};
unsigned short KnightStencilImage[] = {
#include "Icons/knightStencil.icon"
};
mpr_static(KnightBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KnightBlackImage);
mpr_static(KnightWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KnightWhiteImage);
mpr_static(KnightStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KnightStencilImage);
unsigned short BishopBlackImage[] = {
#include "Icons/bishop.icon"
};
unsigned short BishopWhiteImage[] = {
#include "Icons/bishop.icon"
};
unsigned short BishopStencilImage[] = {
#include "Icons/bishopStencil.icon"
};
mpr_static(BishopBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BishopBlackImage);
mpr_static(BishopWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BishopWhiteImage);
mpr_static(BishopStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BishopStencilImage);
unsigned short KingBlackImage[] = {
#include "Icons/king.icon"
};
unsigned short KingWhiteImage[] = {
#include "Icons/king.icon"
};
unsigned short KingStencilImage[] = {
#include "Icons/kingStencil.icon"
};
mpr_static(KingBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KingBlackImage);
mpr_static(KingWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KingWhiteImage);
mpr_static(KingStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KingStencilImage);
unsigned short QueenBlackImage[] = {
#include "Icons/queen.icon"
};
unsigned short QueenWhiteImage[] = {
#include "Icons/queen.icon"
};
unsigned short QueenStencilImage[] = {
#include "Icons/queenStencil.icon"
};
mpr_static(QueenBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, QueenBlackImage);
mpr_static(QueenWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, QueenWhiteImage);
mpr_static(QueenStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, QueenStencilImage);
unsigned short PawnBlackImage[] = {
#include "Icons/pawn.icon"
};
unsigned short PawnWhiteImage[] = {
#include "Icons/pawn.icon"
};
unsigned short PawnStencilImage[] = {
#include "Icons/pawnStencil.icon"
};
mpr_static(PawnBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, PawnBlackImage);
mpr_static(PawnWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, PawnWhiteImage);
mpr_static(PawnStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, PawnStencilImage);
struct pixrect * PieceStencils[6] = {
&PawnStencilPR,
&KnightStencilPR,
&BishopStencilPR,
&RookStencilPR,
&QueenStencilPR,
&KingStencilPR,
};
struct pixrect * PieceIcons[6][2] = {
&PawnBlackPR, &PawnWhitePR,
&KnightBlackPR, &KnightWhitePR,
&BishopBlackPR, &BishopWhitePR,
&RookBlackPR, &RookWhitePR,
&QueenBlackPR, &QueenWhitePR,
&KingBlackPR, &KingWhitePR,
};
/*
* blank square pixrects
*/
unsigned short WhiteSquareImage[] = {
#include "Icons/whiteSquare.icon"
};
mpr_static(WhiteSquarePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, WhiteSquareImage);
unsigned short BlackSquareImage[] = {
#include "Icons/blackSquare.icon"
};
mpr_static(BlackSquarePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BlackSquareImage);
/* board subwindow handles */
struct toolsw * BoardSW;
struct gfxsubwindow * Board;
/* pixrects used for piece animation */
struct pixrect * MoveFromPR, * MoveToPR;
/* pixrect used for victim drawing */
struct pixrect * VictimPR;
/*
* board sigwinch handler
*/
/*ARGSUSED*/
boardSigwinch(sw)
caddr_t sw;
{
gfxsw_interpretesigwinch(Board);
gfxsw_handlesigwinch(Board);
if (Board->gfx_flags & GFX_RESTART) {
Board->gfx_flags &= ~ GFX_RESTART;
DrawBoard();
}
}
/*
* map a mouse coordinate to a board coordinate
*/
void
mapMouseToBoard(mlocp, blocp)
struct pr_pos * mlocp;
BoardCoordinate * blocp;
{
if (MyColor == WHITE) {
blocp->x = mlocp->x / (SQUARE_WIDTH-1);
blocp->y = mlocp->y / (SQUARE_HEIGHT-1);
} else {
blocp->x = (8 * (SQUARE_WIDTH-1) - mlocp->x)/(SQUARE_WIDTH-1);
blocp->y = (8 * (SQUARE_HEIGHT-1) - mlocp->y)/(SQUARE_HEIGHT-1);
}
}
/*
* map a board coordinate to a mouse coordinate
*/
void
mapBoardToMouse(blocp, mlocp)
BoardCoordinate * blocp;
struct pr_pos * mlocp;
{
if (MyColor == WHITE) {
mlocp->x = blocp->x * (SQUARE_WIDTH-1) - 1;
mlocp->y = blocp->y * (SQUARE_HEIGHT-1) - 1;
} else {
mlocp->x = (7 - blocp->x) * (SQUARE_WIDTH-1) - 1;
mlocp->y = (7 - blocp->y) * (SQUARE_WIDTH-1) - 1;
}
}
/*
* put a piece back where we got it (used to abort piece animation for
* various reasons)
*/
void
putPieceBack(from, stencil, icon)
BoardCoordinate * from;
struct pixrect * stencil, * icon;
{
struct pr_pos loc;
mapBoardToMouse(from, &loc);
pw_stencil(Board->gfx_pixwin,
loc.x, loc.y,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC, stencil, 0, 0, icon, 0, 0);
}
/*
* parameters which belong in boardSelected(), but which are shared
* with RequestUndo() so that we can abort piece animation if the
* klutz at the other end panics (via an undo request or a resignation).
* all of them need to be static, anyway.
*/
BoardCoordinate from, to;
struct pixrect * pieceIcon, * pieceStencil;
struct pr_pos lastMouseLoc;
/*
* abort any mouse activity - this really only means aborting piece
* animation.
*/
void
KillMouseActivity()
{
switch (Mouse) {
case PROMOTING_PAWN:
UnDoMove();
break;
case MOVING_PIECE:
/* repaint the background */
pw_rop(Board->gfx_pixwin,
lastMouseLoc.x - MOVE_X_OFFSET,
lastMouseLoc.y - MOVE_Y_OFFSET,
MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, MoveFromPR, 0, 0);
putPieceBack(&from, pieceStencil, pieceIcon);
break;
}
}
/*
* relay a request for an undo by the opponent.
*
* this has the side-effect of aborting any mouse activity that the
* user had going at the time. however, setups will not be interrupted
* by undo requests since the (spurious) undo request will be prevented
* when the opponent's program detects that he hasn't moved yet.
*/
void
RequestUndo()
{
Message("Your opponent wants to undo - left OK, other not OK");
KillMouseActivity();
Mouse = CONFIRMING;
confirmState = CONFIRM_UNDO;
}
/*
* confirm a wish to resign
*/
void
ConfirmResignation()
{
Message("Sure you want to resign? - left yes, other no");
Mouse = CONFIRMING;
confirmState = CONFIRM_RESIGNATION;
}
/*
* board select() handler
*/
/*ARGSUSED*/
boardSelected(nullsw, ibits, obits, ebits, timer)
caddr_t * nullsw;
int * ibits, * obits, * ebits;
struct timeval ** timer;
{
static tickCount = 0;
static Move move;
static SetupChange setup;
struct inputevent ie;
struct pr_pos newMouseLoc;
Square * sqp;
long nbytes;
BOOL clamped;
int color, i;
struct pixrect * pr;
/*
* 1-second ticker. this cannot use SIGALRM, since the RPC
* package already has dibs on that signal for implementing timeouts.
* hence, it uses the subwindow select timeout mechanism.
* the ticker is used to flash the window every 5 seconds if
* there is some event the user hasn't seen yet (opening the
* tool window turns the flasher off).
*
* note - timeouts render the file descriptor masks undefined,
* so we clean up and return w/o checking them.
*/
if ((*timer)->tv_sec == 0L && (*timer)->tv_usec == 0L) {
if (Flashing) {
if (wmgr_iswindowopen(NchessTool->tl_windowfd)) {
tickCount = 0;
Flashing = FALSE;
} else if (tickCount-- <= 0
&& (pr = (struct pixrect *) tool_get_attribute(NchessTool,
WIN_ICON_IMAGE)) != (struct pixrect *) -1)
{
tickCount = 5;
pr_rop(pr, 0, 0, pr->pr_size.x, pr->pr_size.x,
PIX_NOT(PIX_SRC), pr, 0, 0);
tool_set_attributes(NchessTool, WIN_ICON_IMAGE, pr, 0);
pr_rop(pr, 0, 0, pr->pr_size.x, pr->pr_size.x,
PIX_NOT(PIX_SRC), pr, 0, 0);
tool_set_attributes(NchessTool, WIN_ICON_IMAGE, pr, 0);
tool_free_attribute(WIN_ICON_IMAGE, pr);
}
}
/* reset the timer and the file des. masks */
(*timer)->tv_sec = 1L;
(*timer)->tv_usec = 0L;
* ibits = svc_fds | BoardSWMask
| ChessProcessFDs[BLACK] | ChessProcessFDs[WHITE];
* obits = * ebits = 0;
return;
}
/*
* check for RPC service required
*/
if (*ibits & svc_fds) {
svc_getreq(*ibits & svc_fds);
}
/*
* check for machine move received
*
* note: it is possible in some circumstances to receive a move
* from a machine player after the game is over (for example,
* the opponent of the machine which is on move dies).
* in that event, we simply throw the move away.
*/
for (color = BLACK , i = 0 ; i < 2 ; color = WHITE , i++) {
if ((*ibits & ChessProcessFDs[color])
&& GetMachineMove(&move, color)
&& ! GameOver) {
BOOL updateMsgWindow = TRUE;
Flashing = TRUE;
DoMove(&move, TRUE);
Turn = OTHERCOLOR(Turn);
/*
* if we are trying to save a game of machine vs. machine,
* hold up sending the move until both machine states
* have been saved. when subsequently restoring the
* game, this move will be resubmitted.
*/
if (SaveWanted) {
SaveGame(SaveFileName);
SaveWanted = FALSE;
updateMsgWindow = FALSE;
}
/*
* if the player not moving is a machine, send the move
*/
if (IsMachine[OTHERCOLOR(color)]) {
SendMove(&move, OTHERCOLOR(color));
/*
* else if the player not moving is a human that wants an
* undo, back it out
*/
} else if (UndoWanted) {
MachineUndo(color);
UndoWanted = FALSE;
Mouse = IDLE;
}
if (updateMsgWindow)
WhoseMoveMessage((char *) 0);
}
}
/*
* check for board subwindow service required
*/
if (*ibits & BoardSWMask) {
if (input_readevent(BoardSW->ts_windowfd, &ie) == -1) {
perror("input failed");
abort();
}
switch (Mouse) {
/*
* locked: ignore all mouse activity
*/
case LOCKED:
break;
/*
* we are using the mouse to confirm something
*/
case CONFIRMING:
if (win_inputposevent(&ie)
&& ie.ie_code >= BUT_FIRST
&& ie.ie_code <= BUT_LAST) {
Mouse = IDLE;
switch(confirmState) {
case CONFIRM_RESIGNATION:
if (ie.ie_code == MS_LEFT) {
SendResignation(PeerColor);
Mouse = LOCKED; /* game is over */
DoResignation(MyColor);
Message("Resigned");
} else {
WhoseMoveMessage((char *) 0);
}
break;
case CONFIRM_SETUP_END:
if (ie.ie_code == MS_LEFT) {
/*
* if either player is a machine, white always moves
* first following a setup (another brain-damaged
* attribute of the unix chess program).
*/
if (IsMachine[WHITE] || IsMachine[BLACK]) {
BOOL legalSetup = TRUE;
Turn = WHITE;
if (IsMachine[BLACK]) {
legalSetup = MachineSetup(BLACK);
}
if (legalSetup && IsMachine[WHITE]) {
if (legalSetup = MachineSetup(WHITE))
MachineFirst(WHITE);
}
if ( ! legalSetup) {
Message("Illegal setup - try again");
Mouse = SETUP;
} else {
/*
* if both players are machines, the human part
* is over.
*/
if (IsMachine[BLACK] && IsMachine[WHITE])
Mouse = LOCKED;
/*
* else we get to play
*/
else
InitialTurn = WHITE;
WhoseMoveMessage((char *) 0);
SetupMode = FALSE;
}
/*
* else the opponent is a human, and we can specify
* who moves first.
*/
} else {
Message("Left button to move first, other to move second");
Mouse = CONFIRMING;
confirmState = CONFIRM_WHOSE_TURN;
SetupMode = FALSE;
}
} else {
Message("Setup: left - source, middle - delete, right - end");
Mouse = SETUP;
}
break;
case CONFIRM_WHOSE_TURN:
Turn = InitialTurn = (ie.ie_code == MS_LEFT ?
MyColor :
OTHERCOLOR(MyColor));
WhoseMoveMessage((char *) 0);
SendEndRestore();
break;
case CONFIRM_UNDO:
SendUndoAcknowledgement(ie.ie_code == MS_LEFT);
break;
}
}
break;
/*
* we are setting up an initial board layout
*/
case SETUP:
switch (ie.ie_code) {
/*
* generate and pick up a source piece
*/
case MS_LEFT:
if (win_inputposevent(&ie)) {
newMouseLoc.x = ie.ie_locx;
newMouseLoc.y = ie.ie_locy;
mapMouseToBoard(&newMouseLoc, &from);
/* if this a source square */
if (IsSrcPieceAt(&from)) {
Mouse = MOVING_PIECE;
sqp = GetSrcSquare(from.x, from.y);
setup.type = sqp->type;
setup.color = sqp->color;
/*
* create the first background pixrect,
* centered on the selected board square
*/
mapBoardToMouse(&from, &lastMouseLoc);
/* grab the currently displayed image */
pw_read(MoveFromPR,
0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC,
Board->gfx_pixwin,
lastMouseLoc.x - MOVE_X_OFFSET,
lastMouseLoc.y - MOVE_Y_OFFSET);
/* repaint the blank square */
pr_rop(MoveFromPR,
MOVE_X_OFFSET,
MOVE_Y_OFFSET,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC,
((from.x + from.y) & 0x01) ?
&BlackSquarePR :
&WhiteSquarePR,
0, 0);
/*
* remember the pixrect used to paint the piece
* being moved
*/
pieceIcon = PieceIcons[(int) sqp->type][sqp->color];
pieceStencil = PieceStencils[(int) sqp->type];
/*
* if there is a piece at the source square, repaint
* the piece on the background pixrect
*/
sqp = GetSquare(from.x, from.y);
if (sqp->type != NULLPC) {
pr_stencil(MoveFromPR,
MOVE_X_OFFSET,
MOVE_Y_OFFSET,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC,
PieceStencils[(int)sqp->type], 0, 0,
PieceIcons[(int) sqp->type][sqp->color], 0, 0);
}
}
}
break;
/*
* delete a piece
*/
case MS_MIDDLE:
if (win_inputposevent(&ie)) {
newMouseLoc.x = ie.ie_locx;
newMouseLoc.y = ie.ie_locy;
mapMouseToBoard(&newMouseLoc, &from);
setup.x = from.x;
setup.y = from.y;
setup.type = NULLPC;
DoSetupChange(&setup);
SendSetupChange(&setup, PeerColor);
}
break;
/*
* exit setup
*/
case MS_RIGHT:
if (win_inputposevent(&ie)) {
Message("Sure you want to end setup? left - yes, other - no");
Mouse = CONFIRMING;
confirmState = CONFIRM_SETUP_END;
}
break;
}
break;
/*
* we are promoting a pawn
*/
case PROMOTING_PAWN:
switch(ie.ie_code) {
/*
* select the next pawn morph
*/
case MS_LEFT:
if (win_inputposevent(&ie))
move.newPieceType = PromotePawn(&to);
break;
/*
* go for the current morph
*/
case MS_MIDDLE:
if (win_inputposevent(&ie) && SendMove(&move, PeerColor)) {
Turn = OTHERCOLOR(Turn);
WhoseMoveMessage((char *) 0);
Mouse = IDLE;
}
break;
/*
* we exited the window - back out the pawn move
*/
case LOC_WINEXIT:
UnDoMove();
Mouse = IDLE;
break;
}
break;
/*
* we aren't currently doing anything
*/
case IDLE:
switch(ie.ie_code) {
case MS_LEFT:
/*
* if this a left button press
* and it is our turn
* and we aren't waiting for an undo acknowledgement
*/
if (win_inputposevent(&ie) && Turn == MyColor && ! UndoWanted) {
newMouseLoc.x = ie.ie_locx;
newMouseLoc.y = ie.ie_locy;
mapMouseToBoard(&newMouseLoc, &from);
/*
* if there is one of our pieces on this square
*/
if (IsOurPieceAt(&from)) {
Mouse = MOVING_PIECE;
sqp = GetSquare(from.x, from.y);
/*
* create the first background pixrect,
* centered on the selected board square
*/
mapBoardToMouse(&from, &lastMouseLoc);
/* grab the currently displayed image */
pw_read(MoveFromPR,
0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC,
Board->gfx_pixwin,
lastMouseLoc.x - MOVE_X_OFFSET,
lastMouseLoc.y - MOVE_Y_OFFSET);
/* repaint the blank square */
pr_rop(MoveFromPR,
MOVE_X_OFFSET,
MOVE_Y_OFFSET,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC,
((from.x + from.y) & 0x01) ?
&BlackSquarePR :
&WhiteSquarePR,
0, 0);
/*
* remember the pixrect used to paint the piece
* being moved
*/
pieceIcon = PieceIcons[(int) sqp->type][sqp->color];
pieceStencil = PieceStencils[(int) sqp->type];
/*
* a bit un-structured, but we are forced to do this
* if we want the piece to "jump" to the cursor when
* the button is initially depressed ("forced" in the
* sense that we are inside a switch statement).
*/
goto moveIt;
}
}
break;
}
break;
/*
* we are animating a piece
*/
case MOVING_PIECE:
switch(ie.ie_code) {
case MS_LEFT:
/*
* if we are putting down a piece
*/
if (win_inputnegevent(&ie)) {
BOOL legal;
Mouse = IDLE;
newMouseLoc.x = ie.ie_locx;
newMouseLoc.y = ie.ie_locy;
mapMouseToBoard(&newMouseLoc, &to);
legal = TRUE;
move.x1 = from.x; move.y1 = from.y;
move.x2 = to.x; move.y2 = to.y;
if (SetupMode) {
/* repaint the background */
pw_rop(Board->gfx_pixwin,
lastMouseLoc.x - MOVE_X_OFFSET,
lastMouseLoc.y - MOVE_Y_OFFSET,
MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, MoveFromPR, 0, 0);
/* put the piece down no matter what */
setup.x = to.x;
setup.y = to.y;
DoSetupChange(&setup);
SendSetupChange(&setup, PeerColor);
Mouse = SETUP;
} else if ( ! (from.x == to.x && from.y == to.y)
&& Turn == MyColor
&& (legal = IsMoveLegal(&from, &to))) {
/* if this is a pawn promotion */
if (GetSquare(from.x, from.y)->type == PAWN
&& (to.y == 0 || to.y == 7)) {
/* repaint the background */
pw_rop(Board->gfx_pixwin,
lastMouseLoc.x - MOVE_X_OFFSET,
lastMouseLoc.y - MOVE_Y_OFFSET,
MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, MoveFromPR, 0, 0);
move.newPieceType = (int) QUEEN;
DoMove(&move, TRUE);
/* if we are playing the brain-damaged unix chess
* program, can only promote to queens */
if (IsMachine[OTHERCOLOR(MyColor)]) {
Turn = OTHERCOLOR(Turn);
SendMove(&move, PeerColor);
WhoseMoveMessage((char *) 0);
/* else need to have the user select the promoted
* piece type */
} else {
Message("Left button: select piece type, middle: send move.");
Mouse = PROMOTING_PAWN;
}
/* else if we can send the move */
} else if (SendMove(&move, PeerColor)) {
/* repaint the background */
pw_rop(Board->gfx_pixwin,
lastMouseLoc.x - MOVE_X_OFFSET,
lastMouseLoc.y - MOVE_Y_OFFSET,
MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, MoveFromPR, 0, 0);
DoMove(&move, TRUE);
Turn = OTHERCOLOR(Turn);
WhoseMoveMessage((char *) 0);
/* else the peer is dead */
} else {
/* repaint the background */
pw_rop(Board->gfx_pixwin,
lastMouseLoc.x - MOVE_X_OFFSET,
lastMouseLoc.y - MOVE_Y_OFFSET,
MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, MoveFromPR, 0, 0);
putPieceBack(&from, pieceStencil, pieceIcon);
}
} else {
/* repaint the background */
pw_rop(Board->gfx_pixwin,
lastMouseLoc.x - MOVE_X_OFFSET,
lastMouseLoc.y - MOVE_Y_OFFSET,
MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, MoveFromPR, 0, 0);
putPieceBack(&from, pieceStencil, pieceIcon);
if ( ! legal)
Message("Illegal move");
}
}
break;
/*
* exited the window - clean it up.
*/
case LOC_WINEXIT:
/* repaint the background */
pw_rop(Board->gfx_pixwin,
lastMouseLoc.x - MOVE_X_OFFSET,
lastMouseLoc.y - MOVE_Y_OFFSET,
MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, MoveFromPR, 0, 0);
if (SetupMode) {
Mouse = SETUP;
} else {
putPieceBack(&from, pieceStencil, pieceIcon);
Mouse = IDLE;
}
break;
/*
* animate the piece
*/
case LOC_MOVEWHILEBUTDOWN:
moveIt:
/* ignore old motion events */
ioctl(Board->gfx_windowfd, (int) FIONREAD, (char *) &nbytes);
if (nbytes/sizeof(struct inputevent) <= 3) {
do {
newMouseLoc.x = ie.ie_locx - SQUARE_WIDTH/2;
newMouseLoc.y = ie.ie_locy - SQUARE_HEIGHT/2;
clamped = FALSE;
/*
* clamp motion if necessary
*/
if (newMouseLoc.x - lastMouseLoc.x >= MOVE_X_OFFSET) {
newMouseLoc.x = lastMouseLoc.x + (MOVE_X_OFFSET-1);
clamped = TRUE;
} else if (newMouseLoc.x - lastMouseLoc.x <= - MOVE_X_OFFSET) {
newMouseLoc.x = lastMouseLoc.x - (MOVE_X_OFFSET-1);
clamped = TRUE;
}
if (newMouseLoc.y - lastMouseLoc.y >= MOVE_Y_OFFSET) {
newMouseLoc.y = lastMouseLoc.y + (MOVE_Y_OFFSET-1);
clamped = TRUE;
} else if (newMouseLoc.y - lastMouseLoc.y <= - MOVE_Y_OFFSET) {
newMouseLoc.y = lastMouseLoc.y - (MOVE_Y_OFFSET-1);
clamped = TRUE;
}
/* grab the new area */
pw_read(MoveToPR,
0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, Board->gfx_pixwin,
newMouseLoc.x - MOVE_X_OFFSET,
newMouseLoc.y - MOVE_Y_OFFSET);
/* paste the old background over the new area */
pr_rop(MoveToPR,
lastMouseLoc.x - newMouseLoc.x,
lastMouseLoc.y - newMouseLoc.y,
MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, MoveFromPR, 0, 0);
/* save the new background */
pr_rop(MoveFromPR, 0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, MoveToPR, 0, 0);
/* paint the piece on the new area */
pr_stencil(MoveToPR,
MOVE_X_OFFSET, MOVE_Y_OFFSET,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC, pieceStencil, 0, 0, pieceIcon, 0, 0);
/* now paint the new area on the screen */
pw_rop(Board->gfx_pixwin,
newMouseLoc.x - MOVE_X_OFFSET,
newMouseLoc.y - MOVE_Y_OFFSET,
MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
PIX_SRC, MoveToPR, 0, 0);
lastMouseLoc.x = newMouseLoc.x;
lastMouseLoc.y = newMouseLoc.y;
} while (clamped);
}
break;
}
break;
}
}
* ibits = svc_fds | BoardSWMask | ChessProcessFDs[BLACK] | ChessProcessFDs[WHITE];
* obits = * ebits = 0;
}
/*
* initialize the board subwindow
*/
void
InitBoardSW(useRetained, iconDirectory)
BOOL useRetained; /* use a retained pixrect */
char * iconDirectory; /* custom piece icon directory */
{
static struct timeval tickValue;
struct inputmask mask;
register unsigned int i;
int height = (SQUARE_HEIGHT-1) * 8 + ((7 * SQUARE_HEIGHT)/4) + 10;
/*
* initialize the subwindow
*/
if ((BoardSW = gfxsw_createtoolsubwindow(NchessTool, "",
TOOL_SWEXTENDTOEDGE,
/* playing surface + victim area */
/* (SQUARE_HEIGHT-1) * 8 + ((7 * SQUARE_HEIGHT)/4) + 10, */
height,
NULL)) == NULL)
{
fprintf(stderr, "Can't create board subwindow\n");
exit(1);
}
Board = (struct gfxsubwindow *) BoardSW->ts_data;
if (useRetained)
gfxsw_getretained(Board);
BoardSW->ts_io.tio_handlesigwinch = boardSigwinch;
BoardSW->ts_io.tio_selected = boardSelected;
input_imnull(&mask);
win_setinputcodebit(&mask, MS_LEFT);
win_setinputcodebit(&mask, MS_MIDDLE);
win_setinputcodebit(&mask, MS_RIGHT);
win_setinputcodebit(&mask, LOC_MOVEWHILEBUTDOWN);
win_setinputcodebit(&mask, LOC_WINEXIT);
mask.im_flags |= IM_NEGEVENT;
win_setinputmask(BoardSW->ts_windowfd, &mask, NULL, WIN_NULLLINK);
/*
* add the RPC service and chess process file descriptor select
* masks to this subwindow.
*/
BoardSW->ts_io.tio_inputmask = svc_fds
| (BoardSWMask = 1 << BoardSW->ts_windowfd)
| ChessProcessFDs[BLACK]
| ChessProcessFDs[WHITE] ;
/*
* set the timeout to 1 second
*/
tickValue.tv_sec = 1L;
tickValue.tv_usec = 0L;
BoardSW->ts_io.tio_timer = &tickValue;
/*
* create the white pieces by inverting the black pieces, using custom
* pieces where appropriate.
*/
for ( i = 0 ; i < 6 ; i++ ) {
if (iconDirectory != (char *) 0) {
FILE * iconFile, * stencilFile;
icon_header_object iconHeader, stencilHeader;
char fileName[512], errorMsg[IL_ERRORMSG_SIZE + 2];
strcpy(fileName, iconDirectory);
strcat(fileName, "/");
strcat(fileName, PieceIconFileNames[i]);
if ((iconFile = icon_open_header(fileName, errorMsg,
&iconHeader)) != (FILE *) 0)
{
if (iconHeader.width != SQUARE_WIDTH
|| iconHeader.height != SQUARE_HEIGHT
|| iconHeader.depth != 1) {
fprintf(stderr, "warning: bogus icon (ignored): %s\n", fileName);
} else {
strcpy(fileName, iconDirectory);
strcat(fileName, "/");
strcat(fileName, PieceStencilFileNames[i]);
if ((stencilFile = icon_open_header(fileName, errorMsg,
&stencilHeader)) != (FILE *) 0)
{
if (stencilHeader.width != SQUARE_WIDTH
|| stencilHeader.height != SQUARE_HEIGHT
|| stencilHeader.depth != 1) {
fprintf(stderr, "warning: bogus icon (ignored): %s\n", fileName);
} else {
icon_read_pr(iconFile, &iconHeader, PieceIcons[i][BLACK]);
icon_read_pr(stencilFile, &stencilHeader, PieceStencils[i]);
}
fclose(stencilFile);
}
}
fclose(iconFile);
}
}
pr_rop(PieceIcons[i][WHITE], 0, 0, SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_NOT(PIX_SRC),
PieceIcons[i][BLACK], 0, 0);
}
/*
* create the pixrects used for piece animation and victim drawing
*/
if ((MoveFromPR = mem_create(MOVE_PR_WIDTH, MOVE_PR_HEIGHT, 1)) == (struct pixrect *) 0
|| (MoveToPR = mem_create(MOVE_PR_WIDTH, MOVE_PR_HEIGHT, 1)) == (struct pixrect *) 0
|| (VictimPR = mem_create(SQUARE_WIDTH, SQUARE_HEIGHT, 1)) == (struct pixrect *) 0) {
fprintf(stderr, "can't create the animation pixrects\n");
exit(1);
}
}
/*
* draw a square, including the piece (if any)
*/
void
DrawSquare(x, y, sqp)
int x, y;
register Square * sqp;
{
BoardCoordinate bloc;
struct pr_pos mloc;
bloc.x = x; bloc.y = y;
mapBoardToMouse(&bloc, &mloc);
/* paint the blank square */
pw_rop(Board->gfx_pixwin,
mloc.x, mloc.y,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC,
(((x + y) & 0x01) ? &BlackSquarePR : &WhiteSquarePR),
0, 0);
/* paint the piece, if there is one */
if (sqp->type != NULLPC) {
pw_stencil(Board->gfx_pixwin, mloc.x, mloc.y,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC,
PieceStencils[(int) sqp->type], 0, 0,
PieceIcons[(int) sqp->type][sqp->color], 0, 0);
}
}
/*
* draw the playing surface and victim area
*/
void
DrawBoard()
{
register int x, y;
register Square * sqp;
/* clear the board area */
pw_rop(Board->gfx_pixwin,
0, 0, Board->gfx_rect.r_width, Board->gfx_rect.r_height,
PIX_CLR, (struct pixrect *) 0, 0, 0);
/* draw the playing area */
for (x = 0 ; x < 8 ; x++) {
for (y = 0 ; y < 8 ; y++) {
sqp = GetSquare(x, y);
DrawSquare(x, y, sqp);
}
}
/* draw the victims */
drawVictims();
}
/*
* your basic victim
*/
typedef struct {
PieceType type; /* victim type */
BOOL active; /* victim slot state */
int count; /* victim overflow count */
} Victim;
#define NUM_VICTIM_SLOTS 8
Victim victims[2 /* pawns(1) vs. pieces(0) */][2 /* color */ ][NUM_VICTIM_SLOTS /* victim slot # */];
/*
* map the victim specified by the triple
* [ isPawn { 0, 1 }, color { BLACK, WHITE }, slot { 0 .. NUM_VICTIM_SLOTS-1 } ]
* to a mouse coordinate (relative to the board subwindow)
*/
void
mapVictimToMouse(isPawn, color, slot, mlocp)
BOOL isPawn;
int color, slot;
struct pr_pos * mlocp;
{
mlocp->x = slot * (3 * SQUARE_WIDTH/4) + color * (3 * SQUARE_WIDTH/8);
mlocp->y = 8 * (SQUARE_HEIGHT-1) + isPawn * (SQUARE_HEIGHT/2) + color * (SQUARE_HEIGHT/4) + 5;
}
/*
* draw the victims
*/
drawVictims()
{
register int i, j, k;
register Victim * victim;
struct pr_pos victimOrigin;
for (i = 0 ; i < 2 ; i++) {
for (j = 0 ; j < 2 ; j++) {
for (k = 0 ; k < NUM_VICTIM_SLOTS ; k++) {
victim = &victims[i][j][k];
if (victim->active) {
mapVictimToMouse(i, j, k, &victimOrigin);
pw_stencil(Board->gfx_pixwin,
victimOrigin.x, victimOrigin.y,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC,
PieceStencils[(int) victim->type], 0, 0,
PieceIcons[(int) victim->type][j], 0, 0);
}
}
}
}
}
/*
* add a piece to the set of victims
*/
void
AddVictim(type, color, drawIt)
PieceType type;
int color;
BOOL drawIt;
{
register int i, j, k;
int empty, lastMatch, extras;
register Victim * victim;
BOOL isPawn = (type == PAWN);
struct pr_pos victimOrigin, othersOrigin;
/*
* look for the first empty slot and the last slot which
* contains a piece of the same type
*/
for (lastMatch = empty = -1 , i = 0 ; i < NUM_VICTIM_SLOTS ; i++) {
victim = &victims[isPawn][color][i];
if (empty < 0 && ! victim->active)
empty = i;
if (victim->active && victim->type == type)
lastMatch = i;
}
/*
* if there were no empty slots
*/
if (empty == -1) {
/*
* if there was one or more pieces of the same type, update
* the last instance's overflow count (includes coalescing
* all overflows of that type at the last instance)
*/
if (lastMatch >= 0) {
for (extras = i = 0 ; i < lastMatch ; i++) {
victim = &victims[isPawn][color][i];
if (victim->active && victim->type == type && victim->count > 1) {
extras += victim->count - 1;
victim->count = 1;
}
}
victims[isPawn][color][lastMatch].count += extras;
}
/*
* else install the victim in the empty slot
*/
} else {
victim = &victims[isPawn][color][empty];
victim->type = type;
victim->active = TRUE;
victim->count = 1;
if (drawIt) {
/*
* re-draw all the pieces in the victim's slot
*/
mapVictimToMouse(isPawn, color, empty, &victimOrigin);
pr_rop(VictimPR, 0, 0, SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_CLR, (struct pixrect *) 0, 0, 0);
for (i = 0 ; i < 2 ; i++) {
for (j = 0 ; j < 2 ; j++) {
for (k = 0 ; k < NUM_VICTIM_SLOTS ; k++) {
victim = &victims[i][j][k];
if (victim->active) {
mapVictimToMouse(i, j, k, &othersOrigin);
pr_stencil(VictimPR,
othersOrigin.x - victimOrigin.x,
othersOrigin.y - victimOrigin.y,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC,
PieceStencils[(int) victim->type], 0, 0,
PieceIcons[(int) victim->type][j], 0, 0);
}
}
}
}
/*
* now re-draw the slot
*/
pw_rop(Board->gfx_pixwin,
victimOrigin.x, victimOrigin.y,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC, VictimPR, 0, 0);
}
}
}
/*
* reincarnate a victim (via an undo)
*/
void
DeleteVictim(type, color)
PieceType type;
int color;
{
register int i, j, k;
int lastMatch, extras;
register Victim * victim;
BOOL isPawn = (type == PAWN);
struct pr_pos victimOrigin, othersOrigin;
/*
* look for the last slot which contains a piece of this type
*/
for (lastMatch = -1 , i = 0 ; i < NUM_VICTIM_SLOTS ; i++) {
victim = &victims[isPawn][color][i];
if (victim->active && victim->type == type)
lastMatch = i;
}
/*
* if there were no matches, don't do anything
*/
if (lastMatch == -1) {
/* do nothing */
/*
* else if the last match slot contains overflows, simply
* decrement the overflow count
*/
} else if ((victim = &victims[isPawn][color][lastMatch])->count > 1) {
victim->count--;
/*
* else zero out the slot and re-draw it as empty
*/
} else {
victim->active = FALSE;
/*
* re-draw all the remaining pieces in the victim's slot
*/
mapVictimToMouse(isPawn, color, lastMatch, &victimOrigin);
pr_rop(VictimPR, 0, 0, SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_CLR, (struct pixrect *) 0, 0, 0);
for (i = 0 ; i < 2 ; i++) {
for (j = 0 ; j < 2 ; j++) {
for (k = 0 ; k < NUM_VICTIM_SLOTS ; k++) {
victim = &victims[i][j][k];
if (victim->active) {
mapVictimToMouse(i, j, k, &othersOrigin);
pr_stencil(VictimPR,
othersOrigin.x - victimOrigin.x,
othersOrigin.y - victimOrigin.y,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC,
PieceStencils[(int) victim->type], 0, 0,
PieceIcons[(int) victim->type][j], 0, 0);
}
}
}
}
/*
* now re-draw the slot
*/
pw_rop(Board->gfx_pixwin,
victimOrigin.x, victimOrigin.y,
SQUARE_WIDTH, SQUARE_HEIGHT,
PIX_SRC, VictimPR, 0, 0);
}
}
@//E*O*F boardsw.c//
chmod u=r,g=r,o=r boardsw.c
echo x - msgsw.c
sed 's/^@//' > "msgsw.c" <<'@//E*O*F msgsw.c//'
/*
* message subwindow handling
*/
#include <stdio.h>
#include <ctype.h>
#include <suntool/tool_hs.h>
#include <suntool/panel.h>
#include <strings.h>
#include "nchess.h"
struct toolsw * MessageSW;
Panel MessagePanel;
Panel_item MessageItem;
/*
* set up the message subwindow
*/
void
InitMsgSW()
{
if ((MessageSW = panel_create(NchessTool, 0)) == NULL) {
fprintf(stderr, "Can't create message panel\n");
exit(1);
}
MessagePanel = MessageSW->ts_data;
/* create the message panel item */
MessageItem = panel_create_item(MessagePanel, PANEL_MESSAGE,
PANEL_LABEL_STRING,
RestoringGame ? "Please wait..." :
SetupMode ? "Setup: left - source, middle - delete, right - end" :
IsMachine[Turn] || Turn != MyColor ?
(Turn == WHITE ?
"Waiting for white to play..." :
"Waiting for black to play...") :
"Your move" ,
PANEL_SHOW_ITEM, TRUE,
0);
panel_fit_height(MessagePanel);
}
void
Message(cp)
char * cp;
{
panel_set(MessageItem,
PANEL_LABEL_STRING, cp,
PANEL_SHOW_ITEM, TRUE,
0);
}
/*
* write the standard "your move", "waiting ..." message
* pre-pended with the passed string (if non-null)
*/
void
WhoseMoveMessage(cp)
char * cp;
{
char c1[256], c2[256];
if (GameOver)
strcpy(c2, "Game over");
else if (IsMachine[Turn] || Turn != MyColor)
strcpy(c2, Turn == WHITE ?
"Waiting for white to play..." :
"Waiting for black to play...");
else if (InCheck())
strcpy(c2, "Your move (check)");
else
strcpy(c2, "Your move");
if (cp != (char *) 0) {
c2[0] = tolower(c2[0]);
strcpy(c1, cp);
strcat(c1, " - ");
Message(strcat(c1, c2));
} else
Message(c2);
}
@//E*O*F msgsw.c//
chmod u=r,g=r,o=r msgsw.c
echo x - talksw.c
sed 's/^@//' > "talksw.c" <<'@//E*O*F talksw.c//'
/*
* talk subwindow handling
*/
#include <stdio.h>
#include <suntool/tool_hs.h>
#include <suntool/panel.h>
#include <strings.h>
#include "nchess.h"
#define MAX_SEND_LENGTH 60
struct toolsw * TalkSW;
Panel TalkPanel;
Panel_item SendItem;
Panel_item RecvItem;
/*ARGSUSED*/
sendProc(item, event)
Panel_item item;
struct inputevent *event;
{
char c[MAX_SEND_LENGTH+1];
strcpy(c, (char *) panel_get_value(SendItem));
SendTalkMsg(c);
/* set the command text to nil */
panel_set_value(SendItem, "");
}
/*
* set up the talk send and receive subwindows
* (if we are playing against the machine, leave them out)
*/
void
InitTalkSW()
{
if (IsMachine[PeerColor])
return;
if ((TalkSW = panel_create(NchessTool, 0)) == NULL) {
fprintf(stderr, "Can't create talk subwindows\n");
exit(1);
}
TalkPanel = TalkSW->ts_data;
RecvItem = panel_create_item(TalkPanel, PANEL_MESSAGE,
PANEL_LABEL_STRING, "Recv:",
PANEL_SHOW_ITEM, TRUE,
0);
SendItem = panel_create_item(TalkPanel, PANEL_TEXT,
PANEL_LABEL_STRING, "Send:",
PANEL_NOTIFY_STRING, "\n\r",
PANEL_NOTIFY_LEVEL, PANEL_SPECIFIED,
PANEL_NOTIFY_PROC, sendProc,
PANEL_VALUE_STORED_LENGTH, MAX_SEND_LENGTH,
0);
panel_fit_height(TalkPanel);
}
/*
* receive a pithy banality from the opponent
*/
void
RecvTalkMsg(cp)
char *cp;
{
char ncp[128];
strcpy(ncp, "Recv: ");
panel_set(RecvItem,
PANEL_LABEL_STRING, strcat(ncp, cp),
0);
}
@//E*O*F talksw.c//
chmod u=r,g=r,o=r talksw.c
echo x - chessprocess.c
sed 's/^@//' > "chessprocess.c" <<'@//E*O*F chessprocess.c//'
/*
* manage one or two chess game processes
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
#include "nchess.h"
extern char * gets();
int ChessPid[2],
ChessProcessFDs[2];
FILE * ReadChessProcess[2], * WriteChessProcess[2];
BOOL SigChildInterceptOn = FALSE;
BOOL MachineDebug = FALSE;
char * colorStrings[] = { "black", "white" };
/*
* intercept SIGCHLD
*
* print a message for the first chess process that dies and abort the
* game. (note: any change in child status is interpreted as death).
*/
handleSigChild()
{
int pid;
union wait status;
while(1) {
pid = wait3(&status, WNOHANG, (struct rusage *) 0);
if (pid <= 0)
return;
if ( ! GameOver && (pid == ChessPid[BLACK] || pid == ChessPid[WHITE])) {
Message (pid == ChessPid[WHITE] ?
"White's process died" :
"Black's process died" );
KillMouseActivity();
GameOver = TRUE;
Mouse = LOCKED;
}
}
}
/*
* have a chess process make the first move.
*
* note: with the wonderful unix chess program, "first" also implies
* playing the white pieces. nonetheless, color is an argument to this
* function in case we ever find out how to get around this problem.
*/
void
MachineFirst(color)
int color;
{
fputs("first\n", WriteChessProcess[color]);
fflush(WriteChessProcess[color]);
if (MachineDebug)
fprintf(stderr, "sent to %s: first\n", colorStrings[color]);
}
/*
* open a pipe to a chess game process
*
* startIt indicates whether the process should be sent the "first"
* command.
*/
void
InitChessProcess(cp, color, startIt)
char ** cp;
int color;
BOOL startIt;
{
int sv[2];
char c[128];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
fputs("socketpair failed\n", stderr);
exit(1);
}
if ((ChessPid[color] = fork()) == 0) {
dup2(sv[0], 0);
dup2(sv[0], 1);
chdir("/tmp"); /* so that "chess.out" can always be written */
execvp(cp[0], cp);
puts("exec");
fflush(stdout);
_exit(1);
}
/* dup2(sv[1], 0);
dup2(sv[1], 1); */
/* want to intercept SIGCHLD */
if ( ! SigChildInterceptOn) {
SigChildInterceptOn = TRUE;
signal(SIGCHLD, handleSigChild);
}
ChessProcessFDs[color] = (1 << sv[1]);
ReadChessProcess[color] = fdopen(sv[1], "r");
WriteChessProcess[color] = fdopen(sv[1], "w");
setbuf(ReadChessProcess[color], (char *) 0);
/*
* eat the "Chess" prompt
* note: if the child's exec failed,
* catch the "exec" prompt and give up
*/
fgets(c, sizeof(c), ReadChessProcess[color]);
if (strcmp(c, "exec\n") == 0) {
KillChessProcesses();
fprintf(stderr, "exec of %s failed\n", cp[0]);
exit(1);
}
/* set algebraic notation mode */
fputs("alg\n", WriteChessProcess[color]);
fflush(WriteChessProcess[color]);
if (MachineDebug)
fprintf(stderr, "sent to %s: alg\n", colorStrings[color]);
if (startIt)
MachineFirst(color);
}
/*
* reap one or more chess process
*/
void
ReapChessProcesses()
{
union wait status;
while (wait3(&status, WNOHANG, (struct rusage *) 0) >= 0)
;
}
/*
* kill any and all chess processes
*/
void
KillChessProcesses()
{
signal(SIGCHLD, SIG_IGN);
if (ChessPid[BLACK])
kill(ChessPid[BLACK], SIGKILL);
if (ChessPid[WHITE])
kill(ChessPid[WHITE], SIGKILL);
ReapChessProcesses();
}
/*
* get a move from a chess process
*
* return 1 if a move was successfully obtained, 0 if not.
*/
int
GetMachineMove(move, color)
Move * move;
int color;
{
char c[256], c2[256];
char file1, file2;
int rank1, rank2;
if (fgets(c, sizeof(c), ReadChessProcess[color]) == (char *) 0)
return(0);
if (MachineDebug)
fprintf(stderr, "rec'd from %s: %s", colorStrings[color], c);
/* look for special announcements */
if (strcmp(c, "Forced mate\n") == 0) {
Message(color == WHITE ?
"White announces forced mate" :
"Black announces forced mate");
return(0);
}
if (strcmp(c, "Resign\n") == 0) {
Message(color == WHITE ? "White resigns" : "Black resigns");
DoResignation(color);
Mouse = LOCKED;
return(0);
}
if (strcmp(c, "Illegal move\n") == 0) {
Message("Internal botch - illegal move detected");
return(0);
}
if (strncmp(c, "done", 4) == 0) {
return(0);
}
if (strncmp(c, "White wins", 10) == 0
|| strncmp(c, "Black wins", 10) == 0) {
c[10] = '\0';
Message(c);
GameOver = TRUE;
Mouse = LOCKED;
return(0);
}
/* e.g., 1. d2d4 */
if (sscanf(c, "%*d. %c%d%c%d", &file1, &rank1, &file2, &rank2) == 4
/* e.g., 1. ... d2d4 */
|| sscanf(c, "%*d. ... %c%d%c%d", &file1, &rank1, &file2, &rank2) == 4) {
move->x1 = file1 - (isupper(file1) ? 'A' : 'a');
move->y1 = 8 - rank1;
move->x2 = file2 - (isupper(file2) ? 'A' : 'a');
move->y2 = 8 - rank2;
/* TBD: possible non-queen pawn promotion
* (the existing chess program doesn't implement this) */
move->newPieceType = (int) QUEEN;
return(1);
} else {
strcpy(c2, color == WHITE ? "White announces: " : "Black announces: ");
Message(strncat(c2, c, sizeof(c2) - strlen(c2) - 2));
if (strncmp(c, "Draw", 4) == 0) {
GameOver = TRUE;
Mouse = LOCKED;
}
return(0);
}
}
/*
* send a move to a chess process
*
* note: if the process responds with a move too quickly, we won't
* get another select() trigger to get its move. thus, we need to
* check for the availability of a move when the echo is received.
*/
void
SendMachineMove(move, color)
Move * move;
int color;
{
char c[128];
if (move->x1 != move->x2
&& GetSquare(move->x1, move->y1)->type == PAWN
&& GetSquare(move->x2, move->y2)->type == NULLPC) {
/* re-encode en passant captures as horizontal moves */
fprintf(WriteChessProcess[color], "%c%d%c%d\n",
move->x1 + 'a', 8 - move->y1,
move->x2 + 'a', 8 - move->y1);
if (MachineDebug)
fprintf(stderr, "sent move to %s: %c%d%c%d\n",
colorStrings[color],
move->x1 + 'a', 8 - move->y1,
move->x2 + 'a', 8 - move->y1);
} else {
fprintf(WriteChessProcess[color], "%c%d%c%d\n",
move->x1 + 'a', 8 - move->y1,
move->x2 + 'a', 8 - move->y2);
if (MachineDebug)
fprintf(stderr, "sent move to %s: %c%d%c%d\n",
colorStrings[color],
move->x1 + 'a', 8 - move->y1,
move->x2 + 'a', 8 - move->y2);
}
fflush(WriteChessProcess[color]);
fgets(c, sizeof(c), ReadChessProcess[color]); /* eat the move echo */
if (MachineDebug)
fprintf(stderr, "rec'd from %s: %s", colorStrings[color], c);
}
/*
* undo the last machine move and our move
*/
void
MachineUndo(color)
{
fputs("remove\n", WriteChessProcess[color]);
fflush(WriteChessProcess[color]);
if (MachineDebug)
fprintf(stderr, "sent to %s: remove\n", colorStrings[color]);
UnDoMove();
UnDoMove();
}
/*
* set up the board
* (as noted above: with the existing unix chess program, there is no
* apparent way (short of deciphering the chess.out format, which is
* totally un-fun) to inform the chess program whose turn it is and
* which color it is supposed to play - it assumes that white always
* is the first to move.
*/
char whitePieceChars[] = { 'p', 'n', 'b', 'r', 'q', 'k', ' ' };
char blackPieceChars[] = { 'P', 'N', 'B', 'R', 'Q', 'K', ' ' };
/*
* set up a board state against the machine.
* returns TRUE if successful, FALSE otherwise
*/
BOOL
MachineSetup(color)
int color;
{
register int x, y;
Square * sqp;
char c[128];
fputs("setup\n", WriteChessProcess[color]);
if (MachineDebug)
fprintf(stderr, "sent to %s:\nsetup\n", colorStrings[color]);
for (y = 0 ; y < 8 ; y++) {
for (x = 0 ; x < 8 ; x++) {
sqp = GetSquare(x, y);
putc(sqp->color == WHITE ?
whitePieceChars[(int) sqp->type] :
blackPieceChars[(int) sqp->type],
WriteChessProcess[color]);
if (MachineDebug)
fputc(sqp->color == WHITE ?
whitePieceChars[(int) sqp->type] :
blackPieceChars[(int) sqp->type],
stderr);
}
putc('\n', WriteChessProcess[color]);
if (MachineDebug)
fputc('\n', stderr);
}
fflush(WriteChessProcess[color]);
fgets(c, sizeof(c), ReadChessProcess[color]);
if (MachineDebug)
fprintf(stderr, "rec'd from %s: %s", colorStrings[color], c);
return(strcmp(c, "Setup successful\n") == 0);
}
/*
* have a chess process save the game as "/tmp/chess.out".
* return the size of chess.out.
*/
int
MachineSave(color)
int color;
{
FILE * saveFile;
struct stat saveFileStatus;
int saveFileSize;
int retryCount = 0;
fputs("save\n", WriteChessProcess[color]);
fflush(WriteChessProcess[color]);
if (MachineDebug)
fprintf(stderr, "sent to %s: save\n", colorStrings[color]);
sleep((unsigned) 1);
/* wait for the chess process to create chess.out */
do {
if ((saveFile = fopen("/tmp/chess.out", "r")) == (FILE *) 0)
sleep((unsigned) 2);
} while(saveFile == (FILE *) 0 && ++retryCount < 10);
if (saveFile == (FILE *) 0) {
Message("Can't open chess.out!");
return(-1);
}
saveFileStatus.st_size = -1;
/* wait until chess.out stops growing */
do {
sleep((unsigned) 1);
saveFileSize = saveFileStatus.st_size;
fstat(fileno(saveFile), &saveFileStatus);
} while (saveFileSize != saveFileStatus.st_size);
fclose(saveFile);
return(saveFileSize);
}
/*
* restore the game
*/
void
MachineRestore(color)
int color;
{
fputs("restore\n", WriteChessProcess[color]);
fflush(WriteChessProcess[color]);
if (MachineDebug)
fprintf(stderr, "sent to %s: restore\n", colorStrings[color]);
}
@//E*O*F chessprocess.c//
chmod u=r,g=r,o=r chessprocess.c
echo Inspecting for damage in transit...
temp=/tmp/shar$$; dtemp=/tmp/.shar$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
1249 4199 34033 boardsw.c
83 217 1681 msgsw.c
74 154 1462 talksw.c
382 1283 9700 chessprocess.c
1788 5853 46876 total
!!!
wc boardsw.c msgsw.c talksw.c chessprocess.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0
Technical Details
Message-ID:
<260@spock.tc.fluke.COM>Path:
arc1-ca.pugleaf.net!utzoo!mnetor!seismo!lll-lcc!mordor!sri-spam!sri-unix!hplabs!pesnta!amd!intelca!mipos3!omepd!psu-cs!reed!tektronix!uw-beaver!fluke!tomaShow Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: arc1-ca.pugleaf.net!utzoo!mnetor!seismo!lll-lcc!mordor!sri-spam!sri-unix!hplabs!pesnta!amd!intelca!mipos3!omepd!psu-cs!reed!tektronix!uw-beaver!fluke!toma From: toma@tc.fluke.COM (Tom Anderson) Newsgroups: net.sources.games Subject: network chess (5 of 5) Message-ID: <260@spock.tc.fluke.COM> Date: Thu, 8-Jan-87 18:52:36 EST Article-I.D.: spock.260 Posted: Thu Jan 8 18:52:36 1987 Date-Received: Thu, 15-Jan-87 19:33:36 EST Organization: John Fluke Mfg. Co., Inc., Everett, WA Lines: 1831