Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: 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 # 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#include #include #include #include #include #include #include #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 #include #include #include #include #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 #include #include #include #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 #include #include #include #include #include #include #include #include #include #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