v13i057: xboard, Part01/06
dbs at Pa.dec.com
dbs at Pa.dec.com
Mon Jun 24 23:40:20 AEST 1991
Submitted-by: dbs at Pa.dec.com
Posting-number: Volume 13, Issue 57
Archive-name: xboard/part01
XBoard Version 1.2
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.
You can also use XBoard without a chess program to play through games in files
or to play through games manually (force mode). In this case, moves aren't
validated by XBoard. XBoard 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.
XBoard works best with the version 3.1+ of gnuchess. There has been one patch
and it is necessary. This release of gnuchess was dated: Mon Apr 15 10:20 1991
by Mike McGann and should be available from comp.sources.misc archives.
GNU Chess must be compiled with the -DCHESSTOOL option for use with XBoard.
gnuchess version 3.1+ is available on gatekeeper.dec.com
in /pub/comp.sources.misc/volume19/gnuchess
If you DO NOT have the 3.1+ version of gnuchess then you MUST add the following
to your .Xdefaults file:
XBoard*whiteString: white\n
XBoard*blackString: black\n
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.
- 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 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.
Version 1.2 -- Tue Jun 11 17:14:12 PDT 1991
- Added a lex parser for algebraic games. It should be easy to use the parser
for other interfaces such as the Microsoft Windows version.
It parses comments of the form [anything] and ! to the end of a line.
- Corrected the queening code. XBoard was sending the wrong syntax.
It was sending for example h8(Q) when it should have been sending h8q.
Thanks to Paul Vaughan and Mike McGann for pointing this out.
- Moved the man page from xboard.1 to xboard.man. This makes imake man page
installs work correctly. Thanks to Richard K. Lloyd for pointing this out.
- Changed the forwards/backwards/readgamefile code to allow a play to step
back and forth in a game. If he steps all the way to the beginning
he has to restart the game. If he gets into a mated position, same problem.
- Modified the code to use the R4 routines rather than R3 compatibility.
- Added a PopUp dialog for getting file names.
- If the first character of the file is not `1' then the first line
of a game or position file is displayed as the name in a label widget.
- Minor hacks to work with R5 alpha. Had to add an event handler to the
boardWidget to get translations to work. This may go away with the real R5.
Added <Message>WM_PROTOCOLS: QuitProc() for R5 ICCCM compatibility.
- If the DisplayWidth or DisplayHeight is less than 800, use small size mode.
Also the size of the name widget was reduced from 500 pixels to 400 pixels
because in small size mode there was a gap on the right.
Changed the default font from fixed to helvetica_oblique14 to:
-*-helvetica-bold-r-normal--14-*-*-*-*-*-*-*
helvetica_oblique14 is a font alias not on all R4 systems.
Curiously enough, the 17 point is not available on 75dpi systems
and the 18 point font is not available on 100dpi systems.
Thanks to Richard K. Lloyd for pointing these out.
- Fixed a compiler warning for gcc and an error for the IBM RT compilers.
This is the VOID_PROC macro in xboard.h. Thanks to David Jensen for this.
- -iconic doesn't work at all now. The Iconify() does work. This was
a tradeoff and it is really an Xt bug.
- fixed a problem with the new version of gnuchessr where xboard wasn't
getting gnuchessr error messages for illegal moves. The problem seems
to be fixed *without* any gnuchess changes but this is likely to be
highly system dependant. There should be a new line on line 246 of nondsp.c
printz ("Illegal move (no matching move generated)");
The xboard fix was to set non-blocking i/o on the read pipe for gnuchessr
fcntl(from_prog[0], F_SETFL, O_NDELAY);
- The bitmap file names were changed so that none exceeded 14 characters.
This is necessary for R5.
- Added the CHESSDIR environment variable. Game and position files are
found in this directory. If this variable is not declared, then the
current directory is used. File names starting with / are treated
specially.
- Fixed a bug where saving a long game, resetting and saving a short game
resulted in appending the end of the long game to the short one.
If a game is just being played out and there is no reason for gnuchessr
to be used, ignore pipe signals. This allows people to use xboard
as a chess board without need for gnuchess. Also, trivially bad moves
such as e2e2 are not passed on to gnuchessr but instead ignored out of
hand. This allows people using xboard as a chessboard with gnuchessr
to pick a piece up, think and put it back down without making a move.
Thanks to Jeff Kenton for pointing these out.
- Fixed a bug where the checkmate message wasn't being parsed and xboard
kept playing. Also, the message was added to game file if saved.
Thanks to Scott Hemhill for pointing this out.
- enumerations are not really integers on some C compilers. I added casting.
The new version of gnuchess expects the "go" command for two machine
and machine plays white cases. The whiteString resource is for
compatibility with previous gnuchess versions which get confused by go.
Thanks to Martin D. for catching these.
- There was an off by one error with the clock resetting code. Also,
the clock display highliting was wrong. Thanks to Bill Shauck for
pointing these out.
- Changed the protocol that xboard uses to work with the new version of
gnuchessr.
- Turned off the easy mode.
- For version 1.2, Jeff Kenton, Richard LLoyd, David Jensen, Martin D.,
Bill Schmidt, Scott Hemphill, Paul Vaughan and Bill Shauck all found
a lot of bugs that we put into xboard just to see if they were paying
attention. They were.
---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 06/12/1991 22:11 UTC by dbs at dbsmax.pa.dec.com
# Source directory /nfs/catacomb/cc2/dbs/xboard
#
# existing files will NOT be overwritten unless -c is specified
#
# This is part 1 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 80472 -rw-r--r-- xboard/xboard.c
# 3583 -rw-r--r-- xboard/xboard.h
# 11585 -rw-r--r-- xboard/xboard.man
# 21 -rw-r--r-- xboard/patchlevel.h
# 19769 -rw-r--r-- xboard/parser.l
# 893 -rwxr-xr-x xboard/match
# 412 -rw-r--r-- xboard/TODO
# 10539 -rw-r--r-- xboard/README
# 408 -rw-r--r-- xboard/Imakefile
# 2746 -rw-r--r-- xboard/bitmaps/k_sm_ol.bm
# 5099 -rw-r--r-- xboard/bitmaps/ol_p.bm
# 5102 -rw-r--r-- xboard/bitmaps/ol_q.bm
# 5099 -rw-r--r-- xboard/bitmaps/ol_r.bm
# 3296 -rw-r--r-- xboard/bitmaps/q_sm.bm
# 3293 -rw-r--r-- xboard/bitmaps/p_sm.bm
# 3317 -rw-r--r-- xboard/bitmaps/p_sm_ol.bm
# 3293 -rw-r--r-- xboard/bitmaps/r_sm.bm
# 5093 -rw-r--r-- xboard/bitmaps/s_k.bm
# 3320 -rw-r--r-- xboard/bitmaps/q_sm_ol.bm
# 5096 -rw-r--r-- xboard/bitmaps/s_q.bm
# 5093 -rw-r--r-- xboard/bitmaps/s_r.bm
# 3299 -rw-r--r-- xboard/bitmaps/b_sm.bm
# 3323 -rw-r--r-- xboard/bitmaps/b_sm_ol.bm
# 5099 -rw-r--r-- xboard/bitmaps/s_kt.bm
# 5093 -rw-r--r-- xboard/bitmaps/s_p.bm
# 3299 -rw-r--r-- xboard/bitmaps/kt_sm.bm
# 3323 -rw-r--r-- xboard/bitmaps/kt_sm_ol.bm
# 876 -rw-r--r-- xboard/bitmaps/icon.bm
# 5099 -rw-r--r-- xboard/bitmaps/ol_k.bm
# 5105 -rw-r--r-- xboard/bitmaps/ol_b.bm
# 5105 -rw-r--r-- xboard/bitmaps/ol_kt.bm
# 5099 -rw-r--r-- xboard/bitmaps/s_b.bm
# 3293 -rw-r--r-- xboard/bitmaps/k_sm.bm
# 3317 -rw-r--r-- xboard/bitmaps/r_sm_ol.bm
# 6426 -rw-r--r-- xboard/kk13
#
if test -r _shar_seq_.tmp; then
echo 'Must unpack archives in sequence!'
echo Please unpack part `cat _shar_seq_.tmp` next
exit 1
fi
# ============= xboard/xboard.c ==============
if test ! -d 'xboard'; then
echo 'x - creating directory xboard'
mkdir 'xboard'
fi
if test -f 'xboard/xboard.c' -a X"$1" != X"-c"; then
echo 'x - skipping xboard/xboard.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting xboard/xboard.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xboard/xboard.c' &&
/*
X * XBoard -- an Xt/Athena 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 * Revision 1.2 91/06/11
X * Another major bug fix release.
X * lex game file parser.
X * Popup dialogs for file names.
X * SYSV support.
X */
X
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#ifdef __STDC__
#include <stdlib.h>
#endif
#if SYSTEM_FIVE || SYSV
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include <pwd.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Label.h>
#include <X11/cursorfont.h>
#include "xboard.h"
X
#include "bitmaps/s_p.bm"
#include "bitmaps/s_r.bm"
#include "bitmaps/s_kt.bm"
#include "bitmaps/s_b.bm"
#include "bitmaps/s_q.bm"
#include "bitmaps/s_k.bm"
X
#include "bitmaps/ol_p.bm"
#include "bitmaps/ol_r.bm"
#include "bitmaps/ol_kt.bm"
#include "bitmaps/ol_b.bm"
#include "bitmaps/ol_q.bm"
#include "bitmaps/ol_k.bm"
X
#include "bitmaps/p_sm.bm"
#include "bitmaps/r_sm.bm"
#include "bitmaps/kt_sm.bm"
#include "bitmaps/b_sm.bm"
#include "bitmaps/q_sm.bm"
#include "bitmaps/k_sm.bm"
X
#include "bitmaps/p_sm_ol.bm"
#include "bitmaps/r_sm_ol.bm"
#include "bitmaps/kt_sm_ol.bm"
#include "bitmaps/b_sm_ol.bm"
#include "bitmaps/q_sm_ol.bm"
#include "bitmaps/k_sm_ol.bm"
X
#include "bitmaps/icon.bm"
X
void main P((int argc, char **argv));
void CreateGCs P((void));
void CreatePieces P((void));
void ReadBitmap P((String name, Pixmap *pm,
X char big_bits[], char small_bits[]));
void CreateGrid P((void));
int EventToSquare P((int x));
ChessSquare CharToPiece P((int c));
void DrawSquare P((int row, int column, ChessSquare piece));
void EventProc P((Widget widget, caddr_t unused, XEvent *event));
void DrawPosition P((Widget w, XExposeEvent *event));
void InitPosition P((void));
void CopyBoard P((Board to, Board from));
void SendCurrentBoard P((FILE *fp));
void HandleUserMove P((Widget w, XEvent *event));
void HandleMachineMove P((char *message));
void ReadGameFile P((void));
int ReadGameFileProc P((void));
void MakeMove P((ChessMove *move_type, int from_x, int from_y,
X int to_x, int to_y));
void InitChessProgram P((char *host_name, char *program_name, int *pid,
X FILE **to, FILE **from, XtIntervalId *xid));
void ShutdownChessPrograms P((char *message));
void CommentPopUp P((char *label));
void FileNamePopUp P((char *label, void (*proc)(char *name)));
void FileNameCallback P((Widget w, XtPointer client_data, XtPointer call_data));
void FileNameAction P((Widget w, XEvent *event));
void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
void GameProc P((void));
void QuitProc P((void));
int PlayFromGameFileProc P((char *name));
void MachinePlaysBlackProc P((void));
void ForwardProc P((void));
void ResetFileProc P((void));
void ResetProc P((void));
int SetupPositionFromFileProc P((char *name));
void MachinePlaysWhiteProc P((void));
void BackwardProc P((void));
void FlipProc P((void));
void SaveGameProc P((char *name));
void SwitchProc P((void));
void ForceProc P((void));
void HintProc P((void));
void SavePositionProc P((char *name));
void TwoMachinesPlayProc P((void));
void PauseProc P((void));
void Iconify P((void));
void SendToProgram P((char *message, FILE *fp));
void ReceiveFromProgram P((FILE *fp));
void DisplayMessage P((char *message));
void DisplayClocks P((int clock_mode));
void DisplayTimerLabel P((Widget w, char *color, time_t timer));
char *TimeString P((time_t tm));
void Usage P((void));
char *StrStr P((char *string, char *match));
#if SYSTEM_FIVE || SYSV
char *PseudoTTY P((int *ptyv));
#else
void CatchPipeSignal P((void));
#endif
extern int yylex P((void));
X
/*
X * XBoard depends on Xt R4 or higher
X */
int xtVersion = XtSpecificationRelease;
X
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, nameWidget, widgetList[6], commentShell;
XXSegment gridSegments[(BOARD_SIZE + 1) * 2];
XXtIntervalId firstProgramXID = NULL, secondProgramXID = NULL,
X readGameXID = NULL, timerXID = NULL;
XXFontStruct *labelFont;
XXtAppContext appContext;
XXtCallbackProc fileProc;
X
FILE *fromFirstProgFP, *toFirstProgFP, *fromSecondProgFP,
X *toSecondProgFP, *gameFileFP;
int currentMove = 0, forwardMostMove = 0, firstProgramPID = 0,
X secondProgramPID = 0, squareSize = BIG_SQUARE_SIZE, fromX = -1,
X fromY = -1, firstMove = True, flipView = False, forwardForce = False,
X twoProgramState = False, undoMode = False, xboardDebug,
X commentUp = False;
unsigned long timerForegroundPixel, timerBackgroundPixel;
MatchMode matchMode = MatchFalse;
GameMode gameMode = BeginningOfGame, lastGameMode = BeginningOfGame;
char moveList[MAX_MOVES][MOVE_LEN], parseList[MAX_MOVES][MOVE_LEN * 2],
X ptyname[24], *ttyname, *chessDir, *programName;
X
time_t whiteTimeRemaining, blackTimeRemaining;
extern char currentMoveString[];
extern char yytext[];
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
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
Arg shellArgs[] = {
X { XtNwidth, 0 },
X { XtNheight, 0 },
X { XtNminWidth, 0 },
X { XtNminHeight, 0 },
X { XtNmaxWidth, 0 },
X { XtNmaxHeight, 0 }
};
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
Arg commandsArgs[] = {
X { XtNborderWidth, 0 },
X { XtNdefaultColumns, 4 },
X { XtNforceColumns, True },
X { XtNlist, (int) buttonStrings },
X { XtNnumberStrings, XtNumber(buttonStrings) }
};
X
Arg messageArgs[] = {
X { XtNborderWidth, 0 },
X { XtNwidth, 250 },
X { XtNjustify, (int) XtJustifyLeft }
};
X
Arg timerArgs[] = {
X { XtNborderWidth, 0 },
X { XtNjustify, (int) XtJustifyLeft }
};
X
Arg nameArgs[] = {
X { XtNborderWidth, 0 },
X { XtNwidth, 300 },
X { XtNjustify, (int) XtJustifyLeft }
};
X
typedef struct {
X Pixel whitePieceColor;
X Pixel blackPieceColor;
X Pixel lightSquareColor;
X Pixel darkSquareColor;
X int movesPerSession;
X String initString;
X String whiteString;
X String blackString;
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 readGameFile;
X String readPositionFile;
X String saveGameFile;
X String savePositionFile;
X String matchMode;
X Boolean monoMode;
X Boolean debugMode;
X ClockMode clockMode;
X Boolean bigSizeMode;
X int searchTime;
} 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 "whiteString", "whiteString", XtRString, sizeof(String),
X XtOffset(AppDataPtr, whiteString), XtRString, WHITE_STRING
X }, {
X "blackString", "blackString", XtRString, sizeof(String),
X XtOffset(AppDataPtr, blackString), XtRString, BLACK_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, NULL
X }, {
X "solidRookBitmap", "solidRookBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, solidRookBitmap), XtRString, NULL
X }, {
X "solidKnightBitmap", "solidKnightBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, solidKnightBitmap), XtRString, NULL
X }, {
X "solidBishopBitmap", "solidBishopBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, solidBishopBitmap), XtRString, NULL
X }, {
X "solidQueenBitmap", "solidQueenBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, solidQueenBitmap), XtRString, NULL
X }, {
X "solidKingBitmap", "solidKingBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, solidKingBitmap), XtRString, NULL
X }, {
X "outlinePawnBitmap", "outlinePawnBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, outlinePawnBitmap), XtRString, NULL
X }, {
X "outlineRookBitmap", "outlineRookBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, outlineRookBitmap), XtRString, NULL
X }, {
X "outlineKnightBitmap", "outlineKnightBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, outlineKnightBitmap), XtRString, NULL
X }, {
X "outlineBishopBitmap", "outlineBishopBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, outlineBishopBitmap), XtRString, NULL
X }, {
X "outlineQueenBitmap", "outlineQueenBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, outlineQueenBitmap), XtRString, NULL
X }, {
X "outlineKingBitmap", "outlineKingBitmap", XtRString, sizeof(String),
X XtOffset(AppDataPtr, outlineKingBitmap), XtRString, NULL
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 "readGameFile", "readGameFile", XtRString, sizeof(String),
X XtOffset(AppDataPtr, readGameFile), XtRString, NULL
X }, {
X "readPositionFile", "readPositionFile", XtRString, sizeof(String),
X XtOffset(AppDataPtr, readPositionFile), XtRString, NULL
X }, {
X "saveGameFile", "saveGameFile", XtRString, sizeof(String),
X XtOffset(AppDataPtr, saveGameFile), XtRString, ""
X }, {
X "savePositionFile", "savePositionFile", XtRString, sizeof(String),
X XtOffset(AppDataPtr, savePositionFile), XtRString, ""
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
Pixmap *pieceToSolid[] = {
X &solidPawnBitmap, &solidRookBitmap, &solidKnightBitmap,
X &solidBishopBitmap, &solidQueenBitmap, &solidKingBitmap,
X &solidPawnBitmap, &solidRookBitmap, &solidKnightBitmap,
X &solidBishopBitmap, &solidQueenBitmap, &solidKingBitmap
};
X
Pixmap *pieceToOutline[] = {
X &outlinePawnBitmap, &outlineRookBitmap, &outlineKnightBitmap,
X &outlineBishopBitmap, &outlineQueenBitmap, &outlineKingBitmap,
X &outlinePawnBitmap, &outlineRookBitmap, &outlineKnightBitmap,
X &outlineBishopBitmap, &outlineQueenBitmap, &outlineKingBitmap
};
X
char pieceToChar[] = {
X 'P', 'R', 'N', 'B', 'Q', 'K',
X 'p', 'r', 'n', 'b', 'q', 'k', '.'
};
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 { "-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 { "-readGameFile", "readGameFile", XrmoptionSepArg, NULL },
X { "-rgf", "readGameFile", XrmoptionSepArg, NULL },
X { "-readPositionFile", "readPositionFile", XrmoptionSepArg, NULL },
X { "-rpf", "readPositionFile", XrmoptionSepArg, NULL },
X { "-saveGameFile", "saveGameFile", XrmoptionSepArg, NULL },
X { "-sgf", "saveGameFile", XrmoptionSepArg, NULL },
X { "-savePositionFile", "savePositionFile", XrmoptionSepArg, NULL },
X { "-spf", "savePositionFile", 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
XXtActionsRec boardActions[] = {
X { "DrawPosition", DrawPosition },
X { "HandleUserMove", HandleUserMove },
X { "ResetProc", ResetProc },
X { "ResetFileProc", ResetFileProc },
X { "GameProc", GameProc },
X { "QuitProc", QuitProc },
X { "ForwardProc", ForwardProc },
X { "BackwardProc", BackwardProc },
X { "PauseProc", PauseProc },
X { "Iconify", Iconify },
X { "FileNameAction", FileNameAction }
};
X
char translationsTable[] =
X "<Expose>: DrawPosition() \n \
X <BtnDown>: HandleUserMove() \n \
X <BtnUp>: HandleUserMove() \n \
X <Key>r: ResetFileProc() ResetProc() \n \
X <Key>R: ResetFileProc() ResetProc() \n \
X <Key>g: GameProc() \n \
X <Key>G: GameProc() \n \
X <Key>q: QuitProc() \n \
X <Key>Q: QuitProc() \n \
X <Message>WM_PROTOCOLS: 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() \n";
X
String xboardResources[] = {
X "*font: -*-helvetica-medium-o-normal--*-140-*-*-*-*-*-*\n",
X "*Dialog*value.translations: #override \\n <Key>Return: FileNameAction()",
X NULL
};
X
void
main(argc, argv)
X int argc;
X char **argv;
{
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 programName = argv[0];
X
X shellWidget = XtAppInitialize(&appContext, "XBoard", shellOptions,
X XtNumber(shellOptions), &argc, argv, xboardResources, NULL, 0);
X
X if (argc > 1)
X Usage();
X
X if ((chessDir = (char *) getenv("CHESSDIR")) == NULL)
X chessDir = ".";
X
X XtGetApplicationResources(shellWidget, &appData, clientResources,
X XtNumber(clientResources), NULL, 0);
X
X xboardDebug = appData.debugMode;
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, "%s: bad matchMode option %s\n",
X appData.matchMode, programName);
X Usage();
X }
X
X xDisplay = XtDisplay(shellWidget);
X xScreen = DefaultScreen(xDisplay);
X
X if ((DisplayWidth(xDisplay, xScreen) < 800) ||
X (DisplayHeight(xDisplay, xScreen) < 800))
X appData.bigSizeMode = False;
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] = nameWidget = XtCreateWidget("",
X labelWidgetClass, formWidget, nameArgs, XtNumber(nameArgs));
X
X widgetList[3] = messageWidget = XtCreateWidget("message",
X labelWidgetClass, formWidget, messageArgs, XtNumber(messageArgs));
X
X widgetList[4] = commandsWidget = XtCreateWidget("commands",
X listWidgetClass, formWidget, commandsArgs, XtNumber(commandsArgs));
X
X widgetList[5] = 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 XtSetArg(args[0], XtNbackground, &timerForegroundPixel);
X XtSetArg(args[1], XtNforeground, &timerBackgroundPixel);
X XtGetValues(whiteTimerWidget, args, 2);
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], XtNfromHoriz, blackTimerWidget);
X XtSetValues(nameWidget, args, 1);
X XtSetArg(args[0], XtNfromVert, whiteTimerWidget);
X XtSetValues(messageWidget, args, 1);
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 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
X
X XtSetArg(args[0], XtNtranslations,
X XtParseTranslationTable(translationsTable));
X XtSetValues(boardWidget, &args[0], 1);
X XtAddEventHandler(boardWidget, ExposureMask | ButtonPressMask
X | ButtonReleaseMask | Button1MotionMask | KeyPressMask,
X False, EventProc, NULL);
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 XtAppMainLoop(appContext);
}
X
void
CreateGCs()
{
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
void
CreatePieces()
{
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
void
ReadBitmap(name, pm, big_bits, small_bits)
X String name;
X Pixmap *pm;
X char big_bits[], small_bits[];
{
X int x_hot, y_hot;
X u_int w, h;
X
X if (name == NULL || 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
void
CreateGrid()
{
X int i;
X
X for (i = 0; i < BOARD_SIZE + 1; i++) {
X gridSegments[i].x1 = gridSegments[i + BOARD_SIZE + 1].y1 = 0;
X gridSegments[i].y1 = gridSegments[i].y2
X = LINE_GAP / 2 + (i * (squareSize + LINE_GAP));
X gridSegments[i].x2 = LINE_GAP + BOARD_SIZE * (squareSize + LINE_GAP);
X gridSegments[i + BOARD_SIZE + 1].x1 =
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 * 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
EventToSquare(x)
X int 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
ChessSquare
CharToPiece(c)
X int c;
{
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
void
DrawSquare(row, column, piece)
X int row, column;
X ChessSquare piece;
{
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, (int) piece < (int) BlackPawn
X ? *pieceToOutline[(int) piece] : *pieceToSolid[(int) piece],
X xBoardWindow, bwPieceGC, 0, 0, squareSize, squareSize, x, y, 1);
X else XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
X ? *pieceToSolid[(int) piece] : *pieceToOutline[(int) piece],
X xBoardWindow, wbPieceGC, 0, 0, squareSize, squareSize, x, y, 1);
X } else {
X if (square_color)
X XCopyPlane(xDisplay, *pieceToSolid[(int) piece],
X xBoardWindow, (int) piece < (int) BlackPawn ? wlPieceGC
X : blPieceGC, 0, 0, squareSize, squareSize, x, y, 1);
X else XCopyPlane(xDisplay, *pieceToSolid[(int) piece],
X xBoardWindow, (int) piece < (int) BlackPawn ? wdPieceGC
X : bdPieceGC, 0, 0, squareSize, squareSize, x, y, 1);
X }
}
X
void
EventProc(widget, unused, event)
X Widget widget;
X caddr_t unused;
X XEvent *event;
{
X if (event->type == MappingNotify) {
X XRefreshKeyboardMapping((XMappingEvent *) event);
X return;
X }
X
X if (!XtIsRealized(widget))
X return;
X
X if ((event->type == ButtonPress) || (event->type == ButtonRelease))
X if (event->xbutton.button != Button1)
X return;
X
X switch (event->type) {
X case Expose:
X DrawPosition(widget, (XExposeEvent *) event);
X break;
X default:
X return;
X }
}
X
/*
X * event handler for redrawing the board
X */
void
DrawPosition(w, event)
X Widget w;
X XExposeEvent *event;
{
X Arg args[1];
X int i, j;
X
X XtSetArg(args[0], XtNiconic, False);
X XtSetValues(shellWidget, args, 1);
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, boards[currentMove][i][j]);
X
X XSync(xDisplay, False);
}
X
void
InitPosition()
{
X currentMove = forwardMostMove = 0;
X CopyBoard(boards[0], initialPosition);
X DrawPosition(boardWidget, (XExposeEvent *) NULL);
}
X
void
CopyBoard(to, from)
X Board to, from;
{
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
void
SendCurrentBoard(fp)
X FILE *fp;
{
X char message[MSG_SIZ];
X ChessSquare *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 ((int) *bp < (int) BlackPawn) {
X sprintf(message, "%c%c%c\n", pieceToChar[(int) *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 (((int) *bp != (int) EmptySquare)
X && ((int) *bp >= (int) BlackPawn)) {
X sprintf(message, "%c%c%c\n",
X pieceToChar[(int) *bp - (int) BlackPawn], 'a' + j, '1' + i);
X SendToProgram(message, fp);
X }
X }
X }
X
X SendToProgram(".\n", fp);
}
X
/*
X * event handler for parsing user moves
X */
void
HandleUserMove(w, event)
X Widget w;
X XEvent *event;
{
X ChessMove move_type;
X int 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 (WHITE_ON_MOVE)
X return;
X break;
X case MachinePlaysBlack:
X if (!WHITE_ON_MOVE)
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 || ((fromY = EventToSquare(event->xbutton.y)) < 0)) {
X fromX = fromY = -1;
X break;
X }
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 || ((to_y = EventToSquare(event->xbutton.y)) < 0)) {
X fromX = fromY = -1;
X break;
X }
X if (flipView)
X to_x = BOARD_SIZE - 1 - to_x;
X else
X to_y = BOARD_SIZE - 1 - to_y;
X
X if ((fromX == to_x) && (fromY == to_y)) {
X fromX = fromY = -1;
X break;
X }
X
X MakeMove(&move_type, fromX, fromY, to_x, to_y);
X
X switch (move_type) {
X default:
X fprintf(stderr, "%s: Can't happen (yet)\n", programName);
X break;
X case WhitePromotionQueen:
X case BlackPromotionQueen:
X sprintf(user_move, "%c%c%c%cq\n",
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 if (forwardForce) {
X if (gameMode == PauseGame)
X PauseProc();
X if (gameMode == MachinePlaysWhite)
X SendToProgram(appData.whiteString, toFirstProgFP);
X else if (gameMode == MachinePlaysBlack)
X SendToProgram(appData.blackString, toFirstProgFP);
X }
X
X switch (gameMode) {
X case PauseGame:
X PauseProc(); /* a user move restarts a paused game */
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(appData.blackString, toFirstProgFP);
X }
X case MachinePlaysWhite:
X default:
X break;
X }
X break;
X }
}
X
void
HandleMachineMove(message)
X char *message;
{
X char machine_move[MSG_SIZ], buf1[MSG_SIZ], buf2[MSG_SIZ];
X int i, j, from_x, from_y, to_x, to_y;
X ChessMove move_type;
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 if (WHITE_ON_MOVE)
X sprintf(buf1, "Illegal move: %d. %s",
X (currentMove / 2) + 1, moveList[currentMove - 1]);
X else
X sprintf(buf1, "Illegal move: %d. ... %s",
X (currentMove / 2) + 1, moveList[currentMove - 1]);
X ShutdownChessPrograms(buf1);
X return;
X }
X
X currentMove--;
X if (gameMode != ForceMoves)
X DisplayClocks(DisplayTimers);
X sprintf(buf1, "Illegal move: %s", moveList[currentMove]);
X DisplayMessage(buf1);
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, 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 strcpy(moveList[currentMove++], "White wins");
X return;
X } else if (strncmp(message, "Black", 5) == 0) {
X ShutdownChessPrograms("Black wins");
X strcpy(moveList[currentMove++], "Black wins");
X return;
X } else if (strncmp(message, "opponent mates!", 15) == 0) {
X if (gameMode == MachinePlaysBlack)
X ShutdownChessPrograms("White wins");
X else
X ShutdownChessPrograms("Black wins");
X strcpy(moveList[currentMove++], "mate");
X return;
X } else if (strncmp(message, "computer mates!", 15) == 0) {
X if (gameMode == MachinePlaysWhite)
X ShutdownChessPrograms("White wins");
X else
X ShutdownChessPrograms("Black wins");
X strcpy(moveList[currentMove++], "mate");
X return;
X } else if (strncmp(message, "Draw", 4) == 0) {
X ShutdownChessPrograms("Draw");
X strcpy(moveList[currentMove++], "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 case EndOfGame:
X default:
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, WHITE_ON_MOVE
X ? toSecondProgFP : toFirstProgFP);
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(appData.blackString, toFirstProgFP);
X }
X break;
X }
}
X
void
ReadGameFile()
{
X for (;;) {
X if (!ReadGameFileProc())
X return;
X if (matchMode == MatchOpening)
X continue;
X readGameXID = XtAppAddTimeOut(appContext,
X (int) (1000 * appData.timeDelay), ReadGameFile, NULL);
X break;
X }
}
X
int
ReadGameFileProc()
{
X int from_x, from_y, to_x, to_y;
X ChessMove move_type;
X char move[MSG_SIZ];
X
X if (gameFileFP == NULL)
X return (int) False;
X
X if ((gameMode == EndOfGame) || (gameMode == BeginningOfGame)
X || feof(gameFileFP)) {
X fclose(gameFileFP);
X gameFileFP = NULL;
X return (int) False;
X }
X
X if (commentUp) {
X XtPopdown(commentShell);
X XtDestroyWidget(commentShell);
X commentUp = False;
X }
X
X move_type = (ChessMove) yylex();
X
X if (xboardDebug)
X if (move_type == BadMove)
X fprintf(stderr, "BadMove parsing %s\n", yytext);
X else
X fprintf(stderr, "Parsed %s into %s", yytext, currentMoveString);
X
X switch (move_type) {
X case Comment:
X CommentPopUp(yytext);
X return (int) True;
X case WhiteKingSideCastle:
X from_x = 4;
X from_y = 0;
X to_x = 6;
X to_y = 0;
X break;
X case WhiteQueenSideCastle:
X from_x = 4;
X from_y = 0;
X to_x = 2;
X to_y = 0;
X break;
X case BlackKingSideCastle:
X from_x = 4;
X from_y = 7;
X to_x = 6;
X to_y = 7;
X break;
X case BlackQueenSideCastle:
X from_x = 4;
X from_y = 7;
X to_x = 2;
X to_y = 7;
X break;
X case WhiteCapturesEnPassant:
X case BlackCapturesEnPassant:
X case WhitePromotionQueen:
X case BlackPromotionQueen:
X case NormalMove:
X from_x = tolower(currentMoveString[0]) - 'a';
X from_y = tolower(currentMoveString[1]) - '1';
X to_x = tolower(currentMoveString[2]) - 'a';
X to_y = tolower(currentMoveString[3]) - '1';
X break;
X case 0: /* end of file */
X strcpy(parseList[currentMove], "End Of Game");
X case WhiteWins:
X if (move_type == WhiteWins)
X strcpy(parseList[currentMove], "1-0");
X case BlackWins:
X if (move_type == BlackWins)
X strcpy(parseList[currentMove], "0-1");
X case GameIsDrawn:
X if (move_type == GameIsDrawn)
X strcpy(parseList[currentMove], "1/2");
X CopyBoard(boards[currentMove + 1], boards[currentMove]);
X forwardMostMove = currentMove++;
X default:
X case BadMove:
X case WhitePromotionRook: /* TODO: not handled yet */
X case BlackPromotionRook:
X case WhitePromotionBishop:
X case BlackPromotionBishop:
X case WhitePromotionKnight:
X case BlackPromotionKnight:
X if (move_type == (ChessMove) 0)
X DisplayMessage("End Of Game");
X else if (move_type == BadMove) {
X if (WHITE_ON_MOVE)
X sprintf(move, "Bad move: %d. %s",
X (currentMove / 2) + 1, yytext);
X else
X sprintf(move, "Bad move: %d. ... %s",
X (currentMove / 2) + 1, yytext);
X DisplayMessage(move);
X } else
X DisplayMessage(yytext);
X lastGameMode = gameMode;
X gameMode = BeginningOfGame;
X if (readGameXID != NULL) {
X XtRemoveTimeOut(readGameXID);
X readGameXID = NULL;
X }
X fclose(gameFileFP);
X gameFileFP = NULL;
X return (int) False;
X }
X
X SendToProgram(currentMoveString, toFirstProgFP);
X strncpy(moveList[currentMove], currentMoveString, MOVE_LEN);
X
X MakeMove(&move_type, from_x, from_y, to_x, to_y);
X
X return (int) True;
}
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 ChessMove *move_type;
X int from_x, from_y, to_x, to_y;
{
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, boards[currentMove][0][7]);
X DrawSquare(0, 6, boards[currentMove][0][6]);
X DrawSquare(0, 5, boards[currentMove][0][5]);
X DrawSquare(0, 4, boards[currentMove][0][4]);
X if (gameMode == PlayFromGameFile)
X sprintf(message, "%d. %s", move, yytext);
X else
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, boards[currentMove][0][0]);
X DrawSquare(0, 2, boards[currentMove][0][2]);
X DrawSquare(0, 3, boards[currentMove][0][3]);
X DrawSquare(0, 4, boards[currentMove][0][4]);
X if (gameMode == PlayFromGameFile)
X sprintf(message, "%d. %s", move, yytext);
X else
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 = WhitePromotionQueen; /* TODO: gnuchess limitation */
X boards[currentMove][6][from_x] = EmptySquare;
X boards[currentMove][7][to_x] = WhiteQueen;
X DrawSquare(6, from_x, boards[currentMove][6][from_x]);
X DrawSquare(7, to_x, boards[currentMove][7][to_x]);
X if (gameMode == PlayFromGameFile)
X sprintf(message, "%d. %s", move, yytext);
X else
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;
SHAR_EOF
true || echo 'restore of xboard/xboard.c failed'
fi
echo 'End of part 1'
echo 'File xboard/xboard.c is continued in part 2'
echo 2 > _shar_seq_.tmp
exit 0
--
Dan Heller
O'Reilly && Associates Z-Code Software Comp-sources-x:
Senior Writer President comp-sources-x at uunet.uu.net
argv at ora.com argv at zipcode.com
More information about the Comp.sources.x
mailing list