dbs@decwrl.dec.com (02/15/91)
Submitted-by: dbs@decwrl.dec.com Posting-number: Volume 11, Issue 73 Archive-name: xboard/part01 XBoard version 1.1 XBOARD is an X11/R4-based user interface for GNU Chess. It uses the R4 Athena widgets and Xt Intrinsics to provide an interactive referee for managing a chess game between a user and a computer opponent or between two computers. It manages a digital chess clock for each player and resets the clocks if time control is achieved within a given number of moves. A game can be started with the initial chess position, with a series of moves from a game file or with a position from a position file. The "match" shell script runs a series of games between two machines, alternating sides. The man page xboard.1 describes the features of xboard. XBOARD was written by Dan Sears and Chris Sears. XBOARD borrows its colors, icon and piece bitmaps from xchess which was written and copyrighted by Wayne Christopher. We thank him for his work on XChess. CAVEATS XBOARD depends on the R4 Xt Intrinsics and R4 Athena Widget Set. R3 won't do. GNU Chess is available via anonymous FTP from, among other sites, gatekeeper. gatekeeper.dec.com 16.1.0.2 pub/GNU/gnuchess-3.1.tar.Z It must be compiled with the -DCHESSTOOL option. CHANGES Version 1.1 -- Mon Jan 7 14:46:03 PST 1991 - Fixed a bug in HandleUserMove() where the user could make a move while the machine was thinking. The fix detects and ignores these moves. onMove was not being used and was removed. - Substantially rewrote and simplified the clock code. If a game was paused and then resumed, the clocks were out of sync. - Konstantinos Konstantinides added the -searchTime option. - Rewrote TwoMachinesPlay mode. - Rewrote DisplayClocks(). - Hal Peterson contributed a new Imakefile. - Added a declaration, xtVersion, which will quickly break on R3 Intrinsics. - For people who don't like or use chess clocks a clockMode switch has been added. It is on by default. It can be turned off in the .Xdefaults file with XBoard.clockMode: False - Detect if the visual doesn't support color. If so, run in monoMode. An alternative would be to detect grayscale visual and use a collection of gray user interface colors. - Works with gcc now. gcc complained about casting float constants as XtPointers. - Added keyboard equivalents. Added an iconify keystroke, C or c. - Added StrStr() because many systems don't have this ANSI function. - Substantially rewrote and simplified the Two Machine code. - The bitmaps have been pushed into the bitmaps directory. Tue Jan 8 16:23:22 PST 1991 - Fixed a bug where a player could play after a game had been finished. - Fixed a bug where hint didn't work. The local version of gnuchessr had been hacked. The fix was to clone stderr and stdout for gnuchessr. - Kayvan Sylvan <satyr!kayvan@apple.com> contributed a patch for ESIX. It seems that select() on pipes is broken on his system. We declined to incorporate his patch though, because it was a work-around for something that was broken on one system, and selfishly, that system was not my own. Nevertheless, it is likely that other System V users on PC's may need to use this patch and it is is included as the file ESIX.patch. To use it, type patch xboard.c ESIX.patch - Any button restarts a paused game. - Warning messages get displayed in the message box. - getlogin() does not work in all cases. It was replaced by getpwuid(getuid())->pw_name). - For systems with smaller screens, XBoard can use smaller pieces, and a smaller board. -bigSizeMode False uses a smaller set of pieces. These are scaled versions of the large pieces. They look ok but could be improved. - -iconic doesn't work properly. If XBoard is opened iconic then iconifying it later with a keystroke doesn't work. I think this is an Xt bug. - the remoteShell resource was added for HP-UX systems and other systems where the remoteShell isn't rsh. - older non-ANSI versions of Sun compilers complain vociferously. - Roger Dubar, Konstantinos Konstantinides, Wolfgang S. Rupprecht, Paul Scowen, Mvh Smidt and Kayvan Sylvan all helped immensely during beta-testing. #! /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 shell archive." # Contents: ./xboard.c # Wrapped by dbs@dbsmax.pa.dec.com on Sat Jan 26 14:47:31 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f './xboard.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./xboard.c'\" else echo shar: Extracting \"'./xboard.c'\" \(68496 characters\) sed "s/^X//" >'./xboard.c' <<'END_OF_FILE' X/* X * XBoard -- an Xt user interface for GNU Chess X * X * Dan Sears X * Chris Sears X * X * XBoard borrows its colors, icon and piece bitmaps from XChess X * which was written and is copyrighted by Wayne Christopher. X * X * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. X * X * All Rights Reserved X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, X * provided that the above copyright notice appear in all copies and that X * both that copyright notice and this permission notice appear in X * supporting documentation, and that the name of Digital not be X * used in advertising or publicity pertaining to distribution of the X * software without specific, written prior permission. X * X * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING X * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL X * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR X * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, X * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, X * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS X * SOFTWARE. X * X * Revision 1.0 90/10/31 X * Initial release. X * X * Revision 1.1 91/01/26 X * Major bug fix release. X */ X X#include <stdio.h> X#include <signal.h> X#include <pwd.h> X#include <X11/Intrinsic.h> X#include <X11/Shell.h> X#include <X11/Xaw/Form.h> X#include <X11/Xaw/List.h> X#include <X11/Xaw/Label.h> X#include <X11/StringDefs.h> X#include <X11/cursorfont.h> X#include "xboard.h" X X#include "bitmaps/solid_pawn.bitmap" X#include "bitmaps/solid_rook.bitmap" X#include "bitmaps/solid_knight.bitmap" X#include "bitmaps/solid_bishop.bitmap" X#include "bitmaps/solid_queen.bitmap" X#include "bitmaps/solid_king.bitmap" X X#include "bitmaps/outline_pawn.bitmap" X#include "bitmaps/outline_rook.bitmap" X#include "bitmaps/outline_knight.bitmap" X#include "bitmaps/outline_bishop.bitmap" X#include "bitmaps/outline_queen.bitmap" X#include "bitmaps/outline_king.bitmap" X X#include "bitmaps/pawn_small.bitmap" X#include "bitmaps/rook_small.bitmap" X#include "bitmaps/knight_small.bitmap" X#include "bitmaps/bishop_small.bitmap" X#include "bitmaps/queen_small.bitmap" X#include "bitmaps/king_small.bitmap" X X#include "bitmaps/pawn_small_outline.bitmap" X#include "bitmaps/rook_small_outline.bitmap" X#include "bitmaps/knight_small_outline.bitmap" X#include "bitmaps/bishop_small_outline.bitmap" X#include "bitmaps/queen_small_outline.bitmap" X#include "bitmaps/king_small_outline.bitmap" X X#include "bitmaps/icon.bitmap" X X#ifdef __STDC__ void main(int argc, char **argv); void CreateGCs(void); void CreatePieces(void); void ReadBitmap(String name, Pixmap *pm, char big_bits[], char small_bits[]); void CreateGrid(void); int EventToSquare(int x); int CharToPiece(int c); void DrawSquare(int row, int column, int piece); void DrawPosition(Widget w, XExposeEvent *event); void InitPosition(void); void CopyBoard(Board to, Board from); void SendCurrentBoard(FILE *fp); void HandleUserMove(Widget w, XEvent *event); void HandleMachineMove(char *message); void ReadGameFile(void); void MakeMove(int *move_type, int from_x, int from_y, int to_x, int to_y); void InitChessProgram(char *host_name, char *program_name, int *pid, X FILE **to, FILE **from, XtIntervalId *xid); void ShutdownChessPrograms(char *message); void SelectCommand(Widget w, XtPointer client_data, XtPointer call_data); void QuitProc(void); int PlayFromGameFileProc(void); void MachinePlaysBlackProc(void); void ForwardProc(void); void ResetProc(void); int SetupPositionFromFileProc(void); void MachinePlaysWhiteProc(void); void BackwardProc(void); void FlipProc(void); void SaveGameProc(void); void SwitchProc(void); void ForceProc(void); void HintProc(void); void SavePositionProc(void); void TwoMachinesPlayProc(void); void PauseProc(void); void Iconify(void); void SendToProgram(char *message, FILE *fp); void ReceiveFromProgram(FILE *fp); void DisplayMessage(char *message); void DisplayClocks(int clock_mode); void DisplayTimerLabel(Widget w, char *color, time_t timer); char *TimeString(time_t tm); void CatchPipeSignal(void); void Usage(void); char *StrStr(char *string, char *match); X#else void main(); void CreateGCs(); void CreatePieces(); void ReadBitmap(); void CreateGrid(); int EventToSquare(); int CharToPiece(); void DrawSquare(); void DrawPosition(); void InitPosition(); void CopyBoard(); void SendCurrentBoard(); void HandleUserMove(); void HandleMachineMove(); void ReadGameFile(); void MakeMove(); void InitChessProgram(); void ShutdownChessPrograms(); void SelectCommand(); void QuitProc(); int PlayFromGameFileProc(); void MachinePlaysBlackProc(); void ForwardProc(); void ResetProc(); int SetupPositionFromFileProc(); void MachinePlaysWhiteProc(); void BackwardProc(); void FlipProc(); void SaveGameProc(); void SwitchProc(); void ForceProc(); void HintProc(); void SavePositionProc(); void TwoMachinesPlayProc(); void PauseProc(); void Iconify(); void SendToProgram(); void ReceiveFromProgram(); void DisplayMessage(); void DisplayClocks(); void DisplayTimerLabel(); char *TimeString(); void CatchPipeSignal(); void Usage(); char *StrStr(); X#endif X int xtVersion = XtSpecificationRelease; /* XBoard depends on Xt R4 or higher */ int xScreen; Display *xDisplay; Window xBoardWindow; GC lightSquareGC, darkSquareGC, lineGC, wdPieceGC, wlPieceGC, X bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC; Pixmap solidPawnBitmap, solidRookBitmap, solidKnightBitmap, solidBishopBitmap, X solidQueenBitmap, solidKingBitmap, outlinePawnBitmap, outlineRookBitmap, X outlineKnightBitmap, outlineBishopBitmap, outlineQueenBitmap, X outlineKingBitmap, iconPixmap; Widget shellWidget, formWidget, boardWidget, commandsWidget, messageWidget, X whiteTimerWidget, blackTimerWidget, widgetList[5]; XXSegment gridSegments[(BOARD_SIZE + 1) * 2]; XXtIntervalId firstProgramXID = NULL, secondProgramXID = NULL, X readGameXID = NULL, timerXID = NULL; XXFontStruct *labelFont; X XFILE *fromFirstProgFP, *toFirstProgFP, *fromSecondProgFP, X *toSecondProgFP, *gameFileFP; int currentMove = 0, firstMove = True, forwardMostMove = 0, flipView = False, X forwardForce = False, gameMode = BeginningOfGame, matchMode = MatchFalse, X firstProgramPID = 0, secondProgramPID = 0, squareSize = BIG_SQUARE_SIZE, X fromX = -1, fromY = -1, twoProgramState = False, X lastGameMode = BeginningOfGame; char moveList[MAX_MOVES][8]; time_t whiteTimeRemaining, blackTimeRemaining; X Board boards[MAX_MOVES], initialPosition = { X { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, X WhiteKing, WhiteBishop, WhiteKnight, WhiteRook }, X { WhitePawn, WhitePawn, WhitePawn, WhitePawn, X WhitePawn, WhitePawn, WhitePawn, WhitePawn }, X { EmptySquare, EmptySquare, EmptySquare, EmptySquare, X EmptySquare, EmptySquare, EmptySquare, EmptySquare }, X { EmptySquare, EmptySquare, EmptySquare, EmptySquare, X EmptySquare, EmptySquare, EmptySquare, EmptySquare }, X { EmptySquare, EmptySquare, EmptySquare, EmptySquare, X EmptySquare, EmptySquare, EmptySquare, EmptySquare }, X { EmptySquare, EmptySquare, EmptySquare, EmptySquare, X EmptySquare, EmptySquare, EmptySquare, EmptySquare }, X { BlackPawn, BlackPawn, BlackPawn, BlackPawn, X BlackPawn, BlackPawn, BlackPawn, BlackPawn }, X { BlackRook, BlackKnight, BlackBishop, BlackQueen, X BlackKing, BlackBishop, BlackKnight, BlackRook } X}; X String buttonStrings[] = { X "Quit", "Play From File", "Machine Black", "Forward", X "Reset", "Setup From File", "Machine White", "Backward", X "Flip View", "Save Game", "Switch Sides", "Force Moves", X "Hint", "Save Position", "Two Machines", "Pause" X}; X Arg shellArgs[] = { X { XtNwidth, 0 }, X { XtNheight, 0 }, X { XtNminWidth, 0 }, X { XtNminHeight, 0 }, X { XtNmaxWidth, 0 }, X { XtNmaxHeight, 0 } X}; X Arg boardArgs[] = { X { XtNborderWidth, 0 }, X { XtNwidth, LINE_GAP + BOARD_SIZE * (BIG_SQUARE_SIZE + LINE_GAP) }, X { XtNheight, LINE_GAP + BOARD_SIZE * (BIG_SQUARE_SIZE + LINE_GAP) } X}; X Arg commandsArgs[] = { X { XtNborderWidth, 0 }, X { XtNdefaultColumns, 4 }, X { XtNforceColumns, True }, X { XtNlist, (int) buttonStrings }, X { XtNnumberStrings, XtNumber(buttonStrings) } X}; X Arg messageArgs[] = { X { XtNborderWidth, 0 }, X { XtNwidth, 500 }, X { XtNjustify, XtJustifyLeft } X}; X Arg timerArgs[] = { X { XtNborderWidth, 0 }, X { XtNjustify, XtJustifyLeft } X}; X typedef struct { X Pixel whitePieceColor; X Pixel blackPieceColor; X Pixel lightSquareColor; X Pixel darkSquareColor; X int movesPerSession; X String initString; X String firstChessProgram; X String secondChessProgram; X String firstHost; X String secondHost; X String solidPawnBitmap; X String solidRookBitmap; X String solidBishopBitmap; X String solidKnightBitmap; X String solidQueenBitmap; X String solidKingBitmap; X String outlinePawnBitmap; X String outlineRookBitmap; X String outlineBishopBitmap; X String outlineKnightBitmap; X String outlineQueenBitmap; X String outlineKingBitmap; X String remoteShell; X float timeDelay; X int timeControl; X String saveGameFile; X String readGameFile; X String savePositionFile; X String readPositionFile; X String matchMode; X Boolean monoMode; X Boolean debugMode; X Boolean clockMode; X Boolean bigSizeMode; X int searchTime; X} AppData, *AppDataPtr; X AppData appData; X XXtResource clientResources[] = { X { X "whitePieceColor", "whitePieceColor", XtRPixel, sizeof(Pixel), X XtOffset(AppDataPtr, whitePieceColor), XtRString, WHITE_PIECE_COLOR X }, { X "blackPieceColor", "blackPieceColor", XtRPixel, sizeof(Pixel), X XtOffset(AppDataPtr, blackPieceColor), XtRString, BLACK_PIECE_COLOR X }, { X "lightSquareColor", "lightSquareColor", XtRPixel, sizeof(Pixel), X XtOffset(AppDataPtr, lightSquareColor), XtRString, LIGHT_SQUARE_COLOR X }, { X "darkSquareColor", "darkSquareColor", XtRPixel, sizeof(Pixel), X XtOffset(AppDataPtr, darkSquareColor), XtRString, DARK_SQUARE_COLOR X }, { X "movesPerSession", "movesPerSession", XtRInt, sizeof(int), X XtOffset(AppDataPtr, movesPerSession), XtRImmediate, X (XtPointer) MOVES_PER_SESSION X }, { X "initString", "initString", XtRString, sizeof(String), X XtOffset(AppDataPtr, initString), XtRString, INIT_STRING X }, { X "firstChessProgram", "firstChessProgram", XtRString, sizeof(String), X XtOffset(AppDataPtr, firstChessProgram), XtRString, FIRST_CHESS_PROGRAM X }, { X "secondChessProgram", "secondChessProgram", XtRString, sizeof(String), X XtOffset(AppDataPtr, secondChessProgram), XtRString, X SECOND_CHESS_PROGRAM X }, { X "firstHost", "firstHost", XtRString, sizeof(String), X XtOffset(AppDataPtr, firstHost), XtRString, FIRST_HOST X }, { X "secondHost", "secondHost", XtRString, sizeof(String), X XtOffset(AppDataPtr, secondHost), XtRString, SECOND_HOST X }, { X "solidPawnBitmap", "solidPawnBitmap", XtRString, sizeof(String), X XtOffset(AppDataPtr, solidPawnBitmap), XtRString, SOLID_PAWN_BITMAP X }, { X "solidRookBitmap", "solidRookBitmap", XtRString, sizeof(String), X XtOffset(AppDataPtr, solidRookBitmap), XtRString, SOLID_ROOK_BITMAP X }, { X "solidKnightBitmap", "solidKnightBitmap", XtRString, sizeof(String), X XtOffset(AppDataPtr, solidKnightBitmap), XtRString, SOLID_KNIGHT_BITMAP X }, { X "solidBishopBitmap", "solidBishopBitmap", XtRString, sizeof(String), X XtOffset(AppDataPtr, solidBishopBitmap), XtRString, SOLID_BISHOP_BITMAP X }, { X "solidQueenBitmap", "solidQueenBitmap", XtRString, sizeof(String), X XtOffset(AppDataPtr, solidQueenBitmap), XtRString, SOLID_QUEEN_BITMAP X }, { X "solidKingBitmap", "solidKingBitmap", XtRString, sizeof(String), X XtOffset(AppDataPtr, solidKingBitmap), XtRString, SOLID_KING_BITMAP X }, { X "outlinePawnBitmap", "outlinePawnBitmap", XtRString, sizeof(String), X XtOffset(AppDataPtr, outlinePawnBitmap), XtRString, OUTLINE_PAWN_BITMAP X }, { X "outlineRookBitmap", "outlineRookBitmap", XtRString, sizeof(String), X XtOffset(AppDataPtr, outlineRookBitmap), XtRString, OUTLINE_ROOK_BITMAP X }, { X "outlineKnightBitmap", "outlineKnightBitmap", XtRString, X sizeof(String), XtOffset(AppDataPtr, outlineKnightBitmap), XtRString, X OUTLINE_KNIGHT_BITMAP X }, { X "outlineBishopBitmap", "outlineBishopBitmap", XtRString, X sizeof(String), XtOffset(AppDataPtr, outlineBishopBitmap), XtRString, X OUTLINE_BISHOP_BITMAP X }, { X "outlineQueenBitmap", "outlineQueenBitmap", XtRString, sizeof(String), X XtOffset(AppDataPtr, outlineQueenBitmap), XtRString, X OUTLINE_QUEEN_BITMAP X }, { X "outlineKingBitmap", "outlineKingBitmap", XtRString, sizeof(String), X XtOffset(AppDataPtr, outlineKingBitmap), XtRString, OUTLINE_KING_BITMAP X }, { X "remoteShell", "remoteShell", XtRString, sizeof(String), X XtOffset(AppDataPtr, remoteShell), XtRString, "rsh" X }, { X "timeDelay", "timeDelay", XtRFloat, sizeof(float), X XtOffset(AppDataPtr, timeDelay), XtRString, (XtPointer) TIME_DELAY X }, { X "timeControl", "timeControl", XtRInt, sizeof(int), X XtOffset(AppDataPtr, timeControl), XtRImmediate, X (XtPointer) TIME_CONTROL X }, { X "saveGameFile", "saveGameFile", XtRString, sizeof(String), X XtOffset(AppDataPtr, saveGameFile), XtRString, SAVE_GAME_FILE X }, { X "readGameFile", "readGameFile", XtRString, sizeof(String), X XtOffset(AppDataPtr, readGameFile), XtRString, READ_GAME_FILE X }, { X "savePositionFile", "savePositionFile", XtRString, sizeof(String), X XtOffset(AppDataPtr, savePositionFile), XtRString, SAVE_POSITION_FILE X }, { X "readPositionFile", "readPositionFile", XtRString, sizeof(String), X XtOffset(AppDataPtr, readPositionFile), XtRString, READ_POSITION_FILE X }, { X "matchMode", "matchMode", XtRString, sizeof(String), X XtOffset(AppDataPtr, matchMode), XtRString, MATCH_MODE X }, { X "monoMode", "monoMode", XtRBoolean, sizeof(Boolean), X XtOffset(AppDataPtr, monoMode), XtRImmediate, (XtPointer) False X }, { X "debugMode", "debugMode", XtRBoolean, sizeof(Boolean), X XtOffset(AppDataPtr, debugMode), XtRImmediate, (XtPointer) False X }, { X "clockMode", "clockMode", XtRBoolean, sizeof(Boolean), X XtOffset(AppDataPtr, clockMode), XtRImmediate, (XtPointer) True X }, { X "bigSizeMode", "bigSizeMode", XtRBoolean, sizeof(Boolean), X XtOffset(AppDataPtr, bigSizeMode), XtRImmediate, (XtPointer) True X }, { X "searchTime","searchTime", XtRInt, sizeof(int), X XtOffset(AppDataPtr, searchTime), XtRImmediate, (XtPointer) TIME_SEARCH X } X}; X Pixmap *pieceToSolid[] = { X &solidPawnBitmap, &solidRookBitmap, &solidKnightBitmap, X &solidBishopBitmap, &solidQueenBitmap, &solidKingBitmap, X &solidPawnBitmap, &solidRookBitmap, &solidKnightBitmap, X &solidBishopBitmap, &solidQueenBitmap, &solidKingBitmap X}; X Pixmap *pieceToOutline[] = { X &outlinePawnBitmap, &outlineRookBitmap, &outlineKnightBitmap, X &outlineBishopBitmap, &outlineQueenBitmap, &outlineKingBitmap, X &outlinePawnBitmap, &outlineRookBitmap, &outlineKnightBitmap, X &outlineBishopBitmap, &outlineQueenBitmap, &outlineKingBitmap X}; X char pieceToChar[] = { X 'P', 'R', 'N', 'B', 'Q', 'K', X 'p', 'r', 'n', 'b', 'q', 'k', '.' X}; X XXrmOptionDescRec shellOptions[] = { X { "-whitePieceColor", "whitePieceColor", XrmoptionSepArg, NULL }, X { "-wpc", "whitePieceColor", XrmoptionSepArg, NULL }, X { "-blackPieceColor", "blackPieceColor", XrmoptionSepArg, NULL }, X { "-bpc", "blackPieceColor", XrmoptionSepArg, NULL }, X { "-lightSquareColor", "lightSquareColor", XrmoptionSepArg, NULL }, X { "-lsc", "lightSquareColor", XrmoptionSepArg, NULL }, X { "-darkSquareColor", "darkSquareColor", XrmoptionSepArg, NULL }, X { "-dsc", "darkSquareColor", XrmoptionSepArg, NULL }, X { "-movesPerSession", "movesPerSession", XrmoptionSepArg, NULL }, X { "-mps", "movesPerSession", XrmoptionSepArg, NULL }, X { "-initString", "initString", XrmoptionSepArg, NULL }, X { "-init", "initString", XrmoptionSepArg, NULL }, X { "-firstChessProgram", "firstChessProgram", XrmoptionSepArg, NULL }, X { "-fcp", "firstChessProgram", XrmoptionSepArg, NULL }, X { "-secondChessProgram", "secondChessProgram", XrmoptionSepArg, NULL }, X { "-scp", "secondChessProgram", XrmoptionSepArg, NULL }, X { "-firstHost", "firstHost", XrmoptionSepArg, NULL }, X { "-fh", "firstHost", XrmoptionSepArg, NULL }, X { "-secondHost", "secondHost", XrmoptionSepArg, NULL }, X { "-sh", "secondHost", XrmoptionSepArg, NULL }, X { "-solidPawnBitmap", "solidPawnBitmap", XrmoptionSepArg, NULL }, X { "-spb", "solidPawnBitmap", XrmoptionSepArg, NULL }, X { "-solidRookBitmap", "solidRookBitmap", XrmoptionSepArg, NULL }, X { "-srb", "solidRookBitmap", XrmoptionSepArg, NULL }, X { "-solidBishopBitmap", "solidBishopBitmap", XrmoptionSepArg, NULL }, X { "-sbb", "solidBishopBitmap", XrmoptionSepArg, NULL }, X { "-solidKnightBitmap", "solidKnightBitmap", XrmoptionSepArg, NULL }, X { "-skb", "solidKnightBitmap", XrmoptionSepArg, NULL }, X { "-solidQueenBitmap", "solidQueenBitmap", XrmoptionSepArg, NULL }, X { "-sqb", "solidQueenBitmap", XrmoptionSepArg, NULL }, X { "-solidKingBitmap", "solidKingBitmap", XrmoptionSepArg, NULL }, X { "-skb", "solidKingBitmap", XrmoptionSepArg, NULL }, X { "-outlinePawnBitmap", "outlinePawnBitmap", XrmoptionSepArg, NULL }, X { "-opb", "outlinePawnBitmap", XrmoptionSepArg, NULL }, X { "-outlineRookBitmap", "outlineRookBitmap", XrmoptionSepArg, NULL }, X { "-orb", "outlineRookBitmap", XrmoptionSepArg, NULL }, X { "-outlineBishopBitmap", "outlineBishopBitmap", XrmoptionSepArg, NULL }, X { "-obb", "outlineBishopBitmap", XrmoptionSepArg, NULL }, X { "-outlineKnightBitmap", "outlineKnightBitmap", XrmoptionSepArg, NULL }, X { "-okb", "outlineKnightBitmap", XrmoptionSepArg, NULL }, X { "-outlineQueenBitmap", "outlineQueenBitmap", XrmoptionSepArg, NULL }, X { "-oqb", "outlineQueenBitmap", XrmoptionSepArg, NULL }, X { "-outlineKingBitmap", "outlineKingBitmap", XrmoptionSepArg, NULL }, X { "-okb", "outlineKingBitmap", XrmoptionSepArg, NULL }, X { "-remoteShell", "remoteShell", XrmoptionSepArg, NULL }, X { "-rsh", "remoteShell", XrmoptionSepArg, NULL }, X { "-timeDelay", "timeDelay", XrmoptionSepArg, NULL }, X { "-td", "timeDelay", XrmoptionSepArg, NULL }, X { "-timeControl", "timeControl", XrmoptionSepArg, NULL }, X { "-tc", "timeControl", XrmoptionSepArg, NULL }, X { "-saveGameFile", "saveGameFile", XrmoptionSepArg, NULL }, X { "-sgf", "saveGameFile", XrmoptionSepArg, NULL }, X { "-readGameFile", "readGameFile", XrmoptionSepArg, NULL }, X { "-rgf", "readGameFile", XrmoptionSepArg, NULL }, X { "-savePositionFile", "savePositionFile", XrmoptionSepArg, NULL }, X { "-spf", "savePositionFile", XrmoptionSepArg, NULL }, X { "-readPositionFile", "readPositionFile", XrmoptionSepArg, NULL }, X { "-rpf", "readPositionFile", XrmoptionSepArg, NULL }, X { "-matchMode", "matchMode", XrmoptionSepArg, NULL }, X { "-mm", "matchMode", XrmoptionSepArg, NULL }, X { "-monoMode", "monoMode", XrmoptionSepArg, NULL }, X { "-mono", "monoMode", XrmoptionSepArg, NULL }, X { "-debugMode", "debugMode", XrmoptionSepArg, NULL }, X { "-debug", "debugMode", XrmoptionSepArg, NULL }, X { "-clockMode", "clockMode", XrmoptionSepArg, NULL }, X { "-clock", "clockMode", XrmoptionSepArg, NULL }, X { "-bigSizeMode", "bigSizeMode", XrmoptionSepArg, NULL }, X { "-big", "bigSizeMode", XrmoptionSepArg, NULL }, X { "-searchTime", "searchTime", XrmoptionSepArg, NULL }, X { "-st", "searchTime", XrmoptionSepArg, NULL } X}; X XXtActionsRec boardActions[] = { X { "DrawPosition", DrawPosition }, X { "HandleUserMove", HandleUserMove }, X { "QuitProc", QuitProc }, X { "ForwardProc", ForwardProc }, X { "BackwardProc", BackwardProc }, X { "PauseProc", PauseProc }, X { "Iconify", Iconify } X}; X char translationsTable[] = "<Expose>: DrawPosition() \n \ X <BtnDown>: HandleUserMove() \n \ X <BtnUp>: HandleUserMove() \n \ X <Key>q: QuitProc() \n \ X <Key>Q: QuitProc() \n \ X <Key>f: ForwardProc() \n \ X <Key>F: ForwardProc() \n \ X <Key>b: BackwardProc() \n \ X <Key>B: BackwardProc() \n \ X <Key>p: PauseProc() \n \ X <Key>P: PauseProc() \n \ X <Key>i: Iconify() \n \ X <Key>I: Iconify() \n \ X <Key>c: Iconify() \n \ X <Key>C: Iconify()"; X void main(argc, argv) X int argc; X char **argv; X{ X XSetWindowAttributes window_attributes; X char buf[MSG_SIZ]; X Arg args[3]; X int length; X X setbuf(stdout, NULL); setbuf(stderr, NULL); X X shellWidget = XtInitialize(argv[0], "XBoard", shellOptions, X XtNumber(shellOptions), &argc, argv); X X if (argc > 1) X Usage(); X X XtGetApplicationResources(shellWidget, &appData, clientResources, X XtNumber(clientResources), NULL, 0); X X /* X * Determine matchMode state -- poor man's resource converter X */ X if (strcmp(appData.matchMode, "Init") == 0) X matchMode = MatchInit; X else if (strcmp(appData.matchMode, "Position") == 0) X matchMode = MatchPosition; X else if (strcmp(appData.matchMode, "Opening") == 0) X matchMode = MatchOpening; X else if (strcmp(appData.matchMode, "False") == 0) X matchMode = MatchFalse; X else { X fprintf(stderr, "xboard: bad matchMode option %s\n", appData.matchMode); X Usage(); X } X X xDisplay = XtDisplay(shellWidget); X xScreen = DefaultScreen(xDisplay); X X if (!appData.bigSizeMode) { X squareSize = SMALL_SQUARE_SIZE; X XtSetArg(boardArgs[1], XtNwidth, X LINE_GAP + BOARD_SIZE * (SMALL_SQUARE_SIZE + LINE_GAP)); X XtSetArg(boardArgs[2], XtNheight, X LINE_GAP + BOARD_SIZE * (SMALL_SQUARE_SIZE + LINE_GAP)); X } X X /* X * Detect if there are not enough colors are available and adapt. X */ X if (DefaultDepth(xDisplay, xScreen) <= 2) X appData.monoMode = True; X X /* X * widget hierarchy X */ X formWidget = XtCreateManagedWidget("form", X formWidgetClass, shellWidget, NULL, 0); X X widgetList[0] = whiteTimerWidget = XtCreateWidget("white time:", X labelWidgetClass, formWidget, timerArgs, XtNumber(timerArgs)); X X widgetList[1] = blackTimerWidget = XtCreateWidget("black time:", X labelWidgetClass, formWidget, timerArgs, XtNumber(timerArgs)); X X widgetList[2] = messageWidget = XtCreateWidget("message", X labelWidgetClass, formWidget, messageArgs, XtNumber(messageArgs)); X X widgetList[3] = commandsWidget = XtCreateWidget("commands", X listWidgetClass, formWidget, commandsArgs, XtNumber(commandsArgs)); X X widgetList[4] = boardWidget = XtCreateWidget("board", X widgetClass, formWidget, boardArgs, XtNumber(boardArgs)); X X XtManageChildren(widgetList, XtNumber(widgetList)); X X /* X * Calculate the width of the timer labels. X */ X XtSetArg(args[0], XtNfont, &labelFont); X XtGetValues(whiteTimerWidget, args, 1); X if (appData.clockMode) { X sprintf(buf, "White: %s ", TimeString(appData.timeControl * 60)); X length = XTextWidth(labelFont, buf, strlen(buf) - 1); X } else X length = XTextWidth(labelFont, "White ", 7); X XtSetArg(args[0], XtNwidth, length); X XtSetValues(whiteTimerWidget, args, 1); X XtSetValues(blackTimerWidget, args, 1); X X /* X * formWidget uses these constraints but they are stored in the children. X */ X XtSetArg(args[0], XtNfromHoriz, whiteTimerWidget); X XtSetValues(blackTimerWidget, args, 1); X XtSetArg(args[0], XtNfromVert, whiteTimerWidget); X XtSetArg(args[1], XtNbackground, XBlackPixel(xDisplay, xScreen)); X XtSetArg(args[2], XtNforeground, XWhitePixel(xDisplay, xScreen)); X XtSetValues(messageWidget, args, 3); X XtSetArg(args[0], XtNfromVert, messageWidget); X XtSetValues(commandsWidget, args, 1); X XtSetArg(args[0], XtNfromVert, commandsWidget); X XtSetValues(boardWidget, args, 1); X X XtRealizeWidget(shellWidget); X X xBoardWindow = XtWindow(boardWidget); X X /* X * Create an icon. X */ X iconPixmap = XCreateBitmapFromData(xDisplay, XtWindow(shellWidget), X icon_bits, icon_width, icon_height); X XtSetArg(args[0], XtNiconPixmap, iconPixmap); X XtSetValues(shellWidget, args, 1); X X /* X * Create a cursor for the board widget. X */ X window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2); X XChangeWindowAttributes(xDisplay, xBoardWindow, X CWCursor, &window_attributes); X X /* X * Inhibit shell resizing. X */ X XtGetValues(shellWidget, shellArgs, 2); X shellArgs[4].value = shellArgs[2].value = shellArgs[0].value; X shellArgs[5].value = shellArgs[3].value = shellArgs[1].value; X XtSetValues(shellWidget, &shellArgs[2], 4); X X CreateGCs(); X CreateGrid(); X CreatePieces(); X X XtAddCallback(commandsWidget, XtNcallback, SelectCommand, NULL); X XtAddActions(boardActions, XtNumber(boardActions)); X XtOverrideTranslations(boardWidget, X XtParseTranslationTable(translationsTable)); X X DisplayMessage(""); X X /* X * If there is to be a machine match, set it up. X */ X if (matchMode != MatchFalse) X TwoMachinesPlayProc(); X else X ResetProc(); X X XtMainLoop(); X} X void CreateGCs() X{ X XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground X | GCBackground | GCFunction | GCPlaneMask; X XGCValues gc_values; X X gc_values.plane_mask = AllPlanes; X gc_values.line_width = LINE_GAP; X gc_values.line_style = LineSolid; X gc_values.function = GXcopy; X X gc_values.foreground = XBlackPixel(xDisplay, xScreen); X gc_values.background = XBlackPixel(xDisplay, xScreen); X lineGC = XtGetGC(shellWidget, value_mask, &gc_values); X X if (appData.monoMode) { X gc_values.foreground = XWhitePixel(xDisplay, xScreen); X gc_values.background = XBlackPixel(xDisplay, xScreen); X lightSquareGC = wbPieceGC X = XtGetGC(shellWidget, value_mask, &gc_values); X X gc_values.foreground = XBlackPixel(xDisplay, xScreen); X gc_values.background = XWhitePixel(xDisplay, xScreen); X darkSquareGC = bwPieceGC X = XtGetGC(shellWidget, value_mask, &gc_values); X } else { X gc_values.foreground = appData.lightSquareColor; X gc_values.background = appData.darkSquareColor; X lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values); X X gc_values.foreground = appData.darkSquareColor; X gc_values.background = appData.lightSquareColor; X darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values); X X gc_values.foreground = appData.whitePieceColor; X gc_values.background = appData.darkSquareColor; X wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values); X X gc_values.foreground = appData.whitePieceColor; X gc_values.background = appData.lightSquareColor; X wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values); X X gc_values.foreground = appData.blackPieceColor; X gc_values.background = appData.darkSquareColor; X bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values); X X gc_values.foreground = appData.blackPieceColor; X gc_values.background = appData.lightSquareColor; X blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values); X } X} X void CreatePieces() X{ X XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */ X X ReadBitmap(appData.solidPawnBitmap, &solidPawnBitmap, X solid_pawn_bits, pawn_small_bits); X ReadBitmap(appData.solidRookBitmap, &solidRookBitmap, X solid_rook_bits, rook_small_bits); X ReadBitmap(appData.solidKnightBitmap, &solidKnightBitmap, X solid_knight_bits, knight_small_bits); X ReadBitmap(appData.solidBishopBitmap, &solidBishopBitmap, X solid_bishop_bits, bishop_small_bits); X ReadBitmap(appData.solidQueenBitmap, &solidQueenBitmap, X solid_queen_bits, queen_small_bits); X ReadBitmap(appData.solidKingBitmap, &solidKingBitmap, X solid_king_bits, king_small_bits); X X if (appData.monoMode) { X ReadBitmap(appData.outlinePawnBitmap, &outlinePawnBitmap, X outline_pawn_bits, pawn_small_outline_bits); X ReadBitmap(appData.outlineRookBitmap, &outlineRookBitmap, X outline_rook_bits, rook_small_outline_bits); X ReadBitmap(appData.outlineKnightBitmap, &outlineKnightBitmap, X outline_knight_bits, knight_small_outline_bits); X ReadBitmap(appData.outlineBishopBitmap, &outlineBishopBitmap, X outline_bishop_bits, bishop_small_outline_bits); X ReadBitmap(appData.outlineQueenBitmap, &outlineQueenBitmap, X outline_queen_bits, queen_small_outline_bits); X ReadBitmap(appData.outlineKingBitmap, &outlineKingBitmap, X outline_king_bits, king_small_outline_bits); X } X X XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */ X} X void ReadBitmap(name, pm, big_bits, small_bits) X String name; X Pixmap *pm; X char big_bits[], small_bits[]; X{ X int x_hot, y_hot; X u_int w, h; X X if (XReadBitmapFile(xDisplay, xBoardWindow, name, X &w, &h, pm, &x_hot, &y_hot) != BitmapSuccess X || w != squareSize || h != squareSize) { X if (appData.bigSizeMode) X *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, X big_bits, squareSize, squareSize); X else *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, X small_bits, squareSize, squareSize); X } X} X void CreateGrid() X{ X int i; X X for (i = 0; i < BOARD_SIZE + 1; i++) { X gridSegments[i].x1 = 0; X gridSegments[i].y1 = LINE_GAP / 2 + (i * (squareSize + LINE_GAP)); X gridSegments[i].x2 = LINE_GAP + BOARD_SIZE * (squareSize + LINE_GAP); X gridSegments[i].y2 = LINE_GAP / 2 + (i * (squareSize + LINE_GAP)); X gridSegments[i + BOARD_SIZE + 1].x1 = LINE_GAP / 2 X + (i * (squareSize + LINE_GAP)); X gridSegments[i + BOARD_SIZE + 1].y1 = 0; X gridSegments[i + BOARD_SIZE + 1].x2 = LINE_GAP / 2 X + (i * (squareSize + LINE_GAP)); X gridSegments[i + BOARD_SIZE + 1].y2 = X BOARD_SIZE * (squareSize + LINE_GAP); X } X} X X/* X * If the user selects on a border boundary or off the board, return failure. X * Otherwise map the event coordinate to the square. X */ int XEventToSquare(x) X int x; X{ X if (x < LINE_GAP) X return -1; X x -= LINE_GAP; X if ((x % (squareSize + LINE_GAP)) >= squareSize) X return -1; X x /= (squareSize + LINE_GAP); X if (x >= BOARD_SIZE) X return -1; X return x; X} X int CharToPiece(c) X int c; X{ X switch (c) { X default: X case '.': return EmptySquare; X case 'P': return WhitePawn; X case 'R': return WhiteRook; X case 'N': return WhiteKnight; X case 'B': return WhiteBishop; X case 'Q': return WhiteQueen; X case 'K': return WhiteKing; X case 'p': return BlackPawn; X case 'r': return BlackRook; X case 'n': return BlackKnight; X case 'b': return BlackBishop; X case 'q': return BlackQueen; X case 'k': return BlackKing; X } X} X void DrawSquare(row, column, piece) X int row, column, piece; X{ X int square_color, x, y; X X if (flipView) X column = (BOARD_SIZE - 1) - column; X else X row = (BOARD_SIZE - 1) - row; X X square_color = ((column % 2 == 1) && (row % 2 == 1)) X || ((column % 2 == 0) && (row % 2 == 0)); X X x = LINE_GAP + column * (squareSize + LINE_GAP); X y = LINE_GAP + row * (squareSize + LINE_GAP); X X if (piece == EmptySquare) X XFillRectangle(xDisplay, xBoardWindow, square_color X ? lightSquareGC : darkSquareGC, x, y, squareSize, squareSize); X else if (appData.monoMode) { X if (square_color) X XCopyPlane(xDisplay, piece < BlackPawn X ? *pieceToOutline[piece] : *pieceToSolid[piece], xBoardWindow, X bwPieceGC, 0, 0, squareSize, squareSize, x, y, 1); X else XCopyPlane(xDisplay, piece < BlackPawn X ? *pieceToSolid[piece] : *pieceToOutline[piece], xBoardWindow, X wbPieceGC, 0, 0, squareSize, squareSize, x, y, 1); X } else { X if (square_color) X XCopyPlane(xDisplay, *pieceToSolid[piece], X xBoardWindow, piece < BlackPawn ? wlPieceGC : blPieceGC, X 0, 0, squareSize, squareSize, x, y, 1); X else XCopyPlane(xDisplay, *pieceToSolid[piece], X xBoardWindow, piece < BlackPawn ? wdPieceGC : bdPieceGC, X 0, 0, squareSize, squareSize, x, y, 1); X } X} X X/* X * event handler for redrawing the board X */ void DrawPosition(w, event) X Widget w; X XExposeEvent *event; X{ X Arg args[1]; X int i, j; X Boolean iconic; X X /* X * We probably shouldn't have to do this, but R4 Xt gets confused. X */ X XtSetArg(args[0], XtNiconic, &iconic); X XtGetValues(shellWidget, args, 1); X if (iconic == False) { X XtSetArg(args[0], XtNiconic, False); X XtSetValues(shellWidget, args, 1); X } X X /* X * It would be simpler to clear the window with XClearWindow() X * but this causes a very distracting flicker. X */ X XDrawSegments(xDisplay, xBoardWindow, lineGC, X gridSegments, (BOARD_SIZE + 1) * 2); X X for (i = 0; i < BOARD_SIZE; i++) X for (j = 0; j < BOARD_SIZE; j++) X DrawSquare(i, j, (int) boards[currentMove][i][j]); X X XSync(xDisplay, False); X} X void InitPosition() X{ X currentMove = forwardMostMove = 0; X CopyBoard(boards[0], initialPosition); X DrawPosition(boardWidget, (XExposeEvent *) NULL); X} X void CopyBoard(to, from) X Board to, from; X{ X int i, j; X X for (i = 0; i < BOARD_SIZE; i++) X for (j = 0; j < BOARD_SIZE; j++) X to[i][j] = from[i][j]; X} X void SendCurrentBoard(fp) X FILE *fp; X{ X char message[MSG_SIZ]; X u_char *bp; X int i, j; X X SendToProgram("edit\n", fp); X SendToProgram("#\n", fp); X for (i = BOARD_SIZE - 1; i >= 0; i--) { X bp = &boards[currentMove][i][0]; X for (j = 0; j < BOARD_SIZE; j++, bp++) { X if (*bp < BlackPawn) { X sprintf(message, "%c%c%c\n", pieceToChar[*bp], X 'a' + j, '1' + i); X SendToProgram(message, fp); X } X } X } X X SendToProgram("c\n", fp); X for (i = BOARD_SIZE - 1; i >= 0; i--) { X bp = &boards[currentMove][i][0]; X for (j = 0; j < BOARD_SIZE; j++, bp++) { X if ((*bp != EmptySquare) && (*bp >= BlackPawn)) { X sprintf(message, "%c%c%c\n", pieceToChar[*bp - BlackPawn], X 'a' + j, '1' + i); X SendToProgram(message, fp); X } X } X } X X SendToProgram(".\n", fp); X} X X/* X * event handler for parsing user moves X */ void HandleUserMove(w, event) X Widget w; X XEvent *event; X{ X int move_type, to_x, to_y; X char user_move[MSG_SIZ]; X X if ((w != boardWidget) || (matchMode != MatchFalse)) X return; X X switch (gameMode) { X case EndOfGame: X case PlayFromGameFile: X return; X case MachinePlaysWhite: X if ((currentMove % 2) == 0) X return; X break; X case MachinePlaysBlack: X if ((currentMove % 2) == 1) X return; X break; X default: X break; X } X X switch (event->type) { X case ButtonPress: X if ((fromX >= 0) || (fromY >= 0)) X return; X if ((fromX = EventToSquare(event->xbutton.x)) < 0) X break; X if ((fromY = EventToSquare(event->xbutton.y)) < 0) X break; X if (flipView) X fromX = BOARD_SIZE - 1 - fromX; X else X fromY = BOARD_SIZE - 1 - fromY; X break; X case ButtonRelease: X if ((fromX < 0) || (fromY < 0)) X return; X if ((to_x = EventToSquare(event->xbutton.x)) < 0) X break; X if ((to_y = EventToSquare(event->xbutton.y)) < 0) X break; X if (flipView) X to_x = BOARD_SIZE - 1 - to_x; X else X to_y = BOARD_SIZE - 1 - to_y; X X MakeMove(&move_type, fromX, fromY, to_x, to_y); X X switch (move_type) { X case WhitePromotion: X case BlackPromotion: /* GNU Chess limitation of only Q promotion */ X sprintf(user_move, "%c%c%c%c(Q)\n", /* GNU Chess limitation */ X 'a' + fromX, '1' + fromY, 'a' + to_x, '1' + to_y); X break; X case NormalMove: X case WhiteKingSideCastle: X case WhiteQueenSideCastle: X case WhiteCapturesEnPassant: X case BlackKingSideCastle: X case BlackQueenSideCastle: X case BlackCapturesEnPassant: X sprintf(user_move, "%c%c%c%c\n", X 'a' + fromX, '1' + fromY, 'a' + to_x, '1' + to_y); X break; X } X X fromX = fromY = -1; X X SendToProgram(user_move, toFirstProgFP); X strcpy(moveList[currentMove - 1], user_move); X X switch (gameMode) { X case PauseGame: X PauseProc(); /* a user move restarts a paused game */ X break; X case ForceMoves: X forwardForce = False; X break; X case BeginningOfGame: X case SetupPosition: X lastGameMode = gameMode = MachinePlaysBlack; X case MachinePlaysBlack: X /* X * gnuchess prefers to be told that it is black when it is on move. X */ X if (firstMove) { X firstMove = False; X if (currentMove > 1) /* If it is being forced */ X SendToProgram("black\n", toFirstProgFP); X } X case MachinePlaysWhite: X break; X } X break; X } X} X void HandleMachineMove(message) X char *message; X{ X char machine_move[MSG_SIZ], buf1[MSG_SIZ], buf2[MSG_SIZ]; X int i, j, move_type, from_x, from_y, to_x, to_y; X X if (strncmp(message, "warning:", 8) == 0) { X DisplayMessage(message); X return; X } X X /* X * If either host fails, reset to using localhost for both. X * Display an error message. X */ X if ((StrStr(message, "unknown host") != NULL) X || (StrStr(message, "No remote directory") != NULL) X || (StrStr(message, "not found") != NULL)) { X ShutdownChessPrograms(""); X strcpy(appData.firstHost, "localhost"); X strcpy(appData.secondHost, "localhost"); X if (matchMode != MatchFalse) X TwoMachinesPlayProc(); X else X ResetProc(); X strcpy(buf1, "using localhost - "); X strcat(buf1, message); X DisplayMessage(buf1); X return; X } X X /* X * If the move is illegal, cancel it and redraw the board. X */ X if (strncmp(message, "Illegal move", 12) == 0) { X if (gameMode == PlayFromGameFile) { X lastGameMode = gameMode; X gameMode = BeginningOfGame; X sprintf(buf1, "Illegal move: %s", moveList[currentMove - 1]); X ShutdownChessPrograms(buf1); X return; X } X X currentMove--; X DisplayClocks(DisplayTimers); X DisplayMessage(message); X X /* X * Only redraw the squares that have changed. X */ X for (i = 0; i < BOARD_SIZE; i++) X for (j = 0; j < BOARD_SIZE; j++) X if (boards[currentMove][i][j] != boards[currentMove + 1][i][j]) X DrawSquare(i, j, (int) boards[currentMove][i][j]); X X XSync(xDisplay, False); X return; X } X X if (strncmp(message, "Hint:", 5) == 0) { X DisplayMessage(message); X return; X } X X /* X * win, lose or draw X */ X if (strncmp(message, "White", 5) == 0) { X ShutdownChessPrograms("White wins"); X return; X } else if (strncmp(message, "Black", 5) == 0) { X ShutdownChessPrograms("Black wins"); X return; X } else if (strncmp(message, "Draw", 4) == 0) { X ShutdownChessPrograms("Draw"); X return; X } X X /* X * normal machine reply move X */ X if (StrStr(message, "...") != NULL) { X sscanf(message, "%s %s %s", buf1, buf2, machine_move); X if (machine_move[0] == '\0') X return; X } else X return; /* ignore noise */ X X strcpy(moveList[currentMove], machine_move); X X from_x = machine_move[0] - 'a'; X from_y = machine_move[1] - '1'; X to_x = machine_move[2] - 'a'; X to_y = machine_move[3] - '1'; X X MakeMove(&move_type, from_x, from_y, to_x, to_y); X X switch (gameMode) { X case PauseGame: X case SetupPosition: X break; X case ForceMoves: X case PlayFromGameFile: X strncat(machine_move, "\n", 1); X SendToProgram(machine_move, toFirstProgFP); X break; X case TwoMachinesPlay: X strncat(machine_move, "\n", 1); X SendToProgram(machine_move, currentMove % 2 X ? toFirstProgFP : toSecondProgFP); X /* X * gnuchess prefers to be told that it is black when it is on move. X */ X if (firstMove) { X firstMove = False; X SendToProgram("black\n", toFirstProgFP); X } X break; X } X} X void ReadGameFile() X{ X static char move_number[MSG_SIZ], white_move[MSG_SIZ], black_move[MSG_SIZ]; X int move_type, from_x, from_y, to_x, to_y; X char move[MSG_SIZ]; X X if ((gameMode == EndOfGame) || (gameMode == BeginningOfGame)) { X fclose(gameFileFP); X gameFileFP = NULL; X return; X } X next_move: X if (currentMove % 2 == 0) { next_line: X if (fgets(move, sizeof(move), gameFileFP) == (char *) NULL) { X lastGameMode = gameMode = MachinePlaysBlack; end_parse: X if (readGameXID != NULL) { X XtRemoveTimeOut(readGameXID); X readGameXID = NULL; X } X fclose(gameFileFP); X gameFileFP = NULL; X return; X } X X if ((move[0] == '%') || (move[0] == '!')) X goto next_line; X X move_number[0] = white_move[0] = black_move[0] = NULL; X X if (sscanf(move, "%s %s %s", move_number, X white_move, black_move) == EOF) X goto end_parse; X X if (white_move[0] == '\0') { X if (move_number[0] != '\0') X strcpy(white_move, move_number); X else { X DisplayMessage("End of Game"); X goto end_parse; X } X } X X if ((strcmp(white_move, "draw") == 0) X || (strcmp(white_move, "Draw") == 0) X || (strcmp(white_move, "DRAW") == 0) X || (strcmp(white_move, "Resign") == 0) X || (strcmp(white_move, "resign") == 0) X || (strcmp(white_move, "RESIGN") == 0) X || (strcmp(white_move, "0-1") == 0) X || (strcmp(white_move, "1-0") == 0)) { X DisplayMessage(white_move); X lastGameMode = gameMode; X gameMode = BeginningOfGame; X goto end_parse; X } if (strcmp(white_move, "o-o-o") == 0) { X from_x = 4; X from_y = 0; X to_x = 2; X to_y = 0; X } else if (strcmp(white_move, "o-o") == 0) { X from_x = 4; X from_y = 0; X to_x = 6; X to_y = 0; X } else { X from_x = white_move[0] - 'a'; X from_y = white_move[1] - '1'; X to_x = white_move[2] - 'a'; X to_y = white_move[3] - '1'; X } X X strncat(white_move, "\n", 1); X SendToProgram(white_move, toFirstProgFP); X strcpy(moveList[currentMove], white_move); X } else { X if (black_move[0] == '\0') { X DisplayMessage("End of Game"); X goto end_parse; X } if ((strcmp(black_move, "draw") == 0) X || (strcmp(black_move, "Draw") == 0) X || (strcmp(black_move, "DRAW") == 0) X || (strcmp(black_move, "Resign") == 0) X || (strcmp(black_move, "resign") == 0) X || (strcmp(black_move, "RESIGN") == 0) X || (strcmp(black_move, "0-1") == 0) X || (strcmp(black_move, "1-0") == 0)) { X DisplayMessage(black_move); X lastGameMode = gameMode; X gameMode = BeginningOfGame; X goto end_parse; X } if (strcmp(black_move, "o-o-o") == 0) { X from_x = 4; X from_y = 7; X to_x = 2; X to_y = 7; X } else if (strcmp(black_move, "o-o") == 0) { X from_x = 4; X from_y = 7; X to_x = 6; X to_y = 7; X } else { X from_x = black_move[0] - 'a'; X from_y = black_move[1] - '1'; X to_x = black_move[2] - 'a'; X to_y = black_move[3] - '1'; X } X X strncat(black_move, "\n", 1); X SendToProgram(black_move, toFirstProgFP); X strcpy(moveList[currentMove], black_move); X } X X MakeMove(&move_type, from_x, from_y, to_x, to_y); X X if (matchMode == MatchOpening) X goto next_move; X X readGameXID = XtAddTimeOut((int) (1000 * appData.timeDelay), X ReadGameFile, NULL); X} X X/* X * MakeMove() displays moves. If they are illegal, GNU chess will detect X * this and send an Illegal move message. XBoard will then retract the move. X * The clockMode False case is tricky because it displays the player on move. X */ void MakeMove(move_type, from_x, from_y, to_x, to_y) X int *move_type, from_x, from_y, to_x, to_y; X{ X char message[MSG_SIZ]; X int move; X X if ((gameMode != PlayFromGameFile) X && (gameMode != ForceMoves) && appData.clockMode) X DisplayClocks(DisplayTimers); X X CopyBoard(boards[currentMove + 1], boards[currentMove]); X forwardMostMove = ++currentMove; X X move = (currentMove + 1) / 2; X X if (!appData.clockMode) X DisplayClocks(DisplayTimers); X X if (from_y == 0 && from_x == 4 /* white king-side castle */ X && boards[currentMove][from_y][from_x] == WhiteKing X && to_y == 0 && to_x == 6) { X *move_type = WhiteKingSideCastle; X boards[currentMove][0][7] = EmptySquare; X boards[currentMove][0][6] = WhiteKing; X boards[currentMove][0][5] = WhiteRook; X boards[currentMove][0][4] = EmptySquare; X DrawSquare(0, 7, (int) boards[currentMove][0][7]); X DrawSquare(0, 6, (int) boards[currentMove][0][6]); X DrawSquare(0, 5, (int) boards[currentMove][0][5]); X DrawSquare(0, 4, (int) boards[currentMove][0][4]); X sprintf(message, "%d. 0-0", move); X } else if (from_y == 0 && from_x == 4 /* white queen-side castle */ X && boards[currentMove][from_y][from_x] == WhiteKing X && to_y == 0 && to_x == 2) { X *move_type = WhiteQueenSideCastle; X boards[currentMove][0][0] = EmptySquare; X boards[currentMove][0][2] = WhiteKing; X boards[currentMove][0][3] = WhiteRook; X boards[currentMove][0][4] = EmptySquare; X DrawSquare(0, 0, (int) boards[currentMove][0][0]); X DrawSquare(0, 2, (int) boards[currentMove][0][2]); X DrawSquare(0, 3, (int) boards[currentMove][0][3]); X DrawSquare(0, 4, (int) boards[currentMove][0][4]); X sprintf(message, "%d. 0-0-0", move); X } else if (from_y == 6 /* white pawn promotion */ X && boards[currentMove][from_y][from_x] == WhitePawn && to_y == 7) { X *move_type = WhitePromotion; X boards[currentMove][6][from_x] = EmptySquare; X boards[currentMove][7][to_x] = WhiteQueen; X DrawSquare(6, from_x, (int) boards[currentMove][6][from_x]); X DrawSquare(7, to_x, (int) boards[currentMove][7][to_x]); X sprintf(message, "%d. %c8(Q)", move, from_x + 'a'); X } else if ((from_y == 4) /* white captures en passant */ X && (to_x != from_x) X && (boards[currentMove][from_y][from_x] == WhitePawn) X && (boards[currentMove][to_y][to_x] == EmptySquare)) { X *move_type = WhiteCapturesEnPassant; X boards[currentMove][from_y][from_x] = EmptySquare; X boards[currentMove][to_y][to_x] = WhitePawn; X boards[currentMove][to_y - 1][to_x] = EmptySquare; X DrawSquare(from_y, from_x, (int) boards[currentMove][from_y][from_x]); X DrawSquare(to_y, to_x, (int) boards[currentMove][to_y][to_x]); X DrawSquare(to_y - 1, to_x, (int) boards[currentMove][to_y - 1][to_x]); X sprintf(message, "%d. %c%c ep", move, from_x + 'a', to_x + 'a'); X } else if (from_y == 7 && from_x == 4 /* black king-side castle */ X && boards[currentMove][from_y][from_x] == BlackKing X && to_y == 7 && to_x == 6) { X *move_type = BlackKingSideCastle; X boards[currentMove][7][4] = EmptySquare; X boards[currentMove][7][5] = BlackRook; X boards[currentMove][7][6] = BlackKing; X boards[currentMove][7][7] = EmptySquare; X DrawSquare(7, 7, (int) boards[currentMove][7][7]); X DrawSquare(7, 6, (int) boards[currentMove][7][6]); X DrawSquare(7, 5, (int) boards[currentMove][7][5]); X DrawSquare(7, 4, (int) boards[currentMove][7][4]); X sprintf(message, "%d. ... 0-0", move); X } else if (from_y == 7 && from_x == 4 /* black queen-side castle */ X && boards[currentMove][from_y][from_x] == BlackKing X && to_y == 7 && to_x == 2) { X *move_type = BlackQueenSideCastle; X boards[currentMove][7][0] = EmptySquare; X boards[currentMove][7][2] = BlackKing; X boards[currentMove][7][3] = BlackRook; X boards[currentMove][7][4] = EmptySquare; X DrawSquare(7, 0, (int) boards[currentMove][7][0]); X DrawSquare(7, 2, (int) boards[currentMove][7][2]); X DrawSquare(7, 3, (int) boards[currentMove][7][3]); X DrawSquare(7, 4, (int) boards[currentMove][7][4]); X sprintf(message, "%d. ... 0-0-0", move); X } else if (from_y == 1 /* black pawn promotion */ X && boards[currentMove][from_y][from_x] == BlackPawn && to_y == 0) { X *move_type = BlackPromotion; X boards[currentMove][1][from_x] = EmptySquare; X boards[currentMove][0][to_x] = BlackQueen; X DrawSquare(1, from_x, (int) boards[currentMove][1][from_x]); X DrawSquare(0, to_x, (int) boards[currentMove][0][to_x]); X sprintf(message, "%d. ... %c8(Q)", move, from_x + 'a'); X } else if ((from_y == 3) /* black captures en passant */ X && (to_x != from_x) X && (boards[currentMove][from_y][from_x] == BlackPawn) X && (boards[currentMove][to_y][to_x] == EmptySquare)) { X *move_type = BlackCapturesEnPassant; X boards[currentMove][from_y][from_x] = EmptySquare; X boards[currentMove][to_y][to_x] = BlackPawn; X boards[currentMove][to_y + 1][to_x] = EmptySquare; X DrawSquare(from_y, from_x, (int) boards[currentMove][from_y][from_x]); X DrawSquare(to_y, to_x, (int) boards[currentMove][to_y][to_x]); X DrawSquare(to_y + 1, to_x, (int) boards[currentMove][to_y + 1][to_x]); X sprintf(message, "%d. ... %c%c ep", move, from_x + 'a', to_x + 'a'); X } else { X *move_type = NormalMove; X boards[currentMove][to_y][to_x] = boards[currentMove][from_y][from_x]; X boards[currentMove][from_y][from_x] = EmptySquare; X DrawSquare(to_y, to_x, (int) boards[currentMove][to_y][to_x]); X DrawSquare(from_y, from_x, (int) boards[currentMove][from_y][from_x]); X sprintf(message, "%d. %s%c%c%c%c", move, currentMove % 2 ? X "" : "... ", from_x + 'a', from_y + '1', to_x + 'a', to_y + '1'); X } X X DisplayMessage(message); X XSync(xDisplay, False); X} X void InitChessProgram(host_name, program_name, pid, to, from, xid) X char *host_name, *program_name; X int *pid; X FILE **to, **from; X XtIntervalId *xid; X{ X char time_control[10], moves_per_session[10], time_search[10]; X int to_prog[2], from_prog[2]; X FILE *from_fp, *to_fp; X X signal(SIGPIPE, CatchPipeSignal); X pipe(to_prog); X pipe(from_prog); X X if ((*pid = fork()) == 0) { X signal(SIGPIPE, CatchPipeSignal); X dup2(to_prog[0], 0); X dup2(from_prog[1], 1); X close(to_prog[0]); X close(to_prog[1]); X close(from_prog[0]); X close(from_prog[1]); X dup2(1, fileno(stderr)); /* force stderr to the pipe */ X sprintf(time_control, "%d", appData.timeControl); X sprintf(time_search, "%d", appData.searchTime); X sprintf(moves_per_session, "%d", appData.movesPerSession); X if (strcmp(host_name, "localhost") == 0) { X if (appData.searchTime <= 0) X execlp(program_name, program_name, X moves_per_session, time_control, (char *) NULL); X else X execlp(program_name, program_name, time_search, (char *) NULL); X } else { X if (appData.searchTime <= 0) X execlp(appData.remoteShell, appData.remoteShell, X host_name, program_name, moves_per_session, X time_control, (char *) NULL); X else X execlp(appData.remoteShell, appData.remoteShell, X host_name, program_name, time_search, (char *) NULL); X } X X perror(program_name); X exit(1); X } X X close(to_prog[0]); X close(from_prog[1]); X X *from = from_fp = fdopen(from_prog[0], "r"); X *to = to_fp = fdopen(to_prog[1], "w"); X setbuf(from_fp, NULL); setbuf(to_fp, NULL); X X *xid = XtAddInput(fileno(from_fp), XtInputReadMask, X ReceiveFromProgram, from_fp); X X SendToProgram(appData.initString, to_fp); X} X void ShutdownChessPrograms(message) X char *message; X{ X lastGameMode = gameMode; X gameMode = EndOfGame; X DisplayMessage(message); X X if (firstProgramPID != 0) { X fclose(fromFirstProgFP); X fclose(toFirstProgFP); X fromFirstProgFP = toFirstProgFP = NULL; X kill(firstProgramPID, SIGTERM); X } X X if (secondProgramPID != 0) { X fclose(fromSecondProgFP); X fclose(toSecondProgFP); X fromSecondProgFP = toSecondProgFP = NULL; X kill(secondProgramPID, SIGTERM); X } X X if (firstProgramXID != NULL) X XtRemoveInput(firstProgramXID); X if (secondProgramXID != NULL) X XtRemoveInput(secondProgramXID); X if (readGameXID != NULL) X XtRemoveTimeOut(readGameXID); X X firstProgramXID = secondProgramXID = readGameXID = NULL; X firstProgramPID = secondProgramPID = 0; X X DisplayClocks(StopTimers); X} X void SelectCommand(w, client_data, call_data) X Widget w; X XtPointer client_data, call_data; X{ X XawListReturnStruct *list_return = XawListShowCurrent(w); X X fromX = fromY = -1; X X if ((gameMode == PauseGame) && (list_return->list_index != ButtonPause)) X PauseProc(); X X switch (list_return->list_index) { X case ButtonQuit: X QuitProc(); X break; X case ButtonBackward: X BackwardProc(); X break; X case ButtonForward: X ForwardProc(); X break; X case ButtonFlip: X FlipProc(); X break; X case ButtonReset: X ResetProc(); X break; X case ButtonSaveGame: X SaveGameProc(); X break; X case ButtonSavePosition: X SavePositionProc(); X break; X case ButtonHint: X HintProc(); X break; X case ButtonSwitch: X SwitchProc(); X break; X case ButtonSetupFromFile: X (void) SetupPositionFromFileProc(); X break; X case ButtonPlayFromFile: X (void) PlayFromGameFileProc(); X break; X case ButtonMachinePlaysBlack: X MachinePlaysBlackProc(); X break; X case ButtonMachinePlaysWhite: X MachinePlaysWhiteProc(); X break; X case ButtonTwoMachinesPlay: X TwoMachinesPlayProc(); X break; X case ButtonForce: X ForceProc(); X break; X case ButtonPause: X PauseProc(); X break; X } X X XawListUnhighlight(w); X} X X/* X * Button procedures in order. X */ void QuitProc() X{ X ShutdownChessPrograms("Quitting"); X exit(0); X} X int PlayFromGameFileProc() X{ X char buf[MSG_SIZ]; X X if (gameMode != BeginningOfGame) X return False; X X if ((gameFileFP = fopen(appData.readGameFile, "r")) == NULL) { X sprintf(buf, "Can't open %s", appData.readGameFile); X DisplayMessage(buf); X return False; X } X X lastGameMode = gameMode; X gameMode = PlayFromGameFile; X InitPosition(); X DisplayClocks(StopTimers); X SendToProgram(appData.initString, toFirstProgFP); X SendToProgram("force\n", toFirstProgFP); X X /* X * skip header information in game record file X */ X fgets(buf, MSG_SIZ, gameFileFP); X fgets(buf, MSG_SIZ, gameFileFP); X fgets(buf, MSG_SIZ, gameFileFP); X X ReadGameFile(); X X return True; X} X void MachinePlaysBlackProc() X{ X if ((gameMode == EndOfGame) || (gameMode == PlayFromGameFile) X || (matchMode != MatchFalse) || ((currentMove % 2) == 0)) X return; X X lastGameMode = gameMode = MachinePlaysBlack; X SendToProgram("black\n", toFirstProgFP); X} X void XForwardProc() X{ X char buf[MSG_SIZ]; X int i, j; X X if ((gameMode == EndOfGame) || (gameMode == PlayFromGameFile) X || (matchMode != MatchFalse) || (currentMove >= forwardMostMove) X || ((currentMove == 0) && (forwardMostMove == 0))) X return; X X if (forwardForce == False) { X forwardForce = True; X SendToProgram("force\n", toFirstProgFP); X } X X for (i = 0; i < BOARD_SIZE; i++) X for (j = 0; j < BOARD_SIZE; j++) X if (boards[currentMove + 1][i][j] != boards[currentMove][i][j]) X DrawSquare(i, j, (int) boards[currentMove + 1][i][j]); X X strcpy(buf, moveList[currentMove++]); X strncat(buf, "\n", 1); X SendToProgram(buf, toFirstProgFP); X} X void ResetProc() X{ X twoProgramState = flipView = forwardForce = False; X matchMode = MatchFalse; X firstMove = True; X X ShutdownChessPrograms(""); X lastGameMode = gameMode = BeginningOfGame; X InitPosition(); X InitChessProgram(appData.firstHost, appData.firstChessProgram, X &firstProgramPID, &toFirstProgFP, &fromFirstProgFP, &firstProgramXID); X DisplayClocks(ResetTimers); X} X int SetupPositionFromFileProc() X{ X char *p, line[MSG_SIZ], buf[MSG_SIZ]; X Board initial_position; X FILE *position_file_fp; X int i, j; X X if (gameMode != BeginningOfGame) X return False; X X if ((position_file_fp = fopen(appData.readPositionFile, "r")) == NULL) { X sprintf(buf, "Can't open %s", appData.readPositionFile); X ShutdownChessPrograms(buf); X lastGameMode = gameMode = BeginningOfGame; X matchMode = MatchFalse; X InitPosition(); X return False; X } X X lastGameMode = gameMode = SetupPosition; X X /* X * skip header information in position file X */ X fgets(line, MSG_SIZ, position_file_fp); X fgets(line, MSG_SIZ, position_file_fp); X fgets(line, MSG_SIZ, position_file_fp); X X for (i = BOARD_SIZE - 1; i >= 0; i--) { X fgets(line, MSG_SIZ, position_file_fp); X for (p = line, j = 0; j < BOARD_SIZE; p++) { X if (*p == ' ') X continue; X initial_position[i][j++] = CharToPiece(*p); X } X } X fclose(position_file_fp); X X currentMove = forwardMostMove = 0; X CopyBoard(boards[0], initial_position); X SendCurrentBoard(toFirstProgFP); X DrawPosition(boardWidget, (XExposeEvent *) NULL); X X return True; X} X void MachinePlaysWhiteProc() X{ X if ((gameMode == EndOfGame) || (gameMode == PlayFromGameFile) X || (matchMode != MatchFalse) || ((currentMove % 2) == 1)) X return; X X lastGameMode = gameMode = MachinePlaysWhite; X SendToProgram("white\n", toFirstProgFP); X} X void BackwardProc() X{ X int i, j; X X if ((gameMode == EndOfGame) || (gameMode == PlayFromGameFile) X || (currentMove <= 0) || (matchMode != MatchFalse)) X return; X X SendToProgram("undo\n", toFirstProgFP); X currentMove--; X X for (i = 0; i < BOARD_SIZE; i++) X for (j = 0; j < BOARD_SIZE; j++) X if (boards[currentMove][i][j] != boards[currentMove + 1][i][j]) X DrawSquare(i, j, (int) boards[currentMove][i][j]); X} X void XFlipProc() X{ X flipView = !flipView; X DrawPosition(boardWidget, (XExposeEvent *) NULL); X} X void SaveGameProc() X{ X char buf[MSG_SIZ], white_move[MSG_SIZ], black_move[MSG_SIZ]; X int i = 0, len, move = 0; X time_t tm; X X if ((gameFileFP = fopen(appData.saveGameFile, "w")) == NULL) { X sprintf(buf, "Can't open %s", appData.saveGameFile); X DisplayMessage(buf); X return; X } X X tm = time((time_t *) NULL); X gethostname(buf, MSG_SIZ); X X fprintf(gameFileFP, "xboard game file -- %s", ctime(&tm)); X switch (lastGameMode) { X case MachinePlaysWhite: X fprintf(gameFileFP, "\t%s@%s vs. %s@%s\n", appData.firstChessProgram, X appData.firstHost, getpwuid(getuid())->pw_name, buf); X break; X case MachinePlaysBlack: X fprintf(gameFileFP, "\t%s@%s vs. %s@%s\n", getpwuid(getuid())->pw_name, X buf, appData.firstChessProgram, appData.firstHost); X break; X case TwoMachinesPlay: X fprintf(gameFileFP, "\t%s@%s vs. %s@%s\n", X appData.secondChessProgram, appData.secondHost, X appData.firstChessProgram, appData.firstHost); X break; X default: X fprintf(gameFileFP, "\n"); X break; X } X fprintf(gameFileFP, "\talgebraic\n"); X X for (;;) { X if ((len = strlen(moveList[i])) == 0) X break; X /* X * get rid of '\n' added to send the move to GNU Chess X */ X strcpy(white_move, moveList[i++]); X if (white_move[len - 1] == '\n') X white_move[len - 1] = NULL; X fprintf(gameFileFP, "%d. %s ", ++move, white_move); X X if ((len = strlen(moveList[i])) == 0) { X fprintf(gameFileFP, "\n"); X break; X } X strcpy(black_move, moveList[i++]); X if (black_move[len - 1] == '\n') X black_move[len - 1] = NULL; X fprintf(gameFileFP, "%s\n", black_move); X } X fclose(gameFileFP); X gameFileFP = NULL; X} X void SwitchProc() X{ X switch (gameMode) { X default: X return; X case MachinePlaysWhite: X lastGameMode = gameMode = MachinePlaysBlack; X break; X case MachinePlaysBlack: X if (currentMove == 0) { X MachinePlaysWhiteProc(); X return; X } X lastGameMode = gameMode = MachinePlaysWhite; X break; X } X X SendToProgram("switch\n", toFirstProgFP); X} X void XForceProc() X{ X if ((gameMode == EndOfGame) || (gameMode == PlayFromGameFile)) X return; X X switch (gameMode) { X case MachinePlaysWhite: X if ((currentMove % 2) == 0) { X DisplayMessage("Wait until your move"); X return; X } X break; X case MachinePlaysBlack: X if ((currentMove % 2) == 1) { X DisplayMessage("Wait until your move"); X return; X } X case BeginningOfGame: X break; X default: X return; X } X X lastGameMode = gameMode = ForceMoves; X DisplayClocks(StopTimers); X SendToProgram("force\n", toFirstProgFP); X} X void HintProc() X{ X switch (gameMode) { X case MachinePlaysWhite: X case MachinePlaysBlack: X case BeginningOfGame: X SendToProgram("hint\n", toFirstProgFP); X default: X return; X } X} X void SavePositionProc() X{ X char buf[MSG_SIZ], host_name[MSG_SIZ]; X FILE *position_file_fp; X time_t tm; X int i, j; X X if ((position_file_fp = fopen(appData.savePositionFile, "w")) == NULL) { X sprintf(buf, "Can't open %s", appData.savePositionFile); X DisplayMessage(buf); X return; X } X X tm = time((time_t *) NULL); X gethostname(host_name, MSG_SIZ); X X fprintf(position_file_fp, "xboard position file -- %s", ctime(&tm)); X switch (gameMode) { X case MachinePlaysWhite: X fprintf(position_file_fp, "\t%s@%s vs. %s@%s\n", X appData.firstChessProgram, appData.firstHost, X getpwuid(getuid())->pw_name, host_name); X break; X case MachinePlaysBlack: X fprintf(position_file_fp, "\t%s@%s vs. %s@%s\n", X getpwuid(getuid())->pw_name, host_name, X appData.firstChessProgram, appData.firstHost); X break; X case TwoMachinesPlay: X fprintf(position_file_fp, "\t%s@%s vs. %s@%s\n", X appData.secondChessProgram, appData.secondHost, X appData.firstChessProgram, appData.firstHost); X break; X default: X fprintf(position_file_fp, "\n"); X break; X } X fprintf(position_file_fp, "\n"); X X for (i = BOARD_SIZE - 1; i >= 0; i--) { X for (j = 0; j < BOARD_SIZE; j++) { X fprintf(position_file_fp, "%c", X pieceToChar[boards[currentMove][i][j]]); X fputc(j == BOARD_SIZE - 1 ? '\n' : ' ', position_file_fp); X } X } X X fclose(position_file_fp); X} X void TwoMachinesPlayProc() X{ X int i; X X if ((gameMode == EndOfGame) || (twoProgramState == True)) X return; X X if (currentMove % 2) { X DisplayMessage("White must be on move"); X return; X } X X twoProgramState = True; X X if (matchMode == MatchFalse) { X switch (gameMode) { X case MachinePlaysWhite: X case MachinePlaysBlack: X case PauseGame: X case TwoMachinesPlay: X case PlayFromGameFile: X return; X case ForceMoves: X matchMode = MatchOpening; X break; X case SetupPosition: X matchMode = MatchPosition; X break; X case BeginningOfGame: X default: X matchMode = MatchInit; X break; X } X } X X flipView = forwardForce = False; X firstMove = False; X DisplayClocks(ResetTimers); X DisplayClocks(ReStartTimers); X X switch (matchMode) { X case MatchOpening: X if (firstProgramXID == NULL) { X InitChessProgram(appData.firstHost, appData.firstChessProgram, X &firstProgramPID, &toFirstProgFP, &fromFirstProgFP, X &firstProgramXID); X if (!PlayFromGameFileProc()) { X ShutdownChessPrograms("Bad game file"); X return; X } X DrawPosition(boardWidget, (XExposeEvent *) NULL); X } X InitChessProgram(appData.secondHost, appData.secondChessProgram, X &secondProgramPID, &toSecondProgFP, &fromSecondProgFP, X &secondProgramXID); X SendToProgram("force\n", toSecondProgFP); X for (i = 0; i < currentMove; i++) X SendToProgram(moveList[i], toSecondProgFP); X lastGameMode = gameMode = TwoMachinesPlay; X firstMove = True; X SendToProgram("white\n", toSecondProgFP); X break; X case MatchPosition: X if (firstProgramXID == NULL) { X InitChessProgram(appData.firstHost, appData.firstChessProgram, X &firstProgramPID, &toFirstProgFP, &fromFirstProgFP, X &firstProgramXID); X if (!SetupPositionFromFileProc()) X return; X } X InitChessProgram(appData.secondHost, appData.secondChessProgram, X &secondProgramPID, &toSecondProgFP, &fromSecondProgFP, X &secondProgramXID); X SendCurrentBoard(toSecondProgFP); X lastGameMode = gameMode = TwoMachinesPlay; X firstMove = True; X SendToProgram("white\n", toSecondProgFP); X break; X case MatchInit: X InitPosition(); X if (firstProgramXID == NULL) X InitChessProgram(appData.firstHost, appData.firstChessProgram, X &firstProgramPID, &toFirstProgFP, &fromFirstProgFP, X &firstProgramXID); X InitChessProgram(appData.secondHost, appData.secondChessProgram, X &secondProgramPID, &toSecondProgFP, &fromSecondProgFP, X &secondProgramXID); X lastGameMode = gameMode = TwoMachinesPlay; X SendToProgram("white\n", toSecondProgFP); X break; X } X} X void PauseProc() X{ X static int previous_mode = PauseGame; X X switch (gameMode) { X case ForceMoves: X case EndOfGame: X return; X case PauseGame: X gameMode = previous_mode; X previous_mode = PauseGame; X DisplayClocks(ReStartTimers); X DisplayMessage(""); X break; X case PlayFromGameFile: X if (readGameXID == NULL) X readGameXID = XtAddTimeOut((int) (1000 * appData.timeDelay), X ReadGameFile, NULL); X else { X XtRemoveTimeOut(readGameXID); X readGameXID = NULL; X } X DisplayMessage("Pausing"); X break; X default: X if (currentMove == 0) /* don't pause if no one has moved */ X return; X previous_mode = gameMode; X gameMode = PauseGame; X DisplayClocks(StopTimers); X DisplayMessage("Pausing"); X break; X } X} X void Iconify() X{ X Arg args[1]; X X fromX = fromY = -1; X X XtSetArg(args[0], XtNiconic, True); X XtSetValues(shellWidget, args, 1); X} X void SendToProgram(message, fp) X char *message; X FILE *fp; X{ X if (appData.debugMode) X fprintf(stderr, "Sending to %s: %s\n", X fp == toFirstProgFP ? "first" : "second", message); X fputs(message, fp); X} X void ReceiveFromProgram(fp) X FILE *fp; X{ X char message[MSG_SIZ], *end_str; X X if (fgets(message, MSG_SIZ, fp) == NULL) X return; X X if ((end_str = (char *) strchr(message, '\r')) != NULL) X *end_str = '\0'; X if ((end_str = (char *) strchr(message, '\n')) != NULL) X *end_str = '\0'; X X if (appData.debugMode) X fprintf(stderr, "Received from %s: %s\n", X fp == fromFirstProgFP ? "first" : "second", message); X HandleMachineMove(message); X} X void DisplayMessage(message) X char *message; X{ X Arg arg; X X XtSetArg(arg, XtNlabel, message); X XtSetValues(messageWidget, &arg, 1); X} X X/* X * DisplayClocks manages the game clocks. X * X * In tournament play, black starts the clock and then white makes a move. X * DisplayClocks starts black's clock when white makes the first move. X * Also, DisplayClocks doesn't account for network lag so it could get X * out of sync with GNU Chess's clock -- but then, referees are always right. X */ void DisplayClocks(clock_mode) X int clock_mode; X{ X switch (clock_mode) { X case ResetTimers: X if (timerXID != NULL) { X XtRemoveTimeOut(timerXID); X timerXID = NULL; X } X X whiteTimeRemaining = appData.timeControl * 60; X DisplayTimerLabel(whiteTimerWidget, "White", whiteTimeRemaining); X X blackTimeRemaining = appData.timeControl * 60; X DisplayTimerLabel(blackTimerWidget, "Black", blackTimeRemaining); X break; X case DisplayTimers: X if (gameMode == PauseGame) X return; X if (appData.clockMode) { X if (currentMove % 2 == 0) { X if ((currentMove > 0) || (gameMode == TwoMachinesPlay)) X whiteTimeRemaining--; X if (whiteTimeRemaining <= 0) { X whiteTimeRemaining = 0; X DisplayMessage("White's flag dropped"); X } X } else { X blackTimeRemaining--; X if (blackTimeRemaining <= 0) { X blackTimeRemaining = 0; X DisplayMessage("Black's flag dropped"); X } X } X } X X DisplayTimerLabel(whiteTimerWidget, "White", whiteTimeRemaining); X DisplayTimerLabel(blackTimerWidget, "Black", blackTimeRemaining); X X /* X * reset clocks when time control is acheived X */ X if (appData.clockMode X && (((currentMove + 1) % (appData.movesPerSession * 2)) == 0) X && (whiteTimeRemaining > 0) && (blackTimeRemaining > 0)) { X whiteTimeRemaining = appData.timeControl * 60; X blackTimeRemaining = appData.timeControl * 60; X } X X if (timerXID != NULL) { X XtRemoveTimeOut(timerXID); X timerXID = NULL; X } X if (appData.clockMode) X timerXID = XtAddTimeOut(1000, DisplayClocks, DisplayTimers); X break; X case StopTimers: X if (timerXID == NULL) X return; X XtRemoveTimeOut(timerXID); X timerXID = NULL; X break; X case ReStartTimers: X if (timerXID != NULL) X return; X X DisplayTimerLabel(whiteTimerWidget, "White", whiteTimeRemaining); X DisplayTimerLabel(blackTimerWidget, "Black", blackTimeRemaining); X X if (appData.clockMode) X timerXID = XtAddTimeOut(1000, DisplayClocks, DisplayTimers); X break; X } X} X void DisplayTimerLabel(w, color, timer) X Widget w; X char *color; X time_t timer; X{ X char buf[MSG_SIZ]; X Arg args[3]; X X if (appData.clockMode) { X sprintf(buf, "%s: %s", color, TimeString(timer)); X XtSetArg(args[0], XtNlabel, buf); X } else X XtSetArg(args[0], XtNlabel, color); X X if (((color[0] == 'B') && (currentMove % 2 == 0)) X || ((color[0] == 'W') && (currentMove % 2 == 1))) { X XtSetArg(args[1], XtNbackground, XBlackPixel(xDisplay, xScreen)); X XtSetArg(args[2], XtNforeground, XWhitePixel(xDisplay, xScreen)); X } else { X XtSetArg(args[1], XtNbackground, XWhitePixel(xDisplay, xScreen)); X XtSetArg(args[2], XtNforeground, XBlackPixel(xDisplay, xScreen)); X } X XtSetValues(w, args, 3); X} X char * TimeString(tm) X time_t tm; X{ X int second, minute, hour, day; X static char buf[32]; X X if (tm >= (60 * 60 * 24)) { X day = (int) (tm / (60 * 60 * 24)); X tm -= day * 60 * 60 * 24; X } else X day = 0; X X if (tm >= (60 * 60)) { X hour = (int) (tm / (60 * 60)); X tm -= hour * 60 * 60; X } else X hour = 0; X X if (tm >= 60) { X minute = (int) (tm / 60); X tm -= minute * 60; X } else X minute = 0; X X second = tm % 60; X X if (day > 0) X sprintf(buf, " %d:%02d:%02d:%02d ", day, hour, minute, second); X else if (hour > 0) X sprintf(buf, " %d:%02d:%02d ", hour, minute, second); X else X sprintf(buf, " %2d:%02d ", minute, second); X X return buf; X} X void CatchPipeSignal() X{ X if (gameMode != BeginningOfGame) { X fprintf(stderr, "Caught pipe signal\n"); X exit(0); X } X} X void Usage() X{ X fprintf(stderr, "Usage xboard:\n"); X fprintf(stderr, "\tstandard Xt options\n"); X fprintf(stderr, "\t-wpc or -whitePieceColor color\n"); X fprintf(stderr, "\t-bpc or -blackPieceColor color\n"); X fprintf(stderr, "\t-lsc or -lightSquareColor color\n"); X fprintf(stderr, "\t-dsc or -darkSquareColor color\n"); X fprintf(stderr, "\t-mps or -movesPerSession moves\n"); X fprintf(stderr, "\t-init or -initString string\n"); X fprintf(stderr, "\t-fcp or -firstChessProgram program_name\n"); X fprintf(stderr, "\t-scp or -secondChessProgram program_name\n"); X fprintf(stderr, "\t-fh or -firstHost host_name\n"); X fprintf(stderr, "\t-sh or -secondHost host_name\n"); X fprintf(stderr, "\t-spb or -solidPawnBitmap file_name\n"); X fprintf(stderr, "\t-srb or -solidRookBitmap file_name\n"); X fprintf(stderr, "\t-sbb or -solidBishopBitmap file_name\n"); X fprintf(stderr, "\t-skb or -solidKnightBitmap file_name\n"); X fprintf(stderr, "\t-sqb or -solidQueenBitmap file_name\n"); X fprintf(stderr, "\t-skb or -solidKingBitmap file_name\n"); X fprintf(stderr, "\t-opb or -outlinePawnBitmap file_name\n"); X fprintf(stderr, "\t-orb or -outlineRookBitmap file_name\n"); X fprintf(stderr, "\t-obb or -outlineBishopBitmap file_name\n"); X fprintf(stderr, "\t-okb or -outlineKnightBitmap file_name\n"); X fprintf(stderr, "\t-oqb or -outlineQueenBitmap file_name\n"); X fprintf(stderr, "\t-okb or -outlineKingBitmap file_name\n"); X fprintf(stderr, "\t-rsh or -remoteShell shell_name\n"); X fprintf(stderr, "\t-td or -timeDelay seconds\n"); X fprintf(stderr, "\t-tc or -timeControl minutes\n"); X fprintf(stderr, "\t-sgf or -saveGameFile file_name\n"); X fprintf(stderr, "\t-rgf or -readGameFile file_name\n"); X fprintf(stderr, "\t-spf or -savePositionFile file_name\n"); X fprintf(stderr, "\t-rpf or -readPositionFile file_name\n"); X fprintf(stderr, "\t-mm or -matchMode (False | Init | Position | Opening)\n"); X fprintf(stderr, "\t-mono or -monoMode (True | False)\n"); X fprintf(stderr, "\t-debug or -debugMode (True | False)\n"); X fprintf(stderr, "\t-clock or -clockMode (True | False)\n"); X fprintf(stderr, "\t-big or -bigSizeMode (True | False)\n"); X fprintf(stderr, "\t-st or -searchTime seconds\n"); X X exit(0); X} X X/* X * This is necessary because some C libraries aren't ANSI C compliant yet. X */ char * StrStr(string, match) X char *string, *match; X{ X int i, length; X X length = strlen(match); X X for (i = strlen(string) - length; i >= 0; i--, string++) X if (!strncmp(match, string, length)) X return string; X X return NULL; X} END_OF_FILE if test 68496 -ne `wc -c <'./xboard.c'`; then echo shar: \"'./xboard.c'\" unpacked with wrong size! fi # end of './xboard.c' fi echo shar: End of shell archive. exit 0 -- Dan Heller ------------------------------------------------ O'Reilly && Associates Zyrcom Inc Senior Writer President argv@ora.com argv@zipcode.com