Drop -ansi from gcc extra flags.
[gnushogi.git] / xshogi / xshogi.c
blobf88f39a669aebbea8f6b8558ca003ff4862c2b8f
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 "xshogi.h"
96 #define BUF_SIZE 1024
97 #define BOARD 1
98 #define MOVES 2
100 #include "bitmaps.h" /* Piece bitmaps. */
101 #include "xshogifn.h" /* Forward declarations. */
103 #define off_board(x) ((x < 2) || (x > BOARD_SIZE + 1))
106 /**********************************************************************
108 * Global variables, structs etc.
110 **********************************************************************/
113 * NOTE: XShogi depends on Xt R4 or higher
116 int xtVersion = XtSpecificationRelease;
118 XtIntervalId firstProgramXID = 0, secondProgramXID = 0,
119 readGameXID = 0, timerXID = 0, blinkSquareXID = 0;
121 XtAppContext appContext;
123 Boolean (*fileProc) (char *name);
125 FILE *fromFirstProgFP, *toFirstProgFP, *fromSecondProgFP,
126 *toSecondProgFP, *gameFileFP, *lastMsgFP;
128 int currentMove = 0, forwardMostMove = 0, backwardMostMove = 0,
129 firstProgramPID = 0,
130 secondProgramPID = 0, fromX = -1,
131 fromY = -1, firstMove = True, flipView = False,
132 xshogiDebug = True, commentUp = False, filenameUp = False,
133 whitePlaysFirst = False, startedFromSetupPosition = False,
134 searchTime = 0, pmFromX = -1, pmFromY = -1,
135 blackFlag = False, whiteFlag = False, maybeThinking = False,
136 filemodeUp = False;
138 int at_least_gnushogi_1_2p03 = False;
140 int firstSendTime = 2, secondSendTime = 2; /* 0 = don't, 1 = do,
141 2 = test first */
143 MatchMode matchMode = MatchFalse;
144 GameMode gameMode = BeginningOfGame;
145 GameMode lastGameMode = BeginningOfGame;
146 GameMode pausePreviousMode = BeginningOfGame;
148 char moveList[MAX_MOVES][MOVE_LEN], parseList[MAX_MOVES][MOVE_LEN * 2],
149 ptyname[24], *shogiDir, *programName;
151 char endMessage[MOVE_LEN * 4];
153 long blackTimeRemaining, whiteTimeRemaining, timeControl;
154 long timeRemaining[2][MAX_MOVES];
156 extern char currentMoveString[];
158 int updateRemotePlayer = False;
160 Catched catches[MAX_MOVES];
162 #define DIMENSION 100
164 Widget blackPieceMenu, whitePieceMenu, commentShell;
166 XSetWindowAttributes attr;
168 #define pawn 0
169 #define lance 1
170 #define knight 2
171 #define silver 3
172 #define gold 4
173 #define bishop 5
174 #define rook 6
175 #define king 7
176 #define no_piece 8
177 #define ppawn 9
178 #define plance 10
179 #define pknight 11
180 #define psilver 12
181 #define pbishop 13
183 #define NO_PIECES 15
184 #define NO_SQUARES 81
185 #define NO_COLS 9
186 #define NO_ROWS 9
189 char catchedIndexToChar[8] =
191 'P', 'L', 'N', 'S', 'G', 'B', 'R', 'K'
194 ShogiSquare catchedIndexToPiece[2][8] =
197 BlackPawn, BlackLance, BlackKnight, BlackSilver, BlackGold,
198 BlackBishop, BlackRook, BlackKing
201 WhitePawn, WhiteLance, WhiteKnight, WhiteSilver, WhiteGold,
202 WhiteBishop, WhiteRook, WhiteKing
207 int pieceToCatchedIndex[] =
209 pawn, lance, knight, silver, gold, bishop, rook,
210 pawn, lance, knight, silver, bishop, rook, king,
211 pawn, lance, knight, silver, gold, bishop, rook,
212 pawn, lance, knight, silver, bishop, rook, king,
213 no_piece
218 Board boards[MAX_MOVES];
219 Board initialPosition =
221 { BlackLance, BlackKnight, BlackSilver, BlackGold, BlackKing,
222 BlackGold, BlackSilver, BlackKnight, BlackLance },
223 { EmptySquare, BlackBishop, EmptySquare, EmptySquare, EmptySquare,
224 EmptySquare, EmptySquare, BlackRook, EmptySquare },
225 { BlackPawn, BlackPawn, BlackPawn, BlackPawn, BlackPawn,
226 BlackPawn, BlackPawn, BlackPawn, BlackPawn },
227 { EmptySquare, EmptySquare, EmptySquare, EmptySquare, EmptySquare,
228 EmptySquare, EmptySquare, EmptySquare, EmptySquare } ,
229 { EmptySquare, EmptySquare, EmptySquare, EmptySquare, EmptySquare,
230 EmptySquare, EmptySquare, EmptySquare, EmptySquare } ,
231 { EmptySquare, EmptySquare, EmptySquare, EmptySquare, EmptySquare,
232 EmptySquare, EmptySquare, EmptySquare, EmptySquare } ,
233 { WhitePawn, WhitePawn, WhitePawn, WhitePawn, WhitePawn,
234 WhitePawn, WhitePawn, WhitePawn, WhitePawn },
235 { EmptySquare, WhiteRook, EmptySquare, EmptySquare, EmptySquare,
236 EmptySquare, EmptySquare, WhiteBishop, EmptySquare },
237 { WhiteLance, WhiteKnight, WhiteSilver, WhiteGold, WhiteKing,
238 WhiteGold, WhiteSilver, WhiteKnight, WhiteLance }
241 String gnuButtonStrings[] =
243 "Quit", "Load Game", "Machine White", "Forward",
244 "Reset", "Load Position", "Machine Black", "Backward",
245 "Flip View", "Save Game", "Force Moves", "Pause",
246 "Hint", "Save Position", "Two Machines", "Edit Position",
247 "Challenge", "Select Level", "Move NOW",
250 /* must be in same order as buttonStrings! */
251 XtActionProc gnuButtonProcs[] =
253 QuitProc, LoadGameProc, MachineWhiteProc, ForwardProc,
254 ResetProc, LoadPositionProc, MachineBlackProc, BackwardProc,
255 FlipViewProc, SaveGameProc, ForceProc, PauseProc,
256 HintProc, SavePositionProc, TwoMachinesProc, EditPositionProc,
257 ChallengeProc, SelectLevelProc, MoveNowProc,
258 NULL
262 String *buttonStrings;
263 XtActionProc *buttonProcs;
264 int buttonCount;
266 #define PIECE_MENU_SIZE 18
268 String pieceMenuStrings[PIECE_MENU_SIZE] =
270 "----", "Pawn", "Lance", "Knight", "Silver",
271 "Gold", "Bishop", "Rook",
272 "PPawn", "PLance", "PKnight", "PSilver",
273 "PBishop", "PRook", "King",
274 "----", "Empty square", "Clear board"
277 /* must be in same order as PieceMenuStrings! */
278 ShogiSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] =
281 (ShogiSquare) 0, BlackPawn, BlackLance, BlackKnight,
282 BlackSilver, BlackGold, BlackBishop, BlackRook,
283 BlackPPawn, BlackPLance, BlackPKnight, BlackPSilver,
284 BlackPBishop, BlackPRook, BlackKing,
285 (ShogiSquare) 0, EmptySquare, ClearBoard
288 (ShogiSquare) 0, WhitePawn, WhiteLance, WhiteKnight,
289 WhiteSilver, WhiteGold, WhiteBishop, WhiteRook,
290 WhitePPawn, WhitePLance, WhitePKnight, WhitePSilver,
291 WhitePBishop, WhitePRook, WhiteKing,
292 (ShogiSquare) 0, EmptySquare, ClearBoard
297 typedef struct
299 Pixel pieceColor;
300 Pixel squareColor;
301 Pixel charPieceColor;
302 Pixel zeroColor;
303 Pixel oneColor;
304 Boolean westernPieceSet;
305 int movesPerSession;
306 String initString;
307 String blackString;
308 String whiteString;
309 String firstShogiProgram;
310 String secondShogiProgram;
311 Boolean noShogiProgram;
312 String firstHost;
313 String secondHost;
314 String reverseBigSolidBitmap;
315 String reverseSmallSolidBitmap;
316 String normalBigSolidBitmap;
317 String normalSmallSolidBitmap;
318 String reversePawnBitmap;
319 String reverseLanceBitmap;
320 String reverseKnightBitmap;
321 String reverseSilverBitmap;
322 String reverseGoldBitmap;
323 String reverseRookBitmap;
324 String reverseBishopBitmap;
325 String reversePPawnBitmap;
326 String reversePLanceBitmap;
327 String reversePKnightBitmap;
328 String reversePSilverBitmap;
329 String reversePBishopBitmap;
330 String reversePRookBitmap;
331 String reverseKingBitmap;
332 String normalPawnBitmap;
333 String normalLanceBitmap;
334 String normalKnightBitmap;
335 String normalSilverBitmap;
336 String normalGoldBitmap;
337 String normalRookBitmap;
338 String normalBishopBitmap;
339 String normalPPawnBitmap;
340 String normalPLanceBitmap;
341 String normalPKnightBitmap;
342 String normalPSilverBitmap;
343 String normalPBishopBitmap;
344 String normalPRookBitmap;
345 String normalKingBitmap;
346 String remoteShell;
347 float timeDelay;
348 String timeControl;
349 String gameIn;
351 Boolean autoSaveGames;
352 String loadGameFile;
353 String loadPositionFile;
354 String saveGameFile;
355 String savePositionFile;
356 String matchMode;
357 String challengeDisplay;
358 Boolean monoMode;
359 Boolean debugMode;
360 Boolean clockMode;
361 String boardSize;
362 Boolean Iconic;
363 String searchTime;
364 int searchDepth;
365 Boolean showCoords;
366 String mainFont;
367 String coordFont;
368 Boolean ringBellAfterMoves;
369 Boolean autoCallFlag;
370 int borderXoffset;
371 int borderYoffset;
372 } AppData, *AppDataPtr;
375 XtResource clientResources[] =
378 "pieceColor", "pieceColor", XtRPixel, sizeof(Pixel),
379 XtOffset(AppDataPtr, pieceColor), XtRString,
380 PIECE_COLOR
383 "charPieceColor", "CharPieceColor", XtRPixel, sizeof(Pixel),
384 XtOffset(AppDataPtr, charPieceColor), XtRString,
385 CHAR_PIECE_COLOR
388 "oneColor", "OneColor", XtRPixel, sizeof(Pixel),
389 XtOffset(AppDataPtr, oneColor), XtRString,
390 ONE_COLOR
393 "zeroColor", "ZeroColor", XtRPixel, sizeof(Pixel),
394 XtOffset(AppDataPtr, zeroColor), XtRString,
395 ZERO_COLOR
398 "squareColor", "squareColor", XtRPixel,
399 sizeof(Pixel), XtOffset(AppDataPtr, squareColor),
400 XtRString, SQUARE_COLOR
403 "westernPieceSet", "WesternPieceSet", XtRBoolean, sizeof(Boolean),
404 XtOffset(AppDataPtr, westernPieceSet), XtRString,
405 (XtPointer) False
408 "movesPerSession", "movesPerSession", XtRInt, sizeof(int),
409 XtOffset(AppDataPtr, movesPerSession), XtRImmediate,
410 (XtPointer) MOVES_PER_SESSION
413 "initString", "initString", XtRString, sizeof(String),
414 XtOffset(AppDataPtr, initString), XtRString, INIT_STRING
417 "blackString", "blackString", XtRString, sizeof(String),
418 XtOffset(AppDataPtr, blackString), XtRString, BLACK_STRING
421 "whiteString", "whiteString", XtRString, sizeof(String),
422 XtOffset(AppDataPtr, whiteString), XtRString, WHITE_STRING
425 "firstShogiProgram", "firstShogiProgram", XtRString,
426 sizeof(String), XtOffset(AppDataPtr, firstShogiProgram),
427 XtRString, FIRST_SHOGI_PROGRAM
430 "secondShogiProgram", "secondShogiProgram", XtRString,
431 sizeof(String), XtOffset(AppDataPtr, secondShogiProgram),
432 XtRString, SECOND_SHOGI_PROGRAM
435 "noShogiProgram", "noShogiProgram", XtRBoolean,
436 sizeof(Boolean), XtOffset(AppDataPtr, noShogiProgram),
437 XtRImmediate, (XtPointer) False
440 "firstHost", "firstHost", XtRString, sizeof(String),
441 XtOffset(AppDataPtr, firstHost), XtRString, FIRST_HOST
444 "secondHost", "secondHost", XtRString, sizeof(String),
445 XtOffset(AppDataPtr, secondHost), XtRString, SECOND_HOST
448 "reversePawnBitmap", "reversePawnBitmap", XtRString,
449 sizeof(String), XtOffset(AppDataPtr, reversePawnBitmap),
450 XtRString, NULL
453 "reverseLanceBitmap", "reverseLanceBitmap", XtRString,
454 sizeof(String), XtOffset(AppDataPtr, reverseLanceBitmap),
455 XtRString, NULL
458 "reverseKnightBitmap", "reverseKnightBitmap", XtRString,
459 sizeof(String), XtOffset(AppDataPtr, reverseKnightBitmap),
460 XtRString, NULL
463 "reverseSilverBitmap", "reverseSilverBitmap", XtRString,
464 sizeof(String), XtOffset(AppDataPtr, reverseSilverBitmap),
465 XtRString, NULL
468 "reverseGoldBitmap", "reverseGoldBitmap", XtRString,
469 sizeof(String), XtOffset(AppDataPtr, reverseGoldBitmap),
470 XtRString, NULL
473 "reverseRookBitmap", "reverseRookBitmap", XtRString,
474 sizeof(String), XtOffset(AppDataPtr, reverseRookBitmap),
475 XtRString, NULL
478 "reverseBishopBitmap", "reverseBishopBitmap", XtRString,
479 sizeof(String), XtOffset(AppDataPtr, reverseBishopBitmap),
480 XtRString, NULL
483 "reversePPawnBitmap", "reversePPawnBitmap", XtRString,
484 sizeof(String), XtOffset(AppDataPtr, reversePPawnBitmap),
485 XtRString, NULL
488 "reversePLanceBitmap", "reversePLanceBitmap", XtRString,
489 sizeof(String), XtOffset(AppDataPtr, reversePLanceBitmap),
490 XtRString, NULL
493 "reversePKnightBitmap", "reversePKnightBitmap", XtRString,
494 sizeof(String), XtOffset(AppDataPtr, reversePKnightBitmap),
495 XtRString, NULL
498 "reversePSilverBitmap", "reversePSilverBitmap", XtRString,
499 sizeof(String), XtOffset(AppDataPtr, reversePSilverBitmap),
500 XtRString, NULL
503 "reversePRookBitmap", "reversePRookBitmap", XtRString,
504 sizeof(String), XtOffset(AppDataPtr, reversePRookBitmap),
505 XtRString, NULL
508 "reversePBishopBitmap", "reversePBishopBitmap", XtRString,
509 sizeof(String), XtOffset(AppDataPtr, reversePBishopBitmap),
510 XtRString, NULL
513 "reverseKingBitmap", "reverseKingBitmap", XtRString,
514 sizeof(String), XtOffset(AppDataPtr, reverseKingBitmap),
515 XtRString, NULL
518 "normalPawnBitmap", "normalPawnBitmap", XtRString,
519 sizeof(String), XtOffset(AppDataPtr, normalPawnBitmap),
520 XtRString, NULL
523 "normalLanceBitmap", "normalLanceBitmap", XtRString,
524 sizeof(String), XtOffset(AppDataPtr, normalLanceBitmap),
525 XtRString, NULL
528 "normalKnightBitmap", "normalKnightBitmap", XtRString,
529 sizeof(String), XtOffset(AppDataPtr, normalKnightBitmap),
530 XtRString, NULL
533 "normalSilverBitmap", "normalSilverBitmap", XtRString,
534 sizeof(String), XtOffset(AppDataPtr, normalSilverBitmap),
535 XtRString, NULL
538 "normalGoldBitmap", "normalGoldBitmap", XtRString,
539 sizeof(String), XtOffset(AppDataPtr, normalGoldBitmap),
540 XtRString, NULL
543 "normalBishopBitmap", "normalBishopBitmap", XtRString,
544 sizeof(String), XtOffset(AppDataPtr, normalBishopBitmap),
545 XtRString, NULL
548 "normalRookBitmap", "normalRookBitmap", XtRString,
549 sizeof(String), XtOffset(AppDataPtr, normalRookBitmap),
550 XtRString, NULL
553 "normalPPawnBitmap", "normalPPawnBitmap", XtRString,
554 sizeof(String), XtOffset(AppDataPtr, normalPPawnBitmap),
555 XtRString, NULL
558 "normalPLanceBitmap", "normalPLanceBitmap", XtRString,
559 sizeof(String), XtOffset(AppDataPtr, normalPLanceBitmap),
560 XtRString, NULL
563 "normalPKnightBitmap", "normalPKnightBitmap", XtRString,
564 sizeof(String), XtOffset(AppDataPtr, normalPKnightBitmap),
565 XtRString, NULL
568 "normalPSilverBitmap", "normalPSilverBitmap", XtRString,
569 sizeof(String), XtOffset(AppDataPtr, normalPSilverBitmap),
570 XtRString, NULL
573 "normalPBishopBitmap", "normalPBishopBitmap", XtRString,
574 sizeof(String), XtOffset(AppDataPtr, normalPBishopBitmap),
575 XtRString, NULL
578 "normalPRookBitmap", "normalPRookBitmap", XtRString,
579 sizeof(String), XtOffset(AppDataPtr, normalPRookBitmap),
580 XtRString, NULL
583 "normalKingBitmap", "normalKingBitmap", XtRString,
584 sizeof(String), XtOffset(AppDataPtr, normalKingBitmap),
585 XtRString, NULL
588 "remoteShell", "remoteShell", XtRString, sizeof(String),
589 XtOffset(AppDataPtr, remoteShell), XtRString, "rsh"
592 "timeDelay", "timeDelay", XtRFloat, sizeof(float),
593 XtOffset(AppDataPtr, timeDelay), XtRString,
594 (XtPointer) TIME_DELAY
597 "timeControl", "timeControl", XtRString, sizeof(String),
598 XtOffset(AppDataPtr, timeControl), XtRString,
599 (XtPointer) TIME_CONTROL
602 "gameIn", "gameIn",
603 XtRBoolean, sizeof(Boolean),
604 XtOffset(AppDataPtr, gameIn), XtRImmediate,
605 (XtPointer) False
608 "autoSaveGames", "autoSaveGames", XtRBoolean,
609 sizeof(Boolean), XtOffset(AppDataPtr, autoSaveGames),
610 XtRImmediate, (XtPointer) False
613 "loadGameFile", "loadGameFile", XtRString, sizeof(String),
614 XtOffset(AppDataPtr, loadGameFile), XtRString, NULL
617 "loadPositionFile", "loadPositionFile", XtRString,
618 sizeof(String), XtOffset(AppDataPtr, loadPositionFile),
619 XtRString, NULL
622 "saveGameFile", "saveGameFile", XtRString, sizeof(String),
623 XtOffset(AppDataPtr, saveGameFile), XtRString, ""
626 "savePositionFile", "savePositionFile", XtRString,
627 sizeof(String), XtOffset(AppDataPtr, savePositionFile),
628 XtRString, ""
631 "challengeDisplay", "challengeDisplay", XtRString,
632 sizeof(String), XtOffset(AppDataPtr, challengeDisplay),
633 XtRString, NULL
636 "matchMode", "matchMode", XtRString, sizeof(String),
637 XtOffset(AppDataPtr, matchMode), XtRString, MATCH_MODE
640 "monoMode", "monoMode", XtRBoolean, sizeof(Boolean),
641 XtOffset(AppDataPtr, monoMode), XtRImmediate,
642 (XtPointer) False
645 "debugMode", "debugMode", XtRBoolean, sizeof(Boolean),
646 XtOffset(AppDataPtr, debugMode), XtRImmediate,
647 (XtPointer) False
650 "Iconic", "Iconic", XtRBoolean, sizeof(Boolean),
651 XtOffset(AppDataPtr, Iconic), XtRImmediate,
652 (XtPointer) False
655 "clockMode", "clockMode", XtRBoolean, sizeof(Boolean),
656 XtOffset(AppDataPtr, clockMode), XtRImmediate,
657 (XtPointer) True
660 "autoCallFlag", "autoCallFlag", XtRBoolean,
661 sizeof(Boolean), XtOffset(AppDataPtr, autoCallFlag),
662 XtRImmediate, (XtPointer) False
665 "boardSize", "boardSize", XtRString, sizeof(String),
666 XtOffset(AppDataPtr, boardSize), XtRString, DEFAULT_SIZE
669 "searchTime", "searchTime", XtRString, sizeof(String),
670 XtOffset(AppDataPtr, searchTime), XtRString,
671 (XtPointer) NULL
674 "searchDepth", "searchDepth", XtRInt, sizeof(int),
675 XtOffset(AppDataPtr, searchDepth), XtRImmediate,
676 (XtPointer) 0
679 "showCoords", "showCoords", XtRBoolean, sizeof(Boolean),
680 XtOffset(AppDataPtr, showCoords), XtRImmediate,
681 (XtPointer) False
684 "mainFont", "mainFont", XtRString, sizeof(String),
685 XtOffset(AppDataPtr, mainFont), XtRString, MAIN_FONT
688 "coordFont", "coordFont", XtRString, sizeof(String),
689 XtOffset(AppDataPtr, coordFont), XtRString, COORD_FONT
692 "ringBellAfterMoves", "ringBellAfterMoves",
693 XtRBoolean, sizeof(Boolean),
694 XtOffset(AppDataPtr, ringBellAfterMoves),
695 XtRImmediate, (XtPointer) False
698 "borderXoffset", "borderXoffset", XtRInt, sizeof(int),
699 XtOffset(AppDataPtr, borderXoffset), XtRImmediate,
700 (XtPointer) BORDER_X_OFFSET
703 "borderYoffset", "borderYOffset", XtRInt, sizeof(int),
704 XtOffset(AppDataPtr, borderYoffset), XtRImmediate,
705 (XtPointer) BORDER_Y_OFFSET
710 struct DisplayData
712 AppData appData;
714 Arg shellArgs[6];
715 Arg boardArgs[3];
716 Arg commandsArgs[7];
717 Arg messageArgs[3];
718 Arg timerArgs[2];
719 Arg titleArgs[2];
721 Pixmap reversePawnBitmap, reverseLanceBitmap, reverseKnightBitmap,
722 reverseSilverBitmap,
723 reverseGoldBitmap, reverseBishopBitmap, reverseRookBitmap,
724 reversePPawnBitmap, reversePLanceBitmap, reversePKnightBitmap,
725 reversePSilverBitmap, reversePBishopBitmap, reversePRookBitmap,
726 reverseKingBitmap,
727 reverseBigSolidBitmap, reverseSmallSolidBitmap,
728 normalBigSolidBitmap, normalSmallSolidBitmap,
729 normalPawnBitmap, normalLanceBitmap, normalKnightBitmap,
730 normalSilverBitmap, normalGoldBitmap,
731 normalBishopBitmap, normalRookBitmap,
732 normalPPawnBitmap, normalPLanceBitmap, normalPKnightBitmap,
733 normalPSilverBitmap, normalPBishopBitmap, normalPRookBitmap,
734 normalKingBitmap,
735 iconPixmap;
737 Display *xDisplay;
738 int xScreen;
739 Window xBoardWindow;
741 GC squareGC, lineGC, pieceGC, oPieceGC, charPieceGC,
742 squareOffBoardGC, coordGC, dropPiece;
744 Font mainFontID, coordFontID;
745 XFontStruct *mainFontStruct, *coordFontStruct;
747 Widget shellWidget, formWidget, boardWidget,
748 commandsWidget, messageWidget,
749 blackTimerWidget, whiteTimerWidget,
750 titleWidget, widgetList[6],
751 promotionShell,
752 filemodeShell, challengeWidget;
754 XSegment gridSegments[(BOARD_SIZE + 1) * 2];
756 Pixel timerForegroundPixel, timerBackgroundPixel;
758 BoardSize boardSize;
759 int squareSize;
760 int black_pixel_is_zero;
761 int flipView;
762 int promotionUp;
764 Boolean monoMode, showCoords, Iconic;
769 struct DisplayData localPlayer, remotePlayer;
772 typedef struct
774 ShogiSquare piece;
775 int to_x, to_y;
776 } PromotionMoveInfo;
778 static PromotionMoveInfo pmi; /* making this global is gross */
781 Pixmap *pieceToReverse[2][28] =
784 &localPlayer.reversePawnBitmap,
785 &localPlayer.reverseLanceBitmap,
786 &localPlayer.reverseKnightBitmap,
787 &localPlayer.reverseSilverBitmap,
788 &localPlayer.reverseGoldBitmap,
789 &localPlayer.reverseBishopBitmap,
790 &localPlayer.reverseRookBitmap,
791 &localPlayer.reversePPawnBitmap,
792 &localPlayer.reversePLanceBitmap,
793 &localPlayer.reversePKnightBitmap,
794 &localPlayer.reversePSilverBitmap,
795 &localPlayer.reversePBishopBitmap,
796 &localPlayer.reversePRookBitmap,
797 &localPlayer.reverseKingBitmap,
798 &localPlayer.reversePawnBitmap,
799 &localPlayer.reverseLanceBitmap,
800 &localPlayer.reverseKnightBitmap,
801 &localPlayer.reverseSilverBitmap,
802 &localPlayer.reverseGoldBitmap,
803 &localPlayer.reverseBishopBitmap,
804 &localPlayer.reverseRookBitmap,
805 &localPlayer.reversePPawnBitmap,
806 &localPlayer.reversePLanceBitmap,
807 &localPlayer.reversePKnightBitmap,
808 &localPlayer.reversePSilverBitmap,
809 &localPlayer.reversePBishopBitmap,
810 &localPlayer.reversePRookBitmap,
811 &localPlayer.reverseKingBitmap
814 &remotePlayer.reversePawnBitmap,
815 &remotePlayer.reverseLanceBitmap,
816 &remotePlayer.reverseKnightBitmap,
817 &remotePlayer.reverseSilverBitmap,
818 &remotePlayer.reverseGoldBitmap,
819 &remotePlayer.reverseBishopBitmap,
820 &remotePlayer.reverseRookBitmap,
821 &remotePlayer.reversePPawnBitmap,
822 &remotePlayer.reversePLanceBitmap,
823 &remotePlayer.reversePKnightBitmap,
824 &remotePlayer.reversePSilverBitmap,
825 &remotePlayer.reversePBishopBitmap,
826 &remotePlayer.reversePRookBitmap,
827 &remotePlayer.reverseKingBitmap,
828 &remotePlayer.reversePawnBitmap,
829 &remotePlayer.reverseLanceBitmap,
830 &remotePlayer.reverseKnightBitmap,
831 &remotePlayer.reverseSilverBitmap,
832 &remotePlayer.reverseGoldBitmap,
833 &remotePlayer.reverseBishopBitmap,
834 &remotePlayer.reverseRookBitmap,
835 &remotePlayer.reversePPawnBitmap,
836 &remotePlayer.reversePLanceBitmap,
837 &remotePlayer.reversePKnightBitmap,
838 &remotePlayer.reversePSilverBitmap,
839 &remotePlayer.reversePBishopBitmap,
840 &remotePlayer.reversePRookBitmap,
841 &remotePlayer.reverseKingBitmap
847 Pixmap *pieceToNormal[2][28] =
850 &localPlayer.normalPawnBitmap,
851 &localPlayer.normalLanceBitmap,
852 &localPlayer.normalKnightBitmap,
853 &localPlayer.normalSilverBitmap,
854 &localPlayer.normalGoldBitmap,
855 &localPlayer.normalBishopBitmap,
856 &localPlayer.normalRookBitmap,
857 &localPlayer.normalPPawnBitmap,
858 &localPlayer.normalPLanceBitmap,
859 &localPlayer.normalPKnightBitmap,
860 &localPlayer.normalPSilverBitmap,
861 &localPlayer.normalPBishopBitmap,
862 &localPlayer.normalPRookBitmap,
863 &localPlayer.normalKingBitmap,
864 &localPlayer.normalPawnBitmap,
865 &localPlayer.normalLanceBitmap,
866 &localPlayer.normalKnightBitmap,
867 &localPlayer.normalSilverBitmap,
868 &localPlayer.normalGoldBitmap,
869 &localPlayer.normalBishopBitmap,
870 &localPlayer.normalRookBitmap,
871 &localPlayer.normalPPawnBitmap,
872 &localPlayer.normalPLanceBitmap,
873 &localPlayer.normalPKnightBitmap,
874 &localPlayer.normalPSilverBitmap,
875 &localPlayer.normalPBishopBitmap,
876 &localPlayer.normalPRookBitmap,
877 &localPlayer.normalKingBitmap
880 &remotePlayer.normalPawnBitmap,
881 &remotePlayer.normalLanceBitmap,
882 &remotePlayer.normalKnightBitmap,
883 &remotePlayer.normalSilverBitmap,
884 &remotePlayer.normalGoldBitmap,
885 &remotePlayer.normalBishopBitmap,
886 &remotePlayer.normalRookBitmap,
887 &remotePlayer.normalPPawnBitmap,
888 &remotePlayer.normalPLanceBitmap,
889 &remotePlayer.normalPKnightBitmap,
890 &remotePlayer.normalPSilverBitmap,
891 &remotePlayer.normalPBishopBitmap,
892 &remotePlayer.normalPRookBitmap,
893 &remotePlayer.normalKingBitmap,
894 &remotePlayer.normalPawnBitmap,
895 &remotePlayer.normalLanceBitmap,
896 &remotePlayer.normalKnightBitmap,
897 &remotePlayer.normalSilverBitmap,
898 &remotePlayer.normalGoldBitmap,
899 &remotePlayer.normalBishopBitmap,
900 &remotePlayer.normalRookBitmap,
901 &remotePlayer.normalPPawnBitmap,
902 &remotePlayer.normalPLanceBitmap,
903 &remotePlayer.normalPKnightBitmap,
904 &remotePlayer.normalPSilverBitmap,
905 &remotePlayer.normalPBishopBitmap,
906 &remotePlayer.normalPRookBitmap,
907 &remotePlayer.normalKingBitmap
913 Pixmap *pieceToReverseSolid[2][28] =
916 &localPlayer.reverseSmallSolidBitmap,
917 &localPlayer.reverseSmallSolidBitmap,
918 &localPlayer.reverseSmallSolidBitmap,
919 &localPlayer.reverseBigSolidBitmap,
920 &localPlayer.reverseBigSolidBitmap,
921 &localPlayer.reverseBigSolidBitmap,
922 &localPlayer.reverseBigSolidBitmap,
923 &localPlayer.reverseSmallSolidBitmap,
924 &localPlayer.reverseSmallSolidBitmap,
925 &localPlayer.reverseSmallSolidBitmap,
926 &localPlayer.reverseBigSolidBitmap,
927 &localPlayer.reverseBigSolidBitmap,
928 &localPlayer.reverseBigSolidBitmap,
929 &localPlayer.reverseBigSolidBitmap,
930 &localPlayer.reverseSmallSolidBitmap,
931 &localPlayer.reverseSmallSolidBitmap,
932 &localPlayer.reverseSmallSolidBitmap,
933 &localPlayer.reverseBigSolidBitmap,
934 &localPlayer.reverseBigSolidBitmap,
935 &localPlayer.reverseBigSolidBitmap,
936 &localPlayer.reverseBigSolidBitmap,
937 &localPlayer.reverseSmallSolidBitmap,
938 &localPlayer.reverseSmallSolidBitmap,
939 &localPlayer.reverseSmallSolidBitmap,
940 &localPlayer.reverseBigSolidBitmap,
941 &localPlayer.reverseBigSolidBitmap,
942 &localPlayer.reverseBigSolidBitmap,
943 &localPlayer.reverseBigSolidBitmap
946 &remotePlayer.reverseSmallSolidBitmap,
947 &remotePlayer.reverseSmallSolidBitmap,
948 &remotePlayer.reverseSmallSolidBitmap,
949 &remotePlayer.reverseBigSolidBitmap,
950 &remotePlayer.reverseBigSolidBitmap,
951 &remotePlayer.reverseBigSolidBitmap,
952 &remotePlayer.reverseBigSolidBitmap,
953 &remotePlayer.reverseSmallSolidBitmap,
954 &remotePlayer.reverseSmallSolidBitmap,
955 &remotePlayer.reverseSmallSolidBitmap,
956 &remotePlayer.reverseBigSolidBitmap,
957 &remotePlayer.reverseBigSolidBitmap,
958 &remotePlayer.reverseBigSolidBitmap,
959 &remotePlayer.reverseBigSolidBitmap,
960 &remotePlayer.reverseSmallSolidBitmap,
961 &remotePlayer.reverseSmallSolidBitmap,
962 &remotePlayer.reverseSmallSolidBitmap,
963 &remotePlayer.reverseBigSolidBitmap,
964 &remotePlayer.reverseBigSolidBitmap,
965 &remotePlayer.reverseBigSolidBitmap,
966 &remotePlayer.reverseBigSolidBitmap,
967 &remotePlayer.reverseSmallSolidBitmap,
968 &remotePlayer.reverseSmallSolidBitmap,
969 &remotePlayer.reverseSmallSolidBitmap,
970 &remotePlayer.reverseBigSolidBitmap,
971 &remotePlayer.reverseBigSolidBitmap,
972 &remotePlayer.reverseBigSolidBitmap,
973 &remotePlayer.reverseBigSolidBitmap
979 Pixmap *pieceToNormalSolid[2][28] =
982 &localPlayer.normalSmallSolidBitmap,
983 &localPlayer.normalSmallSolidBitmap,
984 &localPlayer.normalSmallSolidBitmap,
985 &localPlayer.normalBigSolidBitmap,
986 &localPlayer.normalBigSolidBitmap,
987 &localPlayer.normalBigSolidBitmap,
988 &localPlayer.normalBigSolidBitmap,
989 &localPlayer.normalSmallSolidBitmap,
990 &localPlayer.normalSmallSolidBitmap,
991 &localPlayer.normalSmallSolidBitmap,
992 &localPlayer.normalBigSolidBitmap,
993 &localPlayer.normalBigSolidBitmap,
994 &localPlayer.normalBigSolidBitmap,
995 &localPlayer.normalBigSolidBitmap,
996 &localPlayer.normalSmallSolidBitmap,
997 &localPlayer.normalSmallSolidBitmap,
998 &localPlayer.normalSmallSolidBitmap,
999 &localPlayer.normalBigSolidBitmap,
1000 &localPlayer.normalBigSolidBitmap,
1001 &localPlayer.normalBigSolidBitmap,
1002 &localPlayer.normalBigSolidBitmap,
1003 &localPlayer.normalSmallSolidBitmap,
1004 &localPlayer.normalSmallSolidBitmap,
1005 &localPlayer.normalSmallSolidBitmap,
1006 &localPlayer.normalBigSolidBitmap,
1007 &localPlayer.normalBigSolidBitmap,
1008 &localPlayer.normalBigSolidBitmap,
1009 &localPlayer.normalBigSolidBitmap
1012 &remotePlayer.normalSmallSolidBitmap,
1013 &remotePlayer.normalSmallSolidBitmap,
1014 &remotePlayer.normalSmallSolidBitmap,
1015 &remotePlayer.normalBigSolidBitmap,
1016 &remotePlayer.normalBigSolidBitmap,
1017 &remotePlayer.normalBigSolidBitmap,
1018 &remotePlayer.normalBigSolidBitmap,
1019 &remotePlayer.normalSmallSolidBitmap,
1020 &remotePlayer.normalSmallSolidBitmap,
1021 &remotePlayer.normalSmallSolidBitmap,
1022 &remotePlayer.normalBigSolidBitmap,
1023 &remotePlayer.normalBigSolidBitmap,
1024 &remotePlayer.normalBigSolidBitmap,
1025 &remotePlayer.normalBigSolidBitmap,
1026 &remotePlayer.normalSmallSolidBitmap,
1027 &remotePlayer.normalSmallSolidBitmap,
1028 &remotePlayer.normalSmallSolidBitmap,
1029 &remotePlayer.normalBigSolidBitmap,
1030 &remotePlayer.normalBigSolidBitmap,
1031 &remotePlayer.normalBigSolidBitmap,
1032 &remotePlayer.normalBigSolidBitmap,
1033 &remotePlayer.normalSmallSolidBitmap,
1034 &remotePlayer.normalSmallSolidBitmap,
1035 &remotePlayer.normalSmallSolidBitmap,
1036 &remotePlayer.normalBigSolidBitmap,
1037 &remotePlayer.normalBigSolidBitmap,
1038 &remotePlayer.normalBigSolidBitmap,
1039 &remotePlayer.normalBigSolidBitmap
1045 int pieceIsPromoted[] =
1047 False, False, False, False, False, False, False,
1048 True, True, True, True, True, True, False,
1049 False, False, False, False, False, False, False,
1050 True, True, True, True, True, True, False,
1051 False
1055 int piecePromotable[] =
1057 True, True, True, True, False, True, True,
1058 False, False, False, False, False, False, False,
1059 True, True, True, True, False, True, True,
1060 False, False, False, False, False, False, False,
1061 False
1065 char pieceToChar[] =
1067 'P', 'L', 'N', 'S', 'G', 'B', 'R', 'P', 'L', 'N', 'S', 'B', 'R', 'K',
1068 'p', 'l', 'n', 's', 'g', 'b', 'r', 'p', 'l', 'n', 's', 'b', 'r', 'k',
1073 ShogiSquare pieceToPromoted[] =
1075 BlackPPawn, BlackPLance, BlackPKnight, BlackPSilver, BlackGold,
1076 BlackPBishop, BlackPRook,
1077 BlackPPawn, BlackPLance, BlackPKnight, BlackPSilver,
1078 BlackPBishop, BlackPRook, BlackKing,
1079 WhitePPawn, WhitePLance, WhitePKnight, WhitePSilver, WhiteGold,
1080 WhitePBishop, WhitePRook,
1081 WhitePPawn, WhitePLance, WhitePKnight, WhitePSilver,
1082 WhitePBishop, WhitePRook, WhiteKing
1087 XrmOptionDescRec shellOptions[] =
1089 { "-pieceColor", "pieceColor", XrmoptionSepArg, NULL },
1090 { "-pc", "pieceColor", XrmoptionSepArg, NULL },
1091 { "-charPieceColor", "charPieceColor", XrmoptionSepArg, NULL },
1092 { "-cpc", "charPieceColor", XrmoptionSepArg, NULL },
1093 { "-zeroColor", "zeroColor", XrmoptionSepArg, NULL },
1094 { "-zc", "zeroColor", XrmoptionSepArg, NULL },
1095 { "-oneColor", "oneColor", XrmoptionSepArg, NULL },
1096 { "-oc", "oneColor", XrmoptionSepArg, NULL },
1097 { "-squareColor", "squareColor", XrmoptionSepArg, NULL },
1098 { "-sc", "squareColor", XrmoptionSepArg, NULL },
1099 { "-westernPieceSet", "westernPieceSet", XrmoptionSepArg, NULL },
1100 { "-wps", "westernPieceSet", XrmoptionSepArg, NULL },
1101 { "-movesPerSession", "movesPerSession", XrmoptionSepArg, NULL },
1102 { "-mps", "movesPerSession", XrmoptionSepArg, NULL },
1103 { "-firstShogiProgram", "firstShogiProgram", XrmoptionSepArg, NULL },
1104 { "-fsp", "firstShogiProgram", XrmoptionSepArg, NULL },
1105 { "-secondShogiProgram", "secondShogiProgram", XrmoptionSepArg, NULL },
1106 { "-ssp", "secondShogiProgram", XrmoptionSepArg, NULL },
1107 { "-noShogiProgram", "noShogiProgram", XrmoptionSepArg, NULL },
1108 { "-nsp", "noShogiProgram", XrmoptionSepArg, NULL },
1109 { "-firstHost", "firstHost", XrmoptionSepArg, NULL },
1110 { "-fh", "firstHost", XrmoptionSepArg, NULL },
1111 { "-secondHost", "secondHost", XrmoptionSepArg, NULL },
1112 { "-sh", "secondHost", XrmoptionSepArg, NULL },
1113 { "-reversePawnBitmap", "reversePawnBitmap", XrmoptionSepArg, NULL },
1114 { "-rpb", "reversePawnBitmap", XrmoptionSepArg, NULL },
1115 { "-reverseLanceBitmap", "reverseLanceBitmap", XrmoptionSepArg, NULL },
1116 { "-rlb", "reverseLanceBitmap", XrmoptionSepArg, NULL },
1117 { "-reverseKnightBitmap", "reverseKnightBitmap", XrmoptionSepArg, NULL },
1118 { "-rnb", "reverseKnightBitmap", XrmoptionSepArg, NULL },
1119 { "-reverseSilverBitmap", "reverseSilverBitmap", XrmoptionSepArg, NULL },
1120 { "-rsb", "reverseSilverBitmap", XrmoptionSepArg, NULL },
1121 { "-reverseGoldBitmap", "reverseGoldBitmap", XrmoptionSepArg, NULL },
1122 { "-rgb", "reverseGoldBitmap", XrmoptionSepArg, NULL },
1123 { "-reverseRookBitmap", "reverseRookBitmap", XrmoptionSepArg, NULL },
1124 { "-rrb", "reverseRookBitmap", XrmoptionSepArg, NULL },
1125 { "-reverseBishopBitmap", "reverseBishopBitmap", XrmoptionSepArg, NULL },
1126 { "-rbb", "reverseBishopBitmap", XrmoptionSepArg, NULL },
1127 { "-reversePPawnBitmap", "reversePPawnBitmap",
1128 XrmoptionSepArg, NULL },
1129 { "-rppb", "reversePPawnBitmap", XrmoptionSepArg, NULL },
1130 { "-reversePLanceBitmap", "reversePLanceBitmap",
1131 XrmoptionSepArg, NULL },
1132 { "-rplb", "reversePLanceBitmap", XrmoptionSepArg, NULL },
1133 { "-reversePKnightBitmap", "reversePKnightBitmap",
1134 XrmoptionSepArg, NULL },
1135 { "-rpnb", "reversePKnightBitmap", XrmoptionSepArg, NULL },
1136 { "-reversePSilverBitmap", "reversePSilverBitmap",
1137 XrmoptionSepArg, NULL },
1138 { "-rpsb", "reversePSilverBitmap", XrmoptionSepArg, NULL },
1139 { "-reversePRookBitmap", "reversePRookBitmap",
1140 XrmoptionSepArg, NULL },
1141 { "-rprb", "reversePRookBitmap", XrmoptionSepArg, NULL },
1142 { "-reversePBishopBitmap", "reversePBishopBitmap",
1143 XrmoptionSepArg, NULL },
1144 { "-rpbb", "reversePBishopBitmap", XrmoptionSepArg, NULL },
1145 { "-reverseKingBitmap", "reverseKingBitmap", XrmoptionSepArg, NULL },
1146 { "-rkb", "reverseKingBitmap", XrmoptionSepArg, NULL },
1147 { "-outlinePawnBitmap", "outlinePawnBitmap", XrmoptionSepArg, NULL },
1148 { "-opb", "normalPawnBitmap", XrmoptionSepArg, NULL },
1149 { "-normalLanceBitmap", "normalLanceBitmap", XrmoptionSepArg, NULL },
1150 { "-olb", "normalLanceBitmap", XrmoptionSepArg, NULL },
1151 { "-normalKnightBitmap", "normalKnightBitmap", XrmoptionSepArg, NULL },
1152 { "-onb", "normalKnightBitmap", XrmoptionSepArg, NULL },
1153 { "-normalSilverBitmap", "normalSilverBitmap", XrmoptionSepArg, NULL },
1154 { "-osb", "normalSilverBitmap", XrmoptionSepArg, NULL },
1155 { "-normalGoldBitmap", "normalGoldBitmap", XrmoptionSepArg, NULL },
1156 { "-ogb", "normalGoldBitmap", XrmoptionSepArg, NULL },
1157 { "-normalRookBitmap", "normalRookBitmap", XrmoptionSepArg, NULL },
1158 { "-orb", "normalRookBitmap", XrmoptionSepArg, NULL },
1159 { "-normalBishopBitmap", "normalBishopBitmap", XrmoptionSepArg, NULL },
1160 { "-obb", "normalBishopBitmap", XrmoptionSepArg, NULL },
1161 { "-normalPPawnBitmap", "normalPPawnBitmap", XrmoptionSepArg, NULL },
1162 { "-oppb", "normalPPawnBitmap", XrmoptionSepArg, NULL },
1163 { "-normalPLanceBitmap", "normalPLanceBitmap", XrmoptionSepArg, NULL },
1164 { "-oplb", "normalPLanceBitmap", XrmoptionSepArg, NULL },
1165 { "-normalPKnightBitmap", "normalPKnightBitmap", XrmoptionSepArg, NULL },
1166 { "-opnb", "normalPKnightBitmap", XrmoptionSepArg, NULL },
1167 { "-normalPSilverBitmap", "normalPSilverBitmap", XrmoptionSepArg, NULL },
1168 { "-opsb", "normalPSilverBitmap", XrmoptionSepArg, NULL },
1169 { "-normalPRookBitmap", "normalPRookBitmap", XrmoptionSepArg, NULL },
1170 { "-oprb", "normalPRookBitmap", XrmoptionSepArg, NULL },
1171 { "-normalPBishopBitmap", "normalPBishopBitmap", XrmoptionSepArg, NULL },
1172 { "-opbb", "normalPBishopBitmap", XrmoptionSepArg, NULL },
1173 { "-normalKingBitmap", "normalKingBitmap", XrmoptionSepArg, NULL },
1174 { "-okb", "outlineKingBitmap", XrmoptionSepArg, NULL },
1175 { "-remoteShell", "remoteShell", XrmoptionSepArg, NULL },
1176 { "-rsh", "remoteShell", XrmoptionSepArg, NULL },
1177 { "-timeDelay", "timeDelay", XrmoptionSepArg, NULL },
1178 { "-td", "timeDelay", XrmoptionSepArg, NULL },
1179 { "-timeControl", "timeControl", XrmoptionSepArg, NULL },
1180 { "-tc", "timeControl", XrmoptionSepArg, NULL },
1181 { "-gameIn", "gameIn", XrmoptionSepArg, NULL },
1182 { "-gi", "gameIn", XrmoptionSepArg, NULL },
1183 { "-loadGameFile", "loadGameFile", XrmoptionSepArg, NULL },
1184 { "-lgf", "loadGameFile", XrmoptionSepArg, NULL },
1185 { "-loadPositionFile", "loadPositionFile", XrmoptionSepArg, NULL },
1186 { "-lpf", "loadPositionFile", XrmoptionSepArg, NULL },
1187 { "-saveGameFile", "saveGameFile", XrmoptionSepArg, NULL },
1188 { "-sgf", "saveGameFile", XrmoptionSepArg, NULL },
1189 { "-savePositionFile", "savePositionFile", XrmoptionSepArg, NULL },
1190 { "-spf", "savePositionFile", XrmoptionSepArg, NULL },
1191 { "-challengeDisplay", "challengeDisplay", XrmoptionSepArg, NULL },
1192 { "-cd", "challengeDisplay", XrmoptionSepArg, NULL },
1193 { "-matchMode", "matchMode", XrmoptionSepArg, NULL },
1194 { "-mm", "matchMode", XrmoptionSepArg, NULL },
1195 { "-monoMode", "monoMode", XrmoptionSepArg, NULL },
1196 { "-mono", "monoMode", XrmoptionSepArg, NULL },
1197 { "-debugMode", "debugMode", XrmoptionSepArg, NULL },
1198 { "-debug", "debugMode", XrmoptionSepArg, NULL },
1199 { "-clockMode", "clockMode", XrmoptionSepArg, NULL },
1200 { "-clock", "clockMode", XrmoptionSepArg, NULL },
1201 { "-boardSize", "boardSize", XrmoptionSepArg, NULL },
1202 { "-size", "boardSize", XrmoptionSepArg, NULL },
1203 { "-searchTime", "searchTime", XrmoptionSepArg, NULL },
1204 { "-st", "searchTime", XrmoptionSepArg, NULL },
1205 { "-searchDepth", "searchDepth", XrmoptionSepArg, NULL },
1206 { "-sd", "searchDepth", XrmoptionSepArg, NULL },
1207 { "-showCoords", "showCoords", XrmoptionSepArg, NULL },
1208 { "-coords", "showCoords", XrmoptionSepArg, NULL },
1209 { "-iconic", "Iconic", XrmoptionNoArg, "True" }
1214 XtActionsRec boardActions[] =
1216 { "DrawPosition", (XtActionProc) DrawPosition },
1217 { "HandleUserMove", (XtActionProc) HandleUserMove },
1218 { "ResetProc", (XtActionProc) ResetProc },
1219 { "ResetFileProc", (XtActionProc) ResetFileProc },
1220 { "LoadGameProc", (XtActionProc) LoadGameProc },
1221 { "QuitProc", (XtActionProc) QuitProc },
1222 { "ForwardProc", (XtActionProc) ForwardProc },
1223 { "BackwardProc", (XtActionProc) BackwardProc },
1224 { "PauseProc", (XtActionProc) PauseProc },
1225 { "Iconify", (XtActionProc) Iconify },
1226 { "FileNameAction", (XtActionProc) FileNameAction },
1227 { "PieceMenuPopup", (XtActionProc) PieceMenuPopup },
1228 { "SetBlackToPlay", (XtActionProc) SetBlackToPlay },
1229 { "SetWhiteToPlay", (XtActionProc) SetWhiteToPlay }
1233 char translationsTable[] =
1234 "<Expose>: DrawPosition() \n \
1235 <Btn1Down>: HandleUserMove() \n \
1236 <Btn1Up>: HandleUserMove() \n \
1237 <Btn2Down>: XawPositionSimpleMenu(menuW) PieceMenuPopup(menuW) \n \
1238 <Btn3Down>: XawPositionSimpleMenu(menuB) PieceMenuPopup(menuB) \n \
1239 <Key>r: ResetFileProc() ResetProc() \n \
1240 <Key>R: ResetFileProc() ResetProc() \n \
1241 <Key>g: LoadGameProc() \n \
1242 <Key>G: LoadGameProc() \n \
1243 <Key>q: QuitProc() \n \
1244 <Key>Q: QuitProc() \n \
1245 <Message>WM_PROTOCOLS: QuitProc() \n \
1246 <Key>f: ForwardProc() \n \
1247 <Key>F: ForwardProc() \n \
1248 <Key>b: BackwardProc() \n \
1249 <Key>B: BackwardProc() \n \
1250 <Key>p: PauseProc() \n \
1251 <Key>P: PauseProc() \n \
1252 <Key>i: Iconify() \n \
1253 <Key>I: Iconify() \n \
1254 <Key>c: Iconify() \n \
1255 <Key>C: Iconify() \n";
1258 char translationsTableReduced[] =
1259 "<Expose>: DrawPosition() \n \
1260 <Btn1Down>: HandleUserMove() \n \
1261 <Btn1Up>: HandleUserMove() \n \
1262 <Message>WM_PROTOCOLS: QuitProc() \n";
1265 char blackTranslations[] = "<BtnDown>: SetBlackToPlay()\n";
1266 char whiteTranslations[] = "<BtnDown>: SetWhiteToPlay()\n";
1268 String xshogiResources[] =
1270 DEFAULT_FONT,
1271 "*Dialog*value.translations: #override "
1272 "\\n <Key>Return: FileNameAction()",
1273 NULL
1277 int global_argc; /* number of command args */
1278 char *global_argv[10]; /* pointers to up to 10 command args */
1282 static struct DisplayData *player;
1285 typedef struct
1287 char mode[2];
1288 char name[100];
1289 } FileModeInfo;
1291 static FileModeInfo fmi;
1295 * This is a hack that allows the parser to tell the program
1296 * that the game it's loading has ended.
1299 int loaded_game_finished = 0;
1302 /**********************************************************************
1304 * End of globals.
1306 **********************************************************************/
1309 void
1310 CreatePlayerWindow(void)
1312 int mainFontPxlSize, coordFontPxlSize;
1313 int min, sec, matched;
1314 XSetWindowAttributes window_attributes;
1315 char buf[MSG_SIZ];
1316 Arg args[10];
1317 Dimension timerWidth, boardWidth, commandsWidth, w, h;
1318 int local;
1319 int fromRemotePlayer = (player == &remotePlayer);
1321 player->monoMode = player->appData.monoMode;
1322 player->showCoords = player->appData.showCoords;
1325 * Parse timeControl resource.
1328 if (player->appData.timeControl != NULL)
1330 matched = sscanf(player->appData.timeControl, "%d:%d", &min, &sec);
1332 if (matched == 1)
1334 timeControl = min * 60 * 1000;
1336 else if (matched == 2)
1338 timeControl = (min * 60 + sec) * 1000;
1340 else
1342 fprintf(stderr, "%s: bad timeControl option %s\n",
1343 programName, player->appData.timeControl);
1344 Usage();
1349 * Parse searchTime resource
1352 if (player->appData.searchTime != NULL)
1354 matched = sscanf(player->appData.searchTime, "%d:%d", &min, &sec);
1356 if (matched == 1)
1358 searchTime = min * 60;
1360 else if (matched == 2)
1362 searchTime = min * 60 + sec;
1364 else
1366 fprintf(stderr, "%s: bad searchTime option %s\n",
1367 programName, player->appData.searchTime);
1368 Usage();
1372 if ((player->appData.searchTime != NULL)
1373 || (player->appData.searchDepth > 0)
1374 || player->appData.noShogiProgram)
1376 player->appData.clockMode = False;
1379 player->Iconic = False;
1380 player->boardSize = Small;
1381 player->squareSize = SMALL_SQUARE_SIZE;
1382 player->flipView = (player == &remotePlayer);
1383 player->promotionUp = False;
1386 * Determine boardSize.
1389 if (strcasecmp(player->appData.boardSize, "Large") == 0)
1391 player->boardSize = Large;
1393 else if (strcasecmp(player->appData.boardSize, "Medium") == 0)
1395 player->boardSize = Medium;
1397 else if (strcasecmp(player->appData.boardSize, "Small") == 0)
1399 player->boardSize = Small;
1401 else
1403 fprintf(stderr, "%s: bad boardSize option %s\n",
1404 programName, player->appData.boardSize);
1405 Usage();
1408 if ((local = (player == &localPlayer)))
1410 player->xDisplay = XtDisplay(player->shellWidget);
1411 player->xScreen = DefaultScreen(player->xDisplay);
1414 #undef DONT_ADJUST_BOARDSIZE
1415 #ifndef DONT_ADJUST_BOARDSIZE
1416 if (((DisplayWidth(player->xDisplay, player->xScreen) < 800)
1417 || (DisplayHeight(player->xDisplay, player->xScreen) < 800))
1418 && (player->boardSize == Large))
1420 player->boardSize = Medium;
1422 #endif
1424 switch (player->boardSize)
1426 case Small:
1427 player->squareSize = SMALL_SQUARE_SIZE;
1428 mainFontPxlSize = 11;
1429 coordFontPxlSize = 10;
1430 break;
1432 case Medium:
1433 player->squareSize = MEDIUM_SQUARE_SIZE;
1434 mainFontPxlSize = 17;
1435 coordFontPxlSize = 12;
1436 break;
1438 default:
1439 case Large:
1440 player->squareSize = LARGE_SQUARE_SIZE;
1441 mainFontPxlSize = 17;
1442 coordFontPxlSize = 14;
1443 break;
1447 * Detect if there are not enough colors are available and adapt.
1450 if (DefaultDepth(player->xDisplay, player->xScreen) <= 2)
1451 player->monoMode = True;
1454 * Determine what fonts to use.
1457 player->appData.mainFont
1458 = FindFont(player->appData.mainFont, mainFontPxlSize);
1459 player->mainFontID
1460 = XLoadFont(player->xDisplay, player->appData.mainFont);
1461 player->mainFontStruct
1462 = XQueryFont(player->xDisplay, player->mainFontID);
1463 player->appData.coordFont
1464 = FindFont(player->appData.coordFont, coordFontPxlSize);
1465 player->coordFontID
1466 = XLoadFont(player->xDisplay, player->appData.coordFont);
1467 player->coordFontStruct
1468 = XQueryFont(player->xDisplay, player->coordFontID);
1471 * Set default arguments.
1474 XtSetArg(player->shellArgs[0], XtNwidth, 0);
1475 XtSetArg(player->shellArgs[1], XtNheight, 0);
1476 XtSetArg(player->shellArgs[2], XtNminWidth, 0);
1477 XtSetArg(player->shellArgs[3], XtNminHeight, 0);
1478 XtSetArg(player->shellArgs[4], XtNmaxWidth, 0);
1479 XtSetArg(player->shellArgs[5], XtNmaxHeight, 0);
1481 XtSetArg(player->boardArgs[0], XtNborderWidth, 0);
1482 XtSetArg(player->boardArgs[1], XtNwidth,
1483 LINE_GAP + (BOARD_SIZE + 4)
1484 * (SMALL_SQUARE_SIZE + LINE_GAP));
1485 XtSetArg(player->boardArgs[2], XtNheight,
1486 LINE_GAP + BOARD_SIZE
1487 * (SMALL_SQUARE_SIZE + LINE_GAP));
1489 XtSetArg(player->commandsArgs[0], XtNborderWidth, 0);
1490 XtSetArg(player->commandsArgs[1], XtNdefaultColumns, 4);
1491 XtSetArg(player->commandsArgs[2], XtNforceColumns, True);
1492 XtSetArg(player->commandsArgs[3], XtNcolumnSpacing, 12);
1493 XtSetArg(player->commandsArgs[4], XtNlist, (XtArgVal) buttonStrings);
1494 XtSetArg(player->commandsArgs[5], XtNnumberStrings, buttonCount);
1495 XtSetArg(player->commandsArgs[6], XtNfont, player->mainFontStruct);
1497 XtSetArg(player->messageArgs[0], XtNborderWidth, 0);
1498 XtSetArg(player->messageArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1499 XtSetArg(player->messageArgs[2], XtNlabel, (XtArgVal) "starting...");
1501 XtSetArg(player->timerArgs[0], XtNborderWidth, 0);
1502 XtSetArg(player->timerArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1504 XtSetArg(player->titleArgs[0], XtNborderWidth, 0);
1505 XtSetArg(player->titleArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1507 boardWidth = LINE_GAP
1508 + (BOARD_SIZE + 4) * (player->squareSize + LINE_GAP);
1510 XtSetArg(player->boardArgs[1], XtNwidth, boardWidth);
1511 XtSetArg(player->boardArgs[2], XtNheight,
1512 LINE_GAP + BOARD_SIZE * (player->squareSize + LINE_GAP));
1515 * widget hierarchy
1518 player->formWidget = XtCreateManagedWidget("form",
1519 formWidgetClass,
1520 player->shellWidget, NULL, 0);
1522 player->widgetList[0] = player->blackTimerWidget
1523 = XtCreateWidget((local ? "black time:" : "rblack time:"),
1524 labelWidgetClass,
1525 player->formWidget, player->timerArgs,
1526 XtNumber(player->timerArgs));
1528 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1529 XtSetValues(player->blackTimerWidget, args, 1);
1531 player->widgetList[1] = player->whiteTimerWidget
1532 = XtCreateWidget((local ? "white time:" : "rwhite time:"),
1533 labelWidgetClass,
1534 player->formWidget, player->timerArgs,
1535 XtNumber(player->timerArgs));
1537 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1538 XtSetValues(player->whiteTimerWidget, args, 1);
1540 player->widgetList[2] = player->titleWidget
1541 = XtCreateWidget((local ? "" : "r"), labelWidgetClass,
1542 player->formWidget, player->titleArgs,
1543 XtNumber(player->titleArgs));
1545 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1546 XtSetValues(player->titleWidget, args, 1);
1548 player->widgetList[3] = player->messageWidget
1549 = XtCreateWidget((local ? "message" : "rmessage"),
1550 labelWidgetClass, player->formWidget,
1551 player->messageArgs,
1552 XtNumber(player->messageArgs));
1554 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1555 XtSetValues(player->messageWidget, args, 1);
1557 player->widgetList[4] = player->commandsWidget
1558 = XtCreateWidget((local ? "commands" : "rcommand"),
1559 listWidgetClass, player->formWidget,
1560 player->commandsArgs,
1561 XtNumber(player->commandsArgs));
1563 player->widgetList[5] = player->boardWidget
1564 = XtCreateWidget((local ? "board" : "rboard"),
1565 widgetClass, player->formWidget,
1566 player->boardArgs,
1567 XtNumber(player->boardArgs));
1569 XtManageChildren(player->widgetList, XtNumber(player->widgetList));
1572 * Calculate the width of the timer labels.
1575 XtSetArg(args[0], XtNfont, &player->mainFontStruct);
1576 XtGetValues(player->blackTimerWidget, args, 1);
1578 if (player->appData.clockMode)
1580 timerWidth = XTextWidth(player->mainFontStruct,
1581 "Black: 8:88:88 ", 15);
1583 else
1585 timerWidth = XTextWidth(player->mainFontStruct, "Black ", 7);
1588 XtSetArg(args[0], XtNwidth, timerWidth);
1589 XtSetValues(player->blackTimerWidget, args, 1);
1590 XtSetValues(player->whiteTimerWidget, args, 1);
1592 XtSetArg(args[0], XtNbackground, &player->timerForegroundPixel);
1593 XtSetArg(args[1], XtNforeground, &player->timerBackgroundPixel);
1594 XtGetValues(player->blackTimerWidget, args, 2);
1597 * Calculate the width of the name and message labels.
1600 XtSetArg(args[0], XtNwidth, &commandsWidth);
1601 XtGetValues(player->commandsWidget, args, 1);
1602 w = ((commandsWidth > boardWidth) ? commandsWidth : boardWidth);
1603 XtSetArg(args[0], XtNwidth, w - timerWidth * 2 - 12);
1604 XtSetValues(player->titleWidget, args, 1);
1605 XtSetArg(args[0], XtNwidth, w - 8);
1606 XtSetValues(player->messageWidget, args, 1);
1609 * 'formWidget' uses these constraints but they are stored
1610 * in the children.
1613 XtSetArg(args[0], XtNfromHoriz, player->blackTimerWidget);
1614 XtSetValues(player->whiteTimerWidget, args, 1);
1615 XtSetArg(args[0], XtNfromHoriz, player->whiteTimerWidget);
1616 XtSetValues(player->titleWidget, args, 1);
1617 XtSetArg(args[0], XtNfromVert, player->blackTimerWidget);
1618 XtSetValues(player->messageWidget, args, 1);
1619 XtSetArg(args[0], XtNfromVert, player->messageWidget);
1620 XtSetValues(player->commandsWidget, args, 1);
1621 XtSetArg(args[0], XtNfromVert, player->commandsWidget);
1622 XtSetValues(player->boardWidget, args, 1);
1624 XtRealizeWidget(player->shellWidget);
1626 player->xBoardWindow = XtWindow(player->boardWidget);
1629 * Create an icon.
1632 player->iconPixmap =
1633 XCreateBitmapFromData(player->xDisplay,
1634 XtWindow(player->shellWidget),
1635 (char *)icon_bits, icon_width, icon_height);
1637 XtSetArg(args[0], XtNiconPixmap, player->iconPixmap);
1638 XtSetValues(player->shellWidget, args, 1);
1641 * Create a cursor for the board widget.
1644 window_attributes.cursor = XCreateFontCursor(player->xDisplay, XC_hand2);
1645 XChangeWindowAttributes(player->xDisplay, player->xBoardWindow,
1646 CWCursor, &window_attributes);
1649 * Inhibit shell resizing.
1652 player->shellArgs[0].value = (XtArgVal) &w;
1653 player->shellArgs[1].value = (XtArgVal) &h;
1654 XtGetValues(player->shellWidget, player->shellArgs, 2);
1655 player->shellArgs[4].value = player->shellArgs[2].value = w;
1656 player->shellArgs[5].value = player->shellArgs[3].value = h;
1657 XtSetValues(player->shellWidget, &player->shellArgs[2], 4);
1660 * Determine value of black pixel.
1663 player->black_pixel_is_zero =
1664 (XBlackPixel(player->xDisplay, player->xScreen) == 0);
1666 CreateGCs();
1667 CreateGrid();
1668 CreatePieces();
1670 if (!fromRemotePlayer)
1671 CreatePieceMenus();
1673 XtAddCallback(player->commandsWidget, XtNcallback, SelectCommand,
1674 (XtPointer)fromRemotePlayer);
1676 if (!fromRemotePlayer)
1677 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1679 if (fromRemotePlayer)
1681 XtSetArg(args[0], XtNtranslations,
1682 XtParseTranslationTable(translationsTableReduced));
1683 /* Disable key commands because often keys are pressed
1684 in the board window if using another talk window. */
1685 XtSetValues(player->boardWidget, &args[0], 1);
1686 XtSetValues(localPlayer.boardWidget, &args[0], 1);
1688 else
1690 XtSetArg(args[0], XtNtranslations,
1691 XtParseTranslationTable(translationsTable));
1692 XtSetValues(player->boardWidget, &args[0], 1);
1693 XtSetArg(args[0], XtNtranslations,
1694 XtParseTranslationTable(blackTranslations));
1695 XtSetValues(player->blackTimerWidget, &args[0], 1);
1696 XtSetArg(args[0], XtNtranslations,
1697 XtParseTranslationTable(whiteTranslations));
1698 XtSetValues(player->whiteTimerWidget, &args[0], 1);
1701 XtAddEventHandler(player->boardWidget, ExposureMask | ButtonPressMask
1702 | ButtonReleaseMask | Button1MotionMask | KeyPressMask,
1703 False, (XtEventHandler)EventProc,
1704 (XtPointer)(player == &remotePlayer));
1706 sprintf(buf, "xshogi version %s based on "
1707 "xboard version %s",
1708 PACKAGE_VERSION, XBOARD_VERSION);
1711 * If there is to be a machine match, set it up.
1714 if (matchMode != MatchFalse && player != &remotePlayer)
1716 if (player->appData.noShogiProgram)
1718 fprintf(stderr,
1719 "%s: can't have a match with no shogi programs!\n",
1720 programName);
1721 exit(1);
1724 DisplayMessage(buf, fromRemotePlayer);
1725 TwoMachinesProc(NULL, NULL, NULL, NULL);
1727 else
1729 Reset(True);
1730 DisplayMessage(buf, fromRemotePlayer);
1738 main(int argc, char **argv)
1740 setbuf(stdout, NULL);
1741 setbuf(stderr, NULL);
1744 * Copy pointers to command line arguments and number of such pointers.
1745 * (argc, argv will be destroyed by XtAppInitialize)
1748 for (global_argc = 0; global_argc < argc; global_argc++)
1749 global_argv[global_argc] = argv[global_argc];
1751 programName = strrchr(argv[0], '/');
1753 if (programName == NULL)
1754 programName = argv[0];
1755 else
1756 programName++;
1758 localPlayer.shellWidget
1759 = XtAppInitialize(&appContext, "XShogi", shellOptions,
1760 XtNumber(shellOptions), &argc, argv,
1761 xshogiResources, NULL, 0);
1763 if (argc > 1)
1764 Usage();
1766 if ((shogiDir = (char *)getenv("SHOGIDIR")) == NULL)
1768 shogiDir = ".";
1770 else
1772 if (chdir(shogiDir) != 0)
1774 fprintf(stderr, "%s: can't cd to SHOGIDIR\n",
1775 programName);
1776 perror(shogiDir);
1777 exit(1);
1781 XtGetApplicationResources(localPlayer.shellWidget,
1782 &localPlayer.appData, clientResources,
1783 XtNumber(clientResources), NULL, 0);
1785 xshogiDebug = localPlayer.appData.debugMode;
1788 * Determine matchMode state -- poor man's resource converter.
1791 if (strcasecmp(localPlayer.appData.matchMode, "Init") == 0)
1793 matchMode = MatchInit;
1795 else if (strcasecmp(localPlayer.appData.matchMode, "Position") == 0)
1797 matchMode = MatchPosition;
1799 else if (strcasecmp(localPlayer.appData.matchMode, "Opening") == 0)
1801 matchMode = MatchOpening;
1803 else if (strcasecmp(localPlayer.appData.matchMode, "False") == 0)
1805 matchMode = MatchFalse;
1807 else
1809 fprintf(stderr, "%s: bad matchMode option %s\n",
1810 programName, localPlayer.appData.matchMode);
1811 Usage();
1814 buttonStrings = gnuButtonStrings;
1815 buttonProcs = gnuButtonProcs;
1816 buttonCount = XtNumber(gnuButtonStrings);
1818 player = &localPlayer;
1820 CreatePlayerWindow();
1822 XtAppMainLoop(appContext);
1824 return 0;
1830 * Find a font that matches "pattern" that is as close as
1831 * possible to the targetPxlSize. Prefer fonts that are k
1832 * pixels smaller to fonts that are k pixels larger. The
1833 * pattern must be in the X Consortium standard format,
1834 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1835 * The return value should be freed with XtFree when no
1836 * longer needed.
1839 char *
1840 FindFont(char *pattern, int targetPxlSize)
1842 char **fonts, *p, *best;
1843 int i, j, nfonts, minerr, err, pxlSize;
1845 fonts = XListFonts(player->xDisplay, pattern, 999999, &nfonts);
1847 if (nfonts < 1)
1849 fprintf(stderr, "%s: No fonts match pattern %s\n",
1850 programName, pattern);
1851 exit(1);
1854 best = "";
1855 minerr = 999999;
1857 for (i = 0; i < nfonts; i++)
1859 j = 0;
1860 p = fonts[i];
1862 if (*p != '-')
1863 continue;
1865 while (j < 7)
1867 if (*p == NULLCHAR)
1868 break;
1870 if (*p++ == '-')
1871 j++;
1874 if (j < 7)
1875 continue;
1877 pxlSize = atoi(p);
1879 if (pxlSize == targetPxlSize)
1881 best = fonts[i];
1882 break;
1885 err = pxlSize - targetPxlSize;
1887 if (abs(err) < abs(minerr)
1888 || ((minerr > 0) && (err < 0) && (-err == minerr)))
1890 best = fonts[i];
1891 minerr = err;
1895 p = (char *)XtMalloc(strlen(best) + 1);
1896 strcpy(p, best);
1897 XFreeFontNames(fonts);
1898 return p;
1904 void
1905 CreateGCs(void)
1907 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
1908 | GCBackground | GCFunction | GCPlaneMask;
1909 XGCValues gc_values;
1911 gc_values.plane_mask = AllPlanes;
1912 gc_values.line_width = LINE_GAP;
1913 gc_values.line_style = LineSolid;
1914 gc_values.function = GXcopy;
1916 gc_values.foreground = XBlackPixel(player->xDisplay, player->xScreen);
1917 gc_values.background = XBlackPixel(player->xDisplay, player->xScreen);
1918 player->lineGC = XtGetGC(player->shellWidget, value_mask, &gc_values);
1920 gc_values.background = XWhitePixel(player->xDisplay, player->xScreen);
1921 player->coordGC = XtGetGC(player->shellWidget, value_mask, &gc_values);
1922 XSetFont(player->xDisplay, player->coordGC, player->coordFontID);
1924 if (player->monoMode)
1926 gc_values.foreground
1927 = XWhitePixel(player->xDisplay, player->xScreen);
1928 gc_values.background
1929 = XWhitePixel(player->xDisplay, player->xScreen);
1931 /* empty square off board */
1932 player->squareOffBoardGC
1933 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1935 /* empty square on board */
1936 player->squareGC
1937 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1939 else
1941 Pixel bg; /* background color */
1942 Arg args[1];
1944 /* Get background color. */
1945 XtSetArg(args[0], XtNbackground, &bg);
1946 XtGetValues(player->shellWidget, args, 1);
1948 /* empty square off board */
1949 gc_values.foreground = gc_values.background = bg;
1950 player->squareOffBoardGC
1951 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1953 /* empty square on board */
1954 gc_values.foreground
1955 = player->appData.squareColor;
1956 gc_values.background
1957 = player->appData.squareColor;
1958 player->squareGC
1959 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1961 /* piece off board */
1962 gc_values.foreground
1963 = player->appData.pieceColor;
1964 gc_values.background = bg;
1965 player->oPieceGC
1966 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1968 /* piece on board */
1969 gc_values.foreground
1970 = player->appData.pieceColor;
1971 gc_values.background
1972 = player->appData.squareColor;
1973 player->pieceGC
1974 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1976 /* piece symbol */
1978 * FIXME: charPieceColor seems to have no effect;
1979 * the bitmap is *always* black.
1981 gc_values.function = (player->black_pixel_is_zero ? GXand : GXor);
1983 gc_values.foreground
1984 = player->appData.charPieceColor;
1985 gc_values.background
1986 = player->appData.charPieceColor;
1988 player->charPieceGC
1989 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1996 void
1997 CreatePieces(void)
1999 XSynchronize(player->xDisplay, True); /* Work-around for xlib/xt
2000 buffering bug */
2002 if (player->appData.westernPieceSet)
2004 ReadBitmap(player->appData.reverseBigSolidBitmap,
2005 &player->reverseBigSolidBitmap,
2006 NULL,
2007 bigsolidR_bits, bigsolidR_m_bits, bigsolidR_l_bits);
2009 ReadBitmap(player->appData.reverseSmallSolidBitmap,
2010 &player->reverseSmallSolidBitmap,
2011 NULL,
2012 smallsolidR_bits, smallsolidR_m_bits, smallsolidR_l_bits);
2014 ReadBitmap(player->appData.normalBigSolidBitmap,
2015 &player->normalBigSolidBitmap,
2016 NULL,
2017 bigsolid_bits, bigsolid_m_bits, bigsolid_l_bits);
2019 ReadBitmap(player->appData.normalSmallSolidBitmap,
2020 &player->normalSmallSolidBitmap,
2021 NULL,
2022 smallsolid_bits, smallsolid_m_bits, smallsolid_l_bits);
2024 ReadBitmap(player->appData.reversePawnBitmap,
2025 &player->reversePawnBitmap,
2026 &player->reverseSmallSolidBitmap,
2027 pawnRW_bits, pawnRW_bits, pawnRW_bits);
2029 ReadBitmap(player->appData.reverseLanceBitmap,
2030 &player->reverseLanceBitmap,
2031 &player->reverseSmallSolidBitmap,
2032 lanceRW_bits, lanceRW_bits, lanceRW_bits);
2034 ReadBitmap(player->appData.reverseKnightBitmap,
2035 &player->reverseKnightBitmap,
2036 &player->reverseSmallSolidBitmap,
2037 knightRW_bits, knightRW_bits, knightRW_bits);
2039 ReadBitmap(player->appData.reverseSilverBitmap,
2040 &player->reverseSilverBitmap,
2041 &player->reverseBigSolidBitmap,
2042 silverRW_bits, silverRW_bits, silverRW_bits);
2044 ReadBitmap(player->appData.reverseGoldBitmap,
2045 &player->reverseGoldBitmap,
2046 &player->reverseBigSolidBitmap,
2047 goldRW_bits, goldRW_bits, goldRW_bits);
2049 ReadBitmap(player->appData.reverseRookBitmap,
2050 &player->reverseRookBitmap,
2051 &player->reverseBigSolidBitmap,
2052 rookRW_bits, rookRW_bits, rookRW_bits);
2054 ReadBitmap(player->appData.reverseBishopBitmap,
2055 &player->reverseBishopBitmap,
2056 &player->reverseBigSolidBitmap,
2057 bishopRW_bits, bishopRW_bits, bishopRW_bits);
2059 ReadBitmap(player->appData.reversePPawnBitmap,
2060 &player->reversePPawnBitmap,
2061 &player->reverseSmallSolidBitmap,
2062 pawnPRW_bits, pawnPRW_bits, pawnPRW_bits);
2064 ReadBitmap(player->appData.reversePLanceBitmap,
2065 &player->reversePLanceBitmap,
2066 &player->reverseSmallSolidBitmap,
2067 lancePRW_bits, lancePRW_bits, lancePRW_bits);
2069 ReadBitmap(player->appData.reversePKnightBitmap,
2070 &player->reversePKnightBitmap,
2071 &player->reverseSmallSolidBitmap,
2072 knightPRW_bits, knightPRW_bits, knightPRW_bits);
2074 ReadBitmap(player->appData.reversePSilverBitmap,
2075 &player->reversePSilverBitmap,
2076 &player->reverseBigSolidBitmap,
2077 silverPRW_bits, silverPRW_bits, silverPRW_bits);
2079 ReadBitmap(player->appData.reversePRookBitmap,
2080 &player->reversePRookBitmap,
2081 &player->reverseBigSolidBitmap,
2082 rookPRW_bits, rookPRW_bits, rookPRW_bits);
2084 ReadBitmap(player->appData.reversePBishopBitmap,
2085 &player->reversePBishopBitmap,
2086 &player->reverseBigSolidBitmap,
2087 bishopPRW_bits, bishopPRW_bits, bishopPRW_bits);
2089 ReadBitmap(player->appData.reverseKingBitmap,
2090 &player->reverseKingBitmap,
2091 &player->reverseBigSolidBitmap,
2092 kingRW_bits, kingRW_bits, kingRW_bits);
2094 ReadBitmap(player->appData.normalPawnBitmap,
2095 &player->normalPawnBitmap,
2096 &player->normalSmallSolidBitmap,
2097 pawnW_bits, pawnW_bits, pawnW_bits);
2099 ReadBitmap(player->appData.normalLanceBitmap,
2100 &player->normalLanceBitmap,
2101 &player->normalSmallSolidBitmap,
2102 lanceW_bits, lanceW_bits, lanceW_bits);
2104 ReadBitmap(player->appData.normalKnightBitmap,
2105 &player->normalKnightBitmap,
2106 &player->normalSmallSolidBitmap,
2107 knightW_bits, knightW_bits, knightW_bits);
2109 ReadBitmap(player->appData.normalSilverBitmap,
2110 &player->normalSilverBitmap,
2111 &player->normalBigSolidBitmap,
2112 silverW_bits, silverW_bits, silverW_bits);
2114 ReadBitmap(player->appData.normalGoldBitmap,
2115 &player->normalGoldBitmap,
2116 &player->normalBigSolidBitmap,
2117 goldW_bits, goldW_bits, goldW_bits);
2119 ReadBitmap(player->appData.normalRookBitmap,
2120 &player->normalRookBitmap,
2121 &player->normalBigSolidBitmap,
2122 rookW_bits, rookW_bits, rookW_bits);
2124 ReadBitmap(player->appData.normalBishopBitmap,
2125 &player->normalBishopBitmap,
2126 &player->normalBigSolidBitmap,
2127 bishopW_bits, bishopW_bits, bishopW_bits);
2129 ReadBitmap(player->appData.normalPPawnBitmap,
2130 &player->normalPPawnBitmap,
2131 &player->normalSmallSolidBitmap,
2132 pawnPW_bits, pawnPW_bits, pawnPW_bits);
2134 ReadBitmap(player->appData.normalPLanceBitmap,
2135 &player->normalPLanceBitmap,
2136 &player->normalSmallSolidBitmap,
2137 lancePW_bits, lancePW_bits, lancePW_bits);
2139 ReadBitmap(player->appData.normalPKnightBitmap,
2140 &player->normalPKnightBitmap,
2141 &player->normalSmallSolidBitmap,
2142 knightPW_bits, knightPW_bits, knightPW_bits);
2144 ReadBitmap(player->appData.normalPSilverBitmap,
2145 &player->normalPSilverBitmap,
2146 &player->normalBigSolidBitmap,
2147 silverPW_bits, silverPW_bits, silverPW_bits);
2149 ReadBitmap(player->appData.normalPRookBitmap,
2150 &player->normalPRookBitmap,
2151 &player->normalBigSolidBitmap,
2152 rookPW_bits, rookPW_bits, rookPW_bits);
2154 ReadBitmap(player->appData.normalPBishopBitmap,
2155 &player->normalPBishopBitmap,
2156 &player->normalBigSolidBitmap,
2157 bishopPW_bits, bishopPW_bits, bishopPW_bits);
2159 ReadBitmap(player->appData.normalKingBitmap,
2160 &player->normalKingBitmap,
2161 &player->normalBigSolidBitmap,
2162 kingW_bits, kingW_bits, kingW_bits);
2164 else
2166 ReadBitmap(player->appData.reverseBigSolidBitmap,
2167 &player->reverseBigSolidBitmap,
2168 NULL,
2169 bigsolidR_bits, bigsolidR_m_bits, bigsolidR_l_bits);
2171 ReadBitmap(player->appData.reverseSmallSolidBitmap,
2172 &player->reverseSmallSolidBitmap,
2173 NULL,
2174 smallsolidR_bits, smallsolidR_m_bits, smallsolidR_l_bits);
2176 ReadBitmap(player->appData.normalBigSolidBitmap,
2177 &player->normalBigSolidBitmap,
2178 NULL,
2179 bigsolid_bits, bigsolid_m_bits, bigsolid_l_bits);
2181 ReadBitmap(player->appData.normalSmallSolidBitmap,
2182 &player->normalSmallSolidBitmap,
2183 NULL,
2184 smallsolid_bits, smallsolid_m_bits, smallsolid_l_bits);
2186 ReadBitmap(player->appData.reversePawnBitmap,
2187 &player->reversePawnBitmap,
2188 &player->reverseSmallSolidBitmap,
2189 pawnR_bits, pawnR_m_bits, pawnR_l_bits);
2191 ReadBitmap(player->appData.reverseLanceBitmap,
2192 &player->reverseLanceBitmap,
2193 &player->reverseSmallSolidBitmap,
2194 lanceR_bits, lanceR_m_bits, lanceR_l_bits);
2196 ReadBitmap(player->appData.reverseKnightBitmap,
2197 &player->reverseKnightBitmap,
2198 &player->reverseSmallSolidBitmap,
2199 knightR_bits, knightR_m_bits, knightR_l_bits);
2201 ReadBitmap(player->appData.reverseSilverBitmap,
2202 &player->reverseSilverBitmap,
2203 &player->reverseBigSolidBitmap,
2204 silverR_bits, silverR_m_bits, silverR_l_bits);
2206 ReadBitmap(player->appData.reverseGoldBitmap,
2207 &player->reverseGoldBitmap,
2208 &player->reverseBigSolidBitmap,
2209 goldR_bits, goldR_m_bits, goldR_l_bits);
2211 ReadBitmap(player->appData.reverseRookBitmap,
2212 &player->reverseRookBitmap,
2213 &player->reverseBigSolidBitmap,
2214 rookR_bits, rookR_m_bits, rookR_l_bits);
2216 ReadBitmap(player->appData.reverseBishopBitmap,
2217 &player->reverseBishopBitmap,
2218 &player->reverseBigSolidBitmap,
2219 bishopR_bits, bishopR_m_bits, bishopR_l_bits);
2221 ReadBitmap(player->appData.reversePPawnBitmap,
2222 &player->reversePPawnBitmap,
2223 &player->reverseSmallSolidBitmap,
2224 pawnPR_bits, pawnPR_m_bits, pawnPR_l_bits);
2226 ReadBitmap(player->appData.reversePLanceBitmap,
2227 &player->reversePLanceBitmap,
2228 &player->reverseSmallSolidBitmap,
2229 lancePR_bits, lancePR_m_bits, lancePR_l_bits);
2231 ReadBitmap(player->appData.reversePKnightBitmap,
2232 &player->reversePKnightBitmap,
2233 &player->reverseSmallSolidBitmap,
2234 knightPR_bits, knightPR_m_bits, knightPR_l_bits);
2236 ReadBitmap(player->appData.reversePSilverBitmap,
2237 &player->reversePSilverBitmap,
2238 &player->reverseBigSolidBitmap,
2239 silverPR_bits, silverPR_m_bits, silverPR_l_bits);
2241 ReadBitmap(player->appData.reversePRookBitmap,
2242 &player->reversePRookBitmap,
2243 &player->reverseBigSolidBitmap,
2244 rookPR_bits, rookPR_m_bits, rookPR_l_bits);
2246 ReadBitmap(player->appData.reversePBishopBitmap,
2247 &player->reversePBishopBitmap,
2248 &player->reverseBigSolidBitmap,
2249 bishopPR_bits, bishopPR_m_bits, bishopPR_l_bits);
2251 ReadBitmap(player->appData.reverseKingBitmap,
2252 &player->reverseKingBitmap,
2253 &player->reverseBigSolidBitmap,
2254 kingR_bits, kingR_m_bits, kingR_l_bits);
2256 ReadBitmap(player->appData.normalPawnBitmap,
2257 &player->normalPawnBitmap,
2258 &player->normalSmallSolidBitmap,
2259 pawn_bits, pawn_m_bits, pawn_l_bits);
2261 ReadBitmap(player->appData.normalLanceBitmap,
2262 &player->normalLanceBitmap,
2263 &player->normalSmallSolidBitmap,
2264 lance_bits, lance_m_bits, lance_l_bits);
2266 ReadBitmap(player->appData.normalKnightBitmap,
2267 &player->normalKnightBitmap,
2268 &player->normalSmallSolidBitmap,
2269 knight_bits, knight_m_bits, knight_l_bits);
2271 ReadBitmap(player->appData.normalSilverBitmap,
2272 &player->normalSilverBitmap,
2273 &player->normalBigSolidBitmap,
2274 silver_bits, silver_m_bits, silver_l_bits);
2276 ReadBitmap(player->appData.normalGoldBitmap,
2277 &player->normalGoldBitmap,
2278 &player->normalBigSolidBitmap,
2279 gold_bits, gold_m_bits, gold_l_bits);
2281 ReadBitmap(player->appData.normalRookBitmap,
2282 &player->normalRookBitmap,
2283 &player->normalBigSolidBitmap,
2284 rook_bits, rook_m_bits, rook_l_bits);
2286 ReadBitmap(player->appData.normalBishopBitmap,
2287 &player->normalBishopBitmap,
2288 &player->normalBigSolidBitmap,
2289 bishop_bits, bishop_m_bits, bishop_l_bits);
2291 ReadBitmap(player->appData.normalPPawnBitmap,
2292 &player->normalPPawnBitmap,
2293 &player->normalSmallSolidBitmap,
2294 pawnP_bits, pawnP_m_bits, pawnP_l_bits);
2296 ReadBitmap(player->appData.normalPLanceBitmap,
2297 &player->normalPLanceBitmap,
2298 &player->normalSmallSolidBitmap,
2299 lanceP_bits, lanceP_m_bits, lanceP_l_bits);
2301 ReadBitmap(player->appData.normalPKnightBitmap,
2302 &player->normalPKnightBitmap,
2303 &player->normalSmallSolidBitmap,
2304 knightP_bits, knightP_m_bits, knightP_l_bits);
2306 ReadBitmap(player->appData.normalPSilverBitmap,
2307 &player->normalPSilverBitmap,
2308 &player->normalBigSolidBitmap,
2309 silverP_bits, silverP_m_bits, silverP_l_bits);
2311 ReadBitmap(player->appData.normalPRookBitmap,
2312 &player->normalPRookBitmap,
2313 &player->normalBigSolidBitmap,
2314 rookP_bits, rookP_m_bits, rookP_l_bits);
2316 ReadBitmap(player->appData.normalPBishopBitmap,
2317 &player->normalPBishopBitmap,
2318 &player->normalBigSolidBitmap,
2319 bishopP_bits, bishopP_m_bits, bishopP_l_bits);
2321 ReadBitmap(player->appData.normalKingBitmap,
2322 &player->normalKingBitmap,
2323 &player->normalBigSolidBitmap,
2324 king_bits, king_m_bits, king_l_bits);
2328 XSynchronize(player->xDisplay, False); /* Work-around for xlib/xt
2329 buffering bug */
2336 ReadBitmapFile(Display *display, Drawable d, char *filename,
2337 unsigned int *width_return,
2338 unsigned int *height_return,
2339 Pixmap *bitmap_return,
2340 int *x_hot_return, int *y_hot_return)
2342 int n;
2344 if ((n = XReadBitmapFile(display, d, filename,
2345 width_return, height_return,
2346 bitmap_return, x_hot_return, y_hot_return))
2347 != BitmapSuccess)
2349 return n;
2351 else
2353 /* transform a 1 plane pixmap to a k plane pixmap */
2354 return BitmapSuccess;
2362 * Create the X pixmap from .xbm file bitmap data. This may
2363 * have to be revised considerably.
2366 void
2367 ReadBitmap(String name, Pixmap *pm, Pixmap *qm,
2368 unsigned char *small_bits,
2369 unsigned char *medium_bits,
2370 unsigned char *large_bits)
2372 int x_hot, y_hot;
2373 unsigned int w, h;
2375 if ((name == NULL)
2376 || (ReadBitmapFile(player->xDisplay, player->xBoardWindow, name,
2377 &w, &h, pm, &x_hot, &y_hot) != BitmapSuccess)
2378 || (w != player->squareSize)
2379 || (h != player->squareSize))
2381 unsigned long fg, bg;
2382 unsigned int depth;
2384 depth = DisplayPlanes(player->xDisplay, player->xScreen);
2386 if (player->monoMode)
2388 fg = XBlackPixel(player->xDisplay, player->xScreen);
2389 bg = XWhitePixel(player->xDisplay, player->xScreen);
2391 else if (qm == NULL)
2393 fg = player->appData.oneColor;
2394 bg = player->appData.zeroColor;
2396 else
2398 fg = (player->black_pixel_is_zero ? 0 : ~0);
2399 bg = (player->black_pixel_is_zero ? ~0 : 0);
2402 switch (player->boardSize)
2404 case Large:
2405 *pm = XCreatePixmapFromBitmapData(player->xDisplay,
2406 player->xBoardWindow,
2407 (char *)large_bits,
2408 player->squareSize,
2409 player->squareSize,
2410 fg, bg, depth);
2411 break;
2413 case Medium:
2414 *pm = XCreatePixmapFromBitmapData(player->xDisplay,
2415 player->xBoardWindow,
2416 (char *)medium_bits,
2417 player->squareSize,
2418 player->squareSize,
2419 fg, bg, depth);
2420 break;
2422 case Small:
2423 *pm = XCreatePixmapFromBitmapData(player->xDisplay,
2424 player->xBoardWindow,
2425 (char *)small_bits,
2426 player->squareSize,
2427 player->squareSize,
2428 fg, bg, depth);
2429 break;
2437 void
2438 CreateGrid(void)
2440 int i, offset;
2442 offset = 2 * (player->squareSize + LINE_GAP);
2444 for (i = 0; i < BOARD_SIZE + 1; i++)
2446 player->gridSegments[i].x1 = offset;
2447 player->gridSegments[i + BOARD_SIZE + 1].y1 = 0;
2448 player->gridSegments[i].y1 = player->gridSegments[i].y2
2449 = LINE_GAP / 2 + (i * (player->squareSize + LINE_GAP));
2450 player->gridSegments[i].x2 = LINE_GAP + BOARD_SIZE *
2451 (player->squareSize + LINE_GAP) + offset;
2452 player->gridSegments[i + BOARD_SIZE + 1].x1
2453 = player->gridSegments[i + BOARD_SIZE + 1].x2 = LINE_GAP / 2
2454 + (i * (player->squareSize + LINE_GAP)) + offset;
2455 player->gridSegments[i + BOARD_SIZE + 1].y2
2456 = BOARD_SIZE * (player->squareSize + LINE_GAP);
2463 void
2464 CreatePieceMenus(void)
2466 int i;
2467 Widget entry;
2468 Arg args[1];
2469 ShogiSquare selection;
2471 XtSetArg(args[0], XtNlabel, "Black");
2472 blackPieceMenu = XtCreatePopupShell("menuW", simpleMenuWidgetClass,
2473 localPlayer.boardWidget, args, 1);
2475 for (i = 0; i < PIECE_MENU_SIZE; i++)
2477 String item = pieceMenuStrings[i];
2479 if (strcmp(item, "----") == 0)
2481 entry = XtCreateManagedWidget(item, smeLineObjectClass,
2482 blackPieceMenu, NULL, 0);
2484 else
2486 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
2487 blackPieceMenu, NULL, 0);
2488 selection = pieceMenuTranslation[0][i];
2489 XtAddCallback(entry, XtNcallback,
2490 (XtCallbackProc)PieceMenuSelect,
2491 (XtPointer)selection);
2493 if (selection == BlackPawn)
2495 XtSetArg(args[0], XtNpopupOnEntry, entry);
2496 XtSetValues(blackPieceMenu, args, 1);
2501 XtSetArg(args[0], XtNlabel, "White");
2502 whitePieceMenu = XtCreatePopupShell("menuB", simpleMenuWidgetClass,
2503 localPlayer.boardWidget, args, 1);
2505 for (i = 0; i < PIECE_MENU_SIZE; i++)
2507 String item = pieceMenuStrings[i];
2509 if (strcmp(item, "----") == 0)
2511 entry = XtCreateManagedWidget(item, smeLineObjectClass,
2512 whitePieceMenu, NULL, 0);
2514 else
2516 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
2517 whitePieceMenu, NULL, 0);
2518 selection = pieceMenuTranslation[1][i];
2519 XtAddCallback(entry, XtNcallback,
2520 (XtCallbackProc)PieceMenuSelect,
2521 (XtPointer)selection);
2523 if (selection == WhitePawn)
2525 XtSetArg(args[0], XtNpopupOnEntry, entry);
2526 XtSetValues(whitePieceMenu, args, 1);
2531 XtRegisterGrabAction(PieceMenuPopup, True,
2532 (unsigned)(ButtonPressMask|ButtonReleaseMask),
2533 GrabModeAsync, GrabModeAsync);
2539 void
2540 PieceMenuPopup(Widget w, XEvent *event, String *params, Cardinal *num_params)
2542 if (event->type != ButtonPress)
2543 return;
2545 if (gameMode != EditPosition)
2546 return;
2548 if (((pmFromX = EventToXSquare(event->xbutton.x)) < 1)
2549 || (pmFromX > BOARD_SIZE + 2)
2550 || ((pmFromY = EventToSquare(event->xbutton.y)) < 0))
2552 pmFromX = pmFromY = -1;
2553 return;
2556 if (localPlayer.flipView)
2557 pmFromX = BOARD_SIZE + 3 - pmFromX;
2558 else
2559 pmFromY = BOARD_SIZE - 1 - pmFromY;
2561 XtPopupSpringLoaded(XtNameToWidget(localPlayer.boardWidget, params[0]));
2567 static void
2568 PieceMenuSelect(Widget w, ShogiSquare piece, char *junk)
2570 if ((pmFromX < 0) || (pmFromY < 0))
2571 return;
2573 if (off_board(pmFromX))
2575 int i, c;
2576 switch (piece)
2578 case ClearBoard:
2579 break;
2581 case BlackPlay:
2582 break;
2584 case WhitePlay:
2585 break;
2587 default:
2588 i = pieceToCatchedIndex[piece];
2589 c = (piece >= WhitePawn);
2590 catches[0][c][i]++;
2591 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2592 XSync(localPlayer.xDisplay, False);
2593 return;
2597 pmFromX -= 2;
2599 switch (piece)
2601 case ClearBoard:
2602 for (pmFromY = 0; pmFromY < BOARD_SIZE; pmFromY++)
2603 for (pmFromX = 0; pmFromX < BOARD_SIZE; pmFromX++)
2604 boards[0][pmFromY][pmFromX] = EmptySquare;
2606 ClearCatches(catches[0]);
2607 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2608 break;
2610 case BlackPlay: /* not currently on menu */
2611 SetBlackToPlay();
2612 break;
2614 case WhitePlay: /* not currently on menu */
2615 SetWhiteToPlay();
2616 break;
2618 default:
2619 boards[0][pmFromY][pmFromX] = piece;
2620 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2621 break;
2624 XSync(localPlayer.xDisplay, False);
2630 static void
2631 SetBlackToPlay(void)
2633 int saveCM;
2635 if (gameMode != EditPosition)
2636 return;
2638 whitePlaysFirst = False;
2639 saveCM = currentMove;
2640 currentMove = 0; /* kludge */
2641 DisplayClocks(ReDisplayTimers);
2642 currentMove = saveCM;
2648 static void
2649 SetWhiteToPlay(void)
2651 int saveCM;
2653 if (gameMode != EditPosition)
2654 return;
2656 whitePlaysFirst = True;
2657 saveCM = currentMove;
2658 currentMove = 1; /* kludge */
2659 DisplayClocks(ReDisplayTimers);
2660 currentMove = saveCM;
2667 * If the user selects on a border boundary or off the board, return failure.
2668 * Otherwise map the event coordinate to the square.
2672 EventToSquare(int x)
2674 if (x < LINE_GAP)
2675 return -1;
2677 x -= LINE_GAP;
2679 if ((x % (player->squareSize + LINE_GAP)) >= player->squareSize)
2680 return -1;
2682 x /= (player->squareSize + LINE_GAP);
2684 if (x >= BOARD_SIZE)
2685 return -1;
2687 return x;
2694 EventToXSquare(int x)
2696 if (x < LINE_GAP)
2697 return -1;
2699 x -= LINE_GAP;
2701 if ((x % (player->squareSize + LINE_GAP)) >= player->squareSize)
2702 return -1;
2704 x /= (player->squareSize + LINE_GAP);
2706 if (x >= BOARD_SIZE + 4)
2707 return -1;
2709 return x;
2715 ShogiSquare
2716 CharToPiece(int c, int p)
2718 if (p)
2720 switch (c)
2722 default:
2723 case '.': return EmptySquare;
2724 case 'P': return BlackPPawn;
2725 case 'L': return BlackPLance;
2726 case 'N': return BlackPKnight;
2727 case 'S': return BlackPSilver;
2728 case 'G': return BlackGold;
2729 case 'R': return BlackPRook;
2730 case 'B': return BlackPBishop;
2731 case 'K': return BlackKing;
2732 case 'p': return WhitePPawn;
2733 case 'l': return WhitePLance;
2734 case 'n': return WhitePKnight;
2735 case 's': return WhitePSilver;
2736 case 'g': return WhiteGold;
2737 case 'r': return WhitePRook;
2738 case 'b': return WhitePBishop;
2739 case 'k': return WhiteKing;
2742 else
2744 switch (c)
2746 default:
2747 case '.': return EmptySquare;
2748 case 'P': return BlackPawn;
2749 case 'L': return BlackLance;
2750 case 'N': return BlackKnight;
2751 case 'S': return BlackSilver;
2752 case 'G': return BlackGold;
2753 case 'R': return BlackRook;
2754 case 'B': return BlackBishop;
2755 case 'K': return BlackKing;
2756 case 'p': return WhitePawn;
2757 case 'l': return WhiteLance;
2758 case 'n': return WhiteKnight;
2759 case 's': return WhiteSilver;
2760 case 'g': return WhiteGold;
2761 case 'r': return WhiteRook;
2762 case 'b': return WhiteBishop;
2763 case 'k': return WhiteKing;
2772 * Convert coordinates to normal algebraic notation.
2773 * promoPiece must be NULLCHAR if not a promotion.
2776 ShogiMove
2777 MakeAlg(int fromX, int fromY, int toX, int toY,
2778 char promoPiece, int currentBoardIndex, char *out)
2780 ShogiSquare piece;
2781 char *outp = out;
2783 if (fromX > 80)
2785 piece = (fromX - 81);
2786 *outp++ = catchedIndexToChar[piece];
2787 *outp++ = '*';
2788 *outp++ = '9' - toX;
2789 *outp++ = 'i' - toY;
2790 *outp++ = NULLCHAR;
2791 return (BlackOnMove(forwardMostMove) ? BlackDrop : WhiteDrop);
2793 else
2795 *outp++ = '9' - fromX;
2796 *outp++ = 'i' - fromY;
2797 *outp++ = '9' - toX;
2798 *outp++ = 'i' - toY;
2799 *outp++ = promoPiece;
2800 *outp++ = NULLCHAR;
2802 if (promoPiece == NULLCHAR)
2804 return NormalMove;
2806 else
2808 return (BlackOnMove(forwardMostMove)
2809 ? BlackPromotion : WhitePromotion);
2817 void
2818 DrawSquare(int row, int column, ShogiSquare piece)
2820 int square_color, x, y, direction, font_ascent, font_descent;
2821 char string[2];
2822 XCharStruct overall;
2823 struct DisplayData *player;
2825 for (player = &localPlayer; True; player = &remotePlayer)
2827 int offset, remote;
2829 remote = (player == &remotePlayer);
2830 offset = 2 * (player->squareSize + LINE_GAP);
2832 if (player->flipView)
2834 x = LINE_GAP + ((BOARD_SIZE - 1) - column) *
2835 (player->squareSize + LINE_GAP) + offset;
2836 y = LINE_GAP + row * (player->squareSize + LINE_GAP);
2838 else
2840 x = LINE_GAP + column * (player->squareSize + LINE_GAP) + offset;
2841 y = LINE_GAP + ((BOARD_SIZE - 1) - row) *
2842 (player->squareSize + LINE_GAP);
2845 square_color = (((column + row) % 2) ? LIGHT : DARK);
2847 if (piece == EmptySquare)
2849 if (column < 0 || column >= BOARD_SIZE)
2851 /* empty square off board */
2852 XFillRectangle(player->xDisplay, player->xBoardWindow,
2853 player->squareOffBoardGC,
2854 x, y, player->squareSize,
2855 player->squareSize);
2857 else
2859 /* empty square on board */
2860 XFillRectangle(player->xDisplay,
2861 player->xBoardWindow,
2862 player->squareGC,
2863 x, y,
2864 player->squareSize,
2865 player->squareSize);
2868 else if (player->monoMode) /* Draw a piece in mono mode. */
2870 XCopyArea(player->xDisplay,
2871 ((((((int)piece) < ((int)WhitePawn)))
2872 ^ player->flipView)
2873 ? *pieceToNormal[remote][(int)piece]
2874 : *pieceToReverse[remote][(int)piece]),
2875 player->xBoardWindow,
2876 (player->monoMode
2877 ? player->squareOffBoardGC /* ??? FIXME? */
2878 : player->pieceGC),
2879 0, 0,
2880 player->squareSize, player->squareSize, x, y);
2882 else /* Draw a piece in color mode. */
2884 if ((column < 0) || (column >= BOARD_SIZE)) /* off board */
2886 /* draw piece background */
2888 XCopyPlane(player->xDisplay,
2889 ((((((int)piece) < ((int)WhitePawn)))
2890 ^ player->flipView)
2891 ? *pieceToNormalSolid[remote][(int)piece]
2892 : *pieceToReverseSolid[remote][(int)piece]),
2893 player->xBoardWindow,
2894 player->oPieceGC,
2895 0, 0,
2896 player->squareSize, player->squareSize, x, y, 1);
2898 /* draw piece bitmap */
2900 XCopyArea(player->xDisplay,
2901 ((((((int)piece) < ((int)WhitePawn)))
2902 ^ player->flipView)
2903 ? *pieceToNormal[remote][(int)piece]
2904 : *pieceToReverse[remote][(int)piece]),
2905 player->xBoardWindow,
2906 player->charPieceGC,
2907 0, 0,
2908 player->squareSize, player->squareSize, x, y);
2910 else /* on board */
2912 /* draw piece background */
2914 XCopyPlane(player->xDisplay,
2915 ((((((int)piece) < ((int)WhitePawn)))
2916 ^ player->flipView)
2917 ? *pieceToNormalSolid[remote][(int)piece]
2918 : *pieceToReverseSolid[remote][(int)piece]),
2919 player->xBoardWindow,
2920 player->pieceGC,
2921 0, 0,
2922 player->squareSize, player->squareSize, x, y, 1);
2924 /* draw piece bitmap */
2926 XCopyArea(player->xDisplay,
2927 ((((((int)piece) < ((int)WhitePawn)))
2928 ^ player->flipView)
2929 ? *pieceToNormal[remote][(int)piece]
2930 : *pieceToReverse[remote][(int)piece]),
2931 player->xBoardWindow,
2932 player->charPieceGC,
2933 0, 0,
2934 player->squareSize, player->squareSize, x, y);
2938 string[1] = NULLCHAR;
2940 if (player->showCoords
2941 && (column >= 0) && (column < 9)
2942 && (row == (player->flipView ? 8 : 0)))
2944 string[0] = '9' - column;
2945 XTextExtents(player->coordFontStruct, string, 1, &direction,
2946 &font_ascent, &font_descent, &overall);
2948 if (player->monoMode)
2950 XDrawImageString(player->xDisplay,
2951 player->xBoardWindow, player->coordGC,
2952 x + player->squareSize - overall.width - 2,
2953 y + player->squareSize - font_descent - 1,
2954 string, 1);
2956 else
2958 XDrawString(player->xDisplay, player->xBoardWindow,
2959 player->coordGC,
2960 x + player->squareSize - overall.width - 2,
2961 y + player->squareSize - font_descent - 1,
2962 string, 1);
2966 if (player->showCoords
2967 && (row >= 0) && (row < 9)
2968 && (column == (player->flipView ? 8 : 0)))
2970 string[0] = 'i' - row;
2971 XTextExtents(player->coordFontStruct, string, 1, &direction,
2972 &font_ascent, &font_descent, &overall);
2974 if (player->monoMode)
2976 XDrawImageString(player->xDisplay,
2977 player->xBoardWindow, player->coordGC,
2978 x + 2, y + font_ascent + 1, string, 1);
2980 else
2982 XDrawString(player->xDisplay, player->xBoardWindow,
2983 player->coordGC,
2984 x + 2, y + font_ascent + 1, string, 1);
2988 if (!updateRemotePlayer || (player == &remotePlayer))
2989 break;
2996 void
2997 EventProc(Widget widget, XtPointer client_data, XEvent *event)
2999 if (event->type == MappingNotify)
3001 XRefreshKeyboardMapping((XMappingEvent *) event);
3002 return;
3005 if (!XtIsRealized(widget))
3006 return;
3008 if ((event->type == ButtonPress) || (event->type == ButtonRelease))
3010 if (event->xbutton.button != Button1)
3011 return;
3014 switch (event->type)
3016 case Expose:
3017 DrawPosition(widget, event, NULL, NULL);
3018 break;
3020 default:
3021 return;
3029 * event handler for redrawing the board
3032 void
3033 DrawPosition(Widget w, XEvent *event, String *prms, Cardinal *nprms)
3035 Arg args[1];
3036 int i, j;
3037 static Board lastBoard;
3038 static Catched lastCatches;
3039 static int lastBoardValid = 0;
3040 static int lastFlipView = 0, lastRemoteFlipView = 1;
3042 if (!player->Iconic)
3044 XtSetArg(args[0], XtNiconic, False);
3045 XtSetValues(localPlayer.shellWidget, args, 1);
3049 * It would be simpler to clear the window with XClearWindow()
3050 * but this causes a very distracting flicker.
3053 if ((w == localPlayer.boardWidget)
3054 && (event == NULL)
3055 && lastBoardValid
3056 && (lastFlipView == localPlayer.flipView)
3057 && (!updateRemotePlayer
3058 || (lastRemoteFlipView == remotePlayer.flipView)))
3060 for (i = 0; i < BOARD_SIZE; i++)
3062 for (j = 0; j < BOARD_SIZE; j++)
3064 if (boards[currentMove][i][j] != lastBoard[i][j])
3065 DrawSquare(i, j, boards[currentMove][i][j]);
3069 for (i = 0; i < 2; i++)
3071 for (j = 0; j < 8; j++)
3073 if (catches[currentMove][i][j] != lastCatches[i][j])
3075 UpdateCatched(i, 0, False, True, currentMove);
3076 break;
3081 else
3083 XDrawSegments(localPlayer.xDisplay,
3084 localPlayer.xBoardWindow, localPlayer.lineGC,
3085 localPlayer.gridSegments, (BOARD_SIZE + 1) * 2);
3087 if (updateRemotePlayer)
3089 XDrawSegments(remotePlayer.xDisplay,
3090 remotePlayer.xBoardWindow, remotePlayer.lineGC,
3091 remotePlayer.gridSegments, (BOARD_SIZE + 1) * 2);
3094 for (i = 0; i < BOARD_SIZE; i++)
3095 for (j = 0; j < BOARD_SIZE; j++)
3096 DrawSquare(i, j, boards[currentMove][i][j]);
3098 UpdateCatched(0, 0, False, True, currentMove);
3099 UpdateCatched(1, 0, False, True, currentMove);
3102 CopyBoard(lastBoard, boards[currentMove]);
3103 CopyCatches(lastCatches, catches[currentMove]);
3104 lastBoardValid = 1;
3105 lastFlipView = localPlayer.flipView;
3107 if (updateRemotePlayer)
3108 lastRemoteFlipView = remotePlayer.flipView;
3110 XSync(localPlayer.xDisplay, False);
3112 if (updateRemotePlayer)
3113 XSync(remotePlayer.xDisplay, False);
3119 void
3120 InitPosition(int redraw)
3122 currentMove = forwardMostMove = backwardMostMove = 0;
3123 CopyBoard(boards[0], initialPosition);
3124 ClearCatches(catches[0]);
3126 if (redraw)
3127 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3133 void
3134 CopyBoard(Board to, Board from)
3136 int i, j;
3138 for (i = 0; i < BOARD_SIZE; i++)
3139 for (j = 0; j < BOARD_SIZE; j++)
3140 to[i][j] = from[i][j];
3146 void
3147 CopyCatches(Catched to, Catched from)
3149 int i, j;
3151 for (i = 0; i < 2; i++)
3152 for (j = 0; j < 8; j++)
3153 to[i][j] = from[i][j];
3159 void
3160 SendCurrentBoard(FILE *fp)
3162 SendBoard(fp, boards[currentMove], catches[currentMove]);
3168 void
3169 SendBoard(FILE *fp, Board board, Catched catches)
3171 char message[MSG_SIZ];
3172 ShogiSquare *bp;
3173 int i, j;
3175 SendToProgram("edit\n", fp);
3176 SendToProgram("#\n", fp);
3178 for (i = BOARD_SIZE - 1; i >= 0; i--)
3180 bp = &board[i][0];
3182 for (j = 0; j < BOARD_SIZE; j++, bp++)
3184 if (((int) *bp) < (int)WhitePawn)
3186 sprintf(message, "%c%c%c%s\n",
3187 pieceToChar[(int) *bp],
3188 '9' - j, 'i' - i,
3189 (pieceIsPromoted[(int) *bp] ? "+" : ""));
3190 SendToProgram(message, fp);
3195 for (i = 0; i <= 7; i++)
3197 int n;
3199 for (n = catches[0][i]; n > 0; n--)
3201 sprintf(message, "%c*\n",
3202 catchedIndexToChar[i]);
3203 SendToProgram(message, fp);
3207 SendToProgram("c\n", fp);
3209 for (i = BOARD_SIZE - 1; i >= 0; i--)
3211 bp = &board[i][0];
3213 for (j = 0; j < BOARD_SIZE; j++, bp++)
3215 if ((((int) *bp) != ((int)EmptySquare))
3216 && (((int) *bp) >= ((int)WhitePawn)))
3218 sprintf(message, "%c%c%c%s\n",
3219 pieceToChar[((int) *bp) - ((int)WhitePawn)],
3220 '9' - j, 'i' - i,
3221 (pieceIsPromoted[(int) *bp] ? "+" : ""));
3222 SendToProgram(message, fp);
3227 for (i = 0; i <= 7; i++)
3229 int n;
3231 for (n = catches[1][i]; n > 0; n--)
3233 sprintf(message, "%c*\n",
3234 catchedIndexToChar[i]);
3235 SendToProgram(message, fp);
3239 SendToProgram(".\n", fp);
3245 static int
3246 PromotionPossible(int fromY, int toY, ShogiSquare piece)
3248 if (((int)piece) < ((int)WhitePawn))
3250 if ((fromY < 6) && (toY < 6))
3251 return False;
3253 else
3255 if ((fromY > 2) && (toY > 2))
3256 return False;
3259 return piecePromotable[(int)piece];
3266 static void
3267 ShowCount(int row, int column, int n)
3269 int offset = 2 * (player->squareSize + LINE_GAP);
3270 int x, y, direction, font_ascent, font_descent;
3271 char string[2];
3272 XCharStruct overall;
3273 struct DisplayData *player;
3275 DrawSquare(row, column, EmptySquare);
3277 if (n <= 1)
3278 return;
3280 for (player = &localPlayer; True; player = &remotePlayer)
3282 if (player->flipView)
3284 x = LINE_GAP + ((BOARD_SIZE - 1) - column) *
3285 (player->squareSize + LINE_GAP) + offset;
3286 y = LINE_GAP + row * (player->squareSize + LINE_GAP);
3288 else
3290 x = LINE_GAP + column * (player->squareSize + LINE_GAP) + offset;
3291 y = LINE_GAP + ((BOARD_SIZE - 1) - row) *
3292 (player->squareSize + LINE_GAP);
3295 x -= player->squareSize / 2;
3297 string[1] = NULLCHAR;
3299 if (n > 9)
3300 string[0] = '*';
3301 else
3302 string[0] = '0' + n;
3304 XTextExtents(player->coordFontStruct, string, 1, &direction,
3305 &font_ascent, &font_descent, &overall);
3307 if (player->monoMode)
3309 XDrawImageString(player->xDisplay, player->xBoardWindow,
3310 player->coordGC,
3311 x + player->squareSize - overall.width - 2,
3312 y + player->squareSize - font_descent - 1,
3313 string, 1);
3315 else
3317 XDrawString(player->xDisplay, player->xBoardWindow,
3318 player->coordGC,
3319 x + player->squareSize - overall.width - 2,
3320 y + player->squareSize - font_descent - 1,
3321 string, 1);
3324 if (!updateRemotePlayer || (player == &remotePlayer))
3325 break;
3332 void
3333 UpdateCatched(int Color, int Figure, int Drop, int DropAll, int currentMove)
3335 int n, F;
3336 int x, y;
3338 /* Determine first row and column. */
3340 if (Color)
3342 x = -1;
3343 y = BOARD_SIZE - 1;
3345 else
3347 x = BOARD_SIZE;
3348 y = 0;
3351 if (DropAll)
3352 n = 0;
3353 else
3354 n = catches[currentMove][Color][Figure];
3356 /* Update the display for captured pieces
3357 if no piece of the dropped type is there (Drop && n==1)
3358 or if a piece type is removed (NOT Drop && n==0).
3359 In the other cases update only the count. */
3361 if (DropAll || (Drop && (n == 1)) || (!Drop && (n == 0)))
3363 /* show all captured pieces */
3364 n = 0;
3366 for (F = pawn; F <= king; F++)
3368 int c;
3370 if ((c = catches[currentMove][Color][F]) > 0)
3372 n++;
3373 DrawSquare(y, x, catchedIndexToPiece[Color][F]);
3374 ShowCount(y, (Color ? (x - 1) : (x + 1)), c);
3376 if (Color)
3377 y--;
3378 else
3379 y++;
3383 if (DropAll)
3385 for (; n < 9; n++)
3387 DrawSquare(y, x, EmptySquare);
3388 ShowCount(y, (Color ? (x - 1) : (x + 1)), 0);
3390 if (Color)
3391 y--;
3392 else
3393 y++;
3396 else if (!Drop)
3398 /* remove one line! */
3399 DrawSquare(y, x, EmptySquare);
3400 ShowCount(y, (Color ? (x - 1) : (x + 1)), 0);
3403 else
3405 /* show the actual count */
3406 for (F = pawn; F <= Figure - 1; F++)
3408 if (catches[currentMove][Color][F] > 0)
3410 if (Color)
3411 y--;
3412 else
3413 y++;
3417 ShowCount(y, (Color ? (x - 1) : (x + 1)), n);
3424 #ifdef BLINK_COUNT
3426 static int BlinkCount = 0;
3427 static int BlinkRow, BlinkCol;
3428 static ShogiSquare BlinkPiece;
3431 void
3432 BlinkSquareProc(void)
3434 if (BlinkCount > 0)
3436 BlinkCount--;
3437 DrawSquare (BlinkRow, BlinkCol,
3438 ((BlinkCount & 1) ? EmptySquare : BlinkPiece));
3440 if (BlinkCount > 0)
3442 blinkSquareXID
3443 = XtAppAddTimeOut(appContext,
3444 150,
3445 (XtTimerCallbackProc)BlinkSquareProc,
3446 NULL);
3449 else
3451 BlinkCount = 0;
3458 void
3459 BlinkSquare(int row, int col, ShogiSquare piece)
3461 BlinkCount = 2 * BLINK_COUNT + 1;
3462 BlinkRow = row;
3463 BlinkCol = col;
3464 BlinkPiece = piece;
3465 BlinkSquareProc();
3469 #endif /* BLINK_COUNT */
3474 static int
3475 PieceOfCatched(int color, int x, int y, int currentMove)
3477 int F, n;
3479 if (color)
3481 if (x != 1)
3482 return (no_piece);
3484 y = 8 - y;
3486 else
3488 if (x != 11)
3489 return no_piece;
3492 for (F = pawn, n = 0; F <= king; F++)
3494 if (catches[currentMove][color][F] > 0)
3496 if (n == y)
3497 return F;
3499 n++;
3503 return no_piece;
3510 * event handler for parsing user moves
3513 void
3514 HandleUserMove(Widget w, XEvent *event)
3516 ShogiMove move_type;
3517 ShogiSquare from_piece;
3518 int to_x, to_y, fromRemotePlayer;
3520 if (updateRemotePlayer)
3522 if (((w != localPlayer.boardWidget)
3523 && (w != remotePlayer.boardWidget))
3524 || (matchMode != MatchFalse))
3526 return;
3529 fromRemotePlayer = (w == remotePlayer.boardWidget);
3531 else
3533 if ((w != localPlayer.boardWidget) || (matchMode != MatchFalse))
3534 return;
3536 fromRemotePlayer = False;
3539 player = (fromRemotePlayer ? &remotePlayer : &localPlayer);
3541 if (player->promotionUp)
3543 XtPopdown(player->promotionShell);
3544 XtDestroyWidget(player->promotionShell);
3545 player->promotionUp = False;
3546 fromX = fromY = -1;
3549 switch (gameMode)
3551 case EndOfGame:
3552 case PlayFromGameFile:
3553 case TwoMachinesPlay:
3554 return;
3556 case MachinePlaysBlack:
3557 if (BlackOnMove(forwardMostMove))
3559 DisplayMessage("It is not your turn", fromRemotePlayer);
3560 return;
3563 break;
3565 case MachinePlaysWhite:
3566 if (!BlackOnMove(forwardMostMove))
3568 DisplayMessage("It is not your turn", fromRemotePlayer);
3569 return;
3572 break;
3574 case ForceMoves:
3575 forwardMostMove = currentMove;
3576 break;
3578 default:
3579 break;
3582 if (currentMove != forwardMostMove)
3584 DisplayMessage("Displayed position is not current",
3585 fromRemotePlayer);
3586 return;
3589 switch (event->type)
3591 case ButtonPress:
3592 if ((fromX >= 0) || (fromY >= 0))
3593 return;
3595 if (((fromX = EventToXSquare(event->xbutton.x)) < 1)
3596 || (fromX > BOARD_SIZE + 2)
3597 || ((fromY = EventToSquare(event->xbutton.y)) < 0))
3599 fromX = fromY = -1;
3600 return;
3603 if (player->flipView)
3604 fromX = BOARD_SIZE + 3 - fromX;
3605 else
3606 fromY = BOARD_SIZE - 1 - fromY;
3608 break;
3610 case ButtonRelease:
3611 if ((fromX < 0) || (fromY < 0))
3612 return;
3614 if (((to_x = EventToXSquare(event->xbutton.x)) < 1)
3615 || (to_x > BOARD_SIZE + 2)
3616 || ((to_y = EventToSquare(event->xbutton.y)) < 0))
3618 if (gameMode == EditPosition && !off_board(fromX))
3620 fromX -= 2;
3621 boards[0][fromY][fromX] = EmptySquare;
3622 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3623 XSync(localPlayer.xDisplay, False);
3625 if (updateRemotePlayer)
3626 XSync(remotePlayer.xDisplay, False);
3629 fromX = fromY = -1;
3630 return;
3633 if (player->flipView)
3634 to_x = BOARD_SIZE + 3 - to_x;
3635 else
3636 to_y = BOARD_SIZE - 1 - to_y;
3638 if ((fromX == to_x) && (fromY == to_y))
3640 fromX = fromY = -1;
3641 return;
3644 if (gameMode == EditPosition)
3646 ShogiSquare piece;
3648 if (off_board(fromX))
3650 /* Remove a catched piece */
3651 int i, c;
3652 c = ((fromX < 5) ^ player->flipView);
3653 i = PieceOfCatched(c, fromX, fromY, 0);
3655 if (i == no_piece)
3657 fromX = fromY = -1;
3658 return;
3660 else
3662 piece = catchedIndexToPiece[c][i];
3663 catches[0][c][i]--;
3666 else
3668 /* remove piece from board field */
3669 fromX -= 2;
3670 piece = boards[0][fromY][fromX];
3671 boards[0][fromY][fromX] = EmptySquare;
3674 if (!off_board(to_x))
3676 /* drop piece to board field */
3677 ShogiSquare catched_piece;
3678 to_x -= 2;
3679 catched_piece = boards[0][to_y][to_x];
3681 if (catched_piece != EmptySquare)
3683 /* put piece to catched pieces */
3684 int i = pieceToCatchedIndex[catched_piece];
3685 int c = (catched_piece < WhitePawn);
3686 catches[0][c][i]++;
3689 /* place moved piece */
3690 boards[0][to_y][to_x] = piece;
3693 fromX = fromY = -1;
3694 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3695 XSync(localPlayer.xDisplay, False);
3697 if (updateRemotePlayer)
3698 XSync(remotePlayer.xDisplay, False);
3700 return;
3703 if (off_board(fromX))
3705 int c = (BlackOnMove(forwardMostMove) ? 0 : 1);
3706 int piece = PieceOfCatched(c, fromX, fromY, currentMove);
3708 if (piece == no_piece)
3710 fromX = fromY = -1;
3711 return;
3713 else
3715 if (updateRemotePlayer
3716 && (BlackOnMove(forwardMostMove) == fromRemotePlayer))
3718 DisplayMessage("Do not try to drop your opponent's pieces!",
3719 fromRemotePlayer);
3720 fromX = fromY = -1;
3721 return;
3724 fromX = fromY = piece + 81;
3725 to_x -= 2;
3726 move_type = (BlackOnMove(forwardMostMove)
3727 ? BlackDrop : WhiteDrop);
3728 MakeMove(&move_type, fromX, fromY, to_x, to_y);
3730 #ifdef BLINK_COUNT
3731 if (updateRemotePlayer)
3732 BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
3733 #endif
3735 FinishUserMove(move_type, to_x, to_y);
3736 break;
3739 else if (off_board(to_x))
3741 fromX = fromY = -1;
3742 return;
3744 else
3746 fromX -= 2;
3747 to_x -= 2;
3748 from_piece = boards[currentMove][fromY][fromX];
3750 if ((from_piece != EmptySquare)
3751 && updateRemotePlayer
3752 && ((from_piece < WhitePawn) == fromRemotePlayer))
3754 DisplayMessage("Do not try to move your opponent's pieces!",
3755 fromRemotePlayer);
3756 fromX = fromY = -1;
3757 return;
3760 if (PromotionPossible(fromY, to_y, from_piece))
3762 PromotionPopUp(from_piece, to_x, to_y, fromRemotePlayer);
3763 return;
3766 move_type = NormalMove;
3767 MakeMove(&move_type, fromX, fromY, to_x, to_y);
3769 #ifdef BLINK_COUNT
3770 if (updateRemotePlayer)
3771 BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
3772 #endif
3774 FinishUserMove(move_type, to_x, to_y);
3775 break;
3783 void
3784 FinishUserMove(ShogiMove move_type, int to_x, int to_y)
3786 char user_move[MSG_SIZ];
3788 /* output move for gnushogi */
3789 switch (move_type)
3791 case BlackPromotion:
3792 case WhitePromotion:
3793 sprintf(user_move, "%c%c%c%c+\n",
3794 '9' - fromX, 'i' - fromY, '9' - to_x, 'i' - to_y);
3795 break;
3797 case BlackDrop:
3798 case WhiteDrop:
3799 sprintf(user_move, "%c*%c%c\n",
3800 catchedIndexToChar[fromX - 81], '9' - to_x, 'i' - to_y);
3801 break;
3803 case NormalMove:
3804 sprintf(user_move, "%c%c%c%c\n",
3805 '9' - fromX, 'i' - fromY, '9' - to_x, 'i' - to_y);
3806 break;
3808 default:
3809 fprintf(stderr, "%s: internal error; bad move_type\n",
3810 (char *)programName);
3811 break;
3814 Attention(firstProgramPID);
3816 if (firstSendTime)
3817 SendTimeRemaining(toFirstProgFP);
3819 SendToProgram(user_move, toFirstProgFP);
3820 strcpy(moveList[currentMove - 1], user_move);
3822 fromX = fromY = -1;
3824 if (gameMode == PauseGame)
3826 /* a user move restarts a paused game*/
3827 PauseProc(NULL, NULL, NULL, NULL);
3830 switch (gameMode)
3832 case ForceMoves:
3833 break;
3835 case BeginningOfGame:
3836 if (localPlayer.appData.noShogiProgram)
3837 lastGameMode = gameMode = ForceMoves;
3838 else
3839 lastGameMode = gameMode = MachinePlaysWhite;
3841 ModeHighlight();
3842 break;
3844 case MachinePlaysWhite:
3845 case MachinePlaysBlack:
3846 default:
3847 break;
3854 /* Simple parser for moves from gnushogi. */
3855 void
3856 ParseMachineMove(char *machine_move, ShogiMove *move_type,
3857 int *from_x, int *from_y, int *to_x, int *to_y)
3859 #define no_digit(c) (c < '0' || c > '9')
3861 if (no_digit(machine_move[0]))
3863 switch (machine_move[0])
3865 case 'P':
3866 *from_x = 81;
3867 break;
3869 case 'L':
3870 *from_x = 82;
3871 break;
3873 case 'N':
3874 *from_x = 83;
3875 break;
3877 case 'S':
3878 *from_x = 84;
3879 break;
3881 case 'G':
3882 *from_x = 85;
3883 break;
3885 case 'B':
3886 *from_x = 86;
3887 break;
3889 case 'R':
3890 *from_x = 87;
3891 break;
3893 case 'K':
3894 *from_x = 88;
3895 break;
3897 default:
3898 *from_x = -1;
3901 *from_y = *from_x;
3902 *to_x = '9' - machine_move[2];
3903 *to_y = 'i' - machine_move[3];
3905 else
3907 *from_x = '9' - machine_move[0] ;
3908 *from_y = 'i' - machine_move[1];
3909 *to_x = '9' - machine_move[2];
3910 *to_y = 'i' - machine_move[3];
3912 switch (machine_move[4])
3914 case '+':
3915 *move_type = (BlackOnMove(forwardMostMove)
3916 ? BlackPromotion : WhitePromotion);
3917 break;
3919 default:
3920 *move_type = NormalMove;
3921 break;
3930 void
3931 SkipString(char **mpr)
3933 while (**mpr == ' ')
3934 (*mpr)++;
3936 while ((**mpr != ' ') && (**mpr != NULLCHAR) && (**mpr != '\n'))
3937 (*mpr)++;
3939 while (**mpr == ' ')
3940 (*mpr)++;
3946 void
3947 HandleMachineMove(char *message, FILE *fp)
3949 char machine_move[MSG_SIZ], buf1[MSG_SIZ], buf2[MSG_SIZ];
3950 int from_x, from_y, to_x, to_y;
3951 ShogiMove move_type;
3952 char *mpr;
3954 #ifdef SYNCHTIME
3955 long time_remaining;
3956 #endif
3958 maybeThinking = False;
3960 if (strncmp(message, "warning:", 8) == 0)
3962 DisplayMessage(message, False);
3964 if (updateRemotePlayer)
3965 DisplayMessage(message, True);
3967 return;
3971 * If shogi program startup fails, exit with an error message.
3972 * Attempts to recover here are futile.
3975 if ((strstr(message, "unknown host") != NULL)
3976 || (strstr(message, "No remote directory") != NULL)
3977 || (strstr(message, "not found") != NULL)
3978 || (strstr(message, "No such file") != NULL)
3979 || (strstr(message, "Permission denied") != NULL))
3981 fprintf(stderr,
3982 "%s: failed to start shogi program %s on %s: %s\n",
3983 programName,
3984 ((fp == fromFirstProgFP)
3985 ? localPlayer.appData.firstShogiProgram
3986 : localPlayer.appData.secondShogiProgram),
3987 ((fp == fromFirstProgFP)
3988 ? localPlayer.appData.firstHost
3989 : localPlayer.appData.secondHost),
3990 message);
3991 ShutdownShogiPrograms(message);
3992 exit(1);
3996 * If the move is illegal, cancel it and redraw the board.
3999 if (strncmp(message, "Illegal move", 12) == 0)
4001 if (fp == fromFirstProgFP && firstSendTime == 2)
4003 /* First program doesn't have the "time" command */
4004 firstSendTime = 0;
4005 return;
4007 else if (fp == fromSecondProgFP && secondSendTime == 2)
4009 /* Second program doesn't have the "time" command */
4010 secondSendTime = 0;
4011 return;
4014 if (forwardMostMove <= backwardMostMove)
4015 return;
4017 if (gameMode == PauseGame)
4018 PauseProc(NULL, NULL, NULL, NULL);
4020 if (gameMode == PlayFromGameFile)
4022 /* Stop reading this game file */
4023 gameMode = ForceMoves;
4024 ModeHighlight();
4027 currentMove = --forwardMostMove;
4029 if ((gameMode == PlayFromGameFile)
4030 || (gameMode == ForceMoves))
4031 DisplayClocks(ReDisplayTimers);
4032 else
4033 DisplayClocks(SwitchTimers);
4035 sprintf(buf1, "Illegal move: %s", parseList[currentMove]);
4036 DisplayMessage(buf1, False);
4038 if (updateRemotePlayer)
4039 DisplayMessage(buf1, True);
4041 #ifdef BLINK_COUNT
4043 * Disable blinking of the target square.
4046 if (BlinkCount > 0)
4048 /* If BlinkCount is even, the piece is currently displayed. */
4049 if (!(BlinkCount & 1))
4050 DrawSquare (BlinkRow, BlinkCol, EmptySquare);
4052 /* BlinkCount = 0 will force the next blink timeout
4053 * to do nothing. */
4054 BlinkCount = 0;
4056 #endif
4058 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
4060 XSync(localPlayer.xDisplay, False);
4062 if (updateRemotePlayer)
4063 XSync(remotePlayer.xDisplay, False);
4065 return;
4068 if (strstr(message, "GNU Shogi") != NULL)
4070 at_least_gnushogi_1_2p03 = True;
4071 return;
4074 if (strncmp(message, "Hint:", 5) == 0)
4076 char promoPiece;
4077 sscanf(message, "Hint: %s", machine_move);
4078 ParseMachineMove(machine_move, &move_type,
4079 &from_x, &from_y, &to_x, &to_y);
4081 if (move_type == WhitePromotion || move_type == BlackPromotion)
4082 promoPiece = '+';
4083 else
4084 promoPiece = NULLCHAR;
4086 move_type = MakeAlg(from_x, from_y, to_x, to_y, promoPiece,
4087 currentMove, buf1);
4088 sprintf(buf2, "Hint: %s", buf1);
4089 DisplayMessage(buf2, False);
4091 if (updateRemotePlayer)
4092 DisplayMessage(buf2, True);
4094 return;
4097 if (strncmp(message, "Clocks:", 7) == 0)
4099 sscanf(message, "Clocks: %ld %ld",
4100 &blackTimeRemaining, &whiteTimeRemaining);
4101 DisplayClocks(ReDisplayTimers);
4103 return;
4107 * win, lose or draw
4110 if (strncmp(message, "Black", 5) == 0)
4112 ShutdownShogiPrograms("Black wins");
4113 return;
4115 else if (strncmp(message, "White", 5) == 0)
4117 ShutdownShogiPrograms("White wins");
4118 return;
4120 else if (strncmp(message, "Repetition", 10) == 0)
4122 ShutdownShogiPrograms("Repetition");
4123 return;
4125 else if (strncmp(message, "opponent mates!", 15) == 0)
4127 switch ((gameMode == PauseGame) ? pausePreviousMode : gameMode)
4129 case MachinePlaysWhite:
4130 ShutdownShogiPrograms("Black wins");
4131 break;
4133 case MachinePlaysBlack:
4134 ShutdownShogiPrograms("White wins");
4135 break;
4137 case TwoMachinesPlay:
4138 ShutdownShogiPrograms((fp == fromFirstProgFP)
4139 ? "Black wins" : "White wins");
4140 break;
4142 default:
4143 /* can't happen */
4144 break;
4147 return;
4149 else if (strncmp(message, "computer mates!", 15) == 0)
4151 switch ((gameMode == PauseGame) ? pausePreviousMode : gameMode)
4153 case MachinePlaysWhite:
4154 ShutdownShogiPrograms("White wins");
4155 break;
4157 case MachinePlaysBlack:
4158 ShutdownShogiPrograms("Black wins");
4159 break;
4161 case TwoMachinesPlay:
4162 ShutdownShogiPrograms((fp == fromFirstProgFP)
4163 ? "White wins" : "Black wins");
4164 break;
4166 default:
4167 /* can't happen */
4168 break;
4171 return;
4173 else if (strncmp(message, "Draw", 4) == 0)
4175 ShutdownShogiPrograms("Draw");
4176 return;
4180 * normal machine reply move
4182 maybeThinking = True;
4184 if (strstr(message, "...") != NULL)
4186 sscanf(message, "%s %s %s", buf1, buf2, machine_move);
4188 #ifdef SYNCHTIME
4189 mpr = message;
4190 SkipString(&mpr); /* skip move number */
4191 SkipString(&mpr); /* skip ... */
4192 SkipString(&mpr); /* skip move */
4194 if ((gameMode != TwoMachinesPlay) && (gameMode != ForceMoves)
4195 && ((*mpr == '-') || ((*mpr >= '0') && (*mpr <= '9'))))
4197 /* synchronize with shogi program clock */
4198 sscanf(mpr, "%ld", &time_remaining);
4200 if (xshogiDebug)
4202 printf("from '%s' synchronize %s clock %ld\n",
4203 message,
4204 (BlackOnMove(forwardMostMove)
4205 ? "Black's"
4206 : "White's"),
4207 time_remaining);
4210 if (BlackOnMove(forwardMostMove))
4211 blackTimeRemaining = time_remaining;
4212 else
4213 whiteTimeRemaining = time_remaining;
4215 #endif
4217 if (machine_move[0] == NULLCHAR)
4218 return;
4220 else
4222 mpr = message;
4224 #ifdef SYNCHTIME
4225 if (strstr(message, "time") == NULL)
4227 /* remaining time will be determined from move */
4228 SkipString(&mpr); /* skip move number */
4229 SkipString(&mpr); /* skip move */
4232 if ((gameMode != TwoMachinesPlay) && (gameMode != ForceMoves)
4233 && ((*mpr == '-') || ((*mpr >= '0') && (*mpr <= '9'))))
4235 /* synchronize with shogi program clock */
4236 sscanf(mpr, "%ld", &time_remaining);
4238 if (xshogiDebug)
4240 printf("from '%s' synchronize %s clock %ld\n",
4241 message,
4242 ((!BlackOnMove(forwardMostMove))
4243 ? "Black's" : "White's"),
4244 time_remaining);
4247 if (!BlackOnMove(forwardMostMove))
4248 blackTimeRemaining = time_remaining;
4249 else
4250 whiteTimeRemaining = time_remaining;
4252 else
4253 #endif
4255 if (xshogiDebug)
4256 printf("ignore noise: '%s'\n", message);
4258 return; /* ignore noise */
4261 strcpy(moveList[forwardMostMove], machine_move);
4263 ParseMachineMove(machine_move, &move_type, &from_x, &from_y,
4264 &to_x, &to_y);
4266 if (gameMode != PauseGame)
4267 currentMove = forwardMostMove; /* display latest move */
4269 MakeMove(&move_type, from_x, from_y, to_x, to_y);
4271 #ifdef BLINK_COUNT
4272 if (gameMode != TwoMachinesPlay)
4273 BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
4274 #endif
4276 if ((gameMode != PauseGame) && localPlayer.appData.ringBellAfterMoves)
4277 putc(BELLCHAR, stderr);
4279 if ((gameMode == TwoMachinesPlay)
4280 || ((gameMode == PauseGame)
4281 && (pausePreviousMode == TwoMachinesPlay)))
4283 strcat(machine_move, "\n");
4285 if (BlackOnMove(forwardMostMove))
4287 Attention(secondProgramPID);
4289 if (secondSendTime)
4290 SendTimeRemaining(toSecondProgFP);
4292 SendToProgram(machine_move, toSecondProgFP);
4294 if (firstMove)
4296 firstMove = False;
4297 SendToProgram(localPlayer.appData.blackString,
4298 toSecondProgFP);
4301 else
4303 Attention(firstProgramPID);
4305 if (firstSendTime)
4306 SendTimeRemaining(toFirstProgFP);
4308 SendToProgram(machine_move, toFirstProgFP);
4310 if (firstMove)
4312 firstMove = False;
4313 SendToProgram(localPlayer.appData.blackString,
4314 toFirstProgFP);
4323 void
4324 ReadGameFile(void)
4326 for (;;)
4328 if (!ReadGameFileProc())
4329 return;
4331 if (matchMode == MatchOpening)
4332 continue;
4334 readGameXID
4335 = XtAppAddTimeOut(appContext,
4336 (int)(1000 * localPlayer.appData.timeDelay),
4337 (XtTimerCallbackProc) ReadGameFile, NULL);
4338 break;
4345 * FIXME: there is a naming inconsistency: here ReadGameFileProc() is
4346 * called by ReadGameFile() while in other places XXXProc() calls XXX().
4350 ReadGameFileProc(void)
4352 ShogiMove move_type;
4353 char move[MSG_SIZ], buf[MSG_SIZ];
4355 if (gameFileFP == NULL)
4356 return (int)False;
4358 if (gameMode == PauseGame)
4359 return True;
4361 if (gameMode != PlayFromGameFile)
4363 fclose(gameFileFP);
4364 gameFileFP = NULL;
4365 return (int)False;
4368 if (commentUp)
4370 XtPopdown(commentShell);
4371 XtDestroyWidget(commentShell);
4372 commentUp = False;
4375 fgets(move, MSG_SIZ, gameFileFP);
4376 move[strlen(move) - 1] = NULLCHAR;
4377 sprintf(buf, "# %s game file", programName);
4379 if (strncmp(move, buf, strlen(buf)))
4381 strcat(move, ": no xshogi game file");
4382 DisplayMessage(move, False);
4383 return (int)False;
4386 DisplayName(move);
4387 rewind(gameFileFP);
4389 parseGameFile();
4391 move_type = (ShogiMove)0;
4393 lastGameMode = gameMode;
4394 gameMode = ForceMoves;
4395 ModeHighlight();
4397 if (!loaded_game_finished)
4398 DisplayMessage("End of game file", False);
4400 if (readGameXID != 0)
4402 XtRemoveTimeOut(readGameXID);
4403 readGameXID = 0;
4406 fclose(gameFileFP);
4407 gameFileFP = NULL;
4409 return (int)False;
4416 * Apply a move to the given board. Oddity: move_type is ignored on input
4417 * unless the move is seen to be a pawn promotion, in which case move_type
4418 * tells us what to promote to.
4421 void
4422 ApplyMove(ShogiMove *move_type, int from_x, int from_y,
4423 int to_x, int to_y, int currentMove)
4425 ShogiSquare piece, cpiece;
4426 char pieceChar;
4427 int i, c;
4429 if (from_x > 80)
4431 i = from_x - 81;
4432 c = (BlackOnMove(currentMove) ? 1 : 0);
4433 cpiece = catchedIndexToPiece[c][i];
4434 boards[currentMove][to_y][to_x] = cpiece;
4435 catches[currentMove][c][i]--;
4437 else if (PromotionPossible(from_y, to_y,
4438 piece = boards[currentMove][from_y][from_x]))
4440 cpiece = boards[currentMove][to_y][to_x];
4442 if (cpiece != EmptySquare)
4444 i = pieceToCatchedIndex[cpiece];
4445 c = (cpiece < WhitePawn);
4446 catches[currentMove][c][i]++;
4449 if (*move_type == NormalMove)
4451 boards[currentMove][to_y][to_x] = piece;
4453 else
4455 boards[currentMove][to_y][to_x] = piece = pieceToPromoted[piece];
4456 pieceChar = '+';
4459 boards[currentMove][from_y][from_x] = EmptySquare;
4461 else
4463 ShogiSquare piece = boards[currentMove][to_y][to_x];
4465 if (piece != EmptySquare)
4467 i = pieceToCatchedIndex[piece];
4468 c = (piece < WhitePawn);
4469 catches[currentMove][c][i]++;
4472 *move_type = NormalMove;
4473 boards[currentMove][to_y][to_x] =
4474 boards[currentMove][from_y][from_x];
4475 boards[currentMove][from_y][from_x] = EmptySquare;
4483 * MakeMove() displays moves. If they are illegal, GNU shogi will detect
4484 * this and send an Illegal move message. XShogi will then retract the move.
4485 * The clockMode False case is tricky because it displays the player on move.
4488 void
4489 MakeMove(ShogiMove *move_type, int from_x, int from_y, int to_x, int to_y)
4491 char message[MSG_SIZ], movestr[MSG_SIZ];
4492 char promoPiece = NULLCHAR;
4494 forwardMostMove++;
4496 CopyBoard(boards[forwardMostMove], boards[forwardMostMove - 1]);
4497 CopyCatches(catches[forwardMostMove], catches[forwardMostMove - 1]);
4499 ApplyMove(move_type, from_x, from_y, to_x, to_y, forwardMostMove);
4501 endMessage[0] = NULLCHAR;
4503 timeRemaining[0][forwardMostMove] = blackTimeRemaining;
4504 timeRemaining[1][forwardMostMove] = whiteTimeRemaining;
4506 if ((gameMode == PauseGame) && (pausePreviousMode != PlayFromGameFile))
4507 return;
4509 currentMove = forwardMostMove;
4511 if (gameMode == PlayFromGameFile)
4513 sprintf(message, "%d. %s%s",
4514 ((currentMove + 1) / 2),
4515 (BlackOnMove(currentMove) ? "... " : ""),
4516 currentMoveString);
4517 strcpy(parseList[currentMove - 1], currentMoveString);
4519 else
4521 if ((*move_type == WhitePromotion) || (*move_type == BlackPromotion))
4522 promoPiece = '+';
4523 else
4524 promoPiece = NULLCHAR;
4526 MakeAlg(from_x, from_y, to_x, to_y, promoPiece,
4527 currentMove - 1, movestr);
4528 sprintf(message, "%d. %s%s",
4529 ((currentMove + 1) / 2),
4530 (BlackOnMove(currentMove) ? "... " : ""),
4531 movestr);
4532 strcpy(parseList[currentMove - 1], movestr);
4535 DisplayMessage(message, False);
4537 if ((gameMode == PlayFromGameFile) || (gameMode == ForceMoves)
4538 || ((gameMode == PauseGame)
4539 && (pausePreviousMode == PlayFromGameFile)))
4541 DisplayClocks(ReDisplayTimers);
4543 else
4545 DisplayClocks(SwitchTimers);
4548 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
4550 XSync(localPlayer.xDisplay, False);
4552 if (updateRemotePlayer)
4554 DisplayMessage(message, True);
4555 XSync(remotePlayer.xDisplay, False);
4562 void
4563 InitShogiProgram(char *host_name, char *program_name, int *pid,
4564 FILE **to, FILE **from, XtIntervalId *xid, int *sendTime)
4566 char arg_buf[10];
4567 char *arg1, *arg2;
4568 int to_prog[2], from_prog[2];
4569 FILE *from_fp, *to_fp;
4570 int dummy_source;
4571 XtInputId dummy_id;
4573 if (localPlayer.appData.noShogiProgram)
4574 return;
4576 signal(SIGPIPE, CatchPipeSignal);
4577 pipe(to_prog);
4578 pipe(from_prog);
4580 if ((*pid = fork()) == 0)
4582 signal(SIGPIPE, CatchPipeSignal);
4584 dup2(to_prog[0], 0);
4585 dup2(from_prog[1], 1);
4586 close(to_prog[0]);
4587 close(to_prog[1]);
4588 close(from_prog[0]);
4589 close(from_prog[1]);
4590 dup2(1, fileno(stderr)); /* force stderr to the pipe */
4592 if (localPlayer.appData.searchTime != NULL)
4594 sprintf(arg_buf, "%d", searchTime);
4595 arg1 = arg_buf;
4596 arg2 = (char *)NULL;
4598 else if (localPlayer.appData.searchDepth > 0)
4600 sprintf(arg_buf, "%d", localPlayer.appData.searchDepth);
4601 arg1 = "1";
4602 arg2 = "9999";
4604 else
4606 sprintf(arg_buf, "%d", localPlayer.appData.movesPerSession);
4607 arg1 = arg_buf;
4608 arg2 = localPlayer.appData.timeControl;
4611 if (strcmp(host_name, "localhost") == 0)
4613 execlp(program_name, program_name, arg1, arg2,
4614 (char *)NULL);
4616 else
4618 execlp(localPlayer.appData.remoteShell,
4619 localPlayer.appData.remoteShell,
4620 host_name, program_name, arg1, arg2,
4621 (char *)NULL);
4624 perror(program_name);
4625 exit(1);
4628 close(to_prog[0]);
4629 close(from_prog[1]);
4631 *from = from_fp = fdopen(from_prog[0], "r");
4632 *to = to_fp = fdopen(to_prog[1], "w");
4633 setbuf(from_fp, NULL);
4634 setbuf(to_fp, NULL);
4636 ReceiveFromProgram(from_fp, &dummy_source, &dummy_id); /* "GNU Shogi"*/
4638 if (!at_least_gnushogi_1_2p03)
4640 fprintf(stderr, "you must have at least gnushogi-1.2p03\n");
4641 exit(1);
4644 if (*pid == 0)
4645 return;
4647 *xid = XtAppAddInput(appContext, fileno(from_fp),
4648 (XtPointer)XtInputReadMask,
4649 (XtInputCallbackProc)ReceiveFromProgram,
4650 (XtPointer)from_fp);
4652 SendToProgram(localPlayer.appData.initString, *to);
4654 if (localPlayer.appData.gameIn)
4655 SendToProgram("gamein\n", *to);
4657 SendSearchDepth(*to);
4659 if (*sendTime == 2)
4661 /* Does program have "time" command? */
4662 char buf[MSG_SIZ];
4664 sprintf(buf, "time %ld\n", blackTimeRemaining / 10);
4665 SendToProgram(buf, to_fp);
4666 ReceiveFromProgram(from_fp, &dummy_source, &dummy_id);
4668 if (*sendTime == 2)
4670 *sendTime = 1; /* yes! */
4671 sprintf(buf, "otime %ld\n", whiteTimeRemaining / 10);
4672 SendToProgram(buf, to_fp);
4673 ReceiveFromProgram(from_fp, &dummy_source, &dummy_id);
4681 void
4682 ShutdownShogiPrograms(char *why)
4684 lastGameMode = gameMode;
4685 gameMode = EndOfGame;
4686 ModeHighlight();
4687 CopyBoard(boards[currentMove + 1], boards[currentMove]);
4688 CopyCatches(catches[currentMove + 1], catches[currentMove]);
4689 strncpy(parseList[currentMove], why, MOVE_LEN);
4690 parseList[currentMove][MOVE_LEN - 1] = NULLCHAR;
4691 currentMove++;
4692 DisplayMessage(why, False);
4694 if (readGameXID != 0)
4695 XtRemoveTimeOut(readGameXID);
4697 readGameXID = 0;
4699 if (firstProgramPID != 0)
4701 fclose(fromFirstProgFP);
4702 fclose(toFirstProgFP);
4703 fromFirstProgFP = toFirstProgFP = NULL;
4705 if (kill(firstProgramPID, SIGTERM) == 0)
4706 WAIT0;
4709 firstProgramPID = 0;
4711 if (firstProgramXID != 0)
4712 XtRemoveInput(firstProgramXID);
4714 firstProgramXID = 0;
4716 if (secondProgramPID != 0)
4718 fclose(fromSecondProgFP);
4719 fclose(toSecondProgFP);
4720 fromSecondProgFP = toSecondProgFP = NULL;
4722 if (kill(secondProgramPID, SIGTERM) == 0)
4723 WAIT0;
4726 secondProgramPID = 0;
4728 if (secondProgramXID != 0)
4729 XtRemoveInput(secondProgramXID);
4731 secondProgramXID = 0;
4733 DisplayClocks(StopTimers);
4735 if (matchMode != MatchFalse)
4737 if (localPlayer.appData.saveGameFile[0] != NULLCHAR)
4738 SaveGame(localPlayer.appData.saveGameFile);
4740 exit(0);
4747 void
4748 CommentPopUp(char *label)
4750 Arg args[2];
4751 Position x, y;
4752 Dimension bw_width, pw_width;
4754 if (commentUp)
4756 XtPopdown(commentShell);
4757 XtDestroyWidget(commentShell);
4758 commentUp = False;
4761 DisplayMessage("Comment", False);
4763 XtSetArg(args[0], XtNwidth, &bw_width);
4764 XtGetValues(localPlayer.formWidget, args, 1);
4766 XtSetArg(args[0], XtNresizable, True);
4767 XtSetArg(args[1], XtNwidth, bw_width - 8);
4769 commentShell = XtCreatePopupShell("Comment",
4770 transientShellWidgetClass,
4771 localPlayer.commandsWidget, args, 2);
4773 XtSetArg(args[0], XtNlabel, label);
4775 (void)XtCreateManagedWidget("commentLabel", labelWidgetClass,
4776 commentShell, args, 1);
4778 XtRealizeWidget(commentShell);
4780 XtSetArg(args[0], XtNwidth, &pw_width);
4781 XtGetValues(commentShell, args, 1);
4783 XtTranslateCoords(localPlayer.shellWidget,
4784 (bw_width - pw_width) / 2, -50, &x, &y);
4786 XtSetArg(args[0], XtNx, x);
4787 XtSetArg(args[1], XtNy, y);
4788 XtSetValues(commentShell, args, 2);
4790 XtPopup(commentShell, XtGrabNone);
4791 commentUp = True;
4797 void
4798 FileNamePopUp(char *label, Boolean (*proc) (char *))
4800 Arg args[2];
4801 Widget popup, dialog;
4802 Position x, y;
4803 Dimension bw_width, pw_width;
4805 fileProc = proc;
4807 XtSetArg(args[0], XtNwidth, &bw_width);
4808 XtGetValues(localPlayer.boardWidget, args, 1);
4810 XtSetArg(args[0], XtNresizable, True);
4811 XtSetArg(args[1], XtNwidth, DIALOG_SIZE);
4813 popup = XtCreatePopupShell("File Name Prompt",
4814 transientShellWidgetClass,
4815 localPlayer.commandsWidget, args, 2);
4817 XtSetArg(args[0], XtNlabel, label);
4818 XtSetArg(args[1], XtNvalue, "");
4820 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
4821 popup, args, 2);
4823 XawDialogAddButton(dialog, "ok", FileNameCallback, (XtPointer) dialog);
4824 XawDialogAddButton(dialog, "cancel", FileNameCallback,
4825 (XtPointer) dialog);
4827 XtRealizeWidget(popup);
4829 XtSetArg(args[0], XtNwidth, &pw_width);
4830 XtGetValues(popup, args, 1);
4832 XtTranslateCoords(localPlayer.boardWidget,
4833 (bw_width - pw_width) / 2, 10, &x, &y);
4835 XtSetArg(args[0], XtNx, x);
4836 XtSetArg(args[1], XtNy, y);
4837 XtSetValues(popup, args, 2);
4839 XtPopup(popup, XtGrabExclusive);
4840 filenameUp = True;
4842 XtSetKeyboardFocus(localPlayer.shellWidget, popup);
4848 void
4849 FileNameCallback(Widget w, XtPointer client_data, XtPointer call_data)
4851 String name;
4852 Arg args[1];
4854 XtSetArg(args[0], XtNlabel, &name);
4855 XtGetValues(w, args, 1);
4857 if (strcmp(name, "cancel") == 0)
4859 XtPopdown(w = XtParent(XtParent(w)));
4860 XtDestroyWidget(w);
4861 filenameUp = False;
4862 ModeHighlight();
4863 return;
4866 FileNameAction(w, NULL, NULL, NULL);
4872 void
4873 FileNameAction(Widget w, XEvent *event, String *prms, Cardinal *nprms)
4875 char buf[MSG_SIZ];
4876 String name;
4878 name = XawDialogGetValueString(w = XtParent(w));
4880 if ((name != NULL) && (*name != NULLCHAR))
4882 strcpy(buf, name);
4883 XtPopdown(w = XtParent(w));
4884 XtDestroyWidget(w);
4885 filenameUp = False;
4886 (*fileProc)(buf); /* I can't see a way not
4887 to use a global here */
4888 ModeHighlight();
4889 return;
4892 XtPopdown(w = XtParent(w));
4893 XtDestroyWidget(w);
4894 filenameUp = False;
4895 ModeHighlight();
4901 void
4902 PromotionPopUp(ShogiSquare piece, int to_x, int to_y, int fromRemotePlayer)
4904 Arg args[2];
4905 Widget dialog;
4906 Position x, y;
4907 Dimension bw_width, bw_height, pw_width, pw_height;
4909 player = (fromRemotePlayer ? &remotePlayer : &localPlayer);
4911 pmi.piece = piece;
4912 pmi.to_x = to_x;
4913 pmi.to_y = to_y;
4915 XtSetArg(args[0], XtNwidth, &bw_width);
4916 XtSetArg(args[1], XtNheight, &bw_height);
4917 XtGetValues(player->boardWidget, args, 2);
4919 XtSetArg(args[0], XtNresizable, True);
4921 player->promotionShell
4922 = XtCreatePopupShell("Promotion",
4923 transientShellWidgetClass,
4924 player->commandsWidget, args, 1);
4926 XtSetArg(args[0], XtNlabel, "Promote piece?");
4927 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
4928 player->promotionShell, args, 1);
4930 XawDialogAddButton(dialog, "Yes", PromotionCallback,
4931 (XtPointer) dialog);
4932 XawDialogAddButton(dialog, "No", PromotionCallback,
4933 (XtPointer) dialog);
4934 XawDialogAddButton(dialog, "cancel", PromotionCallback,
4935 (XtPointer) dialog);
4937 XtRealizeWidget(player->promotionShell);
4939 XtSetArg(args[0], XtNwidth, &pw_width);
4940 XtSetArg(args[1], XtNheight, &pw_height);
4941 XtGetValues(player->promotionShell, args, 2);
4943 XtTranslateCoords(player->boardWidget,
4944 ((bw_width - pw_width) / 2),
4945 (LINE_GAP
4946 + player->squareSize / 3
4947 + (((piece == BlackPawn) ^ (player->flipView))
4949 : (6 * (player->squareSize + LINE_GAP)))),
4950 &x, &y);
4952 XtSetArg(args[0], XtNx, x);
4953 XtSetArg(args[1], XtNy, y);
4954 XtSetValues(player->promotionShell, args, 2);
4956 XtPopup(player->promotionShell, XtGrabNone);
4958 player->promotionUp = True;
4964 void
4965 PromotionCallback(Widget w, XtPointer client_data, XtPointer call_data)
4967 String name;
4968 Arg args[1];
4969 ShogiMove move_type;
4970 struct DisplayData *player;
4972 XtSetArg(args[0], XtNlabel, &name);
4973 XtGetValues(w, args, 1);
4975 w = XtParent(XtParent(w));
4976 player = ((w == remotePlayer.promotionShell)
4977 ? &remotePlayer : &localPlayer);
4978 XtPopdown(w);
4979 XtDestroyWidget(w);
4980 player->promotionUp = False;
4982 if (fromX == -1)
4983 return;
4985 if (strcmp(name, "Yes") == 0)
4987 if ((int)pmi.piece < (int)WhitePawn)
4988 move_type = BlackPromotion;
4989 else
4990 move_type = WhitePromotion;
4992 else if (strcmp(name, "No") == 0)
4994 move_type = NormalMove;
4996 else /* strcmp(name, "cancel") == 0 */
4998 fromX = fromY = -1;
4999 return;
5002 MakeMove(&move_type, fromX, fromY, pmi.to_x, pmi.to_y);
5004 #ifdef BLINK_COUNT
5005 if (updateRemotePlayer)
5007 BlinkSquare(pmi.to_y, pmi.to_x,
5008 boards[currentMove][pmi.to_y][pmi.to_x]);
5010 #endif
5012 FinishUserMove(move_type, pmi.to_x, pmi.to_y);
5018 void
5019 FileModePopUp(char *name)
5021 Arg args[2];
5022 Widget dialog;
5023 Position x, y;
5024 Dimension bw_width, bw_height, pw_width, pw_height;
5026 struct DisplayData *player = &localPlayer;
5028 strcpy(fmi.name, name);
5030 XtSetArg(args[0], XtNwidth, &bw_width);
5031 XtSetArg(args[1], XtNheight, &bw_height);
5032 XtGetValues(player->boardWidget, args, 2);
5034 XtSetArg(args[0], XtNresizable, True);
5035 player->filemodeShell
5036 = XtCreatePopupShell("FileMode",
5037 transientShellWidgetClass,
5038 player->commandsWidget, args, 1);
5040 XtSetArg(args[0], XtNlabel, "Append to existing file?");
5041 dialog = XtCreateManagedWidget("filemode", dialogWidgetClass,
5042 player->filemodeShell, args, 1);
5044 XawDialogAddButton(dialog, "Yes", FileModeCallback,
5045 (XtPointer) dialog);
5046 XawDialogAddButton(dialog, "No", FileModeCallback,
5047 (XtPointer) dialog);
5048 XawDialogAddButton(dialog, "cancel", FileModeCallback,
5049 (XtPointer) dialog);
5051 XtRealizeWidget(player->filemodeShell);
5053 XtSetArg(args[0], XtNwidth, &pw_width);
5054 XtSetArg(args[1], XtNheight, &pw_height);
5055 XtGetValues(player->filemodeShell, args, 2);
5057 XtTranslateCoords(player->boardWidget, (bw_width - pw_width) / 2,
5058 LINE_GAP + player->squareSize/3 +
5059 (6*(player->squareSize + LINE_GAP)),
5060 &x, &y);
5062 XtSetArg(args[0], XtNx, x);
5063 XtSetArg(args[1], XtNy, y);
5064 XtSetValues(player->filemodeShell, args, 2);
5066 XtPopup(player->filemodeShell, XtGrabNone);
5068 filemodeUp = True;
5074 void
5075 FileModeCallback(Widget w, XtPointer client_data, XtPointer call_data)
5077 String name;
5078 Arg args[1];
5080 XtSetArg(args[0], XtNlabel, &name);
5081 XtGetValues(w, args, 1);
5083 XtPopdown(w = XtParent(XtParent(w)));
5084 XtDestroyWidget(w);
5086 if (strcmp(name, "Yes") == 0)
5088 strcpy(fmi.mode, "a");
5090 else if (strcmp(name, "No") == 0)
5092 strcpy(fmi.mode, "w");
5094 else /* strcmp(name, "cancel") == 0 */
5096 filemodeUp = False;
5097 return;
5100 XtPopdown(localPlayer.filemodeShell);
5101 XtDestroyWidget(localPlayer.filemodeShell);
5103 SaveGame(fmi.name);
5105 filemodeUp = False;
5111 void
5112 SelectCommand(Widget w, XtPointer client_data, XtPointer call_data)
5114 Cardinal fromRemotePlayer = (Cardinal)client_data;
5116 XawListReturnStruct *list_return = XawListShowCurrent(w);
5118 player = fromRemotePlayer ? &remotePlayer : &localPlayer;
5120 fromX = fromY = -1;
5122 if (player->promotionUp)
5124 XtPopdown(player->promotionShell);
5125 XtDestroyWidget(player->promotionShell);
5126 player->promotionUp = False;
5129 (*buttonProcs[list_return->list_index])
5130 (w, NULL, NULL, &fromRemotePlayer);
5132 if (!filenameUp)
5133 ModeHighlight();
5139 void
5140 HighlightProcButton(XtActionProc proc)
5142 int i = 0;
5144 if (proc == NULL)
5146 XawListUnhighlight(localPlayer.commandsWidget);
5148 if (updateRemotePlayer)
5149 XawListUnhighlight(remotePlayer.commandsWidget);
5151 return;
5154 for (;;)
5156 if (buttonProcs[i] == NULL)
5158 XawListUnhighlight(localPlayer.commandsWidget);
5160 if (updateRemotePlayer)
5161 XawListUnhighlight(remotePlayer.commandsWidget);
5163 return;
5166 if (buttonProcs[i] == proc)
5168 XawListHighlight(localPlayer.commandsWidget, i);
5170 if (updateRemotePlayer)
5171 XawListHighlight(remotePlayer.commandsWidget, i);
5173 return;
5176 i++;
5183 void
5184 ModeHighlight(void)
5186 switch (gameMode)
5188 case BeginningOfGame:
5189 if (localPlayer.appData.noShogiProgram)
5190 HighlightProcButton(ForceProc);
5191 else
5192 HighlightProcButton(MachineBlackProc);
5194 break;
5196 case MachinePlaysBlack:
5197 HighlightProcButton(MachineBlackProc);
5198 break;
5200 case MachinePlaysWhite:
5201 HighlightProcButton(MachineWhiteProc);
5202 break;
5204 case TwoMachinesPlay:
5205 HighlightProcButton(TwoMachinesProc);
5206 break;
5208 case ForceMoves:
5209 HighlightProcButton(ForceProc);
5211 break;
5213 case PlayFromGameFile:
5214 HighlightProcButton(LoadGameProc);
5215 break;
5217 case PauseGame:
5218 HighlightProcButton(PauseProc);
5219 break;
5221 case EditPosition:
5222 HighlightProcButton(EditPositionProc);
5223 break;
5225 case EndOfGame:
5226 default:
5227 HighlightProcButton(NULL);
5228 break;
5236 * Button procedures
5239 void
5240 QuitRemotePlayerProc(void)
5242 /* This should be modified... */
5243 XCloseDisplay(remotePlayer.xDisplay);
5244 /* XtDestroyWidget(remotePlayer.shellWidget); */
5245 updateRemotePlayer = False;
5246 DisplayMessage("Remote player has pressed Quit", False);
5247 fromX = fromY = -1;
5252 void
5253 QuitProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5255 if (updateRemotePlayer)
5256 QuitRemotePlayerProc();
5258 ShutdownShogiPrograms("Quitting");
5259 exit(0);
5264 void
5265 LoadGameProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5267 int fromRemotePlayer = *nprms;
5269 if (fromRemotePlayer)
5271 DisplayMessage("only opponent may load game", fromRemotePlayer);
5272 return;
5275 if (gameMode != BeginningOfGame)
5277 DisplayMessage("Press Reset first.", False);
5278 return;
5281 if (localPlayer.appData.loadGameFile == NULL)
5282 FileNamePopUp("Game file name?", LoadGame);
5283 else
5284 (void) LoadGame(localPlayer.appData.loadGameFile);
5290 Boolean
5291 LoadGame(char *name)
5293 char buf[MSG_SIZ];
5295 loaded_game_finished = 0;
5297 if (gameMode != BeginningOfGame)
5299 DisplayMessage("Press Reset first", False);
5300 return (int)False;
5303 if (localPlayer.appData.loadGameFile != name)
5305 if (localPlayer.appData.loadGameFile)
5306 XtFree(localPlayer.appData.loadGameFile);
5308 localPlayer.appData.loadGameFile = XtMalloc(strlen(name) + 1);
5309 strcpy(localPlayer.appData.loadGameFile, name);
5312 if ((gameFileFP = fopen(name, "r")) == NULL)
5314 sprintf(buf, "Can't open %s", name);
5315 DisplayMessage(buf, False);
5316 XtFree(localPlayer.appData.loadGameFile);
5317 localPlayer.appData.loadGameFile = NULL;
5318 return (int)False;
5321 lastGameMode = gameMode = PlayFromGameFile;
5322 ModeHighlight();
5323 InitPosition(True);
5324 DisplayClocks(StopTimers);
5326 if (firstProgramXID == 0)
5328 InitShogiProgram(localPlayer.appData.firstHost,
5329 localPlayer.appData.firstShogiProgram,
5330 &firstProgramPID, &toFirstProgFP,
5331 &fromFirstProgFP, &firstProgramXID,
5332 &firstSendTime);
5335 SendToProgram(localPlayer.appData.initString, toFirstProgFP);
5336 SendSearchDepth(toFirstProgFP);
5337 SendToProgram("force\n", toFirstProgFP);
5339 currentMove = forwardMostMove = backwardMostMove = 0;
5341 ReadGameFile();
5343 return True;
5350 * Restart the shogi program and feed it all the moves made so far.
5351 * Used when the user wants to back up from end of game, when gnushogi
5352 * has already exited. Assumes gameMode == EndOfGame.
5355 void
5356 ResurrectShogiProgram(void)
5358 char buf[MSG_SIZ];
5359 int i;
5361 if (currentMove > 0)
5362 currentMove--; /* delete "Black wins" or the like */
5364 InitShogiProgram(localPlayer.appData.firstHost,
5365 localPlayer.appData.firstShogiProgram,
5366 &firstProgramPID, &toFirstProgFP, &fromFirstProgFP,
5367 &firstProgramXID, &firstSendTime);
5369 SendToProgram(localPlayer.appData.initString, toFirstProgFP);
5370 SendSearchDepth(toFirstProgFP);
5371 SendToProgram("force\n", toFirstProgFP);
5372 gameMode = lastGameMode = ForceMoves;
5373 ModeHighlight();
5375 i = (whitePlaysFirst ? 1 : 0);
5377 if (startedFromSetupPosition)
5378 SendBoard(toFirstProgFP, boards[i], catches[i]);
5380 for (; i < currentMove; i++)
5382 strcpy(buf, moveList[i]);
5383 SendToProgram(buf, toFirstProgFP);
5386 if (!firstSendTime)
5388 /* can't tell gnushogi what its clock should read,
5389 so we bow to its notion. */
5390 DisplayClocks(ResetTimers);
5391 timeRemaining[0][currentMove] = blackTimeRemaining;
5392 timeRemaining[1][currentMove] = whiteTimeRemaining;
5399 void
5400 MachineWhiteProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5402 int fromRemotePlayer = *nprms;
5404 if (updateRemotePlayer)
5406 DisplayMessage("no machine moves in challenge mode",
5407 fromRemotePlayer);
5409 return;
5412 if (gameMode == PauseGame)
5413 PauseProc(w, event, prms, nprms);
5415 if (gameMode == PlayFromGameFile)
5416 ForceProc(w, event, prms, nprms);
5418 if (gameMode == EditPosition)
5419 EditPositionDone();
5421 if ((gameMode == EndOfGame)
5422 || (gameMode == PlayFromGameFile)
5423 || (gameMode == TwoMachinesPlay)
5424 || localPlayer.appData.noShogiProgram
5425 || (gameMode == MachinePlaysWhite))
5427 return;
5430 if (BlackOnMove((gameMode == ForceMoves)
5431 ? currentMove
5432 : forwardMostMove))
5434 DisplayMessage("It is not White's turn.", False);
5435 return;
5438 if (gameMode == ForceMoves)
5439 forwardMostMove = currentMove;
5441 lastGameMode = gameMode = MachinePlaysWhite;
5442 ModeHighlight();
5443 SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
5444 DisplayClocks(StartTimers);
5450 void
5451 MachineBlackProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5453 int fromRemotePlayer = *nprms;
5455 if (updateRemotePlayer)
5457 DisplayMessage("no machine moves in challenge mode",
5458 fromRemotePlayer);
5459 return;
5462 if (gameMode == PauseGame)
5463 PauseProc(w, event, prms, nprms);
5465 if (gameMode == PlayFromGameFile)
5466 ForceProc(w, event, prms, nprms);
5468 if (gameMode == EditPosition)
5469 EditPositionDone();
5471 if ((gameMode == EndOfGame)
5472 || (gameMode == PlayFromGameFile)
5473 || (gameMode == TwoMachinesPlay)
5474 || localPlayer.appData.noShogiProgram
5475 || (gameMode == MachinePlaysBlack))
5477 return;
5480 if (!BlackOnMove((gameMode == ForceMoves)
5481 ? currentMove
5482 : forwardMostMove))
5484 DisplayMessage("It is not Black's turn.", False);
5485 return;
5488 if (gameMode == ForceMoves)
5489 forwardMostMove = currentMove;
5491 lastGameMode = gameMode = MachinePlaysBlack;
5492 ModeHighlight();
5493 SendToProgram(localPlayer.appData.blackString, toFirstProgFP);
5494 DisplayClocks(StartTimers);
5500 void
5501 ForwardProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5503 char buf[MSG_SIZ];
5504 int target;
5505 unsigned int state;
5507 int fromRemotePlayer = *nprms;
5509 if (updateRemotePlayer)
5511 DisplayMessage("Forward button disabled.", fromRemotePlayer);
5512 return;
5515 if ((gameMode == EndOfGame) || (gameMode == EditPosition))
5516 return;
5518 if (gameMode == PlayFromGameFile)
5519 PauseProc(w, event, prms, nprms);
5521 if (currentMove >= forwardMostMove)
5522 return;
5524 if (event == NULL)
5526 /* Kludge */
5527 Window root, child;
5528 int root_x, root_y;
5529 int win_x, win_y;
5530 XQueryPointer(localPlayer.xDisplay, localPlayer.xBoardWindow,
5531 &root, &child, &root_x, &root_y,
5532 &win_x, &win_y, &state);
5534 else
5536 state = event->xkey.state;
5539 if (state & ShiftMask)
5540 target = forwardMostMove;
5541 else
5542 target = currentMove + 1;
5544 if (gameMode == ForceMoves)
5546 while (currentMove < target)
5548 strcpy(buf, moveList[currentMove++]);
5549 SendToProgram(buf, toFirstProgFP);
5552 else
5554 currentMove = target;
5557 if (gameMode == ForceMoves)
5559 blackTimeRemaining = timeRemaining[0][currentMove];
5560 whiteTimeRemaining = timeRemaining[1][currentMove];
5563 DisplayClocks(ReDisplayTimers);
5564 DisplayMove(currentMove - 1);
5565 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
5571 void
5572 ResetFileProc(void)
5574 char *buf = "";
5576 if (updateRemotePlayer)
5577 return;
5579 if (localPlayer.appData.loadGameFile)
5580 XtFree(localPlayer.appData.loadGameFile);
5582 if (localPlayer.appData.loadPositionFile)
5583 XtFree(localPlayer.appData.loadPositionFile);
5585 localPlayer.appData.loadGameFile
5586 = localPlayer.appData.loadPositionFile = NULL;
5587 DisplayName(buf);
5589 if (gameFileFP != NULL)
5591 fclose(gameFileFP);
5592 gameFileFP = NULL;
5599 void
5600 ResetChallenge(void)
5602 char *buf = "";
5604 if (localPlayer.appData.challengeDisplay)
5605 XtFree(localPlayer.appData.challengeDisplay);
5607 localPlayer.appData.challengeDisplay = NULL;
5608 DisplayName(buf);
5614 void
5615 ResetProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5617 int fromRemotePlayer = *nprms;
5619 if (fromRemotePlayer)
5621 DisplayMessage("Only your opponent may reset the game.",
5622 fromRemotePlayer);
5623 return;
5626 Reset(True);
5632 void
5633 Reset(int redraw) /* Boolean */
5635 ResetFileProc();
5636 ResetChallenge();
5638 localPlayer.flipView = False;
5639 remotePlayer.flipView = True;
5640 startedFromSetupPosition = whitePlaysFirst = False;
5641 matchMode = MatchFalse;
5642 firstMove = True;
5643 blackFlag = whiteFlag = False;
5644 maybeThinking = False;
5646 endMessage[0] = NULLCHAR;
5648 ShutdownShogiPrograms("");
5649 lastGameMode = gameMode = BeginningOfGame;
5650 ModeHighlight();
5651 InitPosition(redraw);
5652 DisplayClocks(ResetTimers);
5653 timeRemaining[0][0] = blackTimeRemaining;
5654 timeRemaining[1][0] = whiteTimeRemaining;
5655 InitShogiProgram(localPlayer.appData.firstHost,
5656 localPlayer.appData.firstShogiProgram,
5657 &firstProgramPID, &toFirstProgFP,
5658 &fromFirstProgFP, &firstProgramXID,
5659 &firstSendTime);
5661 if (commentUp)
5663 XtPopdown(commentShell);
5664 XtDestroyWidget(commentShell);
5665 commentUp = False;
5668 if (localPlayer.promotionUp)
5670 XtPopdown(localPlayer.promotionShell);
5671 XtDestroyWidget(localPlayer.promotionShell);
5672 localPlayer.promotionUp = False;
5675 if (updateRemotePlayer && remotePlayer.promotionUp)
5677 XtPopdown(remotePlayer.promotionShell);
5678 XtDestroyWidget(remotePlayer.promotionShell);
5679 remotePlayer.promotionUp = False;
5686 void
5687 ClearCatches(int (*catches)[8])
5689 int c, p;
5691 for (c = 0; c <= 1; c++)
5692 for (p = 0; p <= 7; p++)
5693 catches[c][p] = 0;
5699 Boolean
5700 Challenge(char *name)
5702 char buf[MSG_SIZ];
5703 int argc;
5704 char **argv;
5705 XrmDatabase database;
5707 if (gameMode != BeginningOfGame)
5709 DisplayMessage("Press Reset first.", False);
5710 return (int)False;
5713 if (localPlayer.appData.challengeDisplay != name)
5715 if (localPlayer.appData.challengeDisplay)
5716 XtFree(localPlayer.appData.challengeDisplay);
5718 localPlayer.appData.challengeDisplay = XtMalloc(strlen(name) + 1);
5719 strcpy(localPlayer.appData.challengeDisplay, name);
5722 sprintf(buf, "trying to connect to %s.....", name);
5723 DisplayMessage(buf, False);
5725 argc = global_argc;
5726 argv = global_argv;
5728 if ((remotePlayer.xDisplay
5729 = XtOpenDisplay(appContext, name, "XShogi",
5730 "XShogi", 0, 0, &argc, argv)) == NULL)
5732 sprintf(buf, "Can't open display %s", name);
5733 DisplayMessage(buf, False);
5734 XtFree(localPlayer.appData.challengeDisplay);
5735 localPlayer.appData.challengeDisplay = NULL;
5736 return (int)False;
5739 DisplayMessage("connected! creating remote window...", False);
5741 remotePlayer.xScreen = DefaultScreen(remotePlayer.xDisplay);
5743 remotePlayer.shellWidget
5744 = XtAppCreateShell(NULL, "XShogi",
5745 applicationShellWidgetClass,
5746 remotePlayer.xDisplay, NULL, 0);
5748 database = XtDatabase(remotePlayer.xDisplay);
5750 XrmParseCommand(&database,
5751 shellOptions, XtNumber(shellOptions),
5752 "XShogi", &argc, argv);
5754 XtGetApplicationResources(remotePlayer.shellWidget,
5755 &remotePlayer.appData, clientResources,
5756 XtNumber(clientResources), NULL, 0);
5758 player = &remotePlayer;
5760 CreatePlayerWindow();
5762 updateRemotePlayer = True;
5764 DisplayName("REMOTE");
5765 DrawPosition(remotePlayer.boardWidget, NULL, NULL, NULL);
5766 DisplayClocks(ReDisplayTimers);
5768 DisplayMessage("ready to play", False);
5769 DisplayMessage("ready to play", True);
5771 return True;
5777 void
5778 ChallengeProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5780 int fromRemotePlayer = *nprms;
5782 if (updateRemotePlayer)
5784 DisplayMessage("You are already in challenge mode.",
5785 fromRemotePlayer);
5786 return;
5789 if (gameMode != BeginningOfGame)
5791 DisplayMessage("Press Reset first.", False);
5792 return;
5795 if (localPlayer.appData.challengeDisplay == NULL)
5796 FileNamePopUp("Challenge display?", Challenge);
5797 else
5798 (void) Challenge(localPlayer.appData.challengeDisplay);
5804 Boolean
5805 SelectLevel(char *command)
5807 char buf[MSG_SIZ];
5809 sprintf(buf, "level %s\n", command);
5810 SendToProgram(buf, toFirstProgFP);
5812 return True;
5818 void
5819 SelectLevelProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5821 if ((BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysBlack))
5822 || (!BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysWhite)))
5824 DisplayMessage("Wait until your turn.", False);
5826 else
5828 FileNamePopUp("#moves #minutes", SelectLevel);
5835 void
5836 MoveNowProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5838 if ((!BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysBlack))
5839 || (BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysWhite)))
5841 DisplayMessage("Wait until machine's turn.", False);
5843 else
5845 Attention(firstProgramPID);
5852 void
5853 LoadPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5855 int fromRemotePlayer = *nprms;
5857 if (fromRemotePlayer)
5859 DisplayMessage("only opponent may load position", fromRemotePlayer);
5860 return;
5863 if (gameMode != BeginningOfGame)
5865 DisplayMessage("Press Reset first.", False);
5866 return;
5869 FileNamePopUp("Position file name?", LoadPosition);
5875 Boolean
5876 LoadPosition(char *name)
5878 char *p, line[MSG_SIZ], buf[MSG_SIZ];
5879 Board initial_position;
5880 Catched initial_catches;
5881 FILE *fp;
5882 int i, j;
5884 if (gameMode != BeginningOfGame)
5886 DisplayMessage("Press Reset first.", False);
5887 return False;
5890 if (localPlayer.appData.loadPositionFile != name)
5892 if (localPlayer.appData.loadPositionFile)
5893 XtFree(localPlayer.appData.loadPositionFile);
5895 localPlayer.appData.loadPositionFile = XtMalloc(strlen(name) + 1);
5896 strcpy(localPlayer.appData.loadPositionFile, name);
5899 if ((fp = fopen(name, "r")) == NULL)
5901 sprintf(buf, "Can't open %s", name);
5902 DisplayMessage(buf, False);
5903 XtFree(localPlayer.appData.loadPositionFile);
5904 localPlayer.appData.loadPositionFile = NULL;
5905 return False;
5908 lastGameMode = gameMode = ForceMoves;
5909 ModeHighlight();
5910 startedFromSetupPosition = True;
5912 if (firstProgramXID == 0)
5914 InitShogiProgram(localPlayer.appData.firstHost,
5915 localPlayer.appData.firstShogiProgram,
5916 &firstProgramPID, &toFirstProgFP,
5917 &fromFirstProgFP, &firstProgramXID,
5918 &firstSendTime);
5922 * Check and skip header information in position file.
5925 fgets(line, MSG_SIZ, fp);
5926 line[strlen(line) - 1] = NULLCHAR;
5927 sprintf(buf, "# %s position file", programName);
5929 if (strncmp(line, buf, strlen(buf)))
5931 strcat(line, ": no xshogi position file");
5932 DisplayMessage(line, False);
5933 return False;
5936 DisplayName(line);
5937 fgets(line, MSG_SIZ, fp); /* skip opponents */
5939 for (i = BOARD_SIZE - 1; i >= 0; i--)
5941 fgets(line, MSG_SIZ, fp);
5943 for (p = line, j = 0; j < BOARD_SIZE; p++)
5945 int promoted = False; /* CHECKME: is this valid? */
5947 if (*p == '+')
5948 promoted = True;
5950 if (*p == ' ')
5951 promoted = False;
5953 p++;
5954 initial_position[i][j++] = CharToPiece(*p, promoted);
5959 int color;
5961 for (color = 0; color <= 1; color++)
5963 fscanf(fp, "%i%i%i%i%i%i%i%i\n",
5964 &initial_catches[color][pawn],
5965 &initial_catches[color][lance],
5966 &initial_catches[color][knight],
5967 &initial_catches[color][silver],
5968 &initial_catches[color][gold],
5969 &initial_catches[color][bishop],
5970 &initial_catches[color][rook],
5971 &initial_catches[color][king]);
5975 whitePlaysFirst = False;
5977 if (!feof(fp))
5979 fgets(line, MSG_SIZ, fp);
5981 if (strncmp(line, "white", strlen("white")) == 0)
5982 whitePlaysFirst = True;
5985 fclose(fp);
5987 if (whitePlaysFirst)
5989 CopyBoard(boards[0], initial_position);
5990 CopyCatches(catches[0], initial_catches);
5991 strcpy(moveList[0], " ...\n");
5992 strcpy(parseList[0], " ...\n");
5993 currentMove = forwardMostMove = backwardMostMove = 1;
5994 CopyBoard(boards[1], initial_position);
5995 CopyCatches(catches[1], initial_catches);
5996 SendToProgram("white\n", toFirstProgFP);
5997 SendToProgram("force\n", toFirstProgFP);
5998 SendCurrentBoard(toFirstProgFP);
5999 DisplayMessage("White to play", False);
6001 else
6003 currentMove = forwardMostMove = backwardMostMove = 0;
6004 CopyBoard(boards[0], initial_position);
6005 CopyCatches(catches[0], initial_catches);
6006 SendCurrentBoard(toFirstProgFP);
6007 SendToProgram("force\n", toFirstProgFP);
6008 DisplayMessage("Black to play", False);
6011 DisplayClocks(ResetTimers);
6012 timeRemaining[0][1] = blackTimeRemaining;
6013 timeRemaining[1][1] = whiteTimeRemaining;
6015 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6016 return True;
6022 void
6023 EditPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6025 int fromRemotePlayer = *nprms;
6027 if (updateRemotePlayer)
6029 DisplayMessage("Edit button disabled", fromRemotePlayer);
6030 return;
6033 if (gameMode == EditPosition)
6034 return;
6036 ForceProc(w, event, prms, nprms);
6038 if (gameMode != ForceMoves)
6039 return;
6041 DisplayName("<-- Press to set side to play next");
6042 DisplayMessage("Mouse: 1=drag, 2=black, 3=white", False);
6044 lastGameMode = gameMode = EditPosition;
6045 ModeHighlight();
6047 if (currentMove > 0)
6048 CopyBoard(boards[0], boards[currentMove]);
6050 whitePlaysFirst = !BlackOnMove(forwardMostMove);
6051 currentMove = forwardMostMove = backwardMostMove = 0;
6057 void
6058 EditPositionDone(void)
6060 startedFromSetupPosition = True;
6061 SendToProgram(localPlayer.appData.initString, toFirstProgFP);
6062 SendSearchDepth(toFirstProgFP);
6064 if (whitePlaysFirst)
6066 strcpy(moveList[0], " ...\n");
6067 strcpy(parseList[0], " ...\n");
6068 currentMove = forwardMostMove = backwardMostMove = 1;
6069 CopyBoard(boards[1], boards[0]);
6070 CopyCatches(catches[1], catches[0]);
6071 SendToProgram("force\n", toFirstProgFP);
6072 SendCurrentBoard(toFirstProgFP);
6073 DisplayName(" ");
6074 DisplayMessage("White to play", False);
6076 else
6078 currentMove = forwardMostMove = backwardMostMove = 0;
6079 SendCurrentBoard(toFirstProgFP);
6080 SendToProgram("force\n", toFirstProgFP);
6081 DisplayName(" ");
6082 DisplayMessage("Black to play", False);
6085 lastGameMode = gameMode = ForceMoves;
6091 * FUNCTION
6092 * BackwardProc
6094 * DESCRIPTION
6095 * This function executes when undoing a move.
6096 * FIXME: this function is totally hosed!!!
6098 * ARGUMENTS
6099 * Widget w
6100 * XEvent *event
6101 * String *prms
6102 * Cardinal *nprms
6104 * RETURN VALUE
6105 * void
6109 void
6110 BackwardProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6112 int target;
6113 unsigned int state;
6115 int fromRemotePlayer = *nprms;
6117 if (updateRemotePlayer)
6119 DisplayMessage("Backward button disabled", fromRemotePlayer);
6120 return;
6124 * Why do we need this here?
6127 ForceProc(w, event, prms, nprms);
6129 if ((currentMove <= backwardMostMove) || (gameMode == EditPosition))
6130 return;
6132 if (gameMode == EndOfGame)
6133 ResurrectShogiProgram();
6135 if (gameMode == PlayFromGameFile)
6136 PauseProc(w, event, prms, nprms);
6138 if (event == NULL)
6140 /* Kludge */
6141 Window root, child;
6142 int root_x, root_y;
6143 int win_x, win_y;
6145 XQueryPointer(localPlayer.xDisplay, localPlayer.xBoardWindow,
6146 &root, &child, &root_x, &root_y,
6147 &win_x, &win_y, &state);
6149 else
6151 state = event->xkey.state;
6154 if (state & ShiftMask)
6156 target = backwardMostMove;
6158 else
6160 target = currentMove - 1;
6163 if (gameMode == ForceMoves)
6165 Attention(firstProgramPID);
6167 while (currentMove > target)
6169 SendToProgram("undo\n", toFirstProgFP);
6170 currentMove--;
6173 else
6175 currentMove = target;
6178 if (gameMode == ForceMoves)
6180 whiteTimeRemaining = timeRemaining[0][currentMove];
6181 blackTimeRemaining = timeRemaining[1][currentMove];
6184 DisplayClocks(ReDisplayTimers);
6185 DisplayMove(currentMove - 1);
6186 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6192 void
6193 FlipViewProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6195 struct DisplayData *player = (*nprms ? &remotePlayer : &localPlayer);
6197 player->flipView = !player->flipView;
6198 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6204 void
6205 SaveGameProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6207 char def[MSG_SIZ];
6209 int fromRemotePlayer = *nprms;
6211 if (fromRemotePlayer)
6213 DisplayMessage("only opponent may save game", fromRemotePlayer);
6214 return;
6217 def[0] = NULLCHAR;
6219 FileNamePopUp("Filename for saved game?", SaveGame);
6225 Boolean
6226 SaveGame(char *name)
6228 char buf[MSG_SIZ];
6229 int i, len, move = 0;
6230 time_t tm;
6232 if (!filemodeUp) /* if called via FileModeCallback avoid recursion */
6234 if ((gameFileFP = fopen(name, "r")) == NULL)
6236 strcpy(fmi.mode, "w");
6238 else
6240 fclose(gameFileFP);
6241 FileModePopUp(name);
6242 return False; /* CHECKME: what should the return value be? */
6246 if ((gameFileFP = fopen(name, fmi.mode)) == NULL)
6248 sprintf(buf, "Can't open %s (mode %s)", name, fmi.mode);
6249 DisplayMessage(buf, False);
6250 return False;
6253 tm = time((time_t *) NULL);
6255 fprintf(gameFileFP, "# %s game file -- %s", programName, ctime(&tm));
6256 PrintOpponents(gameFileFP);
6258 for (i = 0; i < currentMove;)
6260 if ((i % 5) == 0)
6261 fprintf(gameFileFP, "\n");
6263 fprintf(gameFileFP, "%d. %s ", ++move, parseList[i++]);
6265 if (i >= currentMove)
6267 fprintf(gameFileFP, "\n");
6268 break;
6271 if ((len = strlen(parseList[i])) == 0)
6272 break;
6274 fprintf(gameFileFP, "%s ", parseList[i++]);
6277 fprintf(gameFileFP, "\n");
6279 fclose(gameFileFP);
6280 gameFileFP = NULL;
6282 return True;
6288 void
6289 SwitchProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6291 if (localPlayer.appData.noShogiProgram)
6292 return;
6294 switch (gameMode)
6296 default:
6297 return;
6299 case MachinePlaysBlack:
6300 if (BlackOnMove(forwardMostMove))
6302 DisplayMessage("Wait until your turn", False);
6303 return;
6306 lastGameMode = gameMode = MachinePlaysWhite;
6307 ModeHighlight();
6308 break;
6310 case BeginningOfGame:
6312 case MachinePlaysWhite:
6313 if (!BlackOnMove(forwardMostMove))
6315 DisplayMessage("Wait until your turn", False);
6316 return;
6319 if (forwardMostMove == 0)
6321 MachineBlackProc(w, event, prms, nprms);
6322 return;
6325 lastGameMode = gameMode = MachinePlaysBlack;
6326 ModeHighlight();
6327 break;
6330 Attention(firstProgramPID);
6331 SendToProgram("switch\n", toFirstProgFP);
6337 void
6338 ForceProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6340 int i;
6342 switch (gameMode)
6344 case MachinePlaysBlack:
6345 if (BlackOnMove(forwardMostMove))
6347 DisplayMessage("Wait until your turn", False);
6348 return;
6351 Attention(firstProgramPID);
6352 SendToProgram("force\n", toFirstProgFP);
6353 break;
6355 case MachinePlaysWhite:
6356 if (!BlackOnMove(forwardMostMove))
6358 DisplayMessage("Wait until your turn", False);
6359 return;
6362 Attention(firstProgramPID);
6363 SendToProgram("force\n", toFirstProgFP);
6364 break;
6366 case BeginningOfGame:
6367 SendToProgram("force\n", toFirstProgFP);
6368 break;
6370 case PlayFromGameFile:
6371 if (readGameXID != 0)
6373 XtRemoveTimeOut(readGameXID);
6374 readGameXID = 0;
6377 if (gameFileFP != NULL)
6379 fclose(gameFileFP);
6380 gameFileFP = NULL;
6383 break;
6385 case EndOfGame:
6386 ResurrectShogiProgram();
6387 break;
6389 case EditPosition:
6390 EditPositionDone();
6391 break;
6393 case TwoMachinesPlay:
6394 ShutdownShogiPrograms("");
6395 ResurrectShogiProgram();
6396 return;
6398 default:
6399 return;
6402 if ((gameMode == MachinePlaysWhite)
6403 || (gameMode == MachinePlaysBlack)
6404 || (gameMode == TwoMachinesPlay)
6405 || (gameMode == PlayFromGameFile))
6407 i = forwardMostMove;
6409 while (i > currentMove)
6411 SendToProgram("undo\n", toFirstProgFP);
6412 i--;
6415 blackTimeRemaining = timeRemaining[0][currentMove];
6416 whiteTimeRemaining = timeRemaining[1][currentMove];
6418 if (whiteFlag || blackFlag)
6420 whiteFlag = blackFlag = 0;
6423 DisplayTitle("");
6426 lastGameMode = gameMode = ForceMoves;
6427 ModeHighlight();
6428 DisplayClocks(StopTimers);
6433 void
6434 HintProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6436 int fromRemotePlayer = *nprms;
6438 if (updateRemotePlayer)
6440 DisplayMessage("no hints in challenge mode", fromRemotePlayer);
6441 return;
6444 if (localPlayer.appData.noShogiProgram)
6445 return;
6447 switch (gameMode)
6449 case MachinePlaysBlack:
6450 if (BlackOnMove(forwardMostMove))
6452 DisplayMessage("Wait until your turn", False);
6453 return;
6456 break;
6458 case BeginningOfGame:
6459 case MachinePlaysWhite:
6460 if (!BlackOnMove(forwardMostMove))
6462 DisplayMessage("Wait until your turn", False);
6463 return;
6466 break;
6468 default:
6469 DisplayMessage("No hint available", False);
6470 return;
6473 Attention(firstProgramPID);
6474 SendToProgram("hint\n", toFirstProgFP);
6480 void
6481 PrintPosition(FILE *fp, int move)
6483 int i, j, color;
6485 for (i = BOARD_SIZE - 1; i >= 0; i--)
6487 for (j = 0; j < BOARD_SIZE; j++)
6489 if (pieceIsPromoted[(int)boards[currentMove][i][j]])
6490 fprintf(fp, "%c", '+');
6491 else
6492 fprintf(fp, "%c", ' ');
6494 fprintf(fp, "%c",
6495 pieceToChar[(int)boards[currentMove][i][j]]);
6497 if (j == BOARD_SIZE - 1)
6498 fputc('\n', fp);
6502 for (color = 0; color <= 1; color++)
6504 fprintf(fp, "%i %i %i %i %i %i %i %i\n",
6505 catches[currentMove][color][pawn],
6506 catches[currentMove][color][lance],
6507 catches[currentMove][color][knight],
6508 catches[currentMove][color][silver],
6509 catches[currentMove][color][gold],
6510 catches[currentMove][color][bishop],
6511 catches[currentMove][color][rook],
6512 catches[currentMove][color][king]);
6515 if ((gameMode == EditPosition)
6516 ? !whitePlaysFirst
6517 : BlackOnMove(forwardMostMove))
6519 fprintf(fp, "black to play\n");
6521 else
6523 fprintf(fp, "white to play\n");
6530 void
6531 PrintOpponents(FILE *fp)
6533 char host_name[MSG_SIZ];
6535 #ifdef HAVE_GETHOSTNAME
6536 gethostname(host_name, MSG_SIZ);
6537 #else
6538 strncpy(host_name, "hostname not available", MSG_SIZ);
6539 #endif
6541 switch (lastGameMode)
6543 case MachinePlaysWhite:
6544 fprintf(fp, "# %s@%s vs. %s@%s\n",
6545 localPlayer.appData.firstShogiProgram,
6546 localPlayer.appData.firstHost,
6547 getpwuid(getuid())->pw_name,
6548 host_name);
6549 break;
6551 case MachinePlaysBlack:
6552 fprintf(fp, "# %s@%s vs. %s@%s\n",
6553 getpwuid(getuid())->pw_name,
6554 host_name,
6555 localPlayer.appData.firstShogiProgram,
6556 localPlayer.appData.firstHost);
6557 break;
6559 case TwoMachinesPlay:
6560 fprintf(fp, "# %s@%s vs. %s@%s\n",
6561 localPlayer.appData.secondShogiProgram,
6562 localPlayer.appData.secondHost,
6563 localPlayer.appData.firstShogiProgram,
6564 localPlayer.appData.firstHost);
6565 break;
6567 default:
6568 fprintf(fp, "#\n");
6569 break;
6576 void
6577 SavePositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6579 char def[MSG_SIZ];
6581 int fromRemotePlayer = *nprms;
6583 if (fromRemotePlayer)
6585 DisplayMessage("only opponent may save game", fromRemotePlayer);
6586 return;
6589 def[0] = NULLCHAR;
6591 FileNamePopUp("Filename for saved position?", SavePosition);
6597 Boolean
6598 SavePosition(char *name)
6600 char buf[MSG_SIZ];
6601 FILE *fp;
6602 time_t tm;
6604 if ((fp = fopen(name, "w")) == NULL)
6606 sprintf(buf, "Can't open %s", name);
6607 DisplayMessage(buf, False);
6608 return False;
6611 tm = time((time_t *) NULL);
6613 fprintf(fp, "# %s position file -- %s", programName, ctime(&tm));
6614 PrintOpponents(fp);
6615 PrintPosition(fp, currentMove);
6616 fclose(fp);
6618 return True;
6624 void
6625 TwoMachinesProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6627 int i;
6628 MatchMode matchKind;
6630 int fromRemotePlayer = *nprms;
6632 if (updateRemotePlayer)
6634 DisplayMessage("no machine moves in challenge mode",
6635 fromRemotePlayer);
6636 return;
6639 if (gameMode == PauseGame)
6640 PauseProc(w, event, prms, nprms);
6642 if (gameMode == PlayFromGameFile)
6643 ForceProc(w, event, prms, nprms);
6645 if ((gameMode == EndOfGame)
6646 || (gameMode == TwoMachinesPlay)
6647 || localPlayer.appData.noShogiProgram)
6649 return;
6652 if (matchMode == MatchFalse)
6654 switch (gameMode)
6656 case PauseGame:
6657 case PlayFromGameFile:
6658 return;
6660 case MachinePlaysBlack:
6661 case MachinePlaysWhite:
6662 ForceProc(w, event, prms, nprms);
6664 if (gameMode != ForceMoves)
6665 return;
6667 matchKind = MatchOpening;
6668 break;
6670 case ForceMoves:
6671 matchKind = MatchOpening;
6672 break;
6674 case EditPosition:
6675 EditPositionDone();
6676 matchKind = MatchPosition;
6677 break;
6679 case BeginningOfGame:
6680 default:
6681 matchKind = MatchInit;
6682 break;
6685 else
6687 matchKind = matchMode;
6690 forwardMostMove = currentMove;
6692 localPlayer.flipView = False;
6693 remotePlayer.flipView = True;
6694 firstMove = False;
6695 DisplayClocks(ResetTimers);
6696 DisplayClocks(StartTimers);
6698 switch (matchKind)
6700 case MatchOpening:
6701 if (firstProgramXID == 0)
6703 if (localPlayer.appData.loadGameFile == NULL)
6705 DisplayMessage("Select game file first", False);
6706 return;
6709 InitShogiProgram(localPlayer.appData.firstHost,
6710 localPlayer.appData.firstShogiProgram,
6711 &firstProgramPID, &toFirstProgFP,
6712 &fromFirstProgFP, &firstProgramXID,
6713 &firstSendTime);
6715 if (!LoadGame(localPlayer.appData.loadGameFile))
6717 ShutdownShogiPrograms("Bad game file");
6718 return;
6721 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6724 InitShogiProgram(localPlayer.appData.secondHost,
6725 localPlayer.appData.secondShogiProgram,
6726 &secondProgramPID, &toSecondProgFP,
6727 &fromSecondProgFP, &secondProgramXID,
6728 &secondSendTime);
6730 if (startedFromSetupPosition)
6732 if (whitePlaysFirst)
6734 i = 1;
6735 SendToProgram("force\n", toSecondProgFP);
6736 SendBoard(toSecondProgFP, boards[i], catches[i]);
6738 else
6740 i = 0;
6741 SendBoard(toSecondProgFP, boards[i], catches[i]);
6742 SendToProgram("force\n", toSecondProgFP);
6745 else
6747 i = 0;
6748 SendToProgram("force\n", toSecondProgFP);
6751 for (i = backwardMostMove; i < forwardMostMove; i++)
6752 SendToProgram(moveList[i], toSecondProgFP);
6754 lastGameMode = gameMode = TwoMachinesPlay;
6755 ModeHighlight();
6756 firstMove = True;
6758 if (BlackOnMove(forwardMostMove))
6759 SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6760 else
6761 SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
6763 break;
6765 case MatchPosition:
6766 if (firstProgramXID == 0)
6768 if (localPlayer.appData.loadPositionFile == NULL)
6770 DisplayMessage("Select position file first", False);
6771 return;
6774 InitShogiProgram(localPlayer.appData.firstHost,
6775 localPlayer.appData.firstShogiProgram,
6776 &firstProgramPID, &toFirstProgFP,
6777 &fromFirstProgFP, &firstProgramXID,
6778 &firstSendTime);
6780 if (!LoadPosition(localPlayer.appData.loadPositionFile))
6781 return;
6784 InitShogiProgram(localPlayer.appData.secondHost,
6785 localPlayer.appData.secondShogiProgram,
6786 &secondProgramPID, &toSecondProgFP,
6787 &fromSecondProgFP, &secondProgramXID,
6788 &secondSendTime);
6790 if (whitePlaysFirst)
6791 SendToProgram("force\n", toSecondProgFP);
6793 SendCurrentBoard(toSecondProgFP);
6794 lastGameMode = gameMode = TwoMachinesPlay;
6795 ModeHighlight();
6796 firstMove = True;
6798 if (BlackOnMove(forwardMostMove))
6799 SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6800 else
6801 SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
6803 break;
6805 case MatchInit:
6806 InitPosition(True);
6808 if (firstProgramXID == 0)
6810 InitShogiProgram(localPlayer.appData.firstHost,
6811 localPlayer.appData.firstShogiProgram,
6812 &firstProgramPID, &toFirstProgFP,
6813 &fromFirstProgFP, &firstProgramXID,
6814 &firstSendTime);
6817 InitShogiProgram(localPlayer.appData.secondHost,
6818 localPlayer.appData.secondShogiProgram,
6819 &secondProgramPID, &toSecondProgFP,
6820 &fromSecondProgFP, &secondProgramXID,
6821 &secondSendTime);
6823 lastGameMode = gameMode = TwoMachinesPlay;
6824 ModeHighlight();
6825 SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6827 default:
6828 break;
6831 if (!firstSendTime || !secondSendTime)
6833 DisplayClocks(ResetTimers);
6834 timeRemaining[0][forwardMostMove] = blackTimeRemaining;
6835 timeRemaining[1][forwardMostMove] = whiteTimeRemaining;
6838 DisplayClocks(StartTimers);
6844 void
6845 PauseProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6847 static GameMode previous_mode = PauseGame;
6849 switch (gameMode)
6851 case ForceMoves:
6852 case EndOfGame:
6853 case EditPosition:
6854 default:
6855 return;
6857 case PauseGame:
6858 gameMode = previous_mode;
6859 ModeHighlight();
6860 previous_mode = PauseGame;
6861 DisplayClocks(StartTimers);
6862 DisplayMessage("", False);
6864 if (updateRemotePlayer)
6865 DisplayMessage("", True);
6866 break;
6868 case PlayFromGameFile:
6869 if (readGameXID == 0)
6871 readGameXID =
6872 XtAppAddTimeOut(appContext,
6873 (int)(1000 * localPlayer.appData.timeDelay),
6874 (XtTimerCallbackProc) ReadGameFile, NULL);
6876 else
6878 XtRemoveTimeOut(readGameXID);
6879 readGameXID = 0;
6882 DisplayMessage("Pausing", False);
6884 if (updateRemotePlayer)
6885 DisplayMessage("Pausing", True);
6887 break;
6889 case BeginningOfGame:
6890 case MachinePlaysBlack:
6891 case MachinePlaysWhite:
6892 case TwoMachinesPlay:
6893 if (forwardMostMove == 0) /* Don't pause if no one has moved. */
6894 return;
6896 if (((gameMode == MachinePlaysWhite)
6897 && !BlackOnMove(forwardMostMove))
6898 || ((gameMode == MachinePlaysBlack) &&
6899 BlackOnMove(forwardMostMove)))
6901 DisplayClocks(StopTimers);
6904 previous_mode = gameMode;
6905 gameMode = PauseGame;
6906 ModeHighlight();
6907 DisplayClocks(StopTimers);
6908 DisplayMessage("Pausing", False);
6910 if (updateRemotePlayer)
6911 DisplayMessage("Pausing", True);
6913 break;
6920 void
6921 Iconify(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6923 Arg args[1];
6925 fromX = fromY = -1;
6927 XtSetArg(args[0], XtNiconic, True);
6928 XtSetValues(localPlayer.shellWidget, args, 1);
6934 void
6935 SendToProgram(char *message, FILE *fp)
6937 if (fp == NULL)
6938 return;
6940 lastMsgFP = fp;
6942 if (xshogiDebug)
6944 fprintf(stderr, "Sending to %s: %s\n",
6945 ((fp == toFirstProgFP) ? "first" : "second"), message);
6948 if (message[strlen(message) - 1] != '\n')
6949 fprintf(fp, "\n%s\n", message);
6950 else
6951 fputs(message, fp);
6953 fflush(fp);
6959 void
6960 ReceiveFromProgram(FILE *fp, int *source, XtInputId *id)
6962 char message[MSG_SIZ], *end_str, *number, *name;
6964 if (fgets(message, MSG_SIZ, fp) == NULL)
6966 if (fp == fromFirstProgFP)
6968 number = "first";
6969 name = localPlayer.appData.firstShogiProgram;
6971 else if (fp == fromSecondProgFP)
6973 number = "second";
6974 name = localPlayer.appData.secondShogiProgram;
6976 else
6978 return;
6981 if (ferror(fp) == 0)
6983 sprintf(message, "%s shogi program (%s) exited unexpectedly",
6984 number, name);
6985 fprintf(stderr, "%s: %s\n", programName, message);
6987 else
6989 sprintf(message,
6990 "error reading from %s shogi program (%s): %s",
6991 number, name, strerror(ferror(fp)));
6992 fprintf(stderr, "%s: %s\n", programName, message);
6995 return;
6998 if ((end_str = (char *)strchr(message, '\r')) != NULL)
6999 *end_str = NULLCHAR;
7001 if ((end_str = (char *)strchr(message, '\n')) != NULL)
7002 *end_str = NULLCHAR;
7004 if (xshogiDebug || localPlayer.appData.debugMode)
7006 fprintf(stderr, "Received from %s: %s\n",
7007 ((fp == fromFirstProgFP) ? "first" : "second"), message);
7010 HandleMachineMove(message, fp);
7016 void
7017 SendSearchDepth(FILE *fp)
7019 char message[MSG_SIZ];
7021 if (localPlayer.appData.searchDepth <= 0)
7022 return;
7024 sprintf(message, "depth\n%d\nhelp\n", localPlayer.appData.searchDepth);
7025 /* Note kludge: "help" command forces gnushogi to print
7026 * out something that ends with a newline. */
7027 SendToProgram(message, fp);
7033 void
7034 DisplayMessage(char *message, int toRemotePlayer)
7036 Arg arg;
7038 XtSetArg(arg, XtNlabel, message);
7040 if (!toRemotePlayer)
7041 XtSetValues(localPlayer.messageWidget, &arg, 1);
7043 if (updateRemotePlayer && toRemotePlayer)
7044 XtSetValues(remotePlayer.messageWidget, &arg, 1);
7050 void
7051 DisplayName(char *name)
7053 Arg arg;
7055 XtSetArg(arg, XtNlabel, name);
7056 XtSetValues(localPlayer.titleWidget, &arg, 1);
7058 if (updateRemotePlayer)
7059 XtSetValues(remotePlayer.titleWidget, &arg, 1);
7065 void SendTimeRemaining(FILE *fp)
7067 char message[MSG_SIZ];
7068 long comtime, opptime;
7070 if (BlackOnMove(forwardMostMove) == (fp == toFirstProgFP))
7072 comtime = blackTimeRemaining;
7073 opptime = whiteTimeRemaining;
7075 else
7077 comtime = whiteTimeRemaining;
7078 opptime = blackTimeRemaining;
7081 if (comtime <= 0)
7082 comtime = 1000;
7084 if (opptime <= 0)
7085 opptime = 1000;
7087 sprintf(message, "time %ld\n", comtime / 10);
7088 SendToProgram(message, fp);
7089 sprintf(message, "otime %ld\n", opptime / 10);
7090 SendToProgram(message, fp);
7096 void DisplayMove(int moveNumber)
7098 char message[MSG_SIZ];
7100 if (moveNumber < 0)
7102 if (moveNumber == forwardMostMove - 1)
7103 DisplayMessage(endMessage, False);
7104 else
7105 DisplayMessage("", False);
7107 else
7109 sprintf(message, "%d. %s%s %s",
7110 (moveNumber / 2 + 1),
7111 (BlackOnMove(moveNumber) ? "" : "... "),
7112 parseList[moveNumber],
7113 (moveNumber == (forwardMostMove - 1)) ? endMessage : "");
7114 DisplayMessage(message, False);
7121 void DisplayTitle(char *title)
7123 Arg arg;
7125 XtSetArg(arg, XtNlabel, title);
7126 XtSetValues(localPlayer.titleWidget, &arg, 1);
7133 * This routine used to send a SIGINT (^C interrupt) to gnushogi to awaken it
7134 * if it might be busy thinking on our time. This normally isn't needed,
7135 * but is useful on systems where the FIONREAD ioctl doesn't work since
7136 * on those systems the gnushogi feature that lets you interrupt its thinking
7137 * just by typing a command does not work.
7139 * Now gnushogi periodically checks for user input without a need for
7140 * this hack.
7143 void
7144 Attention(int pid)
7146 #if 0
7147 if (localPlayer.appData.noShogiProgram || (pid == 0))
7148 return;
7150 switch (gameMode)
7152 case MachinePlaysBlack:
7153 case MachinePlaysWhite:
7154 case TwoMachinesPlay:
7155 if ((forwardMostMove > backwardMostMove + 1) && maybeThinking)
7157 if (xshogiDebug || localPlayer.appData.debugMode)
7159 fprintf(stderr, "Sending SIGINT to %s\n",
7160 ((pid == firstProgramPID) ? "first" : "second"));
7163 (void)kill(pid, SIGINT); /* stop it thinking */
7165 break;
7167 default:
7168 break; /* CHECKME: is this OK? */
7170 #endif /* !defined(FIONREAD) */
7176 void
7177 CheckFlags(void)
7179 if (blackTimeRemaining <= 0)
7181 if (!blackFlag)
7183 blackFlag = True;
7185 if (whiteFlag)
7186 DisplayName(" Both flags have fallen");
7187 else
7188 DisplayName(" Black's flag has fallen");
7192 if (whiteTimeRemaining <= 0)
7194 if (!whiteFlag)
7196 whiteFlag = True;
7198 if (blackFlag)
7199 DisplayName(" Both flags have fallen");
7200 else
7201 DisplayName(" White's flag has fallen");
7209 void
7210 CheckTimeControl(void)
7212 if (!localPlayer.appData.clockMode)
7213 return;
7215 if (forwardMostMove == 0)
7216 return;
7219 * Add time to clocks when time control is achieved.
7222 if ((forwardMostMove % (localPlayer.appData.movesPerSession * 2)) == 0)
7224 blackTimeRemaining += timeControl;
7225 whiteTimeRemaining += timeControl;
7232 void
7233 DisplayLabels(void)
7235 DisplayTimerLabel(localPlayer.blackTimerWidget, "Black",
7236 blackTimeRemaining);
7237 DisplayTimerLabel(localPlayer.whiteTimerWidget, "White",
7238 whiteTimeRemaining);
7240 if (updateRemotePlayer)
7242 DisplayTimerLabel(remotePlayer.blackTimerWidget, "Black",
7243 blackTimeRemaining);
7244 DisplayTimerLabel(remotePlayer.whiteTimerWidget, "White",
7245 whiteTimeRemaining);
7252 #ifdef HAVE_GETTIMEOFDAY
7253 static struct timeval tickStartTV;
7254 static int tickLength;
7257 PartialTickLength(void)
7259 struct timeval tv;
7260 int ptl;
7262 gettimeofday(&tv, NULL);
7263 ptl = ((tv.tv_sec - tickStartTV.tv_sec) * 1000000 +
7264 (tv.tv_usec - tickStartTV.tv_usec) + 500) / 1000;
7266 if (ptl > tickLength)
7267 ptl = tickLength;
7269 return ptl;
7271 #else /* !HAVE_GETTIMEOFDAY */
7272 #define tickLength 1000
7273 #endif /* HAVE_GETTIMEOFDAY */
7279 * DisplayClocks manages the game clocks.
7281 * In tournament play, white starts the clock and then black makes a move.
7282 * We give the human user a slight advantage if he is playing black---the
7283 * clocks don't run until he makes his first move, so it takes zero time.
7284 * Also, DisplayClocks doesn't account for network lag so it could get out
7285 * of sync with GNU Shogi's clock -- but then, referees are always right.
7288 void
7289 DisplayClocks(int clock_mode)
7291 long timeRemaining;
7293 switch (clock_mode)
7295 case ResetTimers:
7296 /* Stop clocks and reset to a fresh time control */
7297 if (timerXID != 0)
7299 XtRemoveTimeOut(timerXID);
7300 timerXID = 0;
7303 blackTimeRemaining = timeControl;
7304 whiteTimeRemaining = timeControl;
7306 if (blackFlag || whiteFlag)
7308 DisplayName("");
7309 blackFlag = whiteFlag = False;
7312 DisplayLabels();
7313 break;
7315 case DecrementTimers:
7316 /* Decrement running clock to next 1-second boundary */
7317 if (gameMode == PauseGame)
7318 return;
7320 timerXID = 0;
7322 if (!localPlayer.appData.clockMode)
7323 return;
7325 if (BlackOnMove(forwardMostMove))
7327 timeRemaining = (blackTimeRemaining -= tickLength);
7329 else
7331 timeRemaining = (whiteTimeRemaining -= tickLength);
7334 DisplayLabels();
7335 CheckFlags();
7337 #ifdef HAVE_GETTIMEOFDAY
7338 tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7339 ? 100 : 1000);
7340 gettimeofday(&tickStartTV, NULL);
7341 #endif /* HAVE_GETTIMEOFDAY */
7343 timerXID =
7344 XtAppAddTimeOut(appContext, tickLength,
7345 (XtTimerCallbackProc) DisplayClocks,
7346 (XtPointer) DecrementTimers);
7347 break;
7349 case SwitchTimers:
7350 /* A player has just moved, so stop the previously running
7351 clock and start the other one. */
7353 if (timerXID != 0)
7355 XtRemoveTimeOut(timerXID);
7356 timerXID = 0;
7358 #ifdef HAVE_GETTIMEOFDAY
7359 if (localPlayer.appData.clockMode)
7361 if (BlackOnMove(forwardMostMove))
7362 whiteTimeRemaining -= PartialTickLength();
7363 else
7364 blackTimeRemaining -= PartialTickLength();
7365 CheckFlags();
7367 #endif /* HAVE_GETTIMEOFDAY */
7370 CheckTimeControl();
7371 DisplayLabels();
7373 if (!localPlayer.appData.clockMode)
7374 return;
7376 if ((gameMode == PauseGame)
7377 && ((pausePreviousMode == MachinePlaysBlack)
7378 || (pausePreviousMode == MachinePlaysWhite)))
7380 return;
7383 timeRemaining = (BlackOnMove(forwardMostMove)
7384 ? blackTimeRemaining : whiteTimeRemaining);
7386 #ifdef HAVE_GETTIMEOFDAY
7387 tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7388 ? (((timeRemaining - 1) % 100) + 1)
7389 : (((timeRemaining - 1) % 1000) + 1));
7391 if (tickLength <= 0)
7392 tickLength += 1000;
7394 gettimeofday(&tickStartTV, NULL);
7396 #endif /* HAVE_GETTIMEOFDAY */
7397 timerXID =
7398 XtAppAddTimeOut(appContext, tickLength,
7399 (XtTimerCallbackProc) DisplayClocks,
7400 (XtPointer) DecrementTimers);
7401 break;
7403 case ReDisplayTimers:
7404 /* Display current clock values */
7405 DisplayLabels();
7406 break;
7408 case StopTimers:
7409 /* Stop both clocks */
7410 if (timerXID == 0)
7411 return;
7413 XtRemoveTimeOut(timerXID);
7414 timerXID = 0;
7416 if (!localPlayer.appData.clockMode)
7417 return;
7419 #ifdef HAVE_GETTIMEOFDAY
7420 if (BlackOnMove(forwardMostMove))
7421 blackTimeRemaining -= PartialTickLength();
7422 else
7423 whiteTimeRemaining -= PartialTickLength();
7424 CheckFlags();
7425 DisplayLabels();
7426 #endif /* HAVE_GETTIMEOFDAY */
7427 break;
7429 case StartTimers:
7430 /* Start clock of player on move, if not already running. */
7431 if (timerXID != 0)
7432 return;
7434 DisplayLabels();
7436 if (!localPlayer.appData.clockMode)
7437 return;
7439 timeRemaining = (BlackOnMove(forwardMostMove)
7440 ? blackTimeRemaining : whiteTimeRemaining);
7442 if (timeRemaining == 0)
7443 return;
7445 #ifdef HAVE_GETTIMEOFDAY
7446 tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7447 ? (((timeRemaining - 1) % 100) + 1)
7448 : (((timeRemaining - 1) % 1000) + 1));
7450 if (tickLength <= 0)
7451 tickLength += 1000;
7453 gettimeofday(&tickStartTV, NULL);
7454 #endif /* HAVE_GETTIMEOFDAY */
7456 timerXID =
7457 XtAppAddTimeOut(appContext, tickLength,
7458 (XtTimerCallbackProc) DisplayClocks,
7459 (XtPointer)DecrementTimers);
7460 break;
7467 void
7468 DisplayTimerLabel(Widget w, char *color, long int timer)
7470 char buf[MSG_SIZ];
7471 Arg args[3];
7472 struct DisplayData *player;
7474 player = (((w == localPlayer.blackTimerWidget)
7475 || (w == localPlayer.whiteTimerWidget))
7476 ? &localPlayer : &remotePlayer);
7478 if (localPlayer.appData.clockMode)
7480 sprintf(buf, "%s: %s", color, TimeString(timer));
7481 XtSetArg(args[0], XtNlabel, buf);
7483 else
7485 XtSetArg(args[0], XtNlabel, color);
7488 if (((color[0] == 'W') && BlackOnMove(forwardMostMove))
7489 || ((color[0] == 'B') && !BlackOnMove(forwardMostMove)))
7491 XtSetArg(args[1], XtNbackground, player->timerForegroundPixel);
7492 XtSetArg(args[2], XtNforeground, player->timerBackgroundPixel);
7494 else
7496 XtSetArg(args[1], XtNbackground, player->timerBackgroundPixel);
7497 XtSetArg(args[2], XtNforeground, player->timerForegroundPixel);
7500 XtSetValues(w, args, 3);
7506 char *
7507 TimeString(long tm)
7509 int second, minute, hour, day;
7510 char *sign = "";
7511 static char buf[32];
7513 if ((tm > 0) && (tm <= 900))
7515 /* convert milliseconds to tenths, rounding up */
7516 sprintf(buf, " 0.%1ld ", (tm + 99) / 100);
7517 return buf;
7520 /* convert milliseconds to seconds, rounding up */
7521 tm = (tm + 999) / 1000;
7523 if (tm < 0)
7525 sign = "-";
7526 tm = -tm;
7529 if (tm >= (60 * 60 * 24))
7531 day = (int)(tm / (60 * 60 * 24));
7532 tm -= day * 60 * 60 * 24;
7534 else
7536 day = 0;
7539 if (tm >= (60 * 60))
7541 hour = (int)(tm / (60 * 60));
7542 tm -= hour * 60 * 60;
7544 else
7546 hour = 0;
7549 if (tm >= 60)
7551 minute = (int)(tm / 60);
7552 tm -= minute * 60;
7554 else
7556 minute = 0;
7559 second = tm % 60;
7561 if (day > 0)
7563 sprintf(buf, " %s%d:%02d:%02d:%02d ",
7564 sign, day, hour, minute, second);
7566 else if (hour > 0)
7568 sprintf(buf, " %s%d:%02d:%02d ",
7569 sign, hour, minute, second);
7571 else
7573 sprintf(buf, " %s%2d:%02d ",
7574 sign, minute, second);
7577 return buf;
7583 void
7584 Usage(void)
7586 fprintf(stderr, "Usage: %s\n", programName);
7587 fprintf(stderr, "\tstandard Xt options\n");
7588 fprintf(stderr, "\t-iconic\n");
7589 fprintf(stderr, "\t-tc or -timeControl minutes[:seconds]\n");
7590 fprintf(stderr, "\t-gi or -gameIn (True | False)\n");
7591 fprintf(stderr, "\t-mps or -movesPerSession moves\n");
7592 fprintf(stderr, "\t-st or -searchTime minutes[:seconds]\n");
7593 fprintf(stderr, "\t-sd or -searchDepth number\n");
7594 fprintf(stderr, "\t-clock or -clockMode (True | False)\n");
7595 fprintf(stderr, "\t-td or -timeDelay seconds\n");
7597 fprintf(stderr, "\t-nsp or -noShogiProgram (True | False)\n");
7598 fprintf(stderr, "\t-fsp or -firstShogiProgram program_name\n");
7599 fprintf(stderr, "\t-ssp or -secondShogiProgram program_name\n");
7600 fprintf(stderr, "\t-fh or -firstHost host_name\n");
7601 fprintf(stderr, "\t-sh or -secondHost host_name\n");
7602 fprintf(stderr, "\t-rsh or -remoteShell shell_name\n");
7603 fprintf(stderr,
7604 "\t-mm or -matchMode (False | Init | Position | Opening)\n");
7605 fprintf(stderr, "\t-lgf or -loadGameFile file_name\n");
7606 fprintf(stderr, "\t-lpf or -loadPositionFile file_name\n");
7607 fprintf(stderr, "\t-sgf or -saveGameFile file_name\n");
7608 fprintf(stderr, "\t-spf or -savePositionFile file_name\n");
7609 fprintf(stderr, "\t-size or -boardSize (Large | Medium | Small)\n");
7610 fprintf(stderr, "\t-coords or -showCoords (True | False)\n");
7611 fprintf(stderr, "\t-mono or -monoMode (True | False)\n");
7612 fprintf(stderr, "\t-pc or -pieceColor color\n");
7613 fprintf(stderr, "\t-sc or -squareColor color\n");
7614 fprintf(stderr, "\t-wps or -westernPieceSet (True | False)\n");
7615 fprintf(stderr, "\t-debug or -debugMode (True | False)\n");
7616 exit(2);
7621 void
7622 CatchPipeSignal(int dummy)
7624 char message[MSG_SIZ];
7626 sprintf(message,
7627 "%s shogi program (%s) exited unexpectedly",
7628 ((lastMsgFP == toFirstProgFP) ? "first" : "second"),
7629 ((lastMsgFP == toFirstProgFP)
7630 ? localPlayer.appData.firstShogiProgram
7631 : localPlayer.appData.secondShogiProgram));
7632 fprintf(stderr, "%s: %s\n", programName, message);
7633 ShutdownShogiPrograms(message);
7634 return;