Finally get rid of that highly non-standard use of SIGINT.
[gnushogi.git] / xshogi / xshogi.c
blobff2bdc361c7ab38d5d9f779f0b702c7c5ab62649
1 /*
2 * FILE: xshogi.c
4 * Implementation of the X interface for GNU shogi (xshogi).
6 * ------------------------------------------------------------------------
7 * xshogi is based on XBoard -- an Xt/Athena user interface for GNU Chess.
9 * Original authors: Dan Sears, Chris Sears
10 * Enhancements (Version 2.0 and following): Tim Mann
11 * Modifications to XShogi (Version 1.0): Matthias Mutz
12 * Enhancements to XShogi (Version 1.1): Matthias Mutz
13 * Modified implementation of ISS mode for XShogi: Matthias Mutz
14 * Current maintainer: Michael C. Vanier
16 * XShogi borrows some of its piece bitmaps from CRANES Shogi.
18 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
19 * Enhancements Copyright 1992 Free Software Foundation, Inc.
20 * Enhancements for XShogi Copyright 1993, 1994, 1995 Matthias Mutz
21 * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
23 * The following terms apply to Digital Equipment Corporation's copyright
24 * interest in XBoard:
25 * ------------------------------------------------------------------------
26 * All Rights Reserved
28 * Permission to use, copy, modify, and distribute this software and its
29 * documentation for any purpose and without fee is hereby granted,
30 * provided that the above copyright notice appear in all copies and that
31 * both that copyright notice and this permission notice appear in
32 * supporting documentation, and that the name of Digital not be
33 * used in advertising or publicity pertaining to distribution of the
34 * software without specific, written prior permission.
36 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
37 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
38 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
39 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
40 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
41 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
42 * SOFTWARE.
43 * ------------------------------------------------------------------------
45 * This file is part of GNU shogi.
47 * GNU shogi is free software; you can redistribute it and/or modify
48 * it under the terms of the GNU General Public License as published by
49 * the Free Software Foundation.
51 * GNU shogi is distributed in the hope that it will be useful,
52 * but WITHOUT ANY WARRANTY; without even the implied warranty of
53 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54 * GNU General Public License for more details.
56 * You should have received a copy of the GNU General Public License
57 * along with GNU shogi; see the file COPYING. If not, write to
58 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
60 * ------------------------------------------------------------------------
64 #include "config.h"
66 #ifdef X_DISPLAY_MISSING
67 #error You cannot compile xshogi if X windows is unavailable!
68 #endif
70 #include "sysdeps.h"
72 #define XBOARD_VERSION "2.0/2.1"
74 #include <stdio.h>
75 #include <ctype.h>
76 #include <signal.h>
77 #include <sys/ioctl.h>
79 #include <time.h>
80 #include <pwd.h>
82 #include <X11/Intrinsic.h>
83 #include <X11/StringDefs.h>
84 #include <X11/Shell.h>
85 #include <X11/Xaw/Dialog.h>
86 #include <X11/Xaw/Form.h>
87 #include <X11/Xaw/List.h>
88 #include <X11/Xaw/Label.h>
89 #include <X11/Xaw/SimpleMenu.h>
90 #include <X11/Xaw/SmeBSB.h>
91 #include <X11/Xaw/SmeLine.h>
92 #include <X11/cursorfont.h>
94 #include "../version.h"
95 #include "xshogi.h"
97 #define BUF_SIZE 1024
98 #define BOARD 1
99 #define MOVES 2
101 #include "bitmaps.h" /* Piece bitmaps. */
102 #include "xshogifn.h" /* Forward declarations. */
104 #define off_board(x) ((x < 2) || (x > BOARD_SIZE + 1))
107 /**********************************************************************
109 * Global variables, structs etc.
111 **********************************************************************/
114 * NOTE: XShogi depends on Xt R4 or higher
117 int xtVersion = XtSpecificationRelease;
119 XtIntervalId firstProgramXID = 0, secondProgramXID = 0,
120 readGameXID = 0, timerXID = 0, blinkSquareXID = 0;
122 XtAppContext appContext;
124 Boolean (*fileProc) (char *name);
126 FILE *fromFirstProgFP, *toFirstProgFP, *fromSecondProgFP,
127 *toSecondProgFP, *gameFileFP, *lastMsgFP;
129 int currentMove = 0, forwardMostMove = 0, backwardMostMove = 0,
130 firstProgramPID = 0,
131 secondProgramPID = 0, fromX = -1,
132 fromY = -1, firstMove = True, flipView = False,
133 xshogiDebug = True, commentUp = False, filenameUp = False,
134 whitePlaysFirst = False, startedFromSetupPosition = False,
135 searchTime = 0, pmFromX = -1, pmFromY = -1,
136 blackFlag = False, whiteFlag = False, maybeThinking = False,
137 filemodeUp = False;
139 int at_least_gnushogi_1_2p03 = False;
141 int firstSendTime = 2, secondSendTime = 2; /* 0 = don't, 1 = do,
142 2 = test first */
144 MatchMode matchMode = MatchFalse;
145 GameMode gameMode = BeginningOfGame;
146 GameMode lastGameMode = BeginningOfGame;
147 GameMode pausePreviousMode = BeginningOfGame;
149 char moveList[MAX_MOVES][MOVE_LEN], parseList[MAX_MOVES][MOVE_LEN * 2],
150 ptyname[24], *shogiDir, *programName;
152 char endMessage[MOVE_LEN * 4];
154 long blackTimeRemaining, whiteTimeRemaining, timeControl;
155 long timeRemaining[2][MAX_MOVES];
157 extern char currentMoveString[];
159 int updateRemotePlayer = False;
161 Catched catches[MAX_MOVES];
163 #define DIMENSION 100
165 Widget blackPieceMenu, whitePieceMenu, commentShell;
167 XSetWindowAttributes attr;
169 #define pawn 0
170 #define lance 1
171 #define knight 2
172 #define silver 3
173 #define gold 4
174 #define bishop 5
175 #define rook 6
176 #define king 7
177 #define no_piece 8
178 #define ppawn 9
179 #define plance 10
180 #define pknight 11
181 #define psilver 12
182 #define pbishop 13
184 #define NO_PIECES 15
185 #define NO_SQUARES 81
186 #define NO_COLS 9
187 #define NO_ROWS 9
190 char catchedIndexToChar[8] =
192 'P', 'L', 'N', 'S', 'G', 'B', 'R', 'K'
195 ShogiSquare catchedIndexToPiece[2][8] =
198 BlackPawn, BlackLance, BlackKnight, BlackSilver, BlackGold,
199 BlackBishop, BlackRook, BlackKing
202 WhitePawn, WhiteLance, WhiteKnight, WhiteSilver, WhiteGold,
203 WhiteBishop, WhiteRook, WhiteKing
208 int pieceToCatchedIndex[] =
210 pawn, lance, knight, silver, gold, bishop, rook,
211 pawn, lance, knight, silver, bishop, rook, king,
212 pawn, lance, knight, silver, gold, bishop, rook,
213 pawn, lance, knight, silver, bishop, rook, king,
214 no_piece
219 Board boards[MAX_MOVES];
220 Board initialPosition =
222 { BlackLance, BlackKnight, BlackSilver, BlackGold, BlackKing,
223 BlackGold, BlackSilver, BlackKnight, BlackLance },
224 { EmptySquare, BlackBishop, EmptySquare, EmptySquare, EmptySquare,
225 EmptySquare, EmptySquare, BlackRook, EmptySquare },
226 { BlackPawn, BlackPawn, BlackPawn, BlackPawn, BlackPawn,
227 BlackPawn, BlackPawn, BlackPawn, BlackPawn },
228 { EmptySquare, EmptySquare, EmptySquare, EmptySquare, EmptySquare,
229 EmptySquare, EmptySquare, EmptySquare, EmptySquare } ,
230 { EmptySquare, EmptySquare, EmptySquare, EmptySquare, EmptySquare,
231 EmptySquare, EmptySquare, EmptySquare, EmptySquare } ,
232 { EmptySquare, EmptySquare, EmptySquare, EmptySquare, EmptySquare,
233 EmptySquare, EmptySquare, EmptySquare, EmptySquare } ,
234 { WhitePawn, WhitePawn, WhitePawn, WhitePawn, WhitePawn,
235 WhitePawn, WhitePawn, WhitePawn, WhitePawn },
236 { EmptySquare, WhiteRook, EmptySquare, EmptySquare, EmptySquare,
237 EmptySquare, EmptySquare, WhiteBishop, EmptySquare },
238 { WhiteLance, WhiteKnight, WhiteSilver, WhiteGold, WhiteKing,
239 WhiteGold, WhiteSilver, WhiteKnight, WhiteLance }
242 String gnuButtonStrings[] =
244 "Quit", "Load Game", "Machine White", "Forward",
245 "Reset", "Load Position", "Machine Black", "Backward",
246 "Flip View", "Save Game", "Force Moves", "Pause",
247 "Hint", "Save Position", "Two Machines", "Edit Position",
248 "Challenge", "Select Level", "Move NOW",
251 /* must be in same order as buttonStrings! */
252 XtActionProc gnuButtonProcs[] =
254 QuitProc, LoadGameProc, MachineWhiteProc, ForwardProc,
255 ResetProc, LoadPositionProc, MachineBlackProc, BackwardProc,
256 FlipViewProc, SaveGameProc, ForceProc, PauseProc,
257 HintProc, SavePositionProc, TwoMachinesProc, EditPositionProc,
258 ChallengeProc, SelectLevelProc, MoveNowProc,
259 NULL
263 String *buttonStrings;
264 XtActionProc *buttonProcs;
265 int buttonCount;
267 #define PIECE_MENU_SIZE 18
269 String pieceMenuStrings[PIECE_MENU_SIZE] =
271 "----", "Pawn", "Lance", "Knight", "Silver",
272 "Gold", "Bishop", "Rook",
273 "PPawn", "PLance", "PKnight", "PSilver",
274 "PBishop", "PRook", "King",
275 "----", "Empty square", "Clear board"
278 /* must be in same order as PieceMenuStrings! */
279 ShogiSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] =
282 (ShogiSquare) 0, BlackPawn, BlackLance, BlackKnight,
283 BlackSilver, BlackGold, BlackBishop, BlackRook,
284 BlackPPawn, BlackPLance, BlackPKnight, BlackPSilver,
285 BlackPBishop, BlackPRook, BlackKing,
286 (ShogiSquare) 0, EmptySquare, ClearBoard
289 (ShogiSquare) 0, WhitePawn, WhiteLance, WhiteKnight,
290 WhiteSilver, WhiteGold, WhiteBishop, WhiteRook,
291 WhitePPawn, WhitePLance, WhitePKnight, WhitePSilver,
292 WhitePBishop, WhitePRook, WhiteKing,
293 (ShogiSquare) 0, EmptySquare, ClearBoard
298 typedef struct
300 Pixel pieceColor;
301 Pixel squareColor;
302 Pixel charPieceColor;
303 Pixel zeroColor;
304 Pixel oneColor;
305 Boolean westernPieceSet;
306 int movesPerSession;
307 String initString;
308 String blackString;
309 String whiteString;
310 String firstShogiProgram;
311 String secondShogiProgram;
312 Boolean noShogiProgram;
313 String firstHost;
314 String secondHost;
315 String reverseBigSolidBitmap;
316 String reverseSmallSolidBitmap;
317 String normalBigSolidBitmap;
318 String normalSmallSolidBitmap;
319 String reversePawnBitmap;
320 String reverseLanceBitmap;
321 String reverseKnightBitmap;
322 String reverseSilverBitmap;
323 String reverseGoldBitmap;
324 String reverseRookBitmap;
325 String reverseBishopBitmap;
326 String reversePPawnBitmap;
327 String reversePLanceBitmap;
328 String reversePKnightBitmap;
329 String reversePSilverBitmap;
330 String reversePBishopBitmap;
331 String reversePRookBitmap;
332 String reverseKingBitmap;
333 String normalPawnBitmap;
334 String normalLanceBitmap;
335 String normalKnightBitmap;
336 String normalSilverBitmap;
337 String normalGoldBitmap;
338 String normalRookBitmap;
339 String normalBishopBitmap;
340 String normalPPawnBitmap;
341 String normalPLanceBitmap;
342 String normalPKnightBitmap;
343 String normalPSilverBitmap;
344 String normalPBishopBitmap;
345 String normalPRookBitmap;
346 String normalKingBitmap;
347 String remoteShell;
348 float timeDelay;
349 String timeControl;
350 String gameIn;
352 Boolean autoSaveGames;
353 String loadGameFile;
354 String loadPositionFile;
355 String saveGameFile;
356 String savePositionFile;
357 String matchMode;
358 String challengeDisplay;
359 Boolean monoMode;
360 Boolean debugMode;
361 Boolean clockMode;
362 String boardSize;
363 Boolean Iconic;
364 String searchTime;
365 int searchDepth;
366 Boolean showCoords;
367 String mainFont;
368 String coordFont;
369 Boolean ringBellAfterMoves;
370 Boolean autoCallFlag;
371 int borderXoffset;
372 int borderYoffset;
373 } AppData, *AppDataPtr;
376 XtResource clientResources[] =
379 "pieceColor", "pieceColor", XtRPixel, sizeof(Pixel),
380 XtOffset(AppDataPtr, pieceColor), XtRString,
381 PIECE_COLOR
384 "charPieceColor", "CharPieceColor", XtRPixel, sizeof(Pixel),
385 XtOffset(AppDataPtr, charPieceColor), XtRString,
386 CHAR_PIECE_COLOR
389 "oneColor", "OneColor", XtRPixel, sizeof(Pixel),
390 XtOffset(AppDataPtr, oneColor), XtRString,
391 ONE_COLOR
394 "zeroColor", "ZeroColor", XtRPixel, sizeof(Pixel),
395 XtOffset(AppDataPtr, zeroColor), XtRString,
396 ZERO_COLOR
399 "squareColor", "squareColor", XtRPixel,
400 sizeof(Pixel), XtOffset(AppDataPtr, squareColor),
401 XtRString, SQUARE_COLOR
404 "westernPieceSet", "WesternPieceSet", XtRBoolean, sizeof(Boolean),
405 XtOffset(AppDataPtr, westernPieceSet), XtRString,
406 (XtPointer) False
409 "movesPerSession", "movesPerSession", XtRInt, sizeof(int),
410 XtOffset(AppDataPtr, movesPerSession), XtRImmediate,
411 (XtPointer) MOVES_PER_SESSION
414 "initString", "initString", XtRString, sizeof(String),
415 XtOffset(AppDataPtr, initString), XtRString, INIT_STRING
418 "blackString", "blackString", XtRString, sizeof(String),
419 XtOffset(AppDataPtr, blackString), XtRString, BLACK_STRING
422 "whiteString", "whiteString", XtRString, sizeof(String),
423 XtOffset(AppDataPtr, whiteString), XtRString, WHITE_STRING
426 "firstShogiProgram", "firstShogiProgram", XtRString,
427 sizeof(String), XtOffset(AppDataPtr, firstShogiProgram),
428 XtRString, FIRST_SHOGI_PROGRAM
431 "secondShogiProgram", "secondShogiProgram", XtRString,
432 sizeof(String), XtOffset(AppDataPtr, secondShogiProgram),
433 XtRString, SECOND_SHOGI_PROGRAM
436 "noShogiProgram", "noShogiProgram", XtRBoolean,
437 sizeof(Boolean), XtOffset(AppDataPtr, noShogiProgram),
438 XtRImmediate, (XtPointer) False
441 "firstHost", "firstHost", XtRString, sizeof(String),
442 XtOffset(AppDataPtr, firstHost), XtRString, FIRST_HOST
445 "secondHost", "secondHost", XtRString, sizeof(String),
446 XtOffset(AppDataPtr, secondHost), XtRString, SECOND_HOST
449 "reversePawnBitmap", "reversePawnBitmap", XtRString,
450 sizeof(String), XtOffset(AppDataPtr, reversePawnBitmap),
451 XtRString, NULL
454 "reverseLanceBitmap", "reverseLanceBitmap", XtRString,
455 sizeof(String), XtOffset(AppDataPtr, reverseLanceBitmap),
456 XtRString, NULL
459 "reverseKnightBitmap", "reverseKnightBitmap", XtRString,
460 sizeof(String), XtOffset(AppDataPtr, reverseKnightBitmap),
461 XtRString, NULL
464 "reverseSilverBitmap", "reverseSilverBitmap", XtRString,
465 sizeof(String), XtOffset(AppDataPtr, reverseSilverBitmap),
466 XtRString, NULL
469 "reverseGoldBitmap", "reverseGoldBitmap", XtRString,
470 sizeof(String), XtOffset(AppDataPtr, reverseGoldBitmap),
471 XtRString, NULL
474 "reverseRookBitmap", "reverseRookBitmap", XtRString,
475 sizeof(String), XtOffset(AppDataPtr, reverseRookBitmap),
476 XtRString, NULL
479 "reverseBishopBitmap", "reverseBishopBitmap", XtRString,
480 sizeof(String), XtOffset(AppDataPtr, reverseBishopBitmap),
481 XtRString, NULL
484 "reversePPawnBitmap", "reversePPawnBitmap", XtRString,
485 sizeof(String), XtOffset(AppDataPtr, reversePPawnBitmap),
486 XtRString, NULL
489 "reversePLanceBitmap", "reversePLanceBitmap", XtRString,
490 sizeof(String), XtOffset(AppDataPtr, reversePLanceBitmap),
491 XtRString, NULL
494 "reversePKnightBitmap", "reversePKnightBitmap", XtRString,
495 sizeof(String), XtOffset(AppDataPtr, reversePKnightBitmap),
496 XtRString, NULL
499 "reversePSilverBitmap", "reversePSilverBitmap", XtRString,
500 sizeof(String), XtOffset(AppDataPtr, reversePSilverBitmap),
501 XtRString, NULL
504 "reversePRookBitmap", "reversePRookBitmap", XtRString,
505 sizeof(String), XtOffset(AppDataPtr, reversePRookBitmap),
506 XtRString, NULL
509 "reversePBishopBitmap", "reversePBishopBitmap", XtRString,
510 sizeof(String), XtOffset(AppDataPtr, reversePBishopBitmap),
511 XtRString, NULL
514 "reverseKingBitmap", "reverseKingBitmap", XtRString,
515 sizeof(String), XtOffset(AppDataPtr, reverseKingBitmap),
516 XtRString, NULL
519 "normalPawnBitmap", "normalPawnBitmap", XtRString,
520 sizeof(String), XtOffset(AppDataPtr, normalPawnBitmap),
521 XtRString, NULL
524 "normalLanceBitmap", "normalLanceBitmap", XtRString,
525 sizeof(String), XtOffset(AppDataPtr, normalLanceBitmap),
526 XtRString, NULL
529 "normalKnightBitmap", "normalKnightBitmap", XtRString,
530 sizeof(String), XtOffset(AppDataPtr, normalKnightBitmap),
531 XtRString, NULL
534 "normalSilverBitmap", "normalSilverBitmap", XtRString,
535 sizeof(String), XtOffset(AppDataPtr, normalSilverBitmap),
536 XtRString, NULL
539 "normalGoldBitmap", "normalGoldBitmap", XtRString,
540 sizeof(String), XtOffset(AppDataPtr, normalGoldBitmap),
541 XtRString, NULL
544 "normalBishopBitmap", "normalBishopBitmap", XtRString,
545 sizeof(String), XtOffset(AppDataPtr, normalBishopBitmap),
546 XtRString, NULL
549 "normalRookBitmap", "normalRookBitmap", XtRString,
550 sizeof(String), XtOffset(AppDataPtr, normalRookBitmap),
551 XtRString, NULL
554 "normalPPawnBitmap", "normalPPawnBitmap", XtRString,
555 sizeof(String), XtOffset(AppDataPtr, normalPPawnBitmap),
556 XtRString, NULL
559 "normalPLanceBitmap", "normalPLanceBitmap", XtRString,
560 sizeof(String), XtOffset(AppDataPtr, normalPLanceBitmap),
561 XtRString, NULL
564 "normalPKnightBitmap", "normalPKnightBitmap", XtRString,
565 sizeof(String), XtOffset(AppDataPtr, normalPKnightBitmap),
566 XtRString, NULL
569 "normalPSilverBitmap", "normalPSilverBitmap", XtRString,
570 sizeof(String), XtOffset(AppDataPtr, normalPSilverBitmap),
571 XtRString, NULL
574 "normalPBishopBitmap", "normalPBishopBitmap", XtRString,
575 sizeof(String), XtOffset(AppDataPtr, normalPBishopBitmap),
576 XtRString, NULL
579 "normalPRookBitmap", "normalPRookBitmap", XtRString,
580 sizeof(String), XtOffset(AppDataPtr, normalPRookBitmap),
581 XtRString, NULL
584 "normalKingBitmap", "normalKingBitmap", XtRString,
585 sizeof(String), XtOffset(AppDataPtr, normalKingBitmap),
586 XtRString, NULL
589 "remoteShell", "remoteShell", XtRString, sizeof(String),
590 XtOffset(AppDataPtr, remoteShell), XtRString, "rsh"
593 "timeDelay", "timeDelay", XtRFloat, sizeof(float),
594 XtOffset(AppDataPtr, timeDelay), XtRString,
595 (XtPointer) TIME_DELAY
598 "timeControl", "timeControl", XtRString, sizeof(String),
599 XtOffset(AppDataPtr, timeControl), XtRString,
600 (XtPointer) TIME_CONTROL
603 "gameIn", "gameIn",
604 XtRBoolean, sizeof(Boolean),
605 XtOffset(AppDataPtr, gameIn), XtRImmediate,
606 (XtPointer) False
609 "autoSaveGames", "autoSaveGames", XtRBoolean,
610 sizeof(Boolean), XtOffset(AppDataPtr, autoSaveGames),
611 XtRImmediate, (XtPointer) False
614 "loadGameFile", "loadGameFile", XtRString, sizeof(String),
615 XtOffset(AppDataPtr, loadGameFile), XtRString, NULL
618 "loadPositionFile", "loadPositionFile", XtRString,
619 sizeof(String), XtOffset(AppDataPtr, loadPositionFile),
620 XtRString, NULL
623 "saveGameFile", "saveGameFile", XtRString, sizeof(String),
624 XtOffset(AppDataPtr, saveGameFile), XtRString, ""
627 "savePositionFile", "savePositionFile", XtRString,
628 sizeof(String), XtOffset(AppDataPtr, savePositionFile),
629 XtRString, ""
632 "challengeDisplay", "challengeDisplay", XtRString,
633 sizeof(String), XtOffset(AppDataPtr, challengeDisplay),
634 XtRString, NULL
637 "matchMode", "matchMode", XtRString, sizeof(String),
638 XtOffset(AppDataPtr, matchMode), XtRString, MATCH_MODE
641 "monoMode", "monoMode", XtRBoolean, sizeof(Boolean),
642 XtOffset(AppDataPtr, monoMode), XtRImmediate,
643 (XtPointer) False
646 "debugMode", "debugMode", XtRBoolean, sizeof(Boolean),
647 XtOffset(AppDataPtr, debugMode), XtRImmediate,
648 (XtPointer) False
651 "Iconic", "Iconic", XtRBoolean, sizeof(Boolean),
652 XtOffset(AppDataPtr, Iconic), XtRImmediate,
653 (XtPointer) False
656 "clockMode", "clockMode", XtRBoolean, sizeof(Boolean),
657 XtOffset(AppDataPtr, clockMode), XtRImmediate,
658 (XtPointer) True
661 "autoCallFlag", "autoCallFlag", XtRBoolean,
662 sizeof(Boolean), XtOffset(AppDataPtr, autoCallFlag),
663 XtRImmediate, (XtPointer) False
666 "boardSize", "boardSize", XtRString, sizeof(String),
667 XtOffset(AppDataPtr, boardSize), XtRString, DEFAULT_SIZE
670 "searchTime", "searchTime", XtRString, sizeof(String),
671 XtOffset(AppDataPtr, searchTime), XtRString,
672 (XtPointer) NULL
675 "searchDepth", "searchDepth", XtRInt, sizeof(int),
676 XtOffset(AppDataPtr, searchDepth), XtRImmediate,
677 (XtPointer) 0
680 "showCoords", "showCoords", XtRBoolean, sizeof(Boolean),
681 XtOffset(AppDataPtr, showCoords), XtRImmediate,
682 (XtPointer) False
685 "mainFont", "mainFont", XtRString, sizeof(String),
686 XtOffset(AppDataPtr, mainFont), XtRString, MAIN_FONT
689 "coordFont", "coordFont", XtRString, sizeof(String),
690 XtOffset(AppDataPtr, coordFont), XtRString, COORD_FONT
693 "ringBellAfterMoves", "ringBellAfterMoves",
694 XtRBoolean, sizeof(Boolean),
695 XtOffset(AppDataPtr, ringBellAfterMoves),
696 XtRImmediate, (XtPointer) False
699 "borderXoffset", "borderXoffset", XtRInt, sizeof(int),
700 XtOffset(AppDataPtr, borderXoffset), XtRImmediate,
701 (XtPointer) BORDER_X_OFFSET
704 "borderYoffset", "borderYOffset", XtRInt, sizeof(int),
705 XtOffset(AppDataPtr, borderYoffset), XtRImmediate,
706 (XtPointer) BORDER_Y_OFFSET
711 struct DisplayData
713 AppData appData;
715 Arg shellArgs[6];
716 Arg boardArgs[3];
717 Arg commandsArgs[7];
718 Arg messageArgs[3];
719 Arg timerArgs[2];
720 Arg titleArgs[2];
722 Pixmap reversePawnBitmap, reverseLanceBitmap, reverseKnightBitmap,
723 reverseSilverBitmap,
724 reverseGoldBitmap, reverseBishopBitmap, reverseRookBitmap,
725 reversePPawnBitmap, reversePLanceBitmap, reversePKnightBitmap,
726 reversePSilverBitmap, reversePBishopBitmap, reversePRookBitmap,
727 reverseKingBitmap,
728 reverseBigSolidBitmap, reverseSmallSolidBitmap,
729 normalBigSolidBitmap, normalSmallSolidBitmap,
730 normalPawnBitmap, normalLanceBitmap, normalKnightBitmap,
731 normalSilverBitmap, normalGoldBitmap,
732 normalBishopBitmap, normalRookBitmap,
733 normalPPawnBitmap, normalPLanceBitmap, normalPKnightBitmap,
734 normalPSilverBitmap, normalPBishopBitmap, normalPRookBitmap,
735 normalKingBitmap,
736 iconPixmap;
738 Display *xDisplay;
739 int xScreen;
740 Window xBoardWindow;
742 GC squareGC, lineGC, pieceGC, oPieceGC, charPieceGC,
743 squareOffBoardGC, coordGC, dropPiece;
745 Font mainFontID, coordFontID;
746 XFontStruct *mainFontStruct, *coordFontStruct;
748 Widget shellWidget, formWidget, boardWidget,
749 commandsWidget, messageWidget,
750 blackTimerWidget, whiteTimerWidget,
751 titleWidget, widgetList[6],
752 promotionShell,
753 filemodeShell, challengeWidget;
755 XSegment gridSegments[(BOARD_SIZE + 1) * 2];
757 Pixel timerForegroundPixel, timerBackgroundPixel;
759 BoardSize boardSize;
760 int squareSize;
761 int black_pixel_is_zero;
762 int flipView;
763 int promotionUp;
765 Boolean monoMode, showCoords, Iconic;
770 struct DisplayData localPlayer, remotePlayer;
773 typedef struct
775 ShogiSquare piece;
776 int to_x, to_y;
777 } PromotionMoveInfo;
779 static PromotionMoveInfo pmi; /* making this global is gross */
782 Pixmap *pieceToReverse[2][28] =
785 &localPlayer.reversePawnBitmap,
786 &localPlayer.reverseLanceBitmap,
787 &localPlayer.reverseKnightBitmap,
788 &localPlayer.reverseSilverBitmap,
789 &localPlayer.reverseGoldBitmap,
790 &localPlayer.reverseBishopBitmap,
791 &localPlayer.reverseRookBitmap,
792 &localPlayer.reversePPawnBitmap,
793 &localPlayer.reversePLanceBitmap,
794 &localPlayer.reversePKnightBitmap,
795 &localPlayer.reversePSilverBitmap,
796 &localPlayer.reversePBishopBitmap,
797 &localPlayer.reversePRookBitmap,
798 &localPlayer.reverseKingBitmap,
799 &localPlayer.reversePawnBitmap,
800 &localPlayer.reverseLanceBitmap,
801 &localPlayer.reverseKnightBitmap,
802 &localPlayer.reverseSilverBitmap,
803 &localPlayer.reverseGoldBitmap,
804 &localPlayer.reverseBishopBitmap,
805 &localPlayer.reverseRookBitmap,
806 &localPlayer.reversePPawnBitmap,
807 &localPlayer.reversePLanceBitmap,
808 &localPlayer.reversePKnightBitmap,
809 &localPlayer.reversePSilverBitmap,
810 &localPlayer.reversePBishopBitmap,
811 &localPlayer.reversePRookBitmap,
812 &localPlayer.reverseKingBitmap
815 &remotePlayer.reversePawnBitmap,
816 &remotePlayer.reverseLanceBitmap,
817 &remotePlayer.reverseKnightBitmap,
818 &remotePlayer.reverseSilverBitmap,
819 &remotePlayer.reverseGoldBitmap,
820 &remotePlayer.reverseBishopBitmap,
821 &remotePlayer.reverseRookBitmap,
822 &remotePlayer.reversePPawnBitmap,
823 &remotePlayer.reversePLanceBitmap,
824 &remotePlayer.reversePKnightBitmap,
825 &remotePlayer.reversePSilverBitmap,
826 &remotePlayer.reversePBishopBitmap,
827 &remotePlayer.reversePRookBitmap,
828 &remotePlayer.reverseKingBitmap,
829 &remotePlayer.reversePawnBitmap,
830 &remotePlayer.reverseLanceBitmap,
831 &remotePlayer.reverseKnightBitmap,
832 &remotePlayer.reverseSilverBitmap,
833 &remotePlayer.reverseGoldBitmap,
834 &remotePlayer.reverseBishopBitmap,
835 &remotePlayer.reverseRookBitmap,
836 &remotePlayer.reversePPawnBitmap,
837 &remotePlayer.reversePLanceBitmap,
838 &remotePlayer.reversePKnightBitmap,
839 &remotePlayer.reversePSilverBitmap,
840 &remotePlayer.reversePBishopBitmap,
841 &remotePlayer.reversePRookBitmap,
842 &remotePlayer.reverseKingBitmap
848 Pixmap *pieceToNormal[2][28] =
851 &localPlayer.normalPawnBitmap,
852 &localPlayer.normalLanceBitmap,
853 &localPlayer.normalKnightBitmap,
854 &localPlayer.normalSilverBitmap,
855 &localPlayer.normalGoldBitmap,
856 &localPlayer.normalBishopBitmap,
857 &localPlayer.normalRookBitmap,
858 &localPlayer.normalPPawnBitmap,
859 &localPlayer.normalPLanceBitmap,
860 &localPlayer.normalPKnightBitmap,
861 &localPlayer.normalPSilverBitmap,
862 &localPlayer.normalPBishopBitmap,
863 &localPlayer.normalPRookBitmap,
864 &localPlayer.normalKingBitmap,
865 &localPlayer.normalPawnBitmap,
866 &localPlayer.normalLanceBitmap,
867 &localPlayer.normalKnightBitmap,
868 &localPlayer.normalSilverBitmap,
869 &localPlayer.normalGoldBitmap,
870 &localPlayer.normalBishopBitmap,
871 &localPlayer.normalRookBitmap,
872 &localPlayer.normalPPawnBitmap,
873 &localPlayer.normalPLanceBitmap,
874 &localPlayer.normalPKnightBitmap,
875 &localPlayer.normalPSilverBitmap,
876 &localPlayer.normalPBishopBitmap,
877 &localPlayer.normalPRookBitmap,
878 &localPlayer.normalKingBitmap
881 &remotePlayer.normalPawnBitmap,
882 &remotePlayer.normalLanceBitmap,
883 &remotePlayer.normalKnightBitmap,
884 &remotePlayer.normalSilverBitmap,
885 &remotePlayer.normalGoldBitmap,
886 &remotePlayer.normalBishopBitmap,
887 &remotePlayer.normalRookBitmap,
888 &remotePlayer.normalPPawnBitmap,
889 &remotePlayer.normalPLanceBitmap,
890 &remotePlayer.normalPKnightBitmap,
891 &remotePlayer.normalPSilverBitmap,
892 &remotePlayer.normalPBishopBitmap,
893 &remotePlayer.normalPRookBitmap,
894 &remotePlayer.normalKingBitmap,
895 &remotePlayer.normalPawnBitmap,
896 &remotePlayer.normalLanceBitmap,
897 &remotePlayer.normalKnightBitmap,
898 &remotePlayer.normalSilverBitmap,
899 &remotePlayer.normalGoldBitmap,
900 &remotePlayer.normalBishopBitmap,
901 &remotePlayer.normalRookBitmap,
902 &remotePlayer.normalPPawnBitmap,
903 &remotePlayer.normalPLanceBitmap,
904 &remotePlayer.normalPKnightBitmap,
905 &remotePlayer.normalPSilverBitmap,
906 &remotePlayer.normalPBishopBitmap,
907 &remotePlayer.normalPRookBitmap,
908 &remotePlayer.normalKingBitmap
914 Pixmap *pieceToReverseSolid[2][28] =
917 &localPlayer.reverseSmallSolidBitmap,
918 &localPlayer.reverseSmallSolidBitmap,
919 &localPlayer.reverseSmallSolidBitmap,
920 &localPlayer.reverseBigSolidBitmap,
921 &localPlayer.reverseBigSolidBitmap,
922 &localPlayer.reverseBigSolidBitmap,
923 &localPlayer.reverseBigSolidBitmap,
924 &localPlayer.reverseSmallSolidBitmap,
925 &localPlayer.reverseSmallSolidBitmap,
926 &localPlayer.reverseSmallSolidBitmap,
927 &localPlayer.reverseBigSolidBitmap,
928 &localPlayer.reverseBigSolidBitmap,
929 &localPlayer.reverseBigSolidBitmap,
930 &localPlayer.reverseBigSolidBitmap,
931 &localPlayer.reverseSmallSolidBitmap,
932 &localPlayer.reverseSmallSolidBitmap,
933 &localPlayer.reverseSmallSolidBitmap,
934 &localPlayer.reverseBigSolidBitmap,
935 &localPlayer.reverseBigSolidBitmap,
936 &localPlayer.reverseBigSolidBitmap,
937 &localPlayer.reverseBigSolidBitmap,
938 &localPlayer.reverseSmallSolidBitmap,
939 &localPlayer.reverseSmallSolidBitmap,
940 &localPlayer.reverseSmallSolidBitmap,
941 &localPlayer.reverseBigSolidBitmap,
942 &localPlayer.reverseBigSolidBitmap,
943 &localPlayer.reverseBigSolidBitmap,
944 &localPlayer.reverseBigSolidBitmap
947 &remotePlayer.reverseSmallSolidBitmap,
948 &remotePlayer.reverseSmallSolidBitmap,
949 &remotePlayer.reverseSmallSolidBitmap,
950 &remotePlayer.reverseBigSolidBitmap,
951 &remotePlayer.reverseBigSolidBitmap,
952 &remotePlayer.reverseBigSolidBitmap,
953 &remotePlayer.reverseBigSolidBitmap,
954 &remotePlayer.reverseSmallSolidBitmap,
955 &remotePlayer.reverseSmallSolidBitmap,
956 &remotePlayer.reverseSmallSolidBitmap,
957 &remotePlayer.reverseBigSolidBitmap,
958 &remotePlayer.reverseBigSolidBitmap,
959 &remotePlayer.reverseBigSolidBitmap,
960 &remotePlayer.reverseBigSolidBitmap,
961 &remotePlayer.reverseSmallSolidBitmap,
962 &remotePlayer.reverseSmallSolidBitmap,
963 &remotePlayer.reverseSmallSolidBitmap,
964 &remotePlayer.reverseBigSolidBitmap,
965 &remotePlayer.reverseBigSolidBitmap,
966 &remotePlayer.reverseBigSolidBitmap,
967 &remotePlayer.reverseBigSolidBitmap,
968 &remotePlayer.reverseSmallSolidBitmap,
969 &remotePlayer.reverseSmallSolidBitmap,
970 &remotePlayer.reverseSmallSolidBitmap,
971 &remotePlayer.reverseBigSolidBitmap,
972 &remotePlayer.reverseBigSolidBitmap,
973 &remotePlayer.reverseBigSolidBitmap,
974 &remotePlayer.reverseBigSolidBitmap
980 Pixmap *pieceToNormalSolid[2][28] =
983 &localPlayer.normalSmallSolidBitmap,
984 &localPlayer.normalSmallSolidBitmap,
985 &localPlayer.normalSmallSolidBitmap,
986 &localPlayer.normalBigSolidBitmap,
987 &localPlayer.normalBigSolidBitmap,
988 &localPlayer.normalBigSolidBitmap,
989 &localPlayer.normalBigSolidBitmap,
990 &localPlayer.normalSmallSolidBitmap,
991 &localPlayer.normalSmallSolidBitmap,
992 &localPlayer.normalSmallSolidBitmap,
993 &localPlayer.normalBigSolidBitmap,
994 &localPlayer.normalBigSolidBitmap,
995 &localPlayer.normalBigSolidBitmap,
996 &localPlayer.normalBigSolidBitmap,
997 &localPlayer.normalSmallSolidBitmap,
998 &localPlayer.normalSmallSolidBitmap,
999 &localPlayer.normalSmallSolidBitmap,
1000 &localPlayer.normalBigSolidBitmap,
1001 &localPlayer.normalBigSolidBitmap,
1002 &localPlayer.normalBigSolidBitmap,
1003 &localPlayer.normalBigSolidBitmap,
1004 &localPlayer.normalSmallSolidBitmap,
1005 &localPlayer.normalSmallSolidBitmap,
1006 &localPlayer.normalSmallSolidBitmap,
1007 &localPlayer.normalBigSolidBitmap,
1008 &localPlayer.normalBigSolidBitmap,
1009 &localPlayer.normalBigSolidBitmap,
1010 &localPlayer.normalBigSolidBitmap
1013 &remotePlayer.normalSmallSolidBitmap,
1014 &remotePlayer.normalSmallSolidBitmap,
1015 &remotePlayer.normalSmallSolidBitmap,
1016 &remotePlayer.normalBigSolidBitmap,
1017 &remotePlayer.normalBigSolidBitmap,
1018 &remotePlayer.normalBigSolidBitmap,
1019 &remotePlayer.normalBigSolidBitmap,
1020 &remotePlayer.normalSmallSolidBitmap,
1021 &remotePlayer.normalSmallSolidBitmap,
1022 &remotePlayer.normalSmallSolidBitmap,
1023 &remotePlayer.normalBigSolidBitmap,
1024 &remotePlayer.normalBigSolidBitmap,
1025 &remotePlayer.normalBigSolidBitmap,
1026 &remotePlayer.normalBigSolidBitmap,
1027 &remotePlayer.normalSmallSolidBitmap,
1028 &remotePlayer.normalSmallSolidBitmap,
1029 &remotePlayer.normalSmallSolidBitmap,
1030 &remotePlayer.normalBigSolidBitmap,
1031 &remotePlayer.normalBigSolidBitmap,
1032 &remotePlayer.normalBigSolidBitmap,
1033 &remotePlayer.normalBigSolidBitmap,
1034 &remotePlayer.normalSmallSolidBitmap,
1035 &remotePlayer.normalSmallSolidBitmap,
1036 &remotePlayer.normalSmallSolidBitmap,
1037 &remotePlayer.normalBigSolidBitmap,
1038 &remotePlayer.normalBigSolidBitmap,
1039 &remotePlayer.normalBigSolidBitmap,
1040 &remotePlayer.normalBigSolidBitmap
1046 int pieceIsPromoted[] =
1048 False, False, False, False, False, False, False,
1049 True, True, True, True, True, True, False,
1050 False, False, False, False, False, False, False,
1051 True, True, True, True, True, True, False,
1052 False
1056 int piecePromotable[] =
1058 True, True, True, True, False, True, True,
1059 False, False, False, False, False, False, False,
1060 True, True, True, True, False, True, True,
1061 False, False, False, False, False, False, False,
1062 False
1066 char pieceToChar[] =
1068 'P', 'L', 'N', 'S', 'G', 'B', 'R', 'P', 'L', 'N', 'S', 'B', 'R', 'K',
1069 'p', 'l', 'n', 's', 'g', 'b', 'r', 'p', 'l', 'n', 's', 'b', 'r', 'k',
1074 ShogiSquare pieceToPromoted[] =
1076 BlackPPawn, BlackPLance, BlackPKnight, BlackPSilver, BlackGold,
1077 BlackPBishop, BlackPRook,
1078 BlackPPawn, BlackPLance, BlackPKnight, BlackPSilver,
1079 BlackPBishop, BlackPRook, BlackKing,
1080 WhitePPawn, WhitePLance, WhitePKnight, WhitePSilver, WhiteGold,
1081 WhitePBishop, WhitePRook,
1082 WhitePPawn, WhitePLance, WhitePKnight, WhitePSilver,
1083 WhitePBishop, WhitePRook, WhiteKing
1088 XrmOptionDescRec shellOptions[] =
1090 { "-pieceColor", "pieceColor", XrmoptionSepArg, NULL },
1091 { "-pc", "pieceColor", XrmoptionSepArg, NULL },
1092 { "-charPieceColor", "charPieceColor", XrmoptionSepArg, NULL },
1093 { "-cpc", "charPieceColor", XrmoptionSepArg, NULL },
1094 { "-zeroColor", "zeroColor", XrmoptionSepArg, NULL },
1095 { "-zc", "zeroColor", XrmoptionSepArg, NULL },
1096 { "-oneColor", "oneColor", XrmoptionSepArg, NULL },
1097 { "-oc", "oneColor", XrmoptionSepArg, NULL },
1098 { "-squareColor", "squareColor", XrmoptionSepArg, NULL },
1099 { "-sc", "squareColor", XrmoptionSepArg, NULL },
1100 { "-westernPieceSet", "westernPieceSet", XrmoptionSepArg, NULL },
1101 { "-wps", "westernPieceSet", XrmoptionSepArg, NULL },
1102 { "-movesPerSession", "movesPerSession", XrmoptionSepArg, NULL },
1103 { "-mps", "movesPerSession", XrmoptionSepArg, NULL },
1104 { "-firstShogiProgram", "firstShogiProgram", XrmoptionSepArg, NULL },
1105 { "-fsp", "firstShogiProgram", XrmoptionSepArg, NULL },
1106 { "-secondShogiProgram", "secondShogiProgram", XrmoptionSepArg, NULL },
1107 { "-ssp", "secondShogiProgram", XrmoptionSepArg, NULL },
1108 { "-noShogiProgram", "noShogiProgram", XrmoptionSepArg, NULL },
1109 { "-nsp", "noShogiProgram", XrmoptionSepArg, NULL },
1110 { "-firstHost", "firstHost", XrmoptionSepArg, NULL },
1111 { "-fh", "firstHost", XrmoptionSepArg, NULL },
1112 { "-secondHost", "secondHost", XrmoptionSepArg, NULL },
1113 { "-sh", "secondHost", XrmoptionSepArg, NULL },
1114 { "-reversePawnBitmap", "reversePawnBitmap", XrmoptionSepArg, NULL },
1115 { "-rpb", "reversePawnBitmap", XrmoptionSepArg, NULL },
1116 { "-reverseLanceBitmap", "reverseLanceBitmap", XrmoptionSepArg, NULL },
1117 { "-rlb", "reverseLanceBitmap", XrmoptionSepArg, NULL },
1118 { "-reverseKnightBitmap", "reverseKnightBitmap", XrmoptionSepArg, NULL },
1119 { "-rnb", "reverseKnightBitmap", XrmoptionSepArg, NULL },
1120 { "-reverseSilverBitmap", "reverseSilverBitmap", XrmoptionSepArg, NULL },
1121 { "-rsb", "reverseSilverBitmap", XrmoptionSepArg, NULL },
1122 { "-reverseGoldBitmap", "reverseGoldBitmap", XrmoptionSepArg, NULL },
1123 { "-rgb", "reverseGoldBitmap", XrmoptionSepArg, NULL },
1124 { "-reverseRookBitmap", "reverseRookBitmap", XrmoptionSepArg, NULL },
1125 { "-rrb", "reverseRookBitmap", XrmoptionSepArg, NULL },
1126 { "-reverseBishopBitmap", "reverseBishopBitmap", XrmoptionSepArg, NULL },
1127 { "-rbb", "reverseBishopBitmap", XrmoptionSepArg, NULL },
1128 { "-reversePPawnBitmap", "reversePPawnBitmap",
1129 XrmoptionSepArg, NULL },
1130 { "-rppb", "reversePPawnBitmap", XrmoptionSepArg, NULL },
1131 { "-reversePLanceBitmap", "reversePLanceBitmap",
1132 XrmoptionSepArg, NULL },
1133 { "-rplb", "reversePLanceBitmap", XrmoptionSepArg, NULL },
1134 { "-reversePKnightBitmap", "reversePKnightBitmap",
1135 XrmoptionSepArg, NULL },
1136 { "-rpnb", "reversePKnightBitmap", XrmoptionSepArg, NULL },
1137 { "-reversePSilverBitmap", "reversePSilverBitmap",
1138 XrmoptionSepArg, NULL },
1139 { "-rpsb", "reversePSilverBitmap", XrmoptionSepArg, NULL },
1140 { "-reversePRookBitmap", "reversePRookBitmap",
1141 XrmoptionSepArg, NULL },
1142 { "-rprb", "reversePRookBitmap", XrmoptionSepArg, NULL },
1143 { "-reversePBishopBitmap", "reversePBishopBitmap",
1144 XrmoptionSepArg, NULL },
1145 { "-rpbb", "reversePBishopBitmap", XrmoptionSepArg, NULL },
1146 { "-reverseKingBitmap", "reverseKingBitmap", XrmoptionSepArg, NULL },
1147 { "-rkb", "reverseKingBitmap", XrmoptionSepArg, NULL },
1148 { "-outlinePawnBitmap", "outlinePawnBitmap", XrmoptionSepArg, NULL },
1149 { "-opb", "normalPawnBitmap", XrmoptionSepArg, NULL },
1150 { "-normalLanceBitmap", "normalLanceBitmap", XrmoptionSepArg, NULL },
1151 { "-olb", "normalLanceBitmap", XrmoptionSepArg, NULL },
1152 { "-normalKnightBitmap", "normalKnightBitmap", XrmoptionSepArg, NULL },
1153 { "-onb", "normalKnightBitmap", XrmoptionSepArg, NULL },
1154 { "-normalSilverBitmap", "normalSilverBitmap", XrmoptionSepArg, NULL },
1155 { "-osb", "normalSilverBitmap", XrmoptionSepArg, NULL },
1156 { "-normalGoldBitmap", "normalGoldBitmap", XrmoptionSepArg, NULL },
1157 { "-ogb", "normalGoldBitmap", XrmoptionSepArg, NULL },
1158 { "-normalRookBitmap", "normalRookBitmap", XrmoptionSepArg, NULL },
1159 { "-orb", "normalRookBitmap", XrmoptionSepArg, NULL },
1160 { "-normalBishopBitmap", "normalBishopBitmap", XrmoptionSepArg, NULL },
1161 { "-obb", "normalBishopBitmap", XrmoptionSepArg, NULL },
1162 { "-normalPPawnBitmap", "normalPPawnBitmap", XrmoptionSepArg, NULL },
1163 { "-oppb", "normalPPawnBitmap", XrmoptionSepArg, NULL },
1164 { "-normalPLanceBitmap", "normalPLanceBitmap", XrmoptionSepArg, NULL },
1165 { "-oplb", "normalPLanceBitmap", XrmoptionSepArg, NULL },
1166 { "-normalPKnightBitmap", "normalPKnightBitmap", XrmoptionSepArg, NULL },
1167 { "-opnb", "normalPKnightBitmap", XrmoptionSepArg, NULL },
1168 { "-normalPSilverBitmap", "normalPSilverBitmap", XrmoptionSepArg, NULL },
1169 { "-opsb", "normalPSilverBitmap", XrmoptionSepArg, NULL },
1170 { "-normalPRookBitmap", "normalPRookBitmap", XrmoptionSepArg, NULL },
1171 { "-oprb", "normalPRookBitmap", XrmoptionSepArg, NULL },
1172 { "-normalPBishopBitmap", "normalPBishopBitmap", XrmoptionSepArg, NULL },
1173 { "-opbb", "normalPBishopBitmap", XrmoptionSepArg, NULL },
1174 { "-normalKingBitmap", "normalKingBitmap", XrmoptionSepArg, NULL },
1175 { "-okb", "outlineKingBitmap", XrmoptionSepArg, NULL },
1176 { "-remoteShell", "remoteShell", XrmoptionSepArg, NULL },
1177 { "-rsh", "remoteShell", XrmoptionSepArg, NULL },
1178 { "-timeDelay", "timeDelay", XrmoptionSepArg, NULL },
1179 { "-td", "timeDelay", XrmoptionSepArg, NULL },
1180 { "-timeControl", "timeControl", XrmoptionSepArg, NULL },
1181 { "-tc", "timeControl", XrmoptionSepArg, NULL },
1182 { "-gameIn", "gameIn", XrmoptionSepArg, NULL },
1183 { "-gi", "gameIn", XrmoptionSepArg, NULL },
1184 { "-loadGameFile", "loadGameFile", XrmoptionSepArg, NULL },
1185 { "-lgf", "loadGameFile", XrmoptionSepArg, NULL },
1186 { "-loadPositionFile", "loadPositionFile", XrmoptionSepArg, NULL },
1187 { "-lpf", "loadPositionFile", XrmoptionSepArg, NULL },
1188 { "-saveGameFile", "saveGameFile", XrmoptionSepArg, NULL },
1189 { "-sgf", "saveGameFile", XrmoptionSepArg, NULL },
1190 { "-savePositionFile", "savePositionFile", XrmoptionSepArg, NULL },
1191 { "-spf", "savePositionFile", XrmoptionSepArg, NULL },
1192 { "-challengeDisplay", "challengeDisplay", XrmoptionSepArg, NULL },
1193 { "-cd", "challengeDisplay", XrmoptionSepArg, NULL },
1194 { "-matchMode", "matchMode", XrmoptionSepArg, NULL },
1195 { "-mm", "matchMode", XrmoptionSepArg, NULL },
1196 { "-monoMode", "monoMode", XrmoptionSepArg, NULL },
1197 { "-mono", "monoMode", XrmoptionSepArg, NULL },
1198 { "-debugMode", "debugMode", XrmoptionSepArg, NULL },
1199 { "-debug", "debugMode", XrmoptionSepArg, NULL },
1200 { "-clockMode", "clockMode", XrmoptionSepArg, NULL },
1201 { "-clock", "clockMode", XrmoptionSepArg, NULL },
1202 { "-boardSize", "boardSize", XrmoptionSepArg, NULL },
1203 { "-size", "boardSize", XrmoptionSepArg, NULL },
1204 { "-searchTime", "searchTime", XrmoptionSepArg, NULL },
1205 { "-st", "searchTime", XrmoptionSepArg, NULL },
1206 { "-searchDepth", "searchDepth", XrmoptionSepArg, NULL },
1207 { "-sd", "searchDepth", XrmoptionSepArg, NULL },
1208 { "-showCoords", "showCoords", XrmoptionSepArg, NULL },
1209 { "-coords", "showCoords", XrmoptionSepArg, NULL },
1210 { "-iconic", "Iconic", XrmoptionNoArg, "True" }
1215 XtActionsRec boardActions[] =
1217 { "DrawPosition", (XtActionProc) DrawPosition },
1218 { "HandleUserMove", (XtActionProc) HandleUserMove },
1219 { "ResetProc", (XtActionProc) ResetProc },
1220 { "ResetFileProc", (XtActionProc) ResetFileProc },
1221 { "LoadGameProc", (XtActionProc) LoadGameProc },
1222 { "QuitProc", (XtActionProc) QuitProc },
1223 { "ForwardProc", (XtActionProc) ForwardProc },
1224 { "BackwardProc", (XtActionProc) BackwardProc },
1225 { "PauseProc", (XtActionProc) PauseProc },
1226 { "Iconify", (XtActionProc) Iconify },
1227 { "FileNameAction", (XtActionProc) FileNameAction },
1228 { "PieceMenuPopup", (XtActionProc) PieceMenuPopup },
1229 { "SetBlackToPlay", (XtActionProc) SetBlackToPlay },
1230 { "SetWhiteToPlay", (XtActionProc) SetWhiteToPlay }
1234 char translationsTable[] =
1235 "<Expose>: DrawPosition() \n \
1236 <Btn1Down>: HandleUserMove() \n \
1237 <Btn1Up>: HandleUserMove() \n \
1238 <Btn2Down>: XawPositionSimpleMenu(menuW) PieceMenuPopup(menuW) \n \
1239 <Btn3Down>: XawPositionSimpleMenu(menuB) PieceMenuPopup(menuB) \n \
1240 <Key>r: ResetFileProc() ResetProc() \n \
1241 <Key>R: ResetFileProc() ResetProc() \n \
1242 <Key>g: LoadGameProc() \n \
1243 <Key>G: LoadGameProc() \n \
1244 <Key>q: QuitProc() \n \
1245 <Key>Q: QuitProc() \n \
1246 <Message>WM_PROTOCOLS: QuitProc() \n \
1247 <Key>f: ForwardProc() \n \
1248 <Key>F: ForwardProc() \n \
1249 <Key>b: BackwardProc() \n \
1250 <Key>B: BackwardProc() \n \
1251 <Key>p: PauseProc() \n \
1252 <Key>P: PauseProc() \n \
1253 <Key>i: Iconify() \n \
1254 <Key>I: Iconify() \n \
1255 <Key>c: Iconify() \n \
1256 <Key>C: Iconify() \n";
1259 char translationsTableReduced[] =
1260 "<Expose>: DrawPosition() \n \
1261 <Btn1Down>: HandleUserMove() \n \
1262 <Btn1Up>: HandleUserMove() \n \
1263 <Message>WM_PROTOCOLS: QuitProc() \n";
1266 char blackTranslations[] = "<BtnDown>: SetBlackToPlay()\n";
1267 char whiteTranslations[] = "<BtnDown>: SetWhiteToPlay()\n";
1269 String xshogiResources[] =
1271 DEFAULT_FONT,
1272 "*Dialog*value.translations: #override "
1273 "\\n <Key>Return: FileNameAction()",
1274 NULL
1278 int global_argc; /* number of command args */
1279 char *global_argv[10]; /* pointers to up to 10 command args */
1283 static struct DisplayData *player;
1286 typedef struct
1288 char mode[2];
1289 char name[100];
1290 } FileModeInfo;
1292 static FileModeInfo fmi;
1296 * This is a hack that allows the parser to tell the program
1297 * that the game it's loading has ended.
1300 int loaded_game_finished = 0;
1303 /**********************************************************************
1305 * End of globals.
1307 **********************************************************************/
1310 void
1311 CreatePlayerWindow(void)
1313 int mainFontPxlSize, coordFontPxlSize;
1314 int min, sec, matched;
1315 XSetWindowAttributes window_attributes;
1316 char buf[MSG_SIZ];
1317 Arg args[10];
1318 Dimension timerWidth, boardWidth, commandsWidth, w, h;
1319 int local;
1320 int fromRemotePlayer = (player == &remotePlayer);
1322 player->monoMode = player->appData.monoMode;
1323 player->showCoords = player->appData.showCoords;
1326 * Parse timeControl resource.
1329 if (player->appData.timeControl != NULL)
1331 matched = sscanf(player->appData.timeControl, "%d:%d", &min, &sec);
1333 if (matched == 1)
1335 timeControl = min * 60 * 1000;
1337 else if (matched == 2)
1339 timeControl = (min * 60 + sec) * 1000;
1341 else
1343 fprintf(stderr, "%s: bad timeControl option %s\n",
1344 programName, player->appData.timeControl);
1345 Usage();
1350 * Parse searchTime resource
1353 if (player->appData.searchTime != NULL)
1355 matched = sscanf(player->appData.searchTime, "%d:%d", &min, &sec);
1357 if (matched == 1)
1359 searchTime = min * 60;
1361 else if (matched == 2)
1363 searchTime = min * 60 + sec;
1365 else
1367 fprintf(stderr, "%s: bad searchTime option %s\n",
1368 programName, player->appData.searchTime);
1369 Usage();
1373 if ((player->appData.searchTime != NULL)
1374 || (player->appData.searchDepth > 0)
1375 || player->appData.noShogiProgram)
1377 player->appData.clockMode = False;
1380 player->Iconic = False;
1381 player->boardSize = Small;
1382 player->squareSize = SMALL_SQUARE_SIZE;
1383 player->flipView = (player == &remotePlayer);
1384 player->promotionUp = False;
1387 * Determine boardSize.
1390 if (strcasecmp(player->appData.boardSize, "Large") == 0)
1392 player->boardSize = Large;
1394 else if (strcasecmp(player->appData.boardSize, "Medium") == 0)
1396 player->boardSize = Medium;
1398 else if (strcasecmp(player->appData.boardSize, "Small") == 0)
1400 player->boardSize = Small;
1402 else
1404 fprintf(stderr, "%s: bad boardSize option %s\n",
1405 programName, player->appData.boardSize);
1406 Usage();
1409 if ((local = (player == &localPlayer)))
1411 player->xDisplay = XtDisplay(player->shellWidget);
1412 player->xScreen = DefaultScreen(player->xDisplay);
1415 #undef DONT_ADJUST_BOARDSIZE
1416 #ifndef DONT_ADJUST_BOARDSIZE
1417 if (((DisplayWidth(player->xDisplay, player->xScreen) < 800)
1418 || (DisplayHeight(player->xDisplay, player->xScreen) < 800))
1419 && (player->boardSize == Large))
1421 player->boardSize = Medium;
1423 #endif
1425 switch (player->boardSize)
1427 case Small:
1428 player->squareSize = SMALL_SQUARE_SIZE;
1429 mainFontPxlSize = 11;
1430 coordFontPxlSize = 10;
1431 break;
1433 case Medium:
1434 player->squareSize = MEDIUM_SQUARE_SIZE;
1435 mainFontPxlSize = 17;
1436 coordFontPxlSize = 12;
1437 break;
1439 default:
1440 case Large:
1441 player->squareSize = LARGE_SQUARE_SIZE;
1442 mainFontPxlSize = 17;
1443 coordFontPxlSize = 14;
1444 break;
1448 * Detect if there are not enough colors are available and adapt.
1451 if (DefaultDepth(player->xDisplay, player->xScreen) <= 2)
1452 player->monoMode = True;
1455 * Determine what fonts to use.
1458 player->appData.mainFont
1459 = FindFont(player->appData.mainFont, mainFontPxlSize);
1460 player->mainFontID
1461 = XLoadFont(player->xDisplay, player->appData.mainFont);
1462 player->mainFontStruct
1463 = XQueryFont(player->xDisplay, player->mainFontID);
1464 player->appData.coordFont
1465 = FindFont(player->appData.coordFont, coordFontPxlSize);
1466 player->coordFontID
1467 = XLoadFont(player->xDisplay, player->appData.coordFont);
1468 player->coordFontStruct
1469 = XQueryFont(player->xDisplay, player->coordFontID);
1472 * Set default arguments.
1475 XtSetArg(player->shellArgs[0], XtNwidth, 0);
1476 XtSetArg(player->shellArgs[1], XtNheight, 0);
1477 XtSetArg(player->shellArgs[2], XtNminWidth, 0);
1478 XtSetArg(player->shellArgs[3], XtNminHeight, 0);
1479 XtSetArg(player->shellArgs[4], XtNmaxWidth, 0);
1480 XtSetArg(player->shellArgs[5], XtNmaxHeight, 0);
1482 XtSetArg(player->boardArgs[0], XtNborderWidth, 0);
1483 XtSetArg(player->boardArgs[1], XtNwidth,
1484 LINE_GAP + (BOARD_SIZE + 4)
1485 * (SMALL_SQUARE_SIZE + LINE_GAP));
1486 XtSetArg(player->boardArgs[2], XtNheight,
1487 LINE_GAP + BOARD_SIZE
1488 * (SMALL_SQUARE_SIZE + LINE_GAP));
1490 XtSetArg(player->commandsArgs[0], XtNborderWidth, 0);
1491 XtSetArg(player->commandsArgs[1], XtNdefaultColumns, 4);
1492 XtSetArg(player->commandsArgs[2], XtNforceColumns, True);
1493 XtSetArg(player->commandsArgs[3], XtNcolumnSpacing, 12);
1494 XtSetArg(player->commandsArgs[4], XtNlist, (XtArgVal) buttonStrings);
1495 XtSetArg(player->commandsArgs[5], XtNnumberStrings, buttonCount);
1496 XtSetArg(player->commandsArgs[6], XtNfont, player->mainFontStruct);
1498 XtSetArg(player->messageArgs[0], XtNborderWidth, 0);
1499 XtSetArg(player->messageArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1500 XtSetArg(player->messageArgs[2], XtNlabel, (XtArgVal) "starting...");
1502 XtSetArg(player->timerArgs[0], XtNborderWidth, 0);
1503 XtSetArg(player->timerArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1505 XtSetArg(player->titleArgs[0], XtNborderWidth, 0);
1506 XtSetArg(player->titleArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1508 boardWidth = LINE_GAP
1509 + (BOARD_SIZE + 4) * (player->squareSize + LINE_GAP);
1511 XtSetArg(player->boardArgs[1], XtNwidth, boardWidth);
1512 XtSetArg(player->boardArgs[2], XtNheight,
1513 LINE_GAP + BOARD_SIZE * (player->squareSize + LINE_GAP));
1516 * widget hierarchy
1519 player->formWidget = XtCreateManagedWidget("form",
1520 formWidgetClass,
1521 player->shellWidget, NULL, 0);
1523 player->widgetList[0] = player->blackTimerWidget
1524 = XtCreateWidget((local ? "black time:" : "rblack time:"),
1525 labelWidgetClass,
1526 player->formWidget, player->timerArgs,
1527 XtNumber(player->timerArgs));
1529 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1530 XtSetValues(player->blackTimerWidget, args, 1);
1532 player->widgetList[1] = player->whiteTimerWidget
1533 = XtCreateWidget((local ? "white time:" : "rwhite time:"),
1534 labelWidgetClass,
1535 player->formWidget, player->timerArgs,
1536 XtNumber(player->timerArgs));
1538 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1539 XtSetValues(player->whiteTimerWidget, args, 1);
1541 player->widgetList[2] = player->titleWidget
1542 = XtCreateWidget((local ? "" : "r"), labelWidgetClass,
1543 player->formWidget, player->titleArgs,
1544 XtNumber(player->titleArgs));
1546 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1547 XtSetValues(player->titleWidget, args, 1);
1549 player->widgetList[3] = player->messageWidget
1550 = XtCreateWidget((local ? "message" : "rmessage"),
1551 labelWidgetClass, player->formWidget,
1552 player->messageArgs,
1553 XtNumber(player->messageArgs));
1555 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1556 XtSetValues(player->messageWidget, args, 1);
1558 player->widgetList[4] = player->commandsWidget
1559 = XtCreateWidget((local ? "commands" : "rcommand"),
1560 listWidgetClass, player->formWidget,
1561 player->commandsArgs,
1562 XtNumber(player->commandsArgs));
1564 player->widgetList[5] = player->boardWidget
1565 = XtCreateWidget((local ? "board" : "rboard"),
1566 widgetClass, player->formWidget,
1567 player->boardArgs,
1568 XtNumber(player->boardArgs));
1570 XtManageChildren(player->widgetList, XtNumber(player->widgetList));
1573 * Calculate the width of the timer labels.
1576 XtSetArg(args[0], XtNfont, &player->mainFontStruct);
1577 XtGetValues(player->blackTimerWidget, args, 1);
1579 if (player->appData.clockMode)
1581 timerWidth = XTextWidth(player->mainFontStruct,
1582 "Black: 8:88:88 ", 15);
1584 else
1586 timerWidth = XTextWidth(player->mainFontStruct, "Black ", 7);
1589 XtSetArg(args[0], XtNwidth, timerWidth);
1590 XtSetValues(player->blackTimerWidget, args, 1);
1591 XtSetValues(player->whiteTimerWidget, args, 1);
1593 XtSetArg(args[0], XtNbackground, &player->timerForegroundPixel);
1594 XtSetArg(args[1], XtNforeground, &player->timerBackgroundPixel);
1595 XtGetValues(player->blackTimerWidget, args, 2);
1598 * Calculate the width of the name and message labels.
1601 XtSetArg(args[0], XtNwidth, &commandsWidth);
1602 XtGetValues(player->commandsWidget, args, 1);
1603 w = ((commandsWidth > boardWidth) ? commandsWidth : boardWidth);
1604 XtSetArg(args[0], XtNwidth, w - timerWidth * 2 - 12);
1605 XtSetValues(player->titleWidget, args, 1);
1606 XtSetArg(args[0], XtNwidth, w - 8);
1607 XtSetValues(player->messageWidget, args, 1);
1610 * 'formWidget' uses these constraints but they are stored
1611 * in the children.
1614 XtSetArg(args[0], XtNfromHoriz, player->blackTimerWidget);
1615 XtSetValues(player->whiteTimerWidget, args, 1);
1616 XtSetArg(args[0], XtNfromHoriz, player->whiteTimerWidget);
1617 XtSetValues(player->titleWidget, args, 1);
1618 XtSetArg(args[0], XtNfromVert, player->blackTimerWidget);
1619 XtSetValues(player->messageWidget, args, 1);
1620 XtSetArg(args[0], XtNfromVert, player->messageWidget);
1621 XtSetValues(player->commandsWidget, args, 1);
1622 XtSetArg(args[0], XtNfromVert, player->commandsWidget);
1623 XtSetValues(player->boardWidget, args, 1);
1625 XtRealizeWidget(player->shellWidget);
1627 player->xBoardWindow = XtWindow(player->boardWidget);
1630 * Create an icon.
1633 player->iconPixmap =
1634 XCreateBitmapFromData(player->xDisplay,
1635 XtWindow(player->shellWidget),
1636 (char *)icon_bits, icon_width, icon_height);
1638 XtSetArg(args[0], XtNiconPixmap, player->iconPixmap);
1639 XtSetValues(player->shellWidget, args, 1);
1642 * Create a cursor for the board widget.
1645 window_attributes.cursor = XCreateFontCursor(player->xDisplay, XC_hand2);
1646 XChangeWindowAttributes(player->xDisplay, player->xBoardWindow,
1647 CWCursor, &window_attributes);
1650 * Inhibit shell resizing.
1653 player->shellArgs[0].value = (XtArgVal) &w;
1654 player->shellArgs[1].value = (XtArgVal) &h;
1655 XtGetValues(player->shellWidget, player->shellArgs, 2);
1656 player->shellArgs[4].value = player->shellArgs[2].value = w;
1657 player->shellArgs[5].value = player->shellArgs[3].value = h;
1658 XtSetValues(player->shellWidget, &player->shellArgs[2], 4);
1661 * Determine value of black pixel.
1664 player->black_pixel_is_zero =
1665 (XBlackPixel(player->xDisplay, player->xScreen) == 0);
1667 CreateGCs();
1668 CreateGrid();
1669 CreatePieces();
1671 if (!fromRemotePlayer)
1672 CreatePieceMenus();
1674 XtAddCallback(player->commandsWidget, XtNcallback, SelectCommand,
1675 (XtPointer)fromRemotePlayer);
1677 if (!fromRemotePlayer)
1678 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1680 if (fromRemotePlayer)
1682 XtSetArg(args[0], XtNtranslations,
1683 XtParseTranslationTable(translationsTableReduced));
1684 /* Disable key commands because often keys are pressed
1685 in the board window if using another talk window. */
1686 XtSetValues(player->boardWidget, &args[0], 1);
1687 XtSetValues(localPlayer.boardWidget, &args[0], 1);
1689 else
1691 XtSetArg(args[0], XtNtranslations,
1692 XtParseTranslationTable(translationsTable));
1693 XtSetValues(player->boardWidget, &args[0], 1);
1694 XtSetArg(args[0], XtNtranslations,
1695 XtParseTranslationTable(blackTranslations));
1696 XtSetValues(player->blackTimerWidget, &args[0], 1);
1697 XtSetArg(args[0], XtNtranslations,
1698 XtParseTranslationTable(whiteTranslations));
1699 XtSetValues(player->whiteTimerWidget, &args[0], 1);
1702 XtAddEventHandler(player->boardWidget, ExposureMask | ButtonPressMask
1703 | ButtonReleaseMask | Button1MotionMask | KeyPressMask,
1704 False, (XtEventHandler)EventProc,
1705 (XtPointer)(player == &remotePlayer));
1707 sprintf(buf, "xshogi version %s, patchlevel %s based on "
1708 "xboard version %s",
1709 version, patchlevel, XBOARD_VERSION);
1712 * If there is to be a machine match, set it up.
1715 if (matchMode != MatchFalse && player != &remotePlayer)
1717 if (player->appData.noShogiProgram)
1719 fprintf(stderr,
1720 "%s: can't have a match with no shogi programs!\n",
1721 programName);
1722 exit(1);
1725 DisplayMessage(buf, fromRemotePlayer);
1726 TwoMachinesProc(NULL, NULL, NULL, NULL);
1728 else
1730 Reset(True);
1731 DisplayMessage(buf, fromRemotePlayer);
1739 main(int argc, char **argv)
1741 setbuf(stdout, NULL);
1742 setbuf(stderr, NULL);
1745 * Copy pointers to command line arguments and number of such pointers.
1746 * (argc, argv will be destroyed by XtAppInitialize)
1749 for (global_argc = 0; global_argc < argc; global_argc++)
1750 global_argv[global_argc] = argv[global_argc];
1752 programName = strrchr(argv[0], '/');
1754 if (programName == NULL)
1755 programName = argv[0];
1756 else
1757 programName++;
1759 localPlayer.shellWidget
1760 = XtAppInitialize(&appContext, "XShogi", shellOptions,
1761 XtNumber(shellOptions), &argc, argv,
1762 xshogiResources, NULL, 0);
1764 if (argc > 1)
1765 Usage();
1767 if ((shogiDir = (char *)getenv("SHOGIDIR")) == NULL)
1769 shogiDir = ".";
1771 else
1773 if (chdir(shogiDir) != 0)
1775 fprintf(stderr, "%s: can't cd to SHOGIDIR\n",
1776 programName);
1777 perror(shogiDir);
1778 exit(1);
1782 XtGetApplicationResources(localPlayer.shellWidget,
1783 &localPlayer.appData, clientResources,
1784 XtNumber(clientResources), NULL, 0);
1786 xshogiDebug = localPlayer.appData.debugMode;
1789 * Determine matchMode state -- poor man's resource converter.
1792 if (strcasecmp(localPlayer.appData.matchMode, "Init") == 0)
1794 matchMode = MatchInit;
1796 else if (strcasecmp(localPlayer.appData.matchMode, "Position") == 0)
1798 matchMode = MatchPosition;
1800 else if (strcasecmp(localPlayer.appData.matchMode, "Opening") == 0)
1802 matchMode = MatchOpening;
1804 else if (strcasecmp(localPlayer.appData.matchMode, "False") == 0)
1806 matchMode = MatchFalse;
1808 else
1810 fprintf(stderr, "%s: bad matchMode option %s\n",
1811 programName, localPlayer.appData.matchMode);
1812 Usage();
1815 buttonStrings = gnuButtonStrings;
1816 buttonProcs = gnuButtonProcs;
1817 buttonCount = XtNumber(gnuButtonStrings);
1819 player = &localPlayer;
1821 CreatePlayerWindow();
1823 XtAppMainLoop(appContext);
1825 return 0;
1831 * Find a font that matches "pattern" that is as close as
1832 * possible to the targetPxlSize. Prefer fonts that are k
1833 * pixels smaller to fonts that are k pixels larger. The
1834 * pattern must be in the X Consortium standard format,
1835 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1836 * The return value should be freed with XtFree when no
1837 * longer needed.
1840 char *
1841 FindFont(char *pattern, int targetPxlSize)
1843 char **fonts, *p, *best;
1844 int i, j, nfonts, minerr, err, pxlSize;
1846 fonts = XListFonts(player->xDisplay, pattern, 999999, &nfonts);
1848 if (nfonts < 1)
1850 fprintf(stderr, "%s: No fonts match pattern %s\n",
1851 programName, pattern);
1852 exit(1);
1855 best = "";
1856 minerr = 999999;
1858 for (i = 0; i < nfonts; i++)
1860 j = 0;
1861 p = fonts[i];
1863 if (*p != '-')
1864 continue;
1866 while (j < 7)
1868 if (*p == NULLCHAR)
1869 break;
1871 if (*p++ == '-')
1872 j++;
1875 if (j < 7)
1876 continue;
1878 pxlSize = atoi(p);
1880 if (pxlSize == targetPxlSize)
1882 best = fonts[i];
1883 break;
1886 err = pxlSize - targetPxlSize;
1888 if (abs(err) < abs(minerr)
1889 || ((minerr > 0) && (err < 0) && (-err == minerr)))
1891 best = fonts[i];
1892 minerr = err;
1896 p = (char *)XtMalloc(strlen(best) + 1);
1897 strcpy(p, best);
1898 XFreeFontNames(fonts);
1899 return p;
1905 void
1906 CreateGCs(void)
1908 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
1909 | GCBackground | GCFunction | GCPlaneMask;
1910 XGCValues gc_values;
1912 gc_values.plane_mask = AllPlanes;
1913 gc_values.line_width = LINE_GAP;
1914 gc_values.line_style = LineSolid;
1915 gc_values.function = GXcopy;
1917 gc_values.foreground = XBlackPixel(player->xDisplay, player->xScreen);
1918 gc_values.background = XBlackPixel(player->xDisplay, player->xScreen);
1919 player->lineGC = XtGetGC(player->shellWidget, value_mask, &gc_values);
1921 gc_values.background = XWhitePixel(player->xDisplay, player->xScreen);
1922 player->coordGC = XtGetGC(player->shellWidget, value_mask, &gc_values);
1923 XSetFont(player->xDisplay, player->coordGC, player->coordFontID);
1925 if (player->monoMode)
1927 gc_values.foreground
1928 = XWhitePixel(player->xDisplay, player->xScreen);
1929 gc_values.background
1930 = XWhitePixel(player->xDisplay, player->xScreen);
1932 /* empty square off board */
1933 player->squareOffBoardGC
1934 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1936 /* empty square on board */
1937 player->squareGC
1938 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1940 else
1942 Pixel bg; /* background color */
1943 Arg args[1];
1945 /* Get background color. */
1946 XtSetArg(args[0], XtNbackground, &bg);
1947 XtGetValues(player->shellWidget, args, 1);
1949 /* empty square off board */
1950 gc_values.foreground = gc_values.background = bg;
1951 player->squareOffBoardGC
1952 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1954 /* empty square on board */
1955 gc_values.foreground
1956 = player->appData.squareColor;
1957 gc_values.background
1958 = player->appData.squareColor;
1959 player->squareGC
1960 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1962 /* piece off board */
1963 gc_values.foreground
1964 = player->appData.pieceColor;
1965 gc_values.background = bg;
1966 player->oPieceGC
1967 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1969 /* piece on board */
1970 gc_values.foreground
1971 = player->appData.pieceColor;
1972 gc_values.background
1973 = player->appData.squareColor;
1974 player->pieceGC
1975 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1977 /* piece symbol */
1979 * FIXME: charPieceColor seems to have no effect;
1980 * the bitmap is *always* black.
1982 gc_values.function = (player->black_pixel_is_zero ? GXand : GXor);
1984 gc_values.foreground
1985 = player->appData.charPieceColor;
1986 gc_values.background
1987 = player->appData.charPieceColor;
1989 player->charPieceGC
1990 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1997 void
1998 CreatePieces(void)
2000 XSynchronize(player->xDisplay, True); /* Work-around for xlib/xt
2001 buffering bug */
2003 if (player->appData.westernPieceSet)
2005 ReadBitmap(player->appData.reverseBigSolidBitmap,
2006 &player->reverseBigSolidBitmap,
2007 NULL,
2008 bigsolidR_bits, bigsolidR_m_bits, bigsolidR_l_bits);
2010 ReadBitmap(player->appData.reverseSmallSolidBitmap,
2011 &player->reverseSmallSolidBitmap,
2012 NULL,
2013 smallsolidR_bits, smallsolidR_m_bits, smallsolidR_l_bits);
2015 ReadBitmap(player->appData.normalBigSolidBitmap,
2016 &player->normalBigSolidBitmap,
2017 NULL,
2018 bigsolid_bits, bigsolid_m_bits, bigsolid_l_bits);
2020 ReadBitmap(player->appData.normalSmallSolidBitmap,
2021 &player->normalSmallSolidBitmap,
2022 NULL,
2023 smallsolid_bits, smallsolid_m_bits, smallsolid_l_bits);
2025 ReadBitmap(player->appData.reversePawnBitmap,
2026 &player->reversePawnBitmap,
2027 &player->reverseSmallSolidBitmap,
2028 pawnRW_bits, pawnRW_bits, pawnRW_bits);
2030 ReadBitmap(player->appData.reverseLanceBitmap,
2031 &player->reverseLanceBitmap,
2032 &player->reverseSmallSolidBitmap,
2033 lanceRW_bits, lanceRW_bits, lanceRW_bits);
2035 ReadBitmap(player->appData.reverseKnightBitmap,
2036 &player->reverseKnightBitmap,
2037 &player->reverseSmallSolidBitmap,
2038 knightRW_bits, knightRW_bits, knightRW_bits);
2040 ReadBitmap(player->appData.reverseSilverBitmap,
2041 &player->reverseSilverBitmap,
2042 &player->reverseBigSolidBitmap,
2043 silverRW_bits, silverRW_bits, silverRW_bits);
2045 ReadBitmap(player->appData.reverseGoldBitmap,
2046 &player->reverseGoldBitmap,
2047 &player->reverseBigSolidBitmap,
2048 goldRW_bits, goldRW_bits, goldRW_bits);
2050 ReadBitmap(player->appData.reverseRookBitmap,
2051 &player->reverseRookBitmap,
2052 &player->reverseBigSolidBitmap,
2053 rookRW_bits, rookRW_bits, rookRW_bits);
2055 ReadBitmap(player->appData.reverseBishopBitmap,
2056 &player->reverseBishopBitmap,
2057 &player->reverseBigSolidBitmap,
2058 bishopRW_bits, bishopRW_bits, bishopRW_bits);
2060 ReadBitmap(player->appData.reversePPawnBitmap,
2061 &player->reversePPawnBitmap,
2062 &player->reverseSmallSolidBitmap,
2063 pawnPRW_bits, pawnPRW_bits, pawnPRW_bits);
2065 ReadBitmap(player->appData.reversePLanceBitmap,
2066 &player->reversePLanceBitmap,
2067 &player->reverseSmallSolidBitmap,
2068 lancePRW_bits, lancePRW_bits, lancePRW_bits);
2070 ReadBitmap(player->appData.reversePKnightBitmap,
2071 &player->reversePKnightBitmap,
2072 &player->reverseSmallSolidBitmap,
2073 knightPRW_bits, knightPRW_bits, knightPRW_bits);
2075 ReadBitmap(player->appData.reversePSilverBitmap,
2076 &player->reversePSilverBitmap,
2077 &player->reverseBigSolidBitmap,
2078 silverPRW_bits, silverPRW_bits, silverPRW_bits);
2080 ReadBitmap(player->appData.reversePRookBitmap,
2081 &player->reversePRookBitmap,
2082 &player->reverseBigSolidBitmap,
2083 rookPRW_bits, rookPRW_bits, rookPRW_bits);
2085 ReadBitmap(player->appData.reversePBishopBitmap,
2086 &player->reversePBishopBitmap,
2087 &player->reverseBigSolidBitmap,
2088 bishopPRW_bits, bishopPRW_bits, bishopPRW_bits);
2090 ReadBitmap(player->appData.reverseKingBitmap,
2091 &player->reverseKingBitmap,
2092 &player->reverseBigSolidBitmap,
2093 kingRW_bits, kingRW_bits, kingRW_bits);
2095 ReadBitmap(player->appData.normalPawnBitmap,
2096 &player->normalPawnBitmap,
2097 &player->normalSmallSolidBitmap,
2098 pawnW_bits, pawnW_bits, pawnW_bits);
2100 ReadBitmap(player->appData.normalLanceBitmap,
2101 &player->normalLanceBitmap,
2102 &player->normalSmallSolidBitmap,
2103 lanceW_bits, lanceW_bits, lanceW_bits);
2105 ReadBitmap(player->appData.normalKnightBitmap,
2106 &player->normalKnightBitmap,
2107 &player->normalSmallSolidBitmap,
2108 knightW_bits, knightW_bits, knightW_bits);
2110 ReadBitmap(player->appData.normalSilverBitmap,
2111 &player->normalSilverBitmap,
2112 &player->normalBigSolidBitmap,
2113 silverW_bits, silverW_bits, silverW_bits);
2115 ReadBitmap(player->appData.normalGoldBitmap,
2116 &player->normalGoldBitmap,
2117 &player->normalBigSolidBitmap,
2118 goldW_bits, goldW_bits, goldW_bits);
2120 ReadBitmap(player->appData.normalRookBitmap,
2121 &player->normalRookBitmap,
2122 &player->normalBigSolidBitmap,
2123 rookW_bits, rookW_bits, rookW_bits);
2125 ReadBitmap(player->appData.normalBishopBitmap,
2126 &player->normalBishopBitmap,
2127 &player->normalBigSolidBitmap,
2128 bishopW_bits, bishopW_bits, bishopW_bits);
2130 ReadBitmap(player->appData.normalPPawnBitmap,
2131 &player->normalPPawnBitmap,
2132 &player->normalSmallSolidBitmap,
2133 pawnPW_bits, pawnPW_bits, pawnPW_bits);
2135 ReadBitmap(player->appData.normalPLanceBitmap,
2136 &player->normalPLanceBitmap,
2137 &player->normalSmallSolidBitmap,
2138 lancePW_bits, lancePW_bits, lancePW_bits);
2140 ReadBitmap(player->appData.normalPKnightBitmap,
2141 &player->normalPKnightBitmap,
2142 &player->normalSmallSolidBitmap,
2143 knightPW_bits, knightPW_bits, knightPW_bits);
2145 ReadBitmap(player->appData.normalPSilverBitmap,
2146 &player->normalPSilverBitmap,
2147 &player->normalBigSolidBitmap,
2148 silverPW_bits, silverPW_bits, silverPW_bits);
2150 ReadBitmap(player->appData.normalPRookBitmap,
2151 &player->normalPRookBitmap,
2152 &player->normalBigSolidBitmap,
2153 rookPW_bits, rookPW_bits, rookPW_bits);
2155 ReadBitmap(player->appData.normalPBishopBitmap,
2156 &player->normalPBishopBitmap,
2157 &player->normalBigSolidBitmap,
2158 bishopPW_bits, bishopPW_bits, bishopPW_bits);
2160 ReadBitmap(player->appData.normalKingBitmap,
2161 &player->normalKingBitmap,
2162 &player->normalBigSolidBitmap,
2163 kingW_bits, kingW_bits, kingW_bits);
2165 else
2167 ReadBitmap(player->appData.reverseBigSolidBitmap,
2168 &player->reverseBigSolidBitmap,
2169 NULL,
2170 bigsolidR_bits, bigsolidR_m_bits, bigsolidR_l_bits);
2172 ReadBitmap(player->appData.reverseSmallSolidBitmap,
2173 &player->reverseSmallSolidBitmap,
2174 NULL,
2175 smallsolidR_bits, smallsolidR_m_bits, smallsolidR_l_bits);
2177 ReadBitmap(player->appData.normalBigSolidBitmap,
2178 &player->normalBigSolidBitmap,
2179 NULL,
2180 bigsolid_bits, bigsolid_m_bits, bigsolid_l_bits);
2182 ReadBitmap(player->appData.normalSmallSolidBitmap,
2183 &player->normalSmallSolidBitmap,
2184 NULL,
2185 smallsolid_bits, smallsolid_m_bits, smallsolid_l_bits);
2187 ReadBitmap(player->appData.reversePawnBitmap,
2188 &player->reversePawnBitmap,
2189 &player->reverseSmallSolidBitmap,
2190 pawnR_bits, pawnR_m_bits, pawnR_l_bits);
2192 ReadBitmap(player->appData.reverseLanceBitmap,
2193 &player->reverseLanceBitmap,
2194 &player->reverseSmallSolidBitmap,
2195 lanceR_bits, lanceR_m_bits, lanceR_l_bits);
2197 ReadBitmap(player->appData.reverseKnightBitmap,
2198 &player->reverseKnightBitmap,
2199 &player->reverseSmallSolidBitmap,
2200 knightR_bits, knightR_m_bits, knightR_l_bits);
2202 ReadBitmap(player->appData.reverseSilverBitmap,
2203 &player->reverseSilverBitmap,
2204 &player->reverseBigSolidBitmap,
2205 silverR_bits, silverR_m_bits, silverR_l_bits);
2207 ReadBitmap(player->appData.reverseGoldBitmap,
2208 &player->reverseGoldBitmap,
2209 &player->reverseBigSolidBitmap,
2210 goldR_bits, goldR_m_bits, goldR_l_bits);
2212 ReadBitmap(player->appData.reverseRookBitmap,
2213 &player->reverseRookBitmap,
2214 &player->reverseBigSolidBitmap,
2215 rookR_bits, rookR_m_bits, rookR_l_bits);
2217 ReadBitmap(player->appData.reverseBishopBitmap,
2218 &player->reverseBishopBitmap,
2219 &player->reverseBigSolidBitmap,
2220 bishopR_bits, bishopR_m_bits, bishopR_l_bits);
2222 ReadBitmap(player->appData.reversePPawnBitmap,
2223 &player->reversePPawnBitmap,
2224 &player->reverseSmallSolidBitmap,
2225 pawnPR_bits, pawnPR_m_bits, pawnPR_l_bits);
2227 ReadBitmap(player->appData.reversePLanceBitmap,
2228 &player->reversePLanceBitmap,
2229 &player->reverseSmallSolidBitmap,
2230 lancePR_bits, lancePR_m_bits, lancePR_l_bits);
2232 ReadBitmap(player->appData.reversePKnightBitmap,
2233 &player->reversePKnightBitmap,
2234 &player->reverseSmallSolidBitmap,
2235 knightPR_bits, knightPR_m_bits, knightPR_l_bits);
2237 ReadBitmap(player->appData.reversePSilverBitmap,
2238 &player->reversePSilverBitmap,
2239 &player->reverseBigSolidBitmap,
2240 silverPR_bits, silverPR_m_bits, silverPR_l_bits);
2242 ReadBitmap(player->appData.reversePRookBitmap,
2243 &player->reversePRookBitmap,
2244 &player->reverseBigSolidBitmap,
2245 rookPR_bits, rookPR_m_bits, rookPR_l_bits);
2247 ReadBitmap(player->appData.reversePBishopBitmap,
2248 &player->reversePBishopBitmap,
2249 &player->reverseBigSolidBitmap,
2250 bishopPR_bits, bishopPR_m_bits, bishopPR_l_bits);
2252 ReadBitmap(player->appData.reverseKingBitmap,
2253 &player->reverseKingBitmap,
2254 &player->reverseBigSolidBitmap,
2255 kingR_bits, kingR_m_bits, kingR_l_bits);
2257 ReadBitmap(player->appData.normalPawnBitmap,
2258 &player->normalPawnBitmap,
2259 &player->normalSmallSolidBitmap,
2260 pawn_bits, pawn_m_bits, pawn_l_bits);
2262 ReadBitmap(player->appData.normalLanceBitmap,
2263 &player->normalLanceBitmap,
2264 &player->normalSmallSolidBitmap,
2265 lance_bits, lance_m_bits, lance_l_bits);
2267 ReadBitmap(player->appData.normalKnightBitmap,
2268 &player->normalKnightBitmap,
2269 &player->normalSmallSolidBitmap,
2270 knight_bits, knight_m_bits, knight_l_bits);
2272 ReadBitmap(player->appData.normalSilverBitmap,
2273 &player->normalSilverBitmap,
2274 &player->normalBigSolidBitmap,
2275 silver_bits, silver_m_bits, silver_l_bits);
2277 ReadBitmap(player->appData.normalGoldBitmap,
2278 &player->normalGoldBitmap,
2279 &player->normalBigSolidBitmap,
2280 gold_bits, gold_m_bits, gold_l_bits);
2282 ReadBitmap(player->appData.normalRookBitmap,
2283 &player->normalRookBitmap,
2284 &player->normalBigSolidBitmap,
2285 rook_bits, rook_m_bits, rook_l_bits);
2287 ReadBitmap(player->appData.normalBishopBitmap,
2288 &player->normalBishopBitmap,
2289 &player->normalBigSolidBitmap,
2290 bishop_bits, bishop_m_bits, bishop_l_bits);
2292 ReadBitmap(player->appData.normalPPawnBitmap,
2293 &player->normalPPawnBitmap,
2294 &player->normalSmallSolidBitmap,
2295 pawnP_bits, pawnP_m_bits, pawnP_l_bits);
2297 ReadBitmap(player->appData.normalPLanceBitmap,
2298 &player->normalPLanceBitmap,
2299 &player->normalSmallSolidBitmap,
2300 lanceP_bits, lanceP_m_bits, lanceP_l_bits);
2302 ReadBitmap(player->appData.normalPKnightBitmap,
2303 &player->normalPKnightBitmap,
2304 &player->normalSmallSolidBitmap,
2305 knightP_bits, knightP_m_bits, knightP_l_bits);
2307 ReadBitmap(player->appData.normalPSilverBitmap,
2308 &player->normalPSilverBitmap,
2309 &player->normalBigSolidBitmap,
2310 silverP_bits, silverP_m_bits, silverP_l_bits);
2312 ReadBitmap(player->appData.normalPRookBitmap,
2313 &player->normalPRookBitmap,
2314 &player->normalBigSolidBitmap,
2315 rookP_bits, rookP_m_bits, rookP_l_bits);
2317 ReadBitmap(player->appData.normalPBishopBitmap,
2318 &player->normalPBishopBitmap,
2319 &player->normalBigSolidBitmap,
2320 bishopP_bits, bishopP_m_bits, bishopP_l_bits);
2322 ReadBitmap(player->appData.normalKingBitmap,
2323 &player->normalKingBitmap,
2324 &player->normalBigSolidBitmap,
2325 king_bits, king_m_bits, king_l_bits);
2329 XSynchronize(player->xDisplay, False); /* Work-around for xlib/xt
2330 buffering bug */
2337 ReadBitmapFile(Display *display, Drawable d, char *filename,
2338 unsigned int *width_return,
2339 unsigned int *height_return,
2340 Pixmap *bitmap_return,
2341 int *x_hot_return, int *y_hot_return)
2343 int n;
2345 if ((n = XReadBitmapFile(display, d, filename,
2346 width_return, height_return,
2347 bitmap_return, x_hot_return, y_hot_return))
2348 != BitmapSuccess)
2350 return n;
2352 else
2354 /* transform a 1 plane pixmap to a k plane pixmap */
2355 return BitmapSuccess;
2363 * Create the X pixmap from .xbm file bitmap data. This may
2364 * have to be revised considerably.
2367 void
2368 ReadBitmap(String name, Pixmap *pm, Pixmap *qm,
2369 unsigned char *small_bits,
2370 unsigned char *medium_bits,
2371 unsigned char *large_bits)
2373 int x_hot, y_hot;
2374 unsigned int w, h;
2376 if ((name == NULL)
2377 || (ReadBitmapFile(player->xDisplay, player->xBoardWindow, name,
2378 &w, &h, pm, &x_hot, &y_hot) != BitmapSuccess)
2379 || (w != player->squareSize)
2380 || (h != player->squareSize))
2382 unsigned long fg, bg;
2383 unsigned int depth;
2385 depth = DisplayPlanes(player->xDisplay, player->xScreen);
2387 if (player->monoMode)
2389 fg = XBlackPixel(player->xDisplay, player->xScreen);
2390 bg = XWhitePixel(player->xDisplay, player->xScreen);
2392 else if (qm == NULL)
2394 fg = player->appData.oneColor;
2395 bg = player->appData.zeroColor;
2397 else
2399 fg = (player->black_pixel_is_zero ? 0 : ~0);
2400 bg = (player->black_pixel_is_zero ? ~0 : 0);
2403 switch (player->boardSize)
2405 case Large:
2406 *pm = XCreatePixmapFromBitmapData(player->xDisplay,
2407 player->xBoardWindow,
2408 (char *)large_bits,
2409 player->squareSize,
2410 player->squareSize,
2411 fg, bg, depth);
2412 break;
2414 case Medium:
2415 *pm = XCreatePixmapFromBitmapData(player->xDisplay,
2416 player->xBoardWindow,
2417 (char *)medium_bits,
2418 player->squareSize,
2419 player->squareSize,
2420 fg, bg, depth);
2421 break;
2423 case Small:
2424 *pm = XCreatePixmapFromBitmapData(player->xDisplay,
2425 player->xBoardWindow,
2426 (char *)small_bits,
2427 player->squareSize,
2428 player->squareSize,
2429 fg, bg, depth);
2430 break;
2438 void
2439 CreateGrid(void)
2441 int i, offset;
2443 offset = 2 * (player->squareSize + LINE_GAP);
2445 for (i = 0; i < BOARD_SIZE + 1; i++)
2447 player->gridSegments[i].x1 = offset;
2448 player->gridSegments[i + BOARD_SIZE + 1].y1 = 0;
2449 player->gridSegments[i].y1 = player->gridSegments[i].y2
2450 = LINE_GAP / 2 + (i * (player->squareSize + LINE_GAP));
2451 player->gridSegments[i].x2 = LINE_GAP + BOARD_SIZE *
2452 (player->squareSize + LINE_GAP) + offset;
2453 player->gridSegments[i + BOARD_SIZE + 1].x1
2454 = player->gridSegments[i + BOARD_SIZE + 1].x2 = LINE_GAP / 2
2455 + (i * (player->squareSize + LINE_GAP)) + offset;
2456 player->gridSegments[i + BOARD_SIZE + 1].y2
2457 = BOARD_SIZE * (player->squareSize + LINE_GAP);
2464 void
2465 CreatePieceMenus(void)
2467 int i;
2468 Widget entry;
2469 Arg args[1];
2470 ShogiSquare selection;
2472 XtSetArg(args[0], XtNlabel, "Black");
2473 blackPieceMenu = XtCreatePopupShell("menuW", simpleMenuWidgetClass,
2474 localPlayer.boardWidget, args, 1);
2476 for (i = 0; i < PIECE_MENU_SIZE; i++)
2478 String item = pieceMenuStrings[i];
2480 if (strcmp(item, "----") == 0)
2482 entry = XtCreateManagedWidget(item, smeLineObjectClass,
2483 blackPieceMenu, NULL, 0);
2485 else
2487 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
2488 blackPieceMenu, NULL, 0);
2489 selection = pieceMenuTranslation[0][i];
2490 XtAddCallback(entry, XtNcallback,
2491 (XtCallbackProc)PieceMenuSelect,
2492 (XtPointer)selection);
2494 if (selection == BlackPawn)
2496 XtSetArg(args[0], XtNpopupOnEntry, entry);
2497 XtSetValues(blackPieceMenu, args, 1);
2502 XtSetArg(args[0], XtNlabel, "White");
2503 whitePieceMenu = XtCreatePopupShell("menuB", simpleMenuWidgetClass,
2504 localPlayer.boardWidget, args, 1);
2506 for (i = 0; i < PIECE_MENU_SIZE; i++)
2508 String item = pieceMenuStrings[i];
2510 if (strcmp(item, "----") == 0)
2512 entry = XtCreateManagedWidget(item, smeLineObjectClass,
2513 whitePieceMenu, NULL, 0);
2515 else
2517 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
2518 whitePieceMenu, NULL, 0);
2519 selection = pieceMenuTranslation[1][i];
2520 XtAddCallback(entry, XtNcallback,
2521 (XtCallbackProc)PieceMenuSelect,
2522 (XtPointer)selection);
2524 if (selection == WhitePawn)
2526 XtSetArg(args[0], XtNpopupOnEntry, entry);
2527 XtSetValues(whitePieceMenu, args, 1);
2532 XtRegisterGrabAction(PieceMenuPopup, True,
2533 (unsigned)(ButtonPressMask|ButtonReleaseMask),
2534 GrabModeAsync, GrabModeAsync);
2540 void
2541 PieceMenuPopup(Widget w, XEvent *event, String *params, Cardinal *num_params)
2543 if (event->type != ButtonPress)
2544 return;
2546 if (gameMode != EditPosition)
2547 return;
2549 if (((pmFromX = EventToXSquare(event->xbutton.x)) < 1)
2550 || (pmFromX > BOARD_SIZE + 2)
2551 || ((pmFromY = EventToSquare(event->xbutton.y)) < 0))
2553 pmFromX = pmFromY = -1;
2554 return;
2557 if (localPlayer.flipView)
2558 pmFromX = BOARD_SIZE + 3 - pmFromX;
2559 else
2560 pmFromY = BOARD_SIZE - 1 - pmFromY;
2562 XtPopupSpringLoaded(XtNameToWidget(localPlayer.boardWidget, params[0]));
2568 static void
2569 PieceMenuSelect(Widget w, ShogiSquare piece, char *junk)
2571 if ((pmFromX < 0) || (pmFromY < 0))
2572 return;
2574 if (off_board(pmFromX))
2576 int i, c;
2577 switch (piece)
2579 case ClearBoard:
2580 break;
2582 case BlackPlay:
2583 break;
2585 case WhitePlay:
2586 break;
2588 default:
2589 i = pieceToCatchedIndex[piece];
2590 c = (piece >= WhitePawn);
2591 catches[0][c][i]++;
2592 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2593 XSync(localPlayer.xDisplay, False);
2594 return;
2598 pmFromX -= 2;
2600 switch (piece)
2602 case ClearBoard:
2603 for (pmFromY = 0; pmFromY < BOARD_SIZE; pmFromY++)
2604 for (pmFromX = 0; pmFromX < BOARD_SIZE; pmFromX++)
2605 boards[0][pmFromY][pmFromX] = EmptySquare;
2607 ClearCatches(catches[0]);
2608 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2609 break;
2611 case BlackPlay: /* not currently on menu */
2612 SetBlackToPlay();
2613 break;
2615 case WhitePlay: /* not currently on menu */
2616 SetWhiteToPlay();
2617 break;
2619 default:
2620 boards[0][pmFromY][pmFromX] = piece;
2621 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2622 break;
2625 XSync(localPlayer.xDisplay, False);
2631 static void
2632 SetBlackToPlay(void)
2634 int saveCM;
2636 if (gameMode != EditPosition)
2637 return;
2639 whitePlaysFirst = False;
2640 saveCM = currentMove;
2641 currentMove = 0; /* kludge */
2642 DisplayClocks(ReDisplayTimers);
2643 currentMove = saveCM;
2649 static void
2650 SetWhiteToPlay(void)
2652 int saveCM;
2654 if (gameMode != EditPosition)
2655 return;
2657 whitePlaysFirst = True;
2658 saveCM = currentMove;
2659 currentMove = 1; /* kludge */
2660 DisplayClocks(ReDisplayTimers);
2661 currentMove = saveCM;
2668 * If the user selects on a border boundary or off the board, return failure.
2669 * Otherwise map the event coordinate to the square.
2673 EventToSquare(int x)
2675 if (x < LINE_GAP)
2676 return -1;
2678 x -= LINE_GAP;
2680 if ((x % (player->squareSize + LINE_GAP)) >= player->squareSize)
2681 return -1;
2683 x /= (player->squareSize + LINE_GAP);
2685 if (x >= BOARD_SIZE)
2686 return -1;
2688 return x;
2695 EventToXSquare(int x)
2697 if (x < LINE_GAP)
2698 return -1;
2700 x -= LINE_GAP;
2702 if ((x % (player->squareSize + LINE_GAP)) >= player->squareSize)
2703 return -1;
2705 x /= (player->squareSize + LINE_GAP);
2707 if (x >= BOARD_SIZE + 4)
2708 return -1;
2710 return x;
2716 ShogiSquare
2717 CharToPiece(int c, int p)
2719 if (p)
2721 switch (c)
2723 default:
2724 case '.': return EmptySquare;
2725 case 'P': return BlackPPawn;
2726 case 'L': return BlackPLance;
2727 case 'N': return BlackPKnight;
2728 case 'S': return BlackPSilver;
2729 case 'G': return BlackGold;
2730 case 'R': return BlackPRook;
2731 case 'B': return BlackPBishop;
2732 case 'K': return BlackKing;
2733 case 'p': return WhitePPawn;
2734 case 'l': return WhitePLance;
2735 case 'n': return WhitePKnight;
2736 case 's': return WhitePSilver;
2737 case 'g': return WhiteGold;
2738 case 'r': return WhitePRook;
2739 case 'b': return WhitePBishop;
2740 case 'k': return WhiteKing;
2743 else
2745 switch (c)
2747 default:
2748 case '.': return EmptySquare;
2749 case 'P': return BlackPawn;
2750 case 'L': return BlackLance;
2751 case 'N': return BlackKnight;
2752 case 'S': return BlackSilver;
2753 case 'G': return BlackGold;
2754 case 'R': return BlackRook;
2755 case 'B': return BlackBishop;
2756 case 'K': return BlackKing;
2757 case 'p': return WhitePawn;
2758 case 'l': return WhiteLance;
2759 case 'n': return WhiteKnight;
2760 case 's': return WhiteSilver;
2761 case 'g': return WhiteGold;
2762 case 'r': return WhiteRook;
2763 case 'b': return WhiteBishop;
2764 case 'k': return WhiteKing;
2773 * Convert coordinates to normal algebraic notation.
2774 * promoPiece must be NULLCHAR if not a promotion.
2777 ShogiMove
2778 MakeAlg(int fromX, int fromY, int toX, int toY,
2779 char promoPiece, int currentBoardIndex, char *out)
2781 ShogiSquare piece;
2782 char *outp = out;
2784 if (fromX > 80)
2786 piece = (fromX - 81);
2787 *outp++ = catchedIndexToChar[piece];
2788 *outp++ = '*';
2789 *outp++ = '9' - toX;
2790 *outp++ = 'i' - toY;
2791 *outp++ = NULLCHAR;
2792 return (BlackOnMove(forwardMostMove) ? BlackDrop : WhiteDrop);
2794 else
2796 *outp++ = '9' - fromX;
2797 *outp++ = 'i' - fromY;
2798 *outp++ = '9' - toX;
2799 *outp++ = 'i' - toY;
2800 *outp++ = promoPiece;
2801 *outp++ = NULLCHAR;
2803 if (promoPiece == NULLCHAR)
2805 return NormalMove;
2807 else
2809 return (BlackOnMove(forwardMostMove)
2810 ? BlackPromotion : WhitePromotion);
2818 void
2819 DrawSquare(int row, int column, ShogiSquare piece)
2821 int square_color, x, y, direction, font_ascent, font_descent;
2822 char string[2];
2823 XCharStruct overall;
2824 struct DisplayData *player;
2826 for (player = &localPlayer; True; player = &remotePlayer)
2828 int offset, remote;
2830 remote = (player == &remotePlayer);
2831 offset = 2 * (player->squareSize + LINE_GAP);
2833 if (player->flipView)
2835 x = LINE_GAP + ((BOARD_SIZE - 1) - column) *
2836 (player->squareSize + LINE_GAP) + offset;
2837 y = LINE_GAP + row * (player->squareSize + LINE_GAP);
2839 else
2841 x = LINE_GAP + column * (player->squareSize + LINE_GAP) + offset;
2842 y = LINE_GAP + ((BOARD_SIZE - 1) - row) *
2843 (player->squareSize + LINE_GAP);
2846 square_color = (((column + row) % 2) ? LIGHT : DARK);
2848 if (piece == EmptySquare)
2850 if (column < 0 || column >= BOARD_SIZE)
2852 /* empty square off board */
2853 XFillRectangle(player->xDisplay, player->xBoardWindow,
2854 player->squareOffBoardGC,
2855 x, y, player->squareSize,
2856 player->squareSize);
2858 else
2860 /* empty square on board */
2861 XFillRectangle(player->xDisplay,
2862 player->xBoardWindow,
2863 player->squareGC,
2864 x, y,
2865 player->squareSize,
2866 player->squareSize);
2869 else if (player->monoMode) /* Draw a piece in mono mode. */
2871 XCopyArea(player->xDisplay,
2872 ((((((int)piece) < ((int)WhitePawn)))
2873 ^ player->flipView)
2874 ? *pieceToNormal[remote][(int)piece]
2875 : *pieceToReverse[remote][(int)piece]),
2876 player->xBoardWindow,
2877 (player->monoMode
2878 ? player->squareOffBoardGC /* ??? FIXME? */
2879 : player->pieceGC),
2880 0, 0,
2881 player->squareSize, player->squareSize, x, y);
2883 else /* Draw a piece in color mode. */
2885 if ((column < 0) || (column >= BOARD_SIZE)) /* off board */
2887 /* draw piece background */
2889 XCopyPlane(player->xDisplay,
2890 ((((((int)piece) < ((int)WhitePawn)))
2891 ^ player->flipView)
2892 ? *pieceToNormalSolid[remote][(int)piece]
2893 : *pieceToReverseSolid[remote][(int)piece]),
2894 player->xBoardWindow,
2895 player->oPieceGC,
2896 0, 0,
2897 player->squareSize, player->squareSize, x, y, 1);
2899 /* draw piece bitmap */
2901 XCopyArea(player->xDisplay,
2902 ((((((int)piece) < ((int)WhitePawn)))
2903 ^ player->flipView)
2904 ? *pieceToNormal[remote][(int)piece]
2905 : *pieceToReverse[remote][(int)piece]),
2906 player->xBoardWindow,
2907 player->charPieceGC,
2908 0, 0,
2909 player->squareSize, player->squareSize, x, y);
2911 else /* on board */
2913 /* draw piece background */
2915 XCopyPlane(player->xDisplay,
2916 ((((((int)piece) < ((int)WhitePawn)))
2917 ^ player->flipView)
2918 ? *pieceToNormalSolid[remote][(int)piece]
2919 : *pieceToReverseSolid[remote][(int)piece]),
2920 player->xBoardWindow,
2921 player->pieceGC,
2922 0, 0,
2923 player->squareSize, player->squareSize, x, y, 1);
2925 /* draw piece bitmap */
2927 XCopyArea(player->xDisplay,
2928 ((((((int)piece) < ((int)WhitePawn)))
2929 ^ player->flipView)
2930 ? *pieceToNormal[remote][(int)piece]
2931 : *pieceToReverse[remote][(int)piece]),
2932 player->xBoardWindow,
2933 player->charPieceGC,
2934 0, 0,
2935 player->squareSize, player->squareSize, x, y);
2939 string[1] = NULLCHAR;
2941 if (player->showCoords
2942 && (column >= 0) && (column < 9)
2943 && (row == (player->flipView ? 8 : 0)))
2945 string[0] = '9' - column;
2946 XTextExtents(player->coordFontStruct, string, 1, &direction,
2947 &font_ascent, &font_descent, &overall);
2949 if (player->monoMode)
2951 XDrawImageString(player->xDisplay,
2952 player->xBoardWindow, player->coordGC,
2953 x + player->squareSize - overall.width - 2,
2954 y + player->squareSize - font_descent - 1,
2955 string, 1);
2957 else
2959 XDrawString(player->xDisplay, player->xBoardWindow,
2960 player->coordGC,
2961 x + player->squareSize - overall.width - 2,
2962 y + player->squareSize - font_descent - 1,
2963 string, 1);
2967 if (player->showCoords
2968 && (row >= 0) && (row < 9)
2969 && (column == (player->flipView ? 8 : 0)))
2971 string[0] = 'i' - row;
2972 XTextExtents(player->coordFontStruct, string, 1, &direction,
2973 &font_ascent, &font_descent, &overall);
2975 if (player->monoMode)
2977 XDrawImageString(player->xDisplay,
2978 player->xBoardWindow, player->coordGC,
2979 x + 2, y + font_ascent + 1, string, 1);
2981 else
2983 XDrawString(player->xDisplay, player->xBoardWindow,
2984 player->coordGC,
2985 x + 2, y + font_ascent + 1, string, 1);
2989 if (!updateRemotePlayer || (player == &remotePlayer))
2990 break;
2997 void
2998 EventProc(Widget widget, XtPointer client_data, XEvent *event)
3000 if (event->type == MappingNotify)
3002 XRefreshKeyboardMapping((XMappingEvent *) event);
3003 return;
3006 if (!XtIsRealized(widget))
3007 return;
3009 if ((event->type == ButtonPress) || (event->type == ButtonRelease))
3011 if (event->xbutton.button != Button1)
3012 return;
3015 switch (event->type)
3017 case Expose:
3018 DrawPosition(widget, event, NULL, NULL);
3019 break;
3021 default:
3022 return;
3030 * event handler for redrawing the board
3033 void
3034 DrawPosition(Widget w, XEvent *event, String *prms, Cardinal *nprms)
3036 Arg args[1];
3037 int i, j;
3038 static Board lastBoard;
3039 static Catched lastCatches;
3040 static int lastBoardValid = 0;
3041 static int lastFlipView = 0, lastRemoteFlipView = 1;
3043 if (!player->Iconic)
3045 XtSetArg(args[0], XtNiconic, False);
3046 XtSetValues(localPlayer.shellWidget, args, 1);
3050 * It would be simpler to clear the window with XClearWindow()
3051 * but this causes a very distracting flicker.
3054 if ((w == localPlayer.boardWidget)
3055 && (event == NULL)
3056 && lastBoardValid
3057 && (lastFlipView == localPlayer.flipView)
3058 && (!updateRemotePlayer
3059 || (lastRemoteFlipView == remotePlayer.flipView)))
3061 for (i = 0; i < BOARD_SIZE; i++)
3063 for (j = 0; j < BOARD_SIZE; j++)
3065 if (boards[currentMove][i][j] != lastBoard[i][j])
3066 DrawSquare(i, j, boards[currentMove][i][j]);
3070 for (i = 0; i < 2; i++)
3072 for (j = 0; j < 8; j++)
3074 if (catches[currentMove][i][j] != lastCatches[i][j])
3076 UpdateCatched(i, 0, False, True, currentMove);
3077 break;
3082 else
3084 XDrawSegments(localPlayer.xDisplay,
3085 localPlayer.xBoardWindow, localPlayer.lineGC,
3086 localPlayer.gridSegments, (BOARD_SIZE + 1) * 2);
3088 if (updateRemotePlayer)
3090 XDrawSegments(remotePlayer.xDisplay,
3091 remotePlayer.xBoardWindow, remotePlayer.lineGC,
3092 remotePlayer.gridSegments, (BOARD_SIZE + 1) * 2);
3095 for (i = 0; i < BOARD_SIZE; i++)
3096 for (j = 0; j < BOARD_SIZE; j++)
3097 DrawSquare(i, j, boards[currentMove][i][j]);
3099 UpdateCatched(0, 0, False, True, currentMove);
3100 UpdateCatched(1, 0, False, True, currentMove);
3103 CopyBoard(lastBoard, boards[currentMove]);
3104 CopyCatches(lastCatches, catches[currentMove]);
3105 lastBoardValid = 1;
3106 lastFlipView = localPlayer.flipView;
3108 if (updateRemotePlayer)
3109 lastRemoteFlipView = remotePlayer.flipView;
3111 XSync(localPlayer.xDisplay, False);
3113 if (updateRemotePlayer)
3114 XSync(remotePlayer.xDisplay, False);
3120 void
3121 InitPosition(int redraw)
3123 currentMove = forwardMostMove = backwardMostMove = 0;
3124 CopyBoard(boards[0], initialPosition);
3125 ClearCatches(catches[0]);
3127 if (redraw)
3128 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3134 void
3135 CopyBoard(Board to, Board from)
3137 int i, j;
3139 for (i = 0; i < BOARD_SIZE; i++)
3140 for (j = 0; j < BOARD_SIZE; j++)
3141 to[i][j] = from[i][j];
3147 void
3148 CopyCatches(Catched to, Catched from)
3150 int i, j;
3152 for (i = 0; i < 2; i++)
3153 for (j = 0; j < 8; j++)
3154 to[i][j] = from[i][j];
3160 void
3161 SendCurrentBoard(FILE *fp)
3163 SendBoard(fp, boards[currentMove], catches[currentMove]);
3169 void
3170 SendBoard(FILE *fp, Board board, Catched catches)
3172 char message[MSG_SIZ];
3173 ShogiSquare *bp;
3174 int i, j;
3176 SendToProgram("edit\n", fp);
3177 SendToProgram("#\n", fp);
3179 for (i = BOARD_SIZE - 1; i >= 0; i--)
3181 bp = &board[i][0];
3183 for (j = 0; j < BOARD_SIZE; j++, bp++)
3185 if (((int) *bp) < (int)WhitePawn)
3187 sprintf(message, "%c%c%c%s\n",
3188 pieceToChar[(int) *bp],
3189 '9' - j, 'i' - i,
3190 (pieceIsPromoted[(int) *bp] ? "+" : ""));
3191 SendToProgram(message, fp);
3196 for (i = 0; i <= 7; i++)
3198 int n;
3200 for (n = catches[0][i]; n > 0; n--)
3202 sprintf(message, "%c*\n",
3203 catchedIndexToChar[i]);
3204 SendToProgram(message, fp);
3208 SendToProgram("c\n", fp);
3210 for (i = BOARD_SIZE - 1; i >= 0; i--)
3212 bp = &board[i][0];
3214 for (j = 0; j < BOARD_SIZE; j++, bp++)
3216 if ((((int) *bp) != ((int)EmptySquare))
3217 && (((int) *bp) >= ((int)WhitePawn)))
3219 sprintf(message, "%c%c%c%s\n",
3220 pieceToChar[((int) *bp) - ((int)WhitePawn)],
3221 '9' - j, 'i' - i,
3222 (pieceIsPromoted[(int) *bp] ? "+" : ""));
3223 SendToProgram(message, fp);
3228 for (i = 0; i <= 7; i++)
3230 int n;
3232 for (n = catches[1][i]; n > 0; n--)
3234 sprintf(message, "%c*\n",
3235 catchedIndexToChar[i]);
3236 SendToProgram(message, fp);
3240 SendToProgram(".\n", fp);
3246 static int
3247 PromotionPossible(int fromY, int toY, ShogiSquare piece)
3249 if (((int)piece) < ((int)WhitePawn))
3251 if ((fromY < 6) && (toY < 6))
3252 return False;
3254 else
3256 if ((fromY > 2) && (toY > 2))
3257 return False;
3260 return piecePromotable[(int)piece];
3267 static void
3268 ShowCount(int row, int column, int n)
3270 int offset = 2 * (player->squareSize + LINE_GAP);
3271 int x, y, direction, font_ascent, font_descent;
3272 char string[2];
3273 XCharStruct overall;
3274 struct DisplayData *player;
3276 DrawSquare(row, column, EmptySquare);
3278 if (n <= 1)
3279 return;
3281 for (player = &localPlayer; True; player = &remotePlayer)
3283 if (player->flipView)
3285 x = LINE_GAP + ((BOARD_SIZE - 1) - column) *
3286 (player->squareSize + LINE_GAP) + offset;
3287 y = LINE_GAP + row * (player->squareSize + LINE_GAP);
3289 else
3291 x = LINE_GAP + column * (player->squareSize + LINE_GAP) + offset;
3292 y = LINE_GAP + ((BOARD_SIZE - 1) - row) *
3293 (player->squareSize + LINE_GAP);
3296 x -= player->squareSize / 2;
3298 string[1] = NULLCHAR;
3300 if (n > 9)
3301 string[0] = '*';
3302 else
3303 string[0] = '0' + n;
3305 XTextExtents(player->coordFontStruct, string, 1, &direction,
3306 &font_ascent, &font_descent, &overall);
3308 if (player->monoMode)
3310 XDrawImageString(player->xDisplay, player->xBoardWindow,
3311 player->coordGC,
3312 x + player->squareSize - overall.width - 2,
3313 y + player->squareSize - font_descent - 1,
3314 string, 1);
3316 else
3318 XDrawString(player->xDisplay, player->xBoardWindow,
3319 player->coordGC,
3320 x + player->squareSize - overall.width - 2,
3321 y + player->squareSize - font_descent - 1,
3322 string, 1);
3325 if (!updateRemotePlayer || (player == &remotePlayer))
3326 break;
3333 void
3334 UpdateCatched(int Color, int Figure, int Drop, int DropAll, int currentMove)
3336 int n, F;
3337 int x, y;
3339 /* Determine first row and column. */
3341 if (Color)
3343 x = -1;
3344 y = BOARD_SIZE - 1;
3346 else
3348 x = BOARD_SIZE;
3349 y = 0;
3352 if (DropAll)
3353 n = 0;
3354 else
3355 n = catches[currentMove][Color][Figure];
3357 /* Update the display for captured pieces
3358 if no piece of the dropped type is there (Drop && n==1)
3359 or if a piece type is removed (NOT Drop && n==0).
3360 In the other cases update only the count. */
3362 if (DropAll || (Drop && (n == 1)) || (!Drop && (n == 0)))
3364 /* show all captured pieces */
3365 n = 0;
3367 for (F = pawn; F <= king; F++)
3369 int c;
3371 if ((c = catches[currentMove][Color][F]) > 0)
3373 n++;
3374 DrawSquare(y, x, catchedIndexToPiece[Color][F]);
3375 ShowCount(y, (Color ? (x - 1) : (x + 1)), c);
3377 if (Color)
3378 y--;
3379 else
3380 y++;
3384 if (DropAll)
3386 for (; n < 9; n++)
3388 DrawSquare(y, x, EmptySquare);
3389 ShowCount(y, (Color ? (x - 1) : (x + 1)), 0);
3391 if (Color)
3392 y--;
3393 else
3394 y++;
3397 else if (!Drop)
3399 /* remove one line! */
3400 DrawSquare(y, x, EmptySquare);
3401 ShowCount(y, (Color ? (x - 1) : (x + 1)), 0);
3404 else
3406 /* show the actual count */
3407 for (F = pawn; F <= Figure - 1; F++)
3409 if (catches[currentMove][Color][F] > 0)
3411 if (Color)
3412 y--;
3413 else
3414 y++;
3418 ShowCount(y, (Color ? (x - 1) : (x + 1)), n);
3425 #ifdef BLINK_COUNT
3427 static int BlinkCount = 0;
3428 static int BlinkRow, BlinkCol;
3429 static ShogiSquare BlinkPiece;
3432 void
3433 BlinkSquareProc(void)
3435 if (BlinkCount > 0)
3437 BlinkCount--;
3438 DrawSquare (BlinkRow, BlinkCol,
3439 ((BlinkCount & 1) ? EmptySquare : BlinkPiece));
3441 if (BlinkCount > 0)
3443 blinkSquareXID
3444 = XtAppAddTimeOut(appContext,
3445 150,
3446 (XtTimerCallbackProc)BlinkSquareProc,
3447 NULL);
3450 else
3452 BlinkCount = 0;
3459 void
3460 BlinkSquare(int row, int col, ShogiSquare piece)
3462 BlinkCount = 2 * BLINK_COUNT + 1;
3463 BlinkRow = row;
3464 BlinkCol = col;
3465 BlinkPiece = piece;
3466 BlinkSquareProc();
3470 #endif /* BLINK_COUNT */
3475 static int
3476 PieceOfCatched(int color, int x, int y, int currentMove)
3478 int F, n;
3480 if (color)
3482 if (x != 1)
3483 return (no_piece);
3485 y = 8 - y;
3487 else
3489 if (x != 11)
3490 return no_piece;
3493 for (F = pawn, n = 0; F <= king; F++)
3495 if (catches[currentMove][color][F] > 0)
3497 if (n == y)
3498 return F;
3500 n++;
3504 return no_piece;
3511 * event handler for parsing user moves
3514 void
3515 HandleUserMove(Widget w, XEvent *event)
3517 ShogiMove move_type;
3518 ShogiSquare from_piece;
3519 int to_x, to_y, fromRemotePlayer;
3521 if (updateRemotePlayer)
3523 if (((w != localPlayer.boardWidget)
3524 && (w != remotePlayer.boardWidget))
3525 || (matchMode != MatchFalse))
3527 return;
3530 fromRemotePlayer = (w == remotePlayer.boardWidget);
3532 else
3534 if ((w != localPlayer.boardWidget) || (matchMode != MatchFalse))
3535 return;
3537 fromRemotePlayer = False;
3540 player = (fromRemotePlayer ? &remotePlayer : &localPlayer);
3542 if (player->promotionUp)
3544 XtPopdown(player->promotionShell);
3545 XtDestroyWidget(player->promotionShell);
3546 player->promotionUp = False;
3547 fromX = fromY = -1;
3550 switch (gameMode)
3552 case EndOfGame:
3553 case PlayFromGameFile:
3554 case TwoMachinesPlay:
3555 return;
3557 case MachinePlaysBlack:
3558 if (BlackOnMove(forwardMostMove))
3560 DisplayMessage("It is not your turn", fromRemotePlayer);
3561 return;
3564 break;
3566 case MachinePlaysWhite:
3567 if (!BlackOnMove(forwardMostMove))
3569 DisplayMessage("It is not your turn", fromRemotePlayer);
3570 return;
3573 break;
3575 case ForceMoves:
3576 forwardMostMove = currentMove;
3577 break;
3579 default:
3580 break;
3583 if (currentMove != forwardMostMove)
3585 DisplayMessage("Displayed position is not current",
3586 fromRemotePlayer);
3587 return;
3590 switch (event->type)
3592 case ButtonPress:
3593 if ((fromX >= 0) || (fromY >= 0))
3594 return;
3596 if (((fromX = EventToXSquare(event->xbutton.x)) < 1)
3597 || (fromX > BOARD_SIZE + 2)
3598 || ((fromY = EventToSquare(event->xbutton.y)) < 0))
3600 fromX = fromY = -1;
3601 return;
3604 if (player->flipView)
3605 fromX = BOARD_SIZE + 3 - fromX;
3606 else
3607 fromY = BOARD_SIZE - 1 - fromY;
3609 break;
3611 case ButtonRelease:
3612 if ((fromX < 0) || (fromY < 0))
3613 return;
3615 if (((to_x = EventToXSquare(event->xbutton.x)) < 1)
3616 || (to_x > BOARD_SIZE + 2)
3617 || ((to_y = EventToSquare(event->xbutton.y)) < 0))
3619 if (gameMode == EditPosition && !off_board(fromX))
3621 fromX -= 2;
3622 boards[0][fromY][fromX] = EmptySquare;
3623 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3624 XSync(localPlayer.xDisplay, False);
3626 if (updateRemotePlayer)
3627 XSync(remotePlayer.xDisplay, False);
3630 fromX = fromY = -1;
3631 return;
3634 if (player->flipView)
3635 to_x = BOARD_SIZE + 3 - to_x;
3636 else
3637 to_y = BOARD_SIZE - 1 - to_y;
3639 if ((fromX == to_x) && (fromY == to_y))
3641 fromX = fromY = -1;
3642 return;
3645 if (gameMode == EditPosition)
3647 ShogiSquare piece;
3649 if (off_board(fromX))
3651 /* Remove a catched piece */
3652 int i, c;
3653 c = ((fromX < 5) ^ player->flipView);
3654 i = PieceOfCatched(c, fromX, fromY, 0);
3656 if (i == no_piece)
3658 fromX = fromY = -1;
3659 return;
3661 else
3663 piece = catchedIndexToPiece[c][i];
3664 catches[0][c][i]--;
3667 else
3669 /* remove piece from board field */
3670 fromX -= 2;
3671 piece = boards[0][fromY][fromX];
3672 boards[0][fromY][fromX] = EmptySquare;
3675 if (!off_board(to_x))
3677 /* drop piece to board field */
3678 ShogiSquare catched_piece;
3679 to_x -= 2;
3680 catched_piece = boards[0][to_y][to_x];
3682 if (catched_piece != EmptySquare)
3684 /* put piece to catched pieces */
3685 int i = pieceToCatchedIndex[catched_piece];
3686 int c = (catched_piece < WhitePawn);
3687 catches[0][c][i]++;
3690 /* place moved piece */
3691 boards[0][to_y][to_x] = piece;
3694 fromX = fromY = -1;
3695 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3696 XSync(localPlayer.xDisplay, False);
3698 if (updateRemotePlayer)
3699 XSync(remotePlayer.xDisplay, False);
3701 return;
3704 if (off_board(fromX))
3706 int c = (BlackOnMove(forwardMostMove) ? 0 : 1);
3707 int piece = PieceOfCatched(c, fromX, fromY, currentMove);
3709 if (piece == no_piece)
3711 fromX = fromY = -1;
3712 return;
3714 else
3716 if (updateRemotePlayer
3717 && (BlackOnMove(forwardMostMove) == fromRemotePlayer))
3719 DisplayMessage("Do not try to drop your opponent's pieces!",
3720 fromRemotePlayer);
3721 fromX = fromY = -1;
3722 return;
3725 fromX = fromY = piece + 81;
3726 to_x -= 2;
3727 move_type = (BlackOnMove(forwardMostMove)
3728 ? BlackDrop : WhiteDrop);
3729 MakeMove(&move_type, fromX, fromY, to_x, to_y);
3731 #ifdef BLINK_COUNT
3732 if (updateRemotePlayer)
3733 BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
3734 #endif
3736 FinishUserMove(move_type, to_x, to_y);
3737 break;
3740 else if (off_board(to_x))
3742 fromX = fromY = -1;
3743 return;
3745 else
3747 fromX -= 2;
3748 to_x -= 2;
3749 from_piece = boards[currentMove][fromY][fromX];
3751 if ((from_piece != EmptySquare)
3752 && updateRemotePlayer
3753 && ((from_piece < WhitePawn) == fromRemotePlayer))
3755 DisplayMessage("Do not try to move your opponent's pieces!",
3756 fromRemotePlayer);
3757 fromX = fromY = -1;
3758 return;
3761 if (PromotionPossible(fromY, to_y, from_piece))
3763 PromotionPopUp(from_piece, to_x, to_y, fromRemotePlayer);
3764 return;
3767 move_type = NormalMove;
3768 MakeMove(&move_type, fromX, fromY, to_x, to_y);
3770 #ifdef BLINK_COUNT
3771 if (updateRemotePlayer)
3772 BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
3773 #endif
3775 FinishUserMove(move_type, to_x, to_y);
3776 break;
3784 void
3785 FinishUserMove(ShogiMove move_type, int to_x, int to_y)
3787 char user_move[MSG_SIZ];
3789 /* output move for gnushogi */
3790 switch (move_type)
3792 case BlackPromotion:
3793 case WhitePromotion:
3794 sprintf(user_move, "%c%c%c%c+\n",
3795 '9' - fromX, 'i' - fromY, '9' - to_x, 'i' - to_y);
3796 break;
3798 case BlackDrop:
3799 case WhiteDrop:
3800 sprintf(user_move, "%c*%c%c\n",
3801 catchedIndexToChar[fromX - 81], '9' - to_x, 'i' - to_y);
3802 break;
3804 case NormalMove:
3805 sprintf(user_move, "%c%c%c%c\n",
3806 '9' - fromX, 'i' - fromY, '9' - to_x, 'i' - to_y);
3807 break;
3809 default:
3810 fprintf(stderr, "%s: internal error; bad move_type\n",
3811 (char *)programName);
3812 break;
3815 Attention(firstProgramPID);
3817 if (firstSendTime)
3818 SendTimeRemaining(toFirstProgFP);
3820 SendToProgram(user_move, toFirstProgFP);
3821 strcpy(moveList[currentMove - 1], user_move);
3823 fromX = fromY = -1;
3825 if (gameMode == PauseGame)
3827 /* a user move restarts a paused game*/
3828 PauseProc(NULL, NULL, NULL, NULL);
3831 switch (gameMode)
3833 case ForceMoves:
3834 break;
3836 case BeginningOfGame:
3837 if (localPlayer.appData.noShogiProgram)
3838 lastGameMode = gameMode = ForceMoves;
3839 else
3840 lastGameMode = gameMode = MachinePlaysWhite;
3842 ModeHighlight();
3843 break;
3845 case MachinePlaysWhite:
3846 case MachinePlaysBlack:
3847 default:
3848 break;
3855 /* Simple parser for moves from gnushogi. */
3856 void
3857 ParseMachineMove(char *machine_move, ShogiMove *move_type,
3858 int *from_x, int *from_y, int *to_x, int *to_y)
3860 #define no_digit(c) (c < '0' || c > '9')
3862 if (no_digit(machine_move[0]))
3864 switch (machine_move[0])
3866 case 'P':
3867 *from_x = 81;
3868 break;
3870 case 'L':
3871 *from_x = 82;
3872 break;
3874 case 'N':
3875 *from_x = 83;
3876 break;
3878 case 'S':
3879 *from_x = 84;
3880 break;
3882 case 'G':
3883 *from_x = 85;
3884 break;
3886 case 'B':
3887 *from_x = 86;
3888 break;
3890 case 'R':
3891 *from_x = 87;
3892 break;
3894 case 'K':
3895 *from_x = 88;
3896 break;
3898 default:
3899 *from_x = -1;
3902 *from_y = *from_x;
3903 *to_x = '9' - machine_move[2];
3904 *to_y = 'i' - machine_move[3];
3906 else
3908 *from_x = '9' - machine_move[0] ;
3909 *from_y = 'i' - machine_move[1];
3910 *to_x = '9' - machine_move[2];
3911 *to_y = 'i' - machine_move[3];
3913 switch (machine_move[4])
3915 case '+':
3916 *move_type = (BlackOnMove(forwardMostMove)
3917 ? BlackPromotion : WhitePromotion);
3918 break;
3920 default:
3921 *move_type = NormalMove;
3922 break;
3931 void
3932 SkipString(char **mpr)
3934 while (**mpr == ' ')
3935 (*mpr)++;
3937 while ((**mpr != ' ') && (**mpr != NULLCHAR) && (**mpr != '\n'))
3938 (*mpr)++;
3940 while (**mpr == ' ')
3941 (*mpr)++;
3947 void
3948 HandleMachineMove(char *message, FILE *fp)
3950 char machine_move[MSG_SIZ], buf1[MSG_SIZ], buf2[MSG_SIZ];
3951 int from_x, from_y, to_x, to_y;
3952 ShogiMove move_type;
3953 char *mpr;
3955 #ifdef SYNCHTIME
3956 long time_remaining;
3957 #endif
3959 maybeThinking = False;
3961 if (strncmp(message, "warning:", 8) == 0)
3963 DisplayMessage(message, False);
3965 if (updateRemotePlayer)
3966 DisplayMessage(message, True);
3968 return;
3972 * If shogi program startup fails, exit with an error message.
3973 * Attempts to recover here are futile.
3976 if ((strstr(message, "unknown host") != NULL)
3977 || (strstr(message, "No remote directory") != NULL)
3978 || (strstr(message, "not found") != NULL)
3979 || (strstr(message, "No such file") != NULL)
3980 || (strstr(message, "Permission denied") != NULL))
3982 fprintf(stderr,
3983 "%s: failed to start shogi program %s on %s: %s\n",
3984 programName,
3985 ((fp == fromFirstProgFP)
3986 ? localPlayer.appData.firstShogiProgram
3987 : localPlayer.appData.secondShogiProgram),
3988 ((fp == fromFirstProgFP)
3989 ? localPlayer.appData.firstHost
3990 : localPlayer.appData.secondHost),
3991 message);
3992 ShutdownShogiPrograms(message);
3993 exit(1);
3997 * If the move is illegal, cancel it and redraw the board.
4000 if (strncmp(message, "Illegal move", 12) == 0)
4002 if (fp == fromFirstProgFP && firstSendTime == 2)
4004 /* First program doesn't have the "time" command */
4005 firstSendTime = 0;
4006 return;
4008 else if (fp == fromSecondProgFP && secondSendTime == 2)
4010 /* Second program doesn't have the "time" command */
4011 secondSendTime = 0;
4012 return;
4015 if (forwardMostMove <= backwardMostMove)
4016 return;
4018 if (gameMode == PauseGame)
4019 PauseProc(NULL, NULL, NULL, NULL);
4021 if (gameMode == PlayFromGameFile)
4023 /* Stop reading this game file */
4024 gameMode = ForceMoves;
4025 ModeHighlight();
4028 currentMove = --forwardMostMove;
4030 if ((gameMode == PlayFromGameFile)
4031 || (gameMode == ForceMoves))
4032 DisplayClocks(ReDisplayTimers);
4033 else
4034 DisplayClocks(SwitchTimers);
4036 sprintf(buf1, "Illegal move: %s", parseList[currentMove]);
4037 DisplayMessage(buf1, False);
4039 if (updateRemotePlayer)
4040 DisplayMessage(buf1, True);
4042 #ifdef BLINK_COUNT
4044 * Disable blinking of the target square.
4047 if (BlinkCount > 0)
4049 /* If BlinkCount is even, the piece is currently displayed. */
4050 if (!(BlinkCount & 1))
4051 DrawSquare (BlinkRow, BlinkCol, EmptySquare);
4053 /* BlinkCount = 0 will force the next blink timeout
4054 * to do nothing. */
4055 BlinkCount = 0;
4057 #endif
4059 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
4061 XSync(localPlayer.xDisplay, False);
4063 if (updateRemotePlayer)
4064 XSync(remotePlayer.xDisplay, False);
4066 return;
4069 if (strstr(message, "GNU Shogi") != NULL)
4071 at_least_gnushogi_1_2p03 = True;
4072 return;
4075 if (strncmp(message, "Hint:", 5) == 0)
4077 char promoPiece;
4078 sscanf(message, "Hint: %s", machine_move);
4079 ParseMachineMove(machine_move, &move_type,
4080 &from_x, &from_y, &to_x, &to_y);
4082 if (move_type == WhitePromotion || move_type == BlackPromotion)
4083 promoPiece = '+';
4084 else
4085 promoPiece = NULLCHAR;
4087 move_type = MakeAlg(from_x, from_y, to_x, to_y, promoPiece,
4088 currentMove, buf1);
4089 sprintf(buf2, "Hint: %s", buf1);
4090 DisplayMessage(buf2, False);
4092 if (updateRemotePlayer)
4093 DisplayMessage(buf2, True);
4095 return;
4098 if (strncmp(message, "Clocks:", 7) == 0)
4100 sscanf(message, "Clocks: %ld %ld",
4101 &blackTimeRemaining, &whiteTimeRemaining);
4102 DisplayClocks(ReDisplayTimers);
4104 return;
4108 * win, lose or draw
4111 if (strncmp(message, "Black", 5) == 0)
4113 ShutdownShogiPrograms("Black wins");
4114 return;
4116 else if (strncmp(message, "White", 5) == 0)
4118 ShutdownShogiPrograms("White wins");
4119 return;
4121 else if (strncmp(message, "Repetition", 10) == 0)
4123 ShutdownShogiPrograms("Repetition");
4124 return;
4126 else if (strncmp(message, "opponent mates!", 15) == 0)
4128 switch ((gameMode == PauseGame) ? pausePreviousMode : gameMode)
4130 case MachinePlaysWhite:
4131 ShutdownShogiPrograms("Black wins");
4132 break;
4134 case MachinePlaysBlack:
4135 ShutdownShogiPrograms("White wins");
4136 break;
4138 case TwoMachinesPlay:
4139 ShutdownShogiPrograms((fp == fromFirstProgFP)
4140 ? "Black wins" : "White wins");
4141 break;
4143 default:
4144 /* can't happen */
4145 break;
4148 return;
4150 else if (strncmp(message, "computer mates!", 15) == 0)
4152 switch ((gameMode == PauseGame) ? pausePreviousMode : gameMode)
4154 case MachinePlaysWhite:
4155 ShutdownShogiPrograms("White wins");
4156 break;
4158 case MachinePlaysBlack:
4159 ShutdownShogiPrograms("Black wins");
4160 break;
4162 case TwoMachinesPlay:
4163 ShutdownShogiPrograms((fp == fromFirstProgFP)
4164 ? "White wins" : "Black wins");
4165 break;
4167 default:
4168 /* can't happen */
4169 break;
4172 return;
4174 else if (strncmp(message, "Draw", 4) == 0)
4176 ShutdownShogiPrograms("Draw");
4177 return;
4181 * normal machine reply move
4183 maybeThinking = True;
4185 if (strstr(message, "...") != NULL)
4187 sscanf(message, "%s %s %s", buf1, buf2, machine_move);
4189 #ifdef SYNCHTIME
4190 mpr = message;
4191 SkipString(&mpr); /* skip move number */
4192 SkipString(&mpr); /* skip ... */
4193 SkipString(&mpr); /* skip move */
4195 if ((gameMode != TwoMachinesPlay) && (gameMode != ForceMoves)
4196 && ((*mpr == '-') || ((*mpr >= '0') && (*mpr <= '9'))))
4198 /* synchronize with shogi program clock */
4199 sscanf(mpr, "%ld", &time_remaining);
4201 if (xshogiDebug)
4203 printf("from '%s' synchronize %s clock %ld\n",
4204 message,
4205 (BlackOnMove(forwardMostMove)
4206 ? "Black's"
4207 : "White's"),
4208 time_remaining);
4211 if (BlackOnMove(forwardMostMove))
4212 blackTimeRemaining = time_remaining;
4213 else
4214 whiteTimeRemaining = time_remaining;
4216 #endif
4218 if (machine_move[0] == NULLCHAR)
4219 return;
4221 else
4223 mpr = message;
4225 #ifdef SYNCHTIME
4226 if (strstr(message, "time") == NULL)
4228 /* remaining time will be determined from move */
4229 SkipString(&mpr); /* skip move number */
4230 SkipString(&mpr); /* skip move */
4233 if ((gameMode != TwoMachinesPlay) && (gameMode != ForceMoves)
4234 && ((*mpr == '-') || ((*mpr >= '0') && (*mpr <= '9'))))
4236 /* synchronize with shogi program clock */
4237 sscanf(mpr, "%ld", &time_remaining);
4239 if (xshogiDebug)
4241 printf("from '%s' synchronize %s clock %ld\n",
4242 message,
4243 ((!BlackOnMove(forwardMostMove))
4244 ? "Black's" : "White's"),
4245 time_remaining);
4248 if (!BlackOnMove(forwardMostMove))
4249 blackTimeRemaining = time_remaining;
4250 else
4251 whiteTimeRemaining = time_remaining;
4253 else
4254 #endif
4256 if (xshogiDebug)
4257 printf("ignore noise: '%s'\n", message);
4259 return; /* ignore noise */
4262 strcpy(moveList[forwardMostMove], machine_move);
4264 ParseMachineMove(machine_move, &move_type, &from_x, &from_y,
4265 &to_x, &to_y);
4267 if (gameMode != PauseGame)
4268 currentMove = forwardMostMove; /* display latest move */
4270 MakeMove(&move_type, from_x, from_y, to_x, to_y);
4272 #ifdef BLINK_COUNT
4273 if (gameMode != TwoMachinesPlay)
4274 BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
4275 #endif
4277 if ((gameMode != PauseGame) && localPlayer.appData.ringBellAfterMoves)
4278 putc(BELLCHAR, stderr);
4280 if ((gameMode == TwoMachinesPlay)
4281 || ((gameMode == PauseGame)
4282 && (pausePreviousMode == TwoMachinesPlay)))
4284 strcat(machine_move, "\n");
4286 if (BlackOnMove(forwardMostMove))
4288 Attention(secondProgramPID);
4290 if (secondSendTime)
4291 SendTimeRemaining(toSecondProgFP);
4293 SendToProgram(machine_move, toSecondProgFP);
4295 if (firstMove)
4297 firstMove = False;
4298 SendToProgram(localPlayer.appData.blackString,
4299 toSecondProgFP);
4302 else
4304 Attention(firstProgramPID);
4306 if (firstSendTime)
4307 SendTimeRemaining(toFirstProgFP);
4309 SendToProgram(machine_move, toFirstProgFP);
4311 if (firstMove)
4313 firstMove = False;
4314 SendToProgram(localPlayer.appData.blackString,
4315 toFirstProgFP);
4324 void
4325 ReadGameFile(void)
4327 for (;;)
4329 if (!ReadGameFileProc())
4330 return;
4332 if (matchMode == MatchOpening)
4333 continue;
4335 readGameXID
4336 = XtAppAddTimeOut(appContext,
4337 (int)(1000 * localPlayer.appData.timeDelay),
4338 (XtTimerCallbackProc) ReadGameFile, NULL);
4339 break;
4346 * FIXME: there is a naming inconsistency: here ReadGameFileProc() is
4347 * called by ReadGameFile() while in other places XXXProc() calls XXX().
4351 ReadGameFileProc(void)
4353 ShogiMove move_type;
4354 char move[MSG_SIZ], buf[MSG_SIZ];
4356 if (gameFileFP == NULL)
4357 return (int)False;
4359 if (gameMode == PauseGame)
4360 return True;
4362 if (gameMode != PlayFromGameFile)
4364 fclose(gameFileFP);
4365 gameFileFP = NULL;
4366 return (int)False;
4369 if (commentUp)
4371 XtPopdown(commentShell);
4372 XtDestroyWidget(commentShell);
4373 commentUp = False;
4376 fgets(move, MSG_SIZ, gameFileFP);
4377 move[strlen(move) - 1] = NULLCHAR;
4378 sprintf(buf, "# %s game file", programName);
4380 if (strncmp(move, buf, strlen(buf)))
4382 strcat(move, ": no xshogi game file");
4383 DisplayMessage(move, False);
4384 return (int)False;
4387 DisplayName(move);
4388 rewind(gameFileFP);
4390 parseGameFile();
4392 move_type = (ShogiMove)0;
4394 lastGameMode = gameMode;
4395 gameMode = ForceMoves;
4396 ModeHighlight();
4398 if (!loaded_game_finished)
4399 DisplayMessage("End of game file", False);
4401 if (readGameXID != 0)
4403 XtRemoveTimeOut(readGameXID);
4404 readGameXID = 0;
4407 fclose(gameFileFP);
4408 gameFileFP = NULL;
4410 return (int)False;
4417 * Apply a move to the given board. Oddity: move_type is ignored on input
4418 * unless the move is seen to be a pawn promotion, in which case move_type
4419 * tells us what to promote to.
4422 void
4423 ApplyMove(ShogiMove *move_type, int from_x, int from_y,
4424 int to_x, int to_y, int currentMove)
4426 ShogiSquare piece, cpiece;
4427 char pieceChar;
4428 int i, c;
4430 if (from_x > 80)
4432 i = from_x - 81;
4433 c = (BlackOnMove(currentMove) ? 1 : 0);
4434 cpiece = catchedIndexToPiece[c][i];
4435 boards[currentMove][to_y][to_x] = cpiece;
4436 catches[currentMove][c][i]--;
4438 else if (PromotionPossible(from_y, to_y,
4439 piece = boards[currentMove][from_y][from_x]))
4441 cpiece = boards[currentMove][to_y][to_x];
4443 if (cpiece != EmptySquare)
4445 i = pieceToCatchedIndex[cpiece];
4446 c = (cpiece < WhitePawn);
4447 catches[currentMove][c][i]++;
4450 if (*move_type == NormalMove)
4452 boards[currentMove][to_y][to_x] = piece;
4454 else
4456 boards[currentMove][to_y][to_x] = piece = pieceToPromoted[piece];
4457 pieceChar = '+';
4460 boards[currentMove][from_y][from_x] = EmptySquare;
4462 else
4464 ShogiSquare piece = boards[currentMove][to_y][to_x];
4466 if (piece != EmptySquare)
4468 i = pieceToCatchedIndex[piece];
4469 c = (piece < WhitePawn);
4470 catches[currentMove][c][i]++;
4473 *move_type = NormalMove;
4474 boards[currentMove][to_y][to_x] =
4475 boards[currentMove][from_y][from_x];
4476 boards[currentMove][from_y][from_x] = EmptySquare;
4484 * MakeMove() displays moves. If they are illegal, GNU shogi will detect
4485 * this and send an Illegal move message. XShogi will then retract the move.
4486 * The clockMode False case is tricky because it displays the player on move.
4489 void
4490 MakeMove(ShogiMove *move_type, int from_x, int from_y, int to_x, int to_y)
4492 char message[MSG_SIZ], movestr[MSG_SIZ];
4493 char promoPiece = NULLCHAR;
4495 forwardMostMove++;
4497 CopyBoard(boards[forwardMostMove], boards[forwardMostMove - 1]);
4498 CopyCatches(catches[forwardMostMove], catches[forwardMostMove - 1]);
4500 ApplyMove(move_type, from_x, from_y, to_x, to_y, forwardMostMove);
4502 endMessage[0] = NULLCHAR;
4504 timeRemaining[0][forwardMostMove] = blackTimeRemaining;
4505 timeRemaining[1][forwardMostMove] = whiteTimeRemaining;
4507 if ((gameMode == PauseGame) && (pausePreviousMode != PlayFromGameFile))
4508 return;
4510 currentMove = forwardMostMove;
4512 if (gameMode == PlayFromGameFile)
4514 sprintf(message, "%d. %s%s",
4515 ((currentMove + 1) / 2),
4516 (BlackOnMove(currentMove) ? "... " : ""),
4517 currentMoveString);
4518 strcpy(parseList[currentMove - 1], currentMoveString);
4520 else
4522 if ((*move_type == WhitePromotion) || (*move_type == BlackPromotion))
4523 promoPiece = '+';
4524 else
4525 promoPiece = NULLCHAR;
4527 MakeAlg(from_x, from_y, to_x, to_y, promoPiece,
4528 currentMove - 1, movestr);
4529 sprintf(message, "%d. %s%s",
4530 ((currentMove + 1) / 2),
4531 (BlackOnMove(currentMove) ? "... " : ""),
4532 movestr);
4533 strcpy(parseList[currentMove - 1], movestr);
4536 DisplayMessage(message, False);
4538 if ((gameMode == PlayFromGameFile) || (gameMode == ForceMoves)
4539 || ((gameMode == PauseGame)
4540 && (pausePreviousMode == PlayFromGameFile)))
4542 DisplayClocks(ReDisplayTimers);
4544 else
4546 DisplayClocks(SwitchTimers);
4549 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
4551 XSync(localPlayer.xDisplay, False);
4553 if (updateRemotePlayer)
4555 DisplayMessage(message, True);
4556 XSync(remotePlayer.xDisplay, False);
4563 void
4564 InitShogiProgram(char *host_name, char *program_name, int *pid,
4565 FILE **to, FILE **from, XtIntervalId *xid, int *sendTime)
4567 char arg_buf[10];
4568 char *arg1, *arg2;
4569 int to_prog[2], from_prog[2];
4570 FILE *from_fp, *to_fp;
4571 int dummy_source;
4572 XtInputId dummy_id;
4574 if (localPlayer.appData.noShogiProgram)
4575 return;
4577 signal(SIGPIPE, CatchPipeSignal);
4578 pipe(to_prog);
4579 pipe(from_prog);
4581 if ((*pid = fork()) == 0)
4583 signal(SIGPIPE, CatchPipeSignal);
4585 dup2(to_prog[0], 0);
4586 dup2(from_prog[1], 1);
4587 close(to_prog[0]);
4588 close(to_prog[1]);
4589 close(from_prog[0]);
4590 close(from_prog[1]);
4591 dup2(1, fileno(stderr)); /* force stderr to the pipe */
4593 if (localPlayer.appData.searchTime != NULL)
4595 sprintf(arg_buf, "%d", searchTime);
4596 arg1 = arg_buf;
4597 arg2 = (char *)NULL;
4599 else if (localPlayer.appData.searchDepth > 0)
4601 sprintf(arg_buf, "%d", localPlayer.appData.searchDepth);
4602 arg1 = "1";
4603 arg2 = "9999";
4605 else
4607 sprintf(arg_buf, "%d", localPlayer.appData.movesPerSession);
4608 arg1 = arg_buf;
4609 arg2 = localPlayer.appData.timeControl;
4612 if (strcmp(host_name, "localhost") == 0)
4614 execlp(program_name, program_name, arg1, arg2,
4615 (char *)NULL);
4617 else
4619 execlp(localPlayer.appData.remoteShell,
4620 localPlayer.appData.remoteShell,
4621 host_name, program_name, arg1, arg2,
4622 (char *)NULL);
4625 perror(program_name);
4626 exit(1);
4629 close(to_prog[0]);
4630 close(from_prog[1]);
4632 *from = from_fp = fdopen(from_prog[0], "r");
4633 *to = to_fp = fdopen(to_prog[1], "w");
4634 setbuf(from_fp, NULL);
4635 setbuf(to_fp, NULL);
4637 ReceiveFromProgram(from_fp, &dummy_source, &dummy_id); /* "GNU Shogi"*/
4639 if (!at_least_gnushogi_1_2p03)
4641 fprintf(stderr, "you must have at least gnushogi-1.2p03\n");
4642 exit(1);
4645 if (*pid == 0)
4646 return;
4648 *xid = XtAppAddInput(appContext, fileno(from_fp),
4649 (XtPointer)XtInputReadMask,
4650 (XtInputCallbackProc)ReceiveFromProgram,
4651 (XtPointer)from_fp);
4653 SendToProgram(localPlayer.appData.initString, *to);
4655 if (localPlayer.appData.gameIn)
4656 SendToProgram("gamein\n", *to);
4658 SendSearchDepth(*to);
4660 if (*sendTime == 2)
4662 /* Does program have "time" command? */
4663 char buf[MSG_SIZ];
4665 sprintf(buf, "time %ld\n", blackTimeRemaining / 10);
4666 SendToProgram(buf, to_fp);
4667 ReceiveFromProgram(from_fp, &dummy_source, &dummy_id);
4669 if (*sendTime == 2)
4671 *sendTime = 1; /* yes! */
4672 sprintf(buf, "otime %ld\n", whiteTimeRemaining / 10);
4673 SendToProgram(buf, to_fp);
4674 ReceiveFromProgram(from_fp, &dummy_source, &dummy_id);
4682 void
4683 ShutdownShogiPrograms(char *why)
4685 lastGameMode = gameMode;
4686 gameMode = EndOfGame;
4687 ModeHighlight();
4688 CopyBoard(boards[currentMove + 1], boards[currentMove]);
4689 CopyCatches(catches[currentMove + 1], catches[currentMove]);
4690 strncpy(parseList[currentMove], why, MOVE_LEN);
4691 parseList[currentMove][MOVE_LEN - 1] = NULLCHAR;
4692 currentMove++;
4693 DisplayMessage(why, False);
4695 if (readGameXID != 0)
4696 XtRemoveTimeOut(readGameXID);
4698 readGameXID = 0;
4700 if (firstProgramPID != 0)
4702 fclose(fromFirstProgFP);
4703 fclose(toFirstProgFP);
4704 fromFirstProgFP = toFirstProgFP = NULL;
4706 if (kill(firstProgramPID, SIGTERM) == 0)
4707 WAIT0;
4710 firstProgramPID = 0;
4712 if (firstProgramXID != 0)
4713 XtRemoveInput(firstProgramXID);
4715 firstProgramXID = 0;
4717 if (secondProgramPID != 0)
4719 fclose(fromSecondProgFP);
4720 fclose(toSecondProgFP);
4721 fromSecondProgFP = toSecondProgFP = NULL;
4723 if (kill(secondProgramPID, SIGTERM) == 0)
4724 WAIT0;
4727 secondProgramPID = 0;
4729 if (secondProgramXID != 0)
4730 XtRemoveInput(secondProgramXID);
4732 secondProgramXID = 0;
4734 DisplayClocks(StopTimers);
4736 if (matchMode != MatchFalse)
4738 if (localPlayer.appData.saveGameFile[0] != NULLCHAR)
4739 SaveGame(localPlayer.appData.saveGameFile);
4741 exit(0);
4748 void
4749 CommentPopUp(char *label)
4751 Arg args[2];
4752 Position x, y;
4753 Dimension bw_width, pw_width;
4755 if (commentUp)
4757 XtPopdown(commentShell);
4758 XtDestroyWidget(commentShell);
4759 commentUp = False;
4762 DisplayMessage("Comment", False);
4764 XtSetArg(args[0], XtNwidth, &bw_width);
4765 XtGetValues(localPlayer.formWidget, args, 1);
4767 XtSetArg(args[0], XtNresizable, True);
4768 XtSetArg(args[1], XtNwidth, bw_width - 8);
4770 commentShell = XtCreatePopupShell("Comment",
4771 transientShellWidgetClass,
4772 localPlayer.commandsWidget, args, 2);
4774 XtSetArg(args[0], XtNlabel, label);
4776 (void)XtCreateManagedWidget("commentLabel", labelWidgetClass,
4777 commentShell, args, 1);
4779 XtRealizeWidget(commentShell);
4781 XtSetArg(args[0], XtNwidth, &pw_width);
4782 XtGetValues(commentShell, args, 1);
4784 XtTranslateCoords(localPlayer.shellWidget,
4785 (bw_width - pw_width) / 2, -50, &x, &y);
4787 XtSetArg(args[0], XtNx, x);
4788 XtSetArg(args[1], XtNy, y);
4789 XtSetValues(commentShell, args, 2);
4791 XtPopup(commentShell, XtGrabNone);
4792 commentUp = True;
4798 void
4799 FileNamePopUp(char *label, Boolean (*proc) (char *))
4801 Arg args[2];
4802 Widget popup, dialog;
4803 Position x, y;
4804 Dimension bw_width, pw_width;
4806 fileProc = proc;
4808 XtSetArg(args[0], XtNwidth, &bw_width);
4809 XtGetValues(localPlayer.boardWidget, args, 1);
4811 XtSetArg(args[0], XtNresizable, True);
4812 XtSetArg(args[1], XtNwidth, DIALOG_SIZE);
4814 popup = XtCreatePopupShell("File Name Prompt",
4815 transientShellWidgetClass,
4816 localPlayer.commandsWidget, args, 2);
4818 XtSetArg(args[0], XtNlabel, label);
4819 XtSetArg(args[1], XtNvalue, "");
4821 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
4822 popup, args, 2);
4824 XawDialogAddButton(dialog, "ok", FileNameCallback, (XtPointer) dialog);
4825 XawDialogAddButton(dialog, "cancel", FileNameCallback,
4826 (XtPointer) dialog);
4828 XtRealizeWidget(popup);
4830 XtSetArg(args[0], XtNwidth, &pw_width);
4831 XtGetValues(popup, args, 1);
4833 XtTranslateCoords(localPlayer.boardWidget,
4834 (bw_width - pw_width) / 2, 10, &x, &y);
4836 XtSetArg(args[0], XtNx, x);
4837 XtSetArg(args[1], XtNy, y);
4838 XtSetValues(popup, args, 2);
4840 XtPopup(popup, XtGrabExclusive);
4841 filenameUp = True;
4843 XtSetKeyboardFocus(localPlayer.shellWidget, popup);
4849 void
4850 FileNameCallback(Widget w, XtPointer client_data, XtPointer call_data)
4852 String name;
4853 Arg args[1];
4855 XtSetArg(args[0], XtNlabel, &name);
4856 XtGetValues(w, args, 1);
4858 if (strcmp(name, "cancel") == 0)
4860 XtPopdown(w = XtParent(XtParent(w)));
4861 XtDestroyWidget(w);
4862 filenameUp = False;
4863 ModeHighlight();
4864 return;
4867 FileNameAction(w, NULL, NULL, NULL);
4873 void
4874 FileNameAction(Widget w, XEvent *event, String *prms, Cardinal *nprms)
4876 char buf[MSG_SIZ];
4877 String name;
4879 name = XawDialogGetValueString(w = XtParent(w));
4881 if ((name != NULL) && (*name != NULLCHAR))
4883 strcpy(buf, name);
4884 XtPopdown(w = XtParent(w));
4885 XtDestroyWidget(w);
4886 filenameUp = False;
4887 (*fileProc)(buf); /* I can't see a way not
4888 to use a global here */
4889 ModeHighlight();
4890 return;
4893 XtPopdown(w = XtParent(w));
4894 XtDestroyWidget(w);
4895 filenameUp = False;
4896 ModeHighlight();
4902 void
4903 PromotionPopUp(ShogiSquare piece, int to_x, int to_y, int fromRemotePlayer)
4905 Arg args[2];
4906 Widget dialog;
4907 Position x, y;
4908 Dimension bw_width, bw_height, pw_width, pw_height;
4910 player = (fromRemotePlayer ? &remotePlayer : &localPlayer);
4912 pmi.piece = piece;
4913 pmi.to_x = to_x;
4914 pmi.to_y = to_y;
4916 XtSetArg(args[0], XtNwidth, &bw_width);
4917 XtSetArg(args[1], XtNheight, &bw_height);
4918 XtGetValues(player->boardWidget, args, 2);
4920 XtSetArg(args[0], XtNresizable, True);
4922 player->promotionShell
4923 = XtCreatePopupShell("Promotion",
4924 transientShellWidgetClass,
4925 player->commandsWidget, args, 1);
4927 XtSetArg(args[0], XtNlabel, "Promote piece?");
4928 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
4929 player->promotionShell, args, 1);
4931 XawDialogAddButton(dialog, "Yes", PromotionCallback,
4932 (XtPointer) dialog);
4933 XawDialogAddButton(dialog, "No", PromotionCallback,
4934 (XtPointer) dialog);
4935 XawDialogAddButton(dialog, "cancel", PromotionCallback,
4936 (XtPointer) dialog);
4938 XtRealizeWidget(player->promotionShell);
4940 XtSetArg(args[0], XtNwidth, &pw_width);
4941 XtSetArg(args[1], XtNheight, &pw_height);
4942 XtGetValues(player->promotionShell, args, 2);
4944 XtTranslateCoords(player->boardWidget,
4945 ((bw_width - pw_width) / 2),
4946 (LINE_GAP
4947 + player->squareSize / 3
4948 + (((piece == BlackPawn) ^ (player->flipView))
4950 : (6 * (player->squareSize + LINE_GAP)))),
4951 &x, &y);
4953 XtSetArg(args[0], XtNx, x);
4954 XtSetArg(args[1], XtNy, y);
4955 XtSetValues(player->promotionShell, args, 2);
4957 XtPopup(player->promotionShell, XtGrabNone);
4959 player->promotionUp = True;
4965 void
4966 PromotionCallback(Widget w, XtPointer client_data, XtPointer call_data)
4968 String name;
4969 Arg args[1];
4970 ShogiMove move_type;
4971 struct DisplayData *player;
4973 XtSetArg(args[0], XtNlabel, &name);
4974 XtGetValues(w, args, 1);
4976 w = XtParent(XtParent(w));
4977 player = ((w == remotePlayer.promotionShell)
4978 ? &remotePlayer : &localPlayer);
4979 XtPopdown(w);
4980 XtDestroyWidget(w);
4981 player->promotionUp = False;
4983 if (fromX == -1)
4984 return;
4986 if (strcmp(name, "Yes") == 0)
4988 if ((int)pmi.piece < (int)WhitePawn)
4989 move_type = BlackPromotion;
4990 else
4991 move_type = WhitePromotion;
4993 else if (strcmp(name, "No") == 0)
4995 move_type = NormalMove;
4997 else /* strcmp(name, "cancel") == 0 */
4999 fromX = fromY = -1;
5000 return;
5003 MakeMove(&move_type, fromX, fromY, pmi.to_x, pmi.to_y);
5005 #ifdef BLINK_COUNT
5006 if (updateRemotePlayer)
5008 BlinkSquare(pmi.to_y, pmi.to_x,
5009 boards[currentMove][pmi.to_y][pmi.to_x]);
5011 #endif
5013 FinishUserMove(move_type, pmi.to_x, pmi.to_y);
5019 void
5020 FileModePopUp(char *name)
5022 Arg args[2];
5023 Widget dialog;
5024 Position x, y;
5025 Dimension bw_width, bw_height, pw_width, pw_height;
5027 struct DisplayData *player = &localPlayer;
5029 strcpy(fmi.name, name);
5031 XtSetArg(args[0], XtNwidth, &bw_width);
5032 XtSetArg(args[1], XtNheight, &bw_height);
5033 XtGetValues(player->boardWidget, args, 2);
5035 XtSetArg(args[0], XtNresizable, True);
5036 player->filemodeShell
5037 = XtCreatePopupShell("FileMode",
5038 transientShellWidgetClass,
5039 player->commandsWidget, args, 1);
5041 XtSetArg(args[0], XtNlabel, "Append to existing file?");
5042 dialog = XtCreateManagedWidget("filemode", dialogWidgetClass,
5043 player->filemodeShell, args, 1);
5045 XawDialogAddButton(dialog, "Yes", FileModeCallback,
5046 (XtPointer) dialog);
5047 XawDialogAddButton(dialog, "No", FileModeCallback,
5048 (XtPointer) dialog);
5049 XawDialogAddButton(dialog, "cancel", FileModeCallback,
5050 (XtPointer) dialog);
5052 XtRealizeWidget(player->filemodeShell);
5054 XtSetArg(args[0], XtNwidth, &pw_width);
5055 XtSetArg(args[1], XtNheight, &pw_height);
5056 XtGetValues(player->filemodeShell, args, 2);
5058 XtTranslateCoords(player->boardWidget, (bw_width - pw_width) / 2,
5059 LINE_GAP + player->squareSize/3 +
5060 (6*(player->squareSize + LINE_GAP)),
5061 &x, &y);
5063 XtSetArg(args[0], XtNx, x);
5064 XtSetArg(args[1], XtNy, y);
5065 XtSetValues(player->filemodeShell, args, 2);
5067 XtPopup(player->filemodeShell, XtGrabNone);
5069 filemodeUp = True;
5075 void
5076 FileModeCallback(Widget w, XtPointer client_data, XtPointer call_data)
5078 String name;
5079 Arg args[1];
5081 XtSetArg(args[0], XtNlabel, &name);
5082 XtGetValues(w, args, 1);
5084 XtPopdown(w = XtParent(XtParent(w)));
5085 XtDestroyWidget(w);
5087 if (strcmp(name, "Yes") == 0)
5089 strcpy(fmi.mode, "a");
5091 else if (strcmp(name, "No") == 0)
5093 strcpy(fmi.mode, "w");
5095 else /* strcmp(name, "cancel") == 0 */
5097 filemodeUp = False;
5098 return;
5101 XtPopdown(localPlayer.filemodeShell);
5102 XtDestroyWidget(localPlayer.filemodeShell);
5104 SaveGame(fmi.name);
5106 filemodeUp = False;
5112 void
5113 SelectCommand(Widget w, XtPointer client_data, XtPointer call_data)
5115 Cardinal fromRemotePlayer = (Cardinal)client_data;
5117 XawListReturnStruct *list_return = XawListShowCurrent(w);
5119 player = fromRemotePlayer ? &remotePlayer : &localPlayer;
5121 fromX = fromY = -1;
5123 if (player->promotionUp)
5125 XtPopdown(player->promotionShell);
5126 XtDestroyWidget(player->promotionShell);
5127 player->promotionUp = False;
5130 (*buttonProcs[list_return->list_index])
5131 (w, NULL, NULL, &fromRemotePlayer);
5133 if (!filenameUp)
5134 ModeHighlight();
5140 void
5141 HighlightProcButton(XtActionProc proc)
5143 int i = 0;
5145 if (proc == NULL)
5147 XawListUnhighlight(localPlayer.commandsWidget);
5149 if (updateRemotePlayer)
5150 XawListUnhighlight(remotePlayer.commandsWidget);
5152 return;
5155 for (;;)
5157 if (buttonProcs[i] == NULL)
5159 XawListUnhighlight(localPlayer.commandsWidget);
5161 if (updateRemotePlayer)
5162 XawListUnhighlight(remotePlayer.commandsWidget);
5164 return;
5167 if (buttonProcs[i] == proc)
5169 XawListHighlight(localPlayer.commandsWidget, i);
5171 if (updateRemotePlayer)
5172 XawListHighlight(remotePlayer.commandsWidget, i);
5174 return;
5177 i++;
5184 void
5185 ModeHighlight(void)
5187 switch (gameMode)
5189 case BeginningOfGame:
5190 if (localPlayer.appData.noShogiProgram)
5191 HighlightProcButton(ForceProc);
5192 else
5193 HighlightProcButton(MachineBlackProc);
5195 break;
5197 case MachinePlaysBlack:
5198 HighlightProcButton(MachineBlackProc);
5199 break;
5201 case MachinePlaysWhite:
5202 HighlightProcButton(MachineWhiteProc);
5203 break;
5205 case TwoMachinesPlay:
5206 HighlightProcButton(TwoMachinesProc);
5207 break;
5209 case ForceMoves:
5210 HighlightProcButton(ForceProc);
5212 break;
5214 case PlayFromGameFile:
5215 HighlightProcButton(LoadGameProc);
5216 break;
5218 case PauseGame:
5219 HighlightProcButton(PauseProc);
5220 break;
5222 case EditPosition:
5223 HighlightProcButton(EditPositionProc);
5224 break;
5226 case EndOfGame:
5227 default:
5228 HighlightProcButton(NULL);
5229 break;
5237 * Button procedures
5240 void
5241 QuitRemotePlayerProc(void)
5243 /* This should be modified... */
5244 XCloseDisplay(remotePlayer.xDisplay);
5245 /* XtDestroyWidget(remotePlayer.shellWidget); */
5246 updateRemotePlayer = False;
5247 DisplayMessage("Remote player has pressed Quit", False);
5248 fromX = fromY = -1;
5253 void
5254 QuitProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5256 if (updateRemotePlayer)
5257 QuitRemotePlayerProc();
5259 ShutdownShogiPrograms("Quitting");
5260 exit(0);
5265 void
5266 LoadGameProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5268 int fromRemotePlayer = *nprms;
5270 if (fromRemotePlayer)
5272 DisplayMessage("only opponent may load game", fromRemotePlayer);
5273 return;
5276 if (gameMode != BeginningOfGame)
5278 DisplayMessage("Press Reset first.", False);
5279 return;
5282 if (localPlayer.appData.loadGameFile == NULL)
5283 FileNamePopUp("Game file name?", LoadGame);
5284 else
5285 (void) LoadGame(localPlayer.appData.loadGameFile);
5291 Boolean
5292 LoadGame(char *name)
5294 char buf[MSG_SIZ];
5296 loaded_game_finished = 0;
5298 if (gameMode != BeginningOfGame)
5300 DisplayMessage("Press Reset first", False);
5301 return (int)False;
5304 if (localPlayer.appData.loadGameFile != name)
5306 if (localPlayer.appData.loadGameFile)
5307 XtFree(localPlayer.appData.loadGameFile);
5309 localPlayer.appData.loadGameFile = XtMalloc(strlen(name) + 1);
5310 strcpy(localPlayer.appData.loadGameFile, name);
5313 if ((gameFileFP = fopen(name, "r")) == NULL)
5315 sprintf(buf, "Can't open %s", name);
5316 DisplayMessage(buf, False);
5317 XtFree(localPlayer.appData.loadGameFile);
5318 localPlayer.appData.loadGameFile = NULL;
5319 return (int)False;
5322 lastGameMode = gameMode = PlayFromGameFile;
5323 ModeHighlight();
5324 InitPosition(True);
5325 DisplayClocks(StopTimers);
5327 if (firstProgramXID == 0)
5329 InitShogiProgram(localPlayer.appData.firstHost,
5330 localPlayer.appData.firstShogiProgram,
5331 &firstProgramPID, &toFirstProgFP,
5332 &fromFirstProgFP, &firstProgramXID,
5333 &firstSendTime);
5336 SendToProgram(localPlayer.appData.initString, toFirstProgFP);
5337 SendSearchDepth(toFirstProgFP);
5338 SendToProgram("force\n", toFirstProgFP);
5340 currentMove = forwardMostMove = backwardMostMove = 0;
5342 ReadGameFile();
5344 return True;
5351 * Restart the shogi program and feed it all the moves made so far.
5352 * Used when the user wants to back up from end of game, when gnushogi
5353 * has already exited. Assumes gameMode == EndOfGame.
5356 void
5357 ResurrectShogiProgram(void)
5359 char buf[MSG_SIZ];
5360 int i;
5362 if (currentMove > 0)
5363 currentMove--; /* delete "Black wins" or the like */
5365 InitShogiProgram(localPlayer.appData.firstHost,
5366 localPlayer.appData.firstShogiProgram,
5367 &firstProgramPID, &toFirstProgFP, &fromFirstProgFP,
5368 &firstProgramXID, &firstSendTime);
5370 SendToProgram(localPlayer.appData.initString, toFirstProgFP);
5371 SendSearchDepth(toFirstProgFP);
5372 SendToProgram("force\n", toFirstProgFP);
5373 gameMode = lastGameMode = ForceMoves;
5374 ModeHighlight();
5376 i = (whitePlaysFirst ? 1 : 0);
5378 if (startedFromSetupPosition)
5379 SendBoard(toFirstProgFP, boards[i], catches[i]);
5381 for (; i < currentMove; i++)
5383 strcpy(buf, moveList[i]);
5384 SendToProgram(buf, toFirstProgFP);
5387 if (!firstSendTime)
5389 /* can't tell gnushogi what its clock should read,
5390 so we bow to its notion. */
5391 DisplayClocks(ResetTimers);
5392 timeRemaining[0][currentMove] = blackTimeRemaining;
5393 timeRemaining[1][currentMove] = whiteTimeRemaining;
5400 void
5401 MachineWhiteProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5403 int fromRemotePlayer = *nprms;
5405 if (updateRemotePlayer)
5407 DisplayMessage("no machine moves in challenge mode",
5408 fromRemotePlayer);
5410 return;
5413 if (gameMode == PauseGame)
5414 PauseProc(w, event, prms, nprms);
5416 if (gameMode == PlayFromGameFile)
5417 ForceProc(w, event, prms, nprms);
5419 if (gameMode == EditPosition)
5420 EditPositionDone();
5422 if ((gameMode == EndOfGame)
5423 || (gameMode == PlayFromGameFile)
5424 || (gameMode == TwoMachinesPlay)
5425 || localPlayer.appData.noShogiProgram
5426 || (gameMode == MachinePlaysWhite))
5428 return;
5431 if (BlackOnMove((gameMode == ForceMoves)
5432 ? currentMove
5433 : forwardMostMove))
5435 DisplayMessage("It is not White's turn.", False);
5436 return;
5439 if (gameMode == ForceMoves)
5440 forwardMostMove = currentMove;
5442 lastGameMode = gameMode = MachinePlaysWhite;
5443 ModeHighlight();
5444 SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
5445 DisplayClocks(StartTimers);
5451 void
5452 MachineBlackProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5454 int fromRemotePlayer = *nprms;
5456 if (updateRemotePlayer)
5458 DisplayMessage("no machine moves in challenge mode",
5459 fromRemotePlayer);
5460 return;
5463 if (gameMode == PauseGame)
5464 PauseProc(w, event, prms, nprms);
5466 if (gameMode == PlayFromGameFile)
5467 ForceProc(w, event, prms, nprms);
5469 if (gameMode == EditPosition)
5470 EditPositionDone();
5472 if ((gameMode == EndOfGame)
5473 || (gameMode == PlayFromGameFile)
5474 || (gameMode == TwoMachinesPlay)
5475 || localPlayer.appData.noShogiProgram
5476 || (gameMode == MachinePlaysBlack))
5478 return;
5481 if (!BlackOnMove((gameMode == ForceMoves)
5482 ? currentMove
5483 : forwardMostMove))
5485 DisplayMessage("It is not Black's turn.", False);
5486 return;
5489 if (gameMode == ForceMoves)
5490 forwardMostMove = currentMove;
5492 lastGameMode = gameMode = MachinePlaysBlack;
5493 ModeHighlight();
5494 SendToProgram(localPlayer.appData.blackString, toFirstProgFP);
5495 DisplayClocks(StartTimers);
5501 void
5502 ForwardProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5504 char buf[MSG_SIZ];
5505 int target;
5506 unsigned int state;
5508 int fromRemotePlayer = *nprms;
5510 if (updateRemotePlayer)
5512 DisplayMessage("Forward button disabled.", fromRemotePlayer);
5513 return;
5516 if ((gameMode == EndOfGame) || (gameMode == EditPosition))
5517 return;
5519 if (gameMode == PlayFromGameFile)
5520 PauseProc(w, event, prms, nprms);
5522 if (currentMove >= forwardMostMove)
5523 return;
5525 if (event == NULL)
5527 /* Kludge */
5528 Window root, child;
5529 int root_x, root_y;
5530 int win_x, win_y;
5531 XQueryPointer(localPlayer.xDisplay, localPlayer.xBoardWindow,
5532 &root, &child, &root_x, &root_y,
5533 &win_x, &win_y, &state);
5535 else
5537 state = event->xkey.state;
5540 if (state & ShiftMask)
5541 target = forwardMostMove;
5542 else
5543 target = currentMove + 1;
5545 if (gameMode == ForceMoves)
5547 while (currentMove < target)
5549 strcpy(buf, moveList[currentMove++]);
5550 SendToProgram(buf, toFirstProgFP);
5553 else
5555 currentMove = target;
5558 if (gameMode == ForceMoves)
5560 blackTimeRemaining = timeRemaining[0][currentMove];
5561 whiteTimeRemaining = timeRemaining[1][currentMove];
5564 DisplayClocks(ReDisplayTimers);
5565 DisplayMove(currentMove - 1);
5566 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
5572 void
5573 ResetFileProc(void)
5575 char *buf = "";
5577 if (updateRemotePlayer)
5578 return;
5580 if (localPlayer.appData.loadGameFile)
5581 XtFree(localPlayer.appData.loadGameFile);
5583 if (localPlayer.appData.loadPositionFile)
5584 XtFree(localPlayer.appData.loadPositionFile);
5586 localPlayer.appData.loadGameFile
5587 = localPlayer.appData.loadPositionFile = NULL;
5588 DisplayName(buf);
5590 if (gameFileFP != NULL)
5592 fclose(gameFileFP);
5593 gameFileFP = NULL;
5600 void
5601 ResetChallenge(void)
5603 char *buf = "";
5605 if (localPlayer.appData.challengeDisplay)
5606 XtFree(localPlayer.appData.challengeDisplay);
5608 localPlayer.appData.challengeDisplay = NULL;
5609 DisplayName(buf);
5615 void
5616 ResetProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5618 int fromRemotePlayer = *nprms;
5620 if (fromRemotePlayer)
5622 DisplayMessage("Only your opponent may reset the game.",
5623 fromRemotePlayer);
5624 return;
5627 Reset(True);
5633 void
5634 Reset(int redraw) /* Boolean */
5636 ResetFileProc();
5637 ResetChallenge();
5639 localPlayer.flipView = False;
5640 remotePlayer.flipView = True;
5641 startedFromSetupPosition = whitePlaysFirst = False;
5642 matchMode = MatchFalse;
5643 firstMove = True;
5644 blackFlag = whiteFlag = False;
5645 maybeThinking = False;
5647 endMessage[0] = NULLCHAR;
5649 ShutdownShogiPrograms("");
5650 lastGameMode = gameMode = BeginningOfGame;
5651 ModeHighlight();
5652 InitPosition(redraw);
5653 DisplayClocks(ResetTimers);
5654 timeRemaining[0][0] = blackTimeRemaining;
5655 timeRemaining[1][0] = whiteTimeRemaining;
5656 InitShogiProgram(localPlayer.appData.firstHost,
5657 localPlayer.appData.firstShogiProgram,
5658 &firstProgramPID, &toFirstProgFP,
5659 &fromFirstProgFP, &firstProgramXID,
5660 &firstSendTime);
5662 if (commentUp)
5664 XtPopdown(commentShell);
5665 XtDestroyWidget(commentShell);
5666 commentUp = False;
5669 if (localPlayer.promotionUp)
5671 XtPopdown(localPlayer.promotionShell);
5672 XtDestroyWidget(localPlayer.promotionShell);
5673 localPlayer.promotionUp = False;
5676 if (updateRemotePlayer && remotePlayer.promotionUp)
5678 XtPopdown(remotePlayer.promotionShell);
5679 XtDestroyWidget(remotePlayer.promotionShell);
5680 remotePlayer.promotionUp = False;
5687 void
5688 ClearCatches(int (*catches)[8])
5690 int c, p;
5692 for (c = 0; c <= 1; c++)
5693 for (p = 0; p <= 7; p++)
5694 catches[c][p] = 0;
5700 Boolean
5701 Challenge(char *name)
5703 char buf[MSG_SIZ];
5704 int argc;
5705 char **argv;
5706 XrmDatabase database;
5708 if (gameMode != BeginningOfGame)
5710 DisplayMessage("Press Reset first.", False);
5711 return (int)False;
5714 if (localPlayer.appData.challengeDisplay != name)
5716 if (localPlayer.appData.challengeDisplay)
5717 XtFree(localPlayer.appData.challengeDisplay);
5719 localPlayer.appData.challengeDisplay = XtMalloc(strlen(name) + 1);
5720 strcpy(localPlayer.appData.challengeDisplay, name);
5723 sprintf(buf, "trying to connect to %s.....", name);
5724 DisplayMessage(buf, False);
5726 argc = global_argc;
5727 argv = global_argv;
5729 if ((remotePlayer.xDisplay
5730 = XtOpenDisplay(appContext, name, "XShogi",
5731 "XShogi", 0, 0, &argc, argv)) == NULL)
5733 sprintf(buf, "Can't open display %s", name);
5734 DisplayMessage(buf, False);
5735 XtFree(localPlayer.appData.challengeDisplay);
5736 localPlayer.appData.challengeDisplay = NULL;
5737 return (int)False;
5740 DisplayMessage("connected! creating remote window...", False);
5742 remotePlayer.xScreen = DefaultScreen(remotePlayer.xDisplay);
5744 remotePlayer.shellWidget
5745 = XtAppCreateShell(NULL, "XShogi",
5746 applicationShellWidgetClass,
5747 remotePlayer.xDisplay, NULL, 0);
5749 database = XtDatabase(remotePlayer.xDisplay);
5751 XrmParseCommand(&database,
5752 shellOptions, XtNumber(shellOptions),
5753 "XShogi", &argc, argv);
5755 XtGetApplicationResources(remotePlayer.shellWidget,
5756 &remotePlayer.appData, clientResources,
5757 XtNumber(clientResources), NULL, 0);
5759 player = &remotePlayer;
5761 CreatePlayerWindow();
5763 updateRemotePlayer = True;
5765 DisplayName("REMOTE");
5766 DrawPosition(remotePlayer.boardWidget, NULL, NULL, NULL);
5767 DisplayClocks(ReDisplayTimers);
5769 DisplayMessage("ready to play", False);
5770 DisplayMessage("ready to play", True);
5772 return True;
5778 void
5779 ChallengeProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5781 int fromRemotePlayer = *nprms;
5783 if (updateRemotePlayer)
5785 DisplayMessage("You are already in challenge mode.",
5786 fromRemotePlayer);
5787 return;
5790 if (gameMode != BeginningOfGame)
5792 DisplayMessage("Press Reset first.", False);
5793 return;
5796 if (localPlayer.appData.challengeDisplay == NULL)
5797 FileNamePopUp("Challenge display?", Challenge);
5798 else
5799 (void) Challenge(localPlayer.appData.challengeDisplay);
5805 Boolean
5806 SelectLevel(char *command)
5808 char buf[MSG_SIZ];
5810 sprintf(buf, "level %s\n", command);
5811 SendToProgram(buf, toFirstProgFP);
5813 return True;
5819 void
5820 SelectLevelProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5822 if ((BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysBlack))
5823 || (!BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysWhite)))
5825 DisplayMessage("Wait until your turn.", False);
5827 else
5829 FileNamePopUp("#moves #minutes", SelectLevel);
5836 void
5837 MoveNowProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5839 if ((!BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysBlack))
5840 || (BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysWhite)))
5842 DisplayMessage("Wait until machine's turn.", False);
5844 else
5846 Attention(firstProgramPID);
5853 void
5854 LoadPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5856 int fromRemotePlayer = *nprms;
5858 if (fromRemotePlayer)
5860 DisplayMessage("only opponent may load position", fromRemotePlayer);
5861 return;
5864 if (gameMode != BeginningOfGame)
5866 DisplayMessage("Press Reset first.", False);
5867 return;
5870 FileNamePopUp("Position file name?", LoadPosition);
5876 Boolean
5877 LoadPosition(char *name)
5879 char *p, line[MSG_SIZ], buf[MSG_SIZ];
5880 Board initial_position;
5881 Catched initial_catches;
5882 FILE *fp;
5883 int i, j;
5885 if (gameMode != BeginningOfGame)
5887 DisplayMessage("Press Reset first.", False);
5888 return False;
5891 if (localPlayer.appData.loadPositionFile != name)
5893 if (localPlayer.appData.loadPositionFile)
5894 XtFree(localPlayer.appData.loadPositionFile);
5896 localPlayer.appData.loadPositionFile = XtMalloc(strlen(name) + 1);
5897 strcpy(localPlayer.appData.loadPositionFile, name);
5900 if ((fp = fopen(name, "r")) == NULL)
5902 sprintf(buf, "Can't open %s", name);
5903 DisplayMessage(buf, False);
5904 XtFree(localPlayer.appData.loadPositionFile);
5905 localPlayer.appData.loadPositionFile = NULL;
5906 return False;
5909 lastGameMode = gameMode = ForceMoves;
5910 ModeHighlight();
5911 startedFromSetupPosition = True;
5913 if (firstProgramXID == 0)
5915 InitShogiProgram(localPlayer.appData.firstHost,
5916 localPlayer.appData.firstShogiProgram,
5917 &firstProgramPID, &toFirstProgFP,
5918 &fromFirstProgFP, &firstProgramXID,
5919 &firstSendTime);
5923 * Check and skip header information in position file.
5926 fgets(line, MSG_SIZ, fp);
5927 line[strlen(line) - 1] = NULLCHAR;
5928 sprintf(buf, "# %s position file", programName);
5930 if (strncmp(line, buf, strlen(buf)))
5932 strcat(line, ": no xshogi position file");
5933 DisplayMessage(line, False);
5934 return False;
5937 DisplayName(line);
5938 fgets(line, MSG_SIZ, fp); /* skip opponents */
5940 for (i = BOARD_SIZE - 1; i >= 0; i--)
5942 fgets(line, MSG_SIZ, fp);
5944 for (p = line, j = 0; j < BOARD_SIZE; p++)
5946 int promoted = False; /* CHECKME: is this valid? */
5948 if (*p == '+')
5949 promoted = True;
5951 if (*p == ' ')
5952 promoted = False;
5954 p++;
5955 initial_position[i][j++] = CharToPiece(*p, promoted);
5960 int color;
5962 for (color = 0; color <= 1; color++)
5964 fscanf(fp, "%i%i%i%i%i%i%i%i\n",
5965 &initial_catches[color][pawn],
5966 &initial_catches[color][lance],
5967 &initial_catches[color][knight],
5968 &initial_catches[color][silver],
5969 &initial_catches[color][gold],
5970 &initial_catches[color][bishop],
5971 &initial_catches[color][rook],
5972 &initial_catches[color][king]);
5976 whitePlaysFirst = False;
5978 if (!feof(fp))
5980 fgets(line, MSG_SIZ, fp);
5982 if (strncmp(line, "white", strlen("white")) == 0)
5983 whitePlaysFirst = True;
5986 fclose(fp);
5988 if (whitePlaysFirst)
5990 CopyBoard(boards[0], initial_position);
5991 CopyCatches(catches[0], initial_catches);
5992 strcpy(moveList[0], " ...\n");
5993 strcpy(parseList[0], " ...\n");
5994 currentMove = forwardMostMove = backwardMostMove = 1;
5995 CopyBoard(boards[1], initial_position);
5996 CopyCatches(catches[1], initial_catches);
5997 SendToProgram("white\n", toFirstProgFP);
5998 SendToProgram("force\n", toFirstProgFP);
5999 SendCurrentBoard(toFirstProgFP);
6000 DisplayMessage("White to play", False);
6002 else
6004 currentMove = forwardMostMove = backwardMostMove = 0;
6005 CopyBoard(boards[0], initial_position);
6006 CopyCatches(catches[0], initial_catches);
6007 SendCurrentBoard(toFirstProgFP);
6008 SendToProgram("force\n", toFirstProgFP);
6009 DisplayMessage("Black to play", False);
6012 DisplayClocks(ResetTimers);
6013 timeRemaining[0][1] = blackTimeRemaining;
6014 timeRemaining[1][1] = whiteTimeRemaining;
6016 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6017 return True;
6023 void
6024 EditPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6026 int fromRemotePlayer = *nprms;
6028 if (updateRemotePlayer)
6030 DisplayMessage("Edit button disabled", fromRemotePlayer);
6031 return;
6034 if (gameMode == EditPosition)
6035 return;
6037 ForceProc(w, event, prms, nprms);
6039 if (gameMode != ForceMoves)
6040 return;
6042 DisplayName("<-- Press to set side to play next");
6043 DisplayMessage("Mouse: 1=drag, 2=black, 3=white", False);
6045 lastGameMode = gameMode = EditPosition;
6046 ModeHighlight();
6048 if (currentMove > 0)
6049 CopyBoard(boards[0], boards[currentMove]);
6051 whitePlaysFirst = !BlackOnMove(forwardMostMove);
6052 currentMove = forwardMostMove = backwardMostMove = 0;
6058 void
6059 EditPositionDone(void)
6061 startedFromSetupPosition = True;
6062 SendToProgram(localPlayer.appData.initString, toFirstProgFP);
6063 SendSearchDepth(toFirstProgFP);
6065 if (whitePlaysFirst)
6067 strcpy(moveList[0], " ...\n");
6068 strcpy(parseList[0], " ...\n");
6069 currentMove = forwardMostMove = backwardMostMove = 1;
6070 CopyBoard(boards[1], boards[0]);
6071 CopyCatches(catches[1], catches[0]);
6072 SendToProgram("force\n", toFirstProgFP);
6073 SendCurrentBoard(toFirstProgFP);
6074 DisplayName(" ");
6075 DisplayMessage("White to play", False);
6077 else
6079 currentMove = forwardMostMove = backwardMostMove = 0;
6080 SendCurrentBoard(toFirstProgFP);
6081 SendToProgram("force\n", toFirstProgFP);
6082 DisplayName(" ");
6083 DisplayMessage("Black to play", False);
6086 lastGameMode = gameMode = ForceMoves;
6092 * FUNCTION
6093 * BackwardProc
6095 * DESCRIPTION
6096 * This function executes when undoing a move.
6097 * FIXME: this function is totally hosed!!!
6099 * ARGUMENTS
6100 * Widget w
6101 * XEvent *event
6102 * String *prms
6103 * Cardinal *nprms
6105 * RETURN VALUE
6106 * void
6110 void
6111 BackwardProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6113 int target;
6114 unsigned int state;
6116 int fromRemotePlayer = *nprms;
6118 if (updateRemotePlayer)
6120 DisplayMessage("Backward button disabled", fromRemotePlayer);
6121 return;
6125 * Why do we need this here?
6128 ForceProc(w, event, prms, nprms);
6130 if ((currentMove <= backwardMostMove) || (gameMode == EditPosition))
6131 return;
6133 if (gameMode == EndOfGame)
6134 ResurrectShogiProgram();
6136 if (gameMode == PlayFromGameFile)
6137 PauseProc(w, event, prms, nprms);
6139 if (event == NULL)
6141 /* Kludge */
6142 Window root, child;
6143 int root_x, root_y;
6144 int win_x, win_y;
6146 XQueryPointer(localPlayer.xDisplay, localPlayer.xBoardWindow,
6147 &root, &child, &root_x, &root_y,
6148 &win_x, &win_y, &state);
6150 else
6152 state = event->xkey.state;
6155 if (state & ShiftMask)
6157 target = backwardMostMove;
6159 else
6161 target = currentMove - 1;
6164 if (gameMode == ForceMoves)
6166 Attention(firstProgramPID);
6168 while (currentMove > target)
6170 SendToProgram("undo\n", toFirstProgFP);
6171 currentMove--;
6174 else
6176 currentMove = target;
6179 if (gameMode == ForceMoves)
6181 whiteTimeRemaining = timeRemaining[0][currentMove];
6182 blackTimeRemaining = timeRemaining[1][currentMove];
6185 DisplayClocks(ReDisplayTimers);
6186 DisplayMove(currentMove - 1);
6187 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6193 void
6194 FlipViewProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6196 struct DisplayData *player = (*nprms ? &remotePlayer : &localPlayer);
6198 player->flipView = !player->flipView;
6199 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6205 void
6206 SaveGameProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6208 char def[MSG_SIZ];
6210 int fromRemotePlayer = *nprms;
6212 if (fromRemotePlayer)
6214 DisplayMessage("only opponent may save game", fromRemotePlayer);
6215 return;
6218 def[0] = NULLCHAR;
6220 FileNamePopUp("Filename for saved game?", SaveGame);
6226 Boolean
6227 SaveGame(char *name)
6229 char buf[MSG_SIZ];
6230 int i, len, move = 0;
6231 time_t tm;
6233 if (!filemodeUp) /* if called via FileModeCallback avoid recursion */
6235 if ((gameFileFP = fopen(name, "r")) == NULL)
6237 strcpy(fmi.mode, "w");
6239 else
6241 fclose(gameFileFP);
6242 FileModePopUp(name);
6243 return False; /* CHECKME: what should the return value be? */
6247 if ((gameFileFP = fopen(name, fmi.mode)) == NULL)
6249 sprintf(buf, "Can't open %s (mode %s)", name, fmi.mode);
6250 DisplayMessage(buf, False);
6251 return False;
6254 tm = time((time_t *) NULL);
6256 fprintf(gameFileFP, "# %s game file -- %s", programName, ctime(&tm));
6257 PrintOpponents(gameFileFP);
6259 for (i = 0; i < currentMove;)
6261 if ((i % 5) == 0)
6262 fprintf(gameFileFP, "\n");
6264 fprintf(gameFileFP, "%d. %s ", ++move, parseList[i++]);
6266 if (i >= currentMove)
6268 fprintf(gameFileFP, "\n");
6269 break;
6272 if ((len = strlen(parseList[i])) == 0)
6273 break;
6275 fprintf(gameFileFP, "%s ", parseList[i++]);
6278 fprintf(gameFileFP, "\n");
6280 fclose(gameFileFP);
6281 gameFileFP = NULL;
6283 return True;
6289 void
6290 SwitchProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6292 if (localPlayer.appData.noShogiProgram)
6293 return;
6295 switch (gameMode)
6297 default:
6298 return;
6300 case MachinePlaysBlack:
6301 if (BlackOnMove(forwardMostMove))
6303 DisplayMessage("Wait until your turn", False);
6304 return;
6307 lastGameMode = gameMode = MachinePlaysWhite;
6308 ModeHighlight();
6309 break;
6311 case BeginningOfGame:
6313 case MachinePlaysWhite:
6314 if (!BlackOnMove(forwardMostMove))
6316 DisplayMessage("Wait until your turn", False);
6317 return;
6320 if (forwardMostMove == 0)
6322 MachineBlackProc(w, event, prms, nprms);
6323 return;
6326 lastGameMode = gameMode = MachinePlaysBlack;
6327 ModeHighlight();
6328 break;
6331 Attention(firstProgramPID);
6332 SendToProgram("switch\n", toFirstProgFP);
6338 void
6339 ForceProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6341 int i;
6343 switch (gameMode)
6345 case MachinePlaysBlack:
6346 if (BlackOnMove(forwardMostMove))
6348 DisplayMessage("Wait until your turn", False);
6349 return;
6352 Attention(firstProgramPID);
6353 SendToProgram("force\n", toFirstProgFP);
6354 break;
6356 case MachinePlaysWhite:
6357 if (!BlackOnMove(forwardMostMove))
6359 DisplayMessage("Wait until your turn", False);
6360 return;
6363 Attention(firstProgramPID);
6364 SendToProgram("force\n", toFirstProgFP);
6365 break;
6367 case BeginningOfGame:
6368 SendToProgram("force\n", toFirstProgFP);
6369 break;
6371 case PlayFromGameFile:
6372 if (readGameXID != 0)
6374 XtRemoveTimeOut(readGameXID);
6375 readGameXID = 0;
6378 if (gameFileFP != NULL)
6380 fclose(gameFileFP);
6381 gameFileFP = NULL;
6384 break;
6386 case EndOfGame:
6387 ResurrectShogiProgram();
6388 break;
6390 case EditPosition:
6391 EditPositionDone();
6392 break;
6394 case TwoMachinesPlay:
6395 ShutdownShogiPrograms("");
6396 ResurrectShogiProgram();
6397 return;
6399 default:
6400 return;
6403 if ((gameMode == MachinePlaysWhite)
6404 || (gameMode == MachinePlaysBlack)
6405 || (gameMode == TwoMachinesPlay)
6406 || (gameMode == PlayFromGameFile))
6408 i = forwardMostMove;
6410 while (i > currentMove)
6412 SendToProgram("undo\n", toFirstProgFP);
6413 i--;
6416 blackTimeRemaining = timeRemaining[0][currentMove];
6417 whiteTimeRemaining = timeRemaining[1][currentMove];
6419 if (whiteFlag || blackFlag)
6421 whiteFlag = blackFlag = 0;
6424 DisplayTitle("");
6427 lastGameMode = gameMode = ForceMoves;
6428 ModeHighlight();
6429 DisplayClocks(StopTimers);
6434 void
6435 HintProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6437 int fromRemotePlayer = *nprms;
6439 if (updateRemotePlayer)
6441 DisplayMessage("no hints in challenge mode", fromRemotePlayer);
6442 return;
6445 if (localPlayer.appData.noShogiProgram)
6446 return;
6448 switch (gameMode)
6450 case MachinePlaysBlack:
6451 if (BlackOnMove(forwardMostMove))
6453 DisplayMessage("Wait until your turn", False);
6454 return;
6457 break;
6459 case BeginningOfGame:
6460 case MachinePlaysWhite:
6461 if (!BlackOnMove(forwardMostMove))
6463 DisplayMessage("Wait until your turn", False);
6464 return;
6467 break;
6469 default:
6470 DisplayMessage("No hint available", False);
6471 return;
6474 Attention(firstProgramPID);
6475 SendToProgram("hint\n", toFirstProgFP);
6481 void
6482 PrintPosition(FILE *fp, int move)
6484 int i, j, color;
6486 for (i = BOARD_SIZE - 1; i >= 0; i--)
6488 for (j = 0; j < BOARD_SIZE; j++)
6490 if (pieceIsPromoted[(int)boards[currentMove][i][j]])
6491 fprintf(fp, "%c", '+');
6492 else
6493 fprintf(fp, "%c", ' ');
6495 fprintf(fp, "%c",
6496 pieceToChar[(int)boards[currentMove][i][j]]);
6498 if (j == BOARD_SIZE - 1)
6499 fputc('\n', fp);
6503 for (color = 0; color <= 1; color++)
6505 fprintf(fp, "%i %i %i %i %i %i %i %i\n",
6506 catches[currentMove][color][pawn],
6507 catches[currentMove][color][lance],
6508 catches[currentMove][color][knight],
6509 catches[currentMove][color][silver],
6510 catches[currentMove][color][gold],
6511 catches[currentMove][color][bishop],
6512 catches[currentMove][color][rook],
6513 catches[currentMove][color][king]);
6516 if ((gameMode == EditPosition)
6517 ? !whitePlaysFirst
6518 : BlackOnMove(forwardMostMove))
6520 fprintf(fp, "black to play\n");
6522 else
6524 fprintf(fp, "white to play\n");
6531 void
6532 PrintOpponents(FILE *fp)
6534 char host_name[MSG_SIZ];
6536 #ifdef HAVE_GETHOSTNAME
6537 gethostname(host_name, MSG_SIZ);
6538 #else
6539 strncpy(host_name, "hostname not available", MSG_SIZ);
6540 #endif
6542 switch (lastGameMode)
6544 case MachinePlaysWhite:
6545 fprintf(fp, "# %s@%s vs. %s@%s\n",
6546 localPlayer.appData.firstShogiProgram,
6547 localPlayer.appData.firstHost,
6548 getpwuid(getuid())->pw_name,
6549 host_name);
6550 break;
6552 case MachinePlaysBlack:
6553 fprintf(fp, "# %s@%s vs. %s@%s\n",
6554 getpwuid(getuid())->pw_name,
6555 host_name,
6556 localPlayer.appData.firstShogiProgram,
6557 localPlayer.appData.firstHost);
6558 break;
6560 case TwoMachinesPlay:
6561 fprintf(fp, "# %s@%s vs. %s@%s\n",
6562 localPlayer.appData.secondShogiProgram,
6563 localPlayer.appData.secondHost,
6564 localPlayer.appData.firstShogiProgram,
6565 localPlayer.appData.firstHost);
6566 break;
6568 default:
6569 fprintf(fp, "#\n");
6570 break;
6577 void
6578 SavePositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6580 char def[MSG_SIZ];
6582 int fromRemotePlayer = *nprms;
6584 if (fromRemotePlayer)
6586 DisplayMessage("only opponent may save game", fromRemotePlayer);
6587 return;
6590 def[0] = NULLCHAR;
6592 FileNamePopUp("Filename for saved position?", SavePosition);
6598 Boolean
6599 SavePosition(char *name)
6601 char buf[MSG_SIZ];
6602 FILE *fp;
6603 time_t tm;
6605 if ((fp = fopen(name, "w")) == NULL)
6607 sprintf(buf, "Can't open %s", name);
6608 DisplayMessage(buf, False);
6609 return False;
6612 tm = time((time_t *) NULL);
6614 fprintf(fp, "# %s position file -- %s", programName, ctime(&tm));
6615 PrintOpponents(fp);
6616 PrintPosition(fp, currentMove);
6617 fclose(fp);
6619 return True;
6625 void
6626 TwoMachinesProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6628 int i;
6629 MatchMode matchKind;
6631 int fromRemotePlayer = *nprms;
6633 if (updateRemotePlayer)
6635 DisplayMessage("no machine moves in challenge mode",
6636 fromRemotePlayer);
6637 return;
6640 if (gameMode == PauseGame)
6641 PauseProc(w, event, prms, nprms);
6643 if (gameMode == PlayFromGameFile)
6644 ForceProc(w, event, prms, nprms);
6646 if ((gameMode == EndOfGame)
6647 || (gameMode == TwoMachinesPlay)
6648 || localPlayer.appData.noShogiProgram)
6650 return;
6653 if (matchMode == MatchFalse)
6655 switch (gameMode)
6657 case PauseGame:
6658 case PlayFromGameFile:
6659 return;
6661 case MachinePlaysBlack:
6662 case MachinePlaysWhite:
6663 ForceProc(w, event, prms, nprms);
6665 if (gameMode != ForceMoves)
6666 return;
6668 matchKind = MatchOpening;
6669 break;
6671 case ForceMoves:
6672 matchKind = MatchOpening;
6673 break;
6675 case EditPosition:
6676 EditPositionDone();
6677 matchKind = MatchPosition;
6678 break;
6680 case BeginningOfGame:
6681 default:
6682 matchKind = MatchInit;
6683 break;
6686 else
6688 matchKind = matchMode;
6691 forwardMostMove = currentMove;
6693 localPlayer.flipView = False;
6694 remotePlayer.flipView = True;
6695 firstMove = False;
6696 DisplayClocks(ResetTimers);
6697 DisplayClocks(StartTimers);
6699 switch (matchKind)
6701 case MatchOpening:
6702 if (firstProgramXID == 0)
6704 if (localPlayer.appData.loadGameFile == NULL)
6706 DisplayMessage("Select game file first", False);
6707 return;
6710 InitShogiProgram(localPlayer.appData.firstHost,
6711 localPlayer.appData.firstShogiProgram,
6712 &firstProgramPID, &toFirstProgFP,
6713 &fromFirstProgFP, &firstProgramXID,
6714 &firstSendTime);
6716 if (!LoadGame(localPlayer.appData.loadGameFile))
6718 ShutdownShogiPrograms("Bad game file");
6719 return;
6722 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6725 InitShogiProgram(localPlayer.appData.secondHost,
6726 localPlayer.appData.secondShogiProgram,
6727 &secondProgramPID, &toSecondProgFP,
6728 &fromSecondProgFP, &secondProgramXID,
6729 &secondSendTime);
6731 if (startedFromSetupPosition)
6733 if (whitePlaysFirst)
6735 i = 1;
6736 SendToProgram("force\n", toSecondProgFP);
6737 SendBoard(toSecondProgFP, boards[i], catches[i]);
6739 else
6741 i = 0;
6742 SendBoard(toSecondProgFP, boards[i], catches[i]);
6743 SendToProgram("force\n", toSecondProgFP);
6746 else
6748 i = 0;
6749 SendToProgram("force\n", toSecondProgFP);
6752 for (i = backwardMostMove; i < forwardMostMove; i++)
6753 SendToProgram(moveList[i], toSecondProgFP);
6755 lastGameMode = gameMode = TwoMachinesPlay;
6756 ModeHighlight();
6757 firstMove = True;
6759 if (BlackOnMove(forwardMostMove))
6760 SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6761 else
6762 SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
6764 break;
6766 case MatchPosition:
6767 if (firstProgramXID == 0)
6769 if (localPlayer.appData.loadPositionFile == NULL)
6771 DisplayMessage("Select position file first", False);
6772 return;
6775 InitShogiProgram(localPlayer.appData.firstHost,
6776 localPlayer.appData.firstShogiProgram,
6777 &firstProgramPID, &toFirstProgFP,
6778 &fromFirstProgFP, &firstProgramXID,
6779 &firstSendTime);
6781 if (!LoadPosition(localPlayer.appData.loadPositionFile))
6782 return;
6785 InitShogiProgram(localPlayer.appData.secondHost,
6786 localPlayer.appData.secondShogiProgram,
6787 &secondProgramPID, &toSecondProgFP,
6788 &fromSecondProgFP, &secondProgramXID,
6789 &secondSendTime);
6791 if (whitePlaysFirst)
6792 SendToProgram("force\n", toSecondProgFP);
6794 SendCurrentBoard(toSecondProgFP);
6795 lastGameMode = gameMode = TwoMachinesPlay;
6796 ModeHighlight();
6797 firstMove = True;
6799 if (BlackOnMove(forwardMostMove))
6800 SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6801 else
6802 SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
6804 break;
6806 case MatchInit:
6807 InitPosition(True);
6809 if (firstProgramXID == 0)
6811 InitShogiProgram(localPlayer.appData.firstHost,
6812 localPlayer.appData.firstShogiProgram,
6813 &firstProgramPID, &toFirstProgFP,
6814 &fromFirstProgFP, &firstProgramXID,
6815 &firstSendTime);
6818 InitShogiProgram(localPlayer.appData.secondHost,
6819 localPlayer.appData.secondShogiProgram,
6820 &secondProgramPID, &toSecondProgFP,
6821 &fromSecondProgFP, &secondProgramXID,
6822 &secondSendTime);
6824 lastGameMode = gameMode = TwoMachinesPlay;
6825 ModeHighlight();
6826 SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6828 default:
6829 break;
6832 if (!firstSendTime || !secondSendTime)
6834 DisplayClocks(ResetTimers);
6835 timeRemaining[0][forwardMostMove] = blackTimeRemaining;
6836 timeRemaining[1][forwardMostMove] = whiteTimeRemaining;
6839 DisplayClocks(StartTimers);
6845 void
6846 PauseProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6848 static GameMode previous_mode = PauseGame;
6850 switch (gameMode)
6852 case ForceMoves:
6853 case EndOfGame:
6854 case EditPosition:
6855 default:
6856 return;
6858 case PauseGame:
6859 gameMode = previous_mode;
6860 ModeHighlight();
6861 previous_mode = PauseGame;
6862 DisplayClocks(StartTimers);
6863 DisplayMessage("", False);
6865 if (updateRemotePlayer)
6866 DisplayMessage("", True);
6867 break;
6869 case PlayFromGameFile:
6870 if (readGameXID == 0)
6872 readGameXID =
6873 XtAppAddTimeOut(appContext,
6874 (int)(1000 * localPlayer.appData.timeDelay),
6875 (XtTimerCallbackProc) ReadGameFile, NULL);
6877 else
6879 XtRemoveTimeOut(readGameXID);
6880 readGameXID = 0;
6883 DisplayMessage("Pausing", False);
6885 if (updateRemotePlayer)
6886 DisplayMessage("Pausing", True);
6888 break;
6890 case BeginningOfGame:
6891 case MachinePlaysBlack:
6892 case MachinePlaysWhite:
6893 case TwoMachinesPlay:
6894 if (forwardMostMove == 0) /* Don't pause if no one has moved. */
6895 return;
6897 if (((gameMode == MachinePlaysWhite)
6898 && !BlackOnMove(forwardMostMove))
6899 || ((gameMode == MachinePlaysBlack) &&
6900 BlackOnMove(forwardMostMove)))
6902 DisplayClocks(StopTimers);
6905 previous_mode = gameMode;
6906 gameMode = PauseGame;
6907 ModeHighlight();
6908 DisplayClocks(StopTimers);
6909 DisplayMessage("Pausing", False);
6911 if (updateRemotePlayer)
6912 DisplayMessage("Pausing", True);
6914 break;
6921 void
6922 Iconify(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6924 Arg args[1];
6926 fromX = fromY = -1;
6928 XtSetArg(args[0], XtNiconic, True);
6929 XtSetValues(localPlayer.shellWidget, args, 1);
6935 void
6936 SendToProgram(char *message, FILE *fp)
6938 if (fp == NULL)
6939 return;
6941 lastMsgFP = fp;
6943 if (xshogiDebug)
6945 fprintf(stderr, "Sending to %s: %s\n",
6946 ((fp == toFirstProgFP) ? "first" : "second"), message);
6949 if (message[strlen(message) - 1] != '\n')
6950 fprintf(fp, "\n%s\n", message);
6951 else
6952 fputs(message, fp);
6954 fflush(fp);
6960 void
6961 ReceiveFromProgram(FILE *fp, int *source, XtInputId *id)
6963 char message[MSG_SIZ], *end_str, *number, *name;
6965 if (fgets(message, MSG_SIZ, fp) == NULL)
6967 if (fp == fromFirstProgFP)
6969 number = "first";
6970 name = localPlayer.appData.firstShogiProgram;
6972 else if (fp == fromSecondProgFP)
6974 number = "second";
6975 name = localPlayer.appData.secondShogiProgram;
6977 else
6979 return;
6982 if (ferror(fp) == 0)
6984 sprintf(message, "%s shogi program (%s) exited unexpectedly",
6985 number, name);
6986 fprintf(stderr, "%s: %s\n", programName, message);
6988 else
6990 sprintf(message,
6991 "error reading from %s shogi program (%s): %s",
6992 number, name, strerror(ferror(fp)));
6993 fprintf(stderr, "%s: %s\n", programName, message);
6996 return;
6999 if ((end_str = (char *)strchr(message, '\r')) != NULL)
7000 *end_str = NULLCHAR;
7002 if ((end_str = (char *)strchr(message, '\n')) != NULL)
7003 *end_str = NULLCHAR;
7005 if (xshogiDebug || localPlayer.appData.debugMode)
7007 fprintf(stderr, "Received from %s: %s\n",
7008 ((fp == fromFirstProgFP) ? "first" : "second"), message);
7011 HandleMachineMove(message, fp);
7017 void
7018 SendSearchDepth(FILE *fp)
7020 char message[MSG_SIZ];
7022 if (localPlayer.appData.searchDepth <= 0)
7023 return;
7025 sprintf(message, "depth\n%d\nhelp\n", localPlayer.appData.searchDepth);
7026 /* Note kludge: "help" command forces gnushogi to print
7027 * out something that ends with a newline. */
7028 SendToProgram(message, fp);
7034 void
7035 DisplayMessage(char *message, int toRemotePlayer)
7037 Arg arg;
7039 XtSetArg(arg, XtNlabel, message);
7041 if (!toRemotePlayer)
7042 XtSetValues(localPlayer.messageWidget, &arg, 1);
7044 if (updateRemotePlayer && toRemotePlayer)
7045 XtSetValues(remotePlayer.messageWidget, &arg, 1);
7051 void
7052 DisplayName(char *name)
7054 Arg arg;
7056 XtSetArg(arg, XtNlabel, name);
7057 XtSetValues(localPlayer.titleWidget, &arg, 1);
7059 if (updateRemotePlayer)
7060 XtSetValues(remotePlayer.titleWidget, &arg, 1);
7066 void SendTimeRemaining(FILE *fp)
7068 char message[MSG_SIZ];
7069 long comtime, opptime;
7071 if (BlackOnMove(forwardMostMove) == (fp == toFirstProgFP))
7073 comtime = blackTimeRemaining;
7074 opptime = whiteTimeRemaining;
7076 else
7078 comtime = whiteTimeRemaining;
7079 opptime = blackTimeRemaining;
7082 if (comtime <= 0)
7083 comtime = 1000;
7085 if (opptime <= 0)
7086 opptime = 1000;
7088 sprintf(message, "time %ld\n", comtime / 10);
7089 SendToProgram(message, fp);
7090 sprintf(message, "otime %ld\n", opptime / 10);
7091 SendToProgram(message, fp);
7097 void DisplayMove(int moveNumber)
7099 char message[MSG_SIZ];
7101 if (moveNumber < 0)
7103 if (moveNumber == forwardMostMove - 1)
7104 DisplayMessage(endMessage, False);
7105 else
7106 DisplayMessage("", False);
7108 else
7110 sprintf(message, "%d. %s%s %s",
7111 (moveNumber / 2 + 1),
7112 (BlackOnMove(moveNumber) ? "" : "... "),
7113 parseList[moveNumber],
7114 (moveNumber == (forwardMostMove - 1)) ? endMessage : "");
7115 DisplayMessage(message, False);
7122 void DisplayTitle(char *title)
7124 Arg arg;
7126 XtSetArg(arg, XtNlabel, title);
7127 XtSetValues(localPlayer.titleWidget, &arg, 1);
7134 * This routine used to send a SIGINT (^C interrupt) to gnushogi to awaken it
7135 * if it might be busy thinking on our time. This normally isn't needed,
7136 * but is useful on systems where the FIONREAD ioctl doesn't work since
7137 * on those systems the gnushogi feature that lets you interrupt its thinking
7138 * just by typing a command does not work.
7140 * Now gnushogi periodically checks for user input without a need for
7141 * this hack.
7144 void
7145 Attention(int pid)
7147 #if 0
7148 if (localPlayer.appData.noShogiProgram || (pid == 0))
7149 return;
7151 switch (gameMode)
7153 case MachinePlaysBlack:
7154 case MachinePlaysWhite:
7155 case TwoMachinesPlay:
7156 if ((forwardMostMove > backwardMostMove + 1) && maybeThinking)
7158 if (xshogiDebug || localPlayer.appData.debugMode)
7160 fprintf(stderr, "Sending SIGINT to %s\n",
7161 ((pid == firstProgramPID) ? "first" : "second"));
7164 (void)kill(pid, SIGINT); /* stop it thinking */
7166 break;
7168 default:
7169 break; /* CHECKME: is this OK? */
7171 #endif /* !defined(FIONREAD) */
7177 void
7178 CheckFlags(void)
7180 if (blackTimeRemaining <= 0)
7182 if (!blackFlag)
7184 blackFlag = True;
7186 if (whiteFlag)
7187 DisplayName(" Both flags have fallen");
7188 else
7189 DisplayName(" Black's flag has fallen");
7193 if (whiteTimeRemaining <= 0)
7195 if (!whiteFlag)
7197 whiteFlag = True;
7199 if (blackFlag)
7200 DisplayName(" Both flags have fallen");
7201 else
7202 DisplayName(" White's flag has fallen");
7210 void
7211 CheckTimeControl(void)
7213 if (!localPlayer.appData.clockMode)
7214 return;
7216 if (forwardMostMove == 0)
7217 return;
7220 * Add time to clocks when time control is achieved.
7223 if ((forwardMostMove % (localPlayer.appData.movesPerSession * 2)) == 0)
7225 blackTimeRemaining += timeControl;
7226 whiteTimeRemaining += timeControl;
7233 void
7234 DisplayLabels(void)
7236 DisplayTimerLabel(localPlayer.blackTimerWidget, "Black",
7237 blackTimeRemaining);
7238 DisplayTimerLabel(localPlayer.whiteTimerWidget, "White",
7239 whiteTimeRemaining);
7241 if (updateRemotePlayer)
7243 DisplayTimerLabel(remotePlayer.blackTimerWidget, "Black",
7244 blackTimeRemaining);
7245 DisplayTimerLabel(remotePlayer.whiteTimerWidget, "White",
7246 whiteTimeRemaining);
7253 #ifdef HAVE_GETTIMEOFDAY
7254 static struct timeval tickStartTV;
7255 static int tickLength;
7258 PartialTickLength(void)
7260 struct timeval tv;
7261 int ptl;
7263 gettimeofday(&tv, NULL);
7264 ptl = ((tv.tv_sec - tickStartTV.tv_sec) * 1000000 +
7265 (tv.tv_usec - tickStartTV.tv_usec) + 500) / 1000;
7267 if (ptl > tickLength)
7268 ptl = tickLength;
7270 return ptl;
7272 #else /* !HAVE_GETTIMEOFDAY */
7273 #define tickLength 1000
7274 #endif /* HAVE_GETTIMEOFDAY */
7280 * DisplayClocks manages the game clocks.
7282 * In tournament play, white starts the clock and then black makes a move.
7283 * We give the human user a slight advantage if he is playing black---the
7284 * clocks don't run until he makes his first move, so it takes zero time.
7285 * Also, DisplayClocks doesn't account for network lag so it could get out
7286 * of sync with GNU Shogi's clock -- but then, referees are always right.
7289 void
7290 DisplayClocks(int clock_mode)
7292 long timeRemaining;
7294 switch (clock_mode)
7296 case ResetTimers:
7297 /* Stop clocks and reset to a fresh time control */
7298 if (timerXID != 0)
7300 XtRemoveTimeOut(timerXID);
7301 timerXID = 0;
7304 blackTimeRemaining = timeControl;
7305 whiteTimeRemaining = timeControl;
7307 if (blackFlag || whiteFlag)
7309 DisplayName("");
7310 blackFlag = whiteFlag = False;
7313 DisplayLabels();
7314 break;
7316 case DecrementTimers:
7317 /* Decrement running clock to next 1-second boundary */
7318 if (gameMode == PauseGame)
7319 return;
7321 timerXID = 0;
7323 if (!localPlayer.appData.clockMode)
7324 return;
7326 if (BlackOnMove(forwardMostMove))
7328 timeRemaining = (blackTimeRemaining -= tickLength);
7330 else
7332 timeRemaining = (whiteTimeRemaining -= tickLength);
7335 DisplayLabels();
7336 CheckFlags();
7338 #ifdef HAVE_GETTIMEOFDAY
7339 tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7340 ? 100 : 1000);
7341 gettimeofday(&tickStartTV, NULL);
7342 #endif /* HAVE_GETTIMEOFDAY */
7344 timerXID =
7345 XtAppAddTimeOut(appContext, tickLength,
7346 (XtTimerCallbackProc) DisplayClocks,
7347 (XtPointer) DecrementTimers);
7348 break;
7350 case SwitchTimers:
7351 /* A player has just moved, so stop the previously running
7352 clock and start the other one. */
7354 if (timerXID != 0)
7356 XtRemoveTimeOut(timerXID);
7357 timerXID = 0;
7359 #ifdef HAVE_GETTIMEOFDAY
7360 if (localPlayer.appData.clockMode)
7362 if (BlackOnMove(forwardMostMove))
7363 whiteTimeRemaining -= PartialTickLength();
7364 else
7365 blackTimeRemaining -= PartialTickLength();
7366 CheckFlags();
7368 #endif /* HAVE_GETTIMEOFDAY */
7371 CheckTimeControl();
7372 DisplayLabels();
7374 if (!localPlayer.appData.clockMode)
7375 return;
7377 if ((gameMode == PauseGame)
7378 && ((pausePreviousMode == MachinePlaysBlack)
7379 || (pausePreviousMode == MachinePlaysWhite)))
7381 return;
7384 timeRemaining = (BlackOnMove(forwardMostMove)
7385 ? blackTimeRemaining : whiteTimeRemaining);
7387 #ifdef HAVE_GETTIMEOFDAY
7388 tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7389 ? (((timeRemaining - 1) % 100) + 1)
7390 : (((timeRemaining - 1) % 1000) + 1));
7392 if (tickLength <= 0)
7393 tickLength += 1000;
7395 gettimeofday(&tickStartTV, NULL);
7397 #endif /* HAVE_GETTIMEOFDAY */
7398 timerXID =
7399 XtAppAddTimeOut(appContext, tickLength,
7400 (XtTimerCallbackProc) DisplayClocks,
7401 (XtPointer) DecrementTimers);
7402 break;
7404 case ReDisplayTimers:
7405 /* Display current clock values */
7406 DisplayLabels();
7407 break;
7409 case StopTimers:
7410 /* Stop both clocks */
7411 if (timerXID == 0)
7412 return;
7414 XtRemoveTimeOut(timerXID);
7415 timerXID = 0;
7417 if (!localPlayer.appData.clockMode)
7418 return;
7420 #ifdef HAVE_GETTIMEOFDAY
7421 if (BlackOnMove(forwardMostMove))
7422 blackTimeRemaining -= PartialTickLength();
7423 else
7424 whiteTimeRemaining -= PartialTickLength();
7425 CheckFlags();
7426 DisplayLabels();
7427 #endif /* HAVE_GETTIMEOFDAY */
7428 break;
7430 case StartTimers:
7431 /* Start clock of player on move, if not already running. */
7432 if (timerXID != 0)
7433 return;
7435 DisplayLabels();
7437 if (!localPlayer.appData.clockMode)
7438 return;
7440 timeRemaining = (BlackOnMove(forwardMostMove)
7441 ? blackTimeRemaining : whiteTimeRemaining);
7443 if (timeRemaining == 0)
7444 return;
7446 #ifdef HAVE_GETTIMEOFDAY
7447 tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7448 ? (((timeRemaining - 1) % 100) + 1)
7449 : (((timeRemaining - 1) % 1000) + 1));
7451 if (tickLength <= 0)
7452 tickLength += 1000;
7454 gettimeofday(&tickStartTV, NULL);
7455 #endif /* HAVE_GETTIMEOFDAY */
7457 timerXID =
7458 XtAppAddTimeOut(appContext, tickLength,
7459 (XtTimerCallbackProc) DisplayClocks,
7460 (XtPointer)DecrementTimers);
7461 break;
7468 void
7469 DisplayTimerLabel(Widget w, char *color, long int timer)
7471 char buf[MSG_SIZ];
7472 Arg args[3];
7473 struct DisplayData *player;
7475 player = (((w == localPlayer.blackTimerWidget)
7476 || (w == localPlayer.whiteTimerWidget))
7477 ? &localPlayer : &remotePlayer);
7479 if (localPlayer.appData.clockMode)
7481 sprintf(buf, "%s: %s", color, TimeString(timer));
7482 XtSetArg(args[0], XtNlabel, buf);
7484 else
7486 XtSetArg(args[0], XtNlabel, color);
7489 if (((color[0] == 'W') && BlackOnMove(forwardMostMove))
7490 || ((color[0] == 'B') && !BlackOnMove(forwardMostMove)))
7492 XtSetArg(args[1], XtNbackground, player->timerForegroundPixel);
7493 XtSetArg(args[2], XtNforeground, player->timerBackgroundPixel);
7495 else
7497 XtSetArg(args[1], XtNbackground, player->timerBackgroundPixel);
7498 XtSetArg(args[2], XtNforeground, player->timerForegroundPixel);
7501 XtSetValues(w, args, 3);
7507 char *
7508 TimeString(long tm)
7510 int second, minute, hour, day;
7511 char *sign = "";
7512 static char buf[32];
7514 if ((tm > 0) && (tm <= 900))
7516 /* convert milliseconds to tenths, rounding up */
7517 sprintf(buf, " 0.%1ld ", (tm + 99) / 100);
7518 return buf;
7521 /* convert milliseconds to seconds, rounding up */
7522 tm = (tm + 999) / 1000;
7524 if (tm < 0)
7526 sign = "-";
7527 tm = -tm;
7530 if (tm >= (60 * 60 * 24))
7532 day = (int)(tm / (60 * 60 * 24));
7533 tm -= day * 60 * 60 * 24;
7535 else
7537 day = 0;
7540 if (tm >= (60 * 60))
7542 hour = (int)(tm / (60 * 60));
7543 tm -= hour * 60 * 60;
7545 else
7547 hour = 0;
7550 if (tm >= 60)
7552 minute = (int)(tm / 60);
7553 tm -= minute * 60;
7555 else
7557 minute = 0;
7560 second = tm % 60;
7562 if (day > 0)
7564 sprintf(buf, " %s%d:%02d:%02d:%02d ",
7565 sign, day, hour, minute, second);
7567 else if (hour > 0)
7569 sprintf(buf, " %s%d:%02d:%02d ",
7570 sign, hour, minute, second);
7572 else
7574 sprintf(buf, " %s%2d:%02d ",
7575 sign, minute, second);
7578 return buf;
7584 void
7585 Usage(void)
7587 fprintf(stderr, "Usage: %s\n", programName);
7588 fprintf(stderr, "\tstandard Xt options\n");
7589 fprintf(stderr, "\t-iconic\n");
7590 fprintf(stderr, "\t-tc or -timeControl minutes[:seconds]\n");
7591 fprintf(stderr, "\t-gi or -gameIn (True | False)\n");
7592 fprintf(stderr, "\t-mps or -movesPerSession moves\n");
7593 fprintf(stderr, "\t-st or -searchTime minutes[:seconds]\n");
7594 fprintf(stderr, "\t-sd or -searchDepth number\n");
7595 fprintf(stderr, "\t-clock or -clockMode (True | False)\n");
7596 fprintf(stderr, "\t-td or -timeDelay seconds\n");
7598 fprintf(stderr, "\t-nsp or -noShogiProgram (True | False)\n");
7599 fprintf(stderr, "\t-fsp or -firstShogiProgram program_name\n");
7600 fprintf(stderr, "\t-ssp or -secondShogiProgram program_name\n");
7601 fprintf(stderr, "\t-fh or -firstHost host_name\n");
7602 fprintf(stderr, "\t-sh or -secondHost host_name\n");
7603 fprintf(stderr, "\t-rsh or -remoteShell shell_name\n");
7604 fprintf(stderr,
7605 "\t-mm or -matchMode (False | Init | Position | Opening)\n");
7606 fprintf(stderr, "\t-lgf or -loadGameFile file_name\n");
7607 fprintf(stderr, "\t-lpf or -loadPositionFile file_name\n");
7608 fprintf(stderr, "\t-sgf or -saveGameFile file_name\n");
7609 fprintf(stderr, "\t-spf or -savePositionFile file_name\n");
7610 fprintf(stderr, "\t-size or -boardSize (Large | Medium | Small)\n");
7611 fprintf(stderr, "\t-coords or -showCoords (True | False)\n");
7612 fprintf(stderr, "\t-mono or -monoMode (True | False)\n");
7613 fprintf(stderr, "\t-pc or -pieceColor color\n");
7614 fprintf(stderr, "\t-sc or -squareColor color\n");
7615 fprintf(stderr, "\t-wps or -westernPieceSet (True | False)\n");
7616 fprintf(stderr, "\t-debug or -debugMode (True | False)\n");
7617 exit(2);
7622 void
7623 CatchPipeSignal(int dummy)
7625 char message[MSG_SIZ];
7627 sprintf(message,
7628 "%s shogi program (%s) exited unexpectedly",
7629 ((lastMsgFP == toFirstProgFP) ? "first" : "second"),
7630 ((lastMsgFP == toFirstProgFP)
7631 ? localPlayer.appData.firstShogiProgram
7632 : localPlayer.appData.secondShogiProgram));
7633 fprintf(stderr, "%s: %s\n", programName, message);
7634 ShutdownShogiPrograms(message);
7635 return;