1 /*
2 * FILE: xshogi.c
3 *
4 * Implementation of the X interface for GNU shogi (xshogi).
5 *
6 * ------------------------------------------------------------------------
7 * xshogi is based on XBoard -- an Xt/Athena user interface for GNU Chess.
8 *
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
15 *
16 * XShogi borrows some of its piece bitmaps from CRANES Shogi.
17 *
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
22 *
23 * The following terms apply to Digital Equipment Corporation's copyright
24 * interest in XBoard:
25 * ------------------------------------------------------------------------
26 * All Rights Reserved
27 *
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.
35 *
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 * ------------------------------------------------------------------------
44 *
45 * This file is part of GNU shogi.
46 *
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.
50 *
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.
55 *
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.
59 *
60 * ------------------------------------------------------------------------
61 *
62 */
63
64 #include "config.h"
65
66 #ifdef X_DISPLAY_MISSING
67 #error You cannot compile xshogi if X windows is unavailable!
68 #endif
69
70 #include "sysdeps.h"
71
72 #define XBOARD_VERSION "2.0/2.1"
73
74 #include <stdio.h>
75 #include <ctype.h>
76 #include <signal.h>
77 #include <sys/ioctl.h>
78
79 #include <time.h>
80 #include <pwd.h>
81
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>
93
94 #include "xshogi.h"
95
96 #define BUF_SIZE 1024
97 #define BOARD 1
98 #define MOVES 2
99
100 #include "bitmaps.h" /* Piece bitmaps. */
101 #include "xshogifn.h" /* Forward declarations. */
102
103 #define off_board(x) ((x < 2) || (x > BOARD_SIZE + 1))
104
105
106 /**********************************************************************
107 *
108 * Global variables, structs etc.
109 *
110 **********************************************************************/
111
112 /*
113 * NOTE: XShogi depends on Xt R4 or higher
114 */
115
116 int xtVersion = XtSpecificationRelease;
117
118 XtIntervalId firstProgramXID = 0, secondProgramXID = 0,
119 readGameXID = 0, timerXID = 0, blinkSquareXID = 0;
120
121 XtAppContext appContext;
122
123 Boolean (*fileProc) (char *name);
124
125 FILE *fromFirstProgFP, *toFirstProgFP, *fromSecondProgFP,
126 *toSecondProgFP, *gameFileFP, *lastMsgFP;
127
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;
137
138 int at_least_gnushogi_1_2p03 = False;
139
140 int firstSendTime = 2, secondSendTime = 2; /* 0 = don't, 1 = do,
141 2 = test first */
142
143 MatchMode matchMode = MatchFalse;
144 GameMode gameMode = BeginningOfGame;
145 GameMode lastGameMode = BeginningOfGame;
146 GameMode pausePreviousMode = BeginningOfGame;
147
148 char moveList[MAX_MOVES][MOVE_LEN], parseList[MAX_MOVES][MOVE_LEN * 2],
149 ptyname[24], *shogiDir, *programName;
150
151 char endMessage[MOVE_LEN * 4];
152
153 long blackTimeRemaining, whiteTimeRemaining, timeControl;
154 long timeRemaining[2][MAX_MOVES];
155
156 extern char currentMoveString[];
157
158 int updateRemotePlayer = False;
159
160 Catched catches[MAX_MOVES];
161
162 #define DIMENSION 100
163
164 Widget blackPieceMenu, whitePieceMenu, commentShell;
165
166 XSetWindowAttributes attr;
167
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
182
183 #define NO_PIECES 15
184 #define NO_SQUARES 81
185 #define NO_COLS 9
186 #define NO_ROWS 9
187
188
189 char catchedIndexToChar[8] =
190 {
191 'P', 'L', 'N', 'S', 'G', 'B', 'R', 'K'
192 };
193
194 ShogiSquare catchedIndexToPiece[2][8] =
195 {
196 {
197 BlackPawn, BlackLance, BlackKnight, BlackSilver, BlackGold,
198 BlackBishop, BlackRook, BlackKing
199 },
200 {
201 WhitePawn, WhiteLance, WhiteKnight, WhiteSilver, WhiteGold,
202 WhiteBishop, WhiteRook, WhiteKing
203 }
204 };
205
206
207 int pieceToCatchedIndex[] =
208 {
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
214 };
215
216
217
218 Board boards[MAX_MOVES];
219 Board initialPosition =
220 {
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 }
239 };
240
241 String gnuButtonStrings[] =
242 {
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",
248 };
249
250 /* must be in same order as buttonStrings! */
251 XtActionProc gnuButtonProcs[] =
252 {
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
259 };
260
261
262 String *buttonStrings;
263 XtActionProc *buttonProcs;
264 int buttonCount;
265
266 #define PIECE_MENU_SIZE 18
267
268 String pieceMenuStrings[PIECE_MENU_SIZE] =
269 {
270 "----", "Pawn", "Lance", "Knight", "Silver",
271 "Gold", "Bishop", "Rook",
272 "PPawn", "PLance", "PKnight", "PSilver",
273 "PBishop", "PRook", "King",
274 "----", "Empty square", "Clear board"
275 };
276
277 /* must be in same order as PieceMenuStrings! */
278 ShogiSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] =
279 {
280 {
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
286 },
287 {
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
293 },
294 };
295
296
297 typedef struct
298 {
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;
350
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;
373
374
375 XtResource clientResources[] =
376 {
377 {
378 "pieceColor", "pieceColor", XtRPixel, sizeof(Pixel),
379 XtOffset(AppDataPtr, pieceColor), XtRString,
380 PIECE_COLOR
381 },
382 {
383 "charPieceColor", "CharPieceColor", XtRPixel, sizeof(Pixel),
384 XtOffset(AppDataPtr, charPieceColor), XtRString,
385 CHAR_PIECE_COLOR
386 },
387 {
388 "oneColor", "OneColor", XtRPixel, sizeof(Pixel),
389 XtOffset(AppDataPtr, oneColor), XtRString,
390 ONE_COLOR
391 },
392 {
393 "zeroColor", "ZeroColor", XtRPixel, sizeof(Pixel),
394 XtOffset(AppDataPtr, zeroColor), XtRString,
395 ZERO_COLOR
396 },
397 {
398 "squareColor", "squareColor", XtRPixel,
399 sizeof(Pixel), XtOffset(AppDataPtr, squareColor),
400 XtRString, SQUARE_COLOR
401 },
402 {
403 "westernPieceSet", "WesternPieceSet", XtRBoolean, sizeof(Boolean),
404 XtOffset(AppDataPtr, westernPieceSet), XtRString,
405 (XtPointer) False
406 },
407 {
408 "movesPerSession", "movesPerSession", XtRInt, sizeof(int),
409 XtOffset(AppDataPtr, movesPerSession), XtRImmediate,
410 (XtPointer) MOVES_PER_SESSION
411 },
412 {
413 "initString", "initString", XtRString, sizeof(String),
414 XtOffset(AppDataPtr, initString), XtRString, INIT_STRING
415 },
416 {
417 "blackString", "blackString", XtRString, sizeof(String),
418 XtOffset(AppDataPtr, blackString), XtRString, BLACK_STRING
419 },
420 {
421 "whiteString", "whiteString", XtRString, sizeof(String),
422 XtOffset(AppDataPtr, whiteString), XtRString, WHITE_STRING
423 },
424 {
425 "firstShogiProgram", "firstShogiProgram", XtRString,
426 sizeof(String), XtOffset(AppDataPtr, firstShogiProgram),
427 XtRString, FIRST_SHOGI_PROGRAM
428 },
429 {
430 "secondShogiProgram", "secondShogiProgram", XtRString,
431 sizeof(String), XtOffset(AppDataPtr, secondShogiProgram),
432 XtRString, SECOND_SHOGI_PROGRAM
433 },
434 {
435 "noShogiProgram", "noShogiProgram", XtRBoolean,
436 sizeof(Boolean), XtOffset(AppDataPtr, noShogiProgram),
437 XtRImmediate, (XtPointer) False
438 },
439 {
440 "firstHost", "firstHost", XtRString, sizeof(String),
441 XtOffset(AppDataPtr, firstHost), XtRString, FIRST_HOST
442 },
443 {
444 "secondHost", "secondHost", XtRString, sizeof(String),
445 XtOffset(AppDataPtr, secondHost), XtRString, SECOND_HOST
446 },
447 {
448 "reversePawnBitmap", "reversePawnBitmap", XtRString,
449 sizeof(String), XtOffset(AppDataPtr, reversePawnBitmap),
450 XtRString, NULL
451 },
452 {
453 "reverseLanceBitmap", "reverseLanceBitmap", XtRString,
454 sizeof(String), XtOffset(AppDataPtr, reverseLanceBitmap),
455 XtRString, NULL
456 },
457 {
458 "reverseKnightBitmap", "reverseKnightBitmap", XtRString,
459 sizeof(String), XtOffset(AppDataPtr, reverseKnightBitmap),
460 XtRString, NULL
461 },
462 {
463 "reverseSilverBitmap", "reverseSilverBitmap", XtRString,
464 sizeof(String), XtOffset(AppDataPtr, reverseSilverBitmap),
465 XtRString, NULL
466 },
467 {
468 "reverseGoldBitmap", "reverseGoldBitmap", XtRString,
469 sizeof(String), XtOffset(AppDataPtr, reverseGoldBitmap),
470 XtRString, NULL
471 },
472 {
473 "reverseRookBitmap", "reverseRookBitmap", XtRString,
474 sizeof(String), XtOffset(AppDataPtr, reverseRookBitmap),
475 XtRString, NULL
476 },
477 {
478 "reverseBishopBitmap", "reverseBishopBitmap", XtRString,
479 sizeof(String), XtOffset(AppDataPtr, reverseBishopBitmap),
480 XtRString, NULL
481 },
482 {
483 "reversePPawnBitmap", "reversePPawnBitmap", XtRString,
484 sizeof(String), XtOffset(AppDataPtr, reversePPawnBitmap),
485 XtRString, NULL
486 },
487 {
488 "reversePLanceBitmap", "reversePLanceBitmap", XtRString,
489 sizeof(String), XtOffset(AppDataPtr, reversePLanceBitmap),
490 XtRString, NULL
491 },
492 {
493 "reversePKnightBitmap", "reversePKnightBitmap", XtRString,
494 sizeof(String), XtOffset(AppDataPtr, reversePKnightBitmap),
495 XtRString, NULL
496 },
497 {
498 "reversePSilverBitmap", "reversePSilverBitmap", XtRString,
499 sizeof(String), XtOffset(AppDataPtr, reversePSilverBitmap),
500 XtRString, NULL
501 },
502 {
503 "reversePRookBitmap", "reversePRookBitmap", XtRString,
504 sizeof(String), XtOffset(AppDataPtr, reversePRookBitmap),
505 XtRString, NULL
506 },
507 {
508 "reversePBishopBitmap", "reversePBishopBitmap", XtRString,
509 sizeof(String), XtOffset(AppDataPtr, reversePBishopBitmap),
510 XtRString, NULL
511 },
512 {
513 "reverseKingBitmap", "reverseKingBitmap", XtRString,
514 sizeof(String), XtOffset(AppDataPtr, reverseKingBitmap),
515 XtRString, NULL
516 },
517 {
518 "normalPawnBitmap", "normalPawnBitmap", XtRString,
519 sizeof(String), XtOffset(AppDataPtr, normalPawnBitmap),
520 XtRString, NULL
521 },
522 {
523 "normalLanceBitmap", "normalLanceBitmap", XtRString,
524 sizeof(String), XtOffset(AppDataPtr, normalLanceBitmap),
525 XtRString, NULL
526 },
527 {
528 "normalKnightBitmap", "normalKnightBitmap", XtRString,
529 sizeof(String), XtOffset(AppDataPtr, normalKnightBitmap),
530 XtRString, NULL
531 },
532 {
533 "normalSilverBitmap", "normalSilverBitmap", XtRString,
534 sizeof(String), XtOffset(AppDataPtr, normalSilverBitmap),
535 XtRString, NULL
536 },
537 {
538 "normalGoldBitmap", "normalGoldBitmap", XtRString,
539 sizeof(String), XtOffset(AppDataPtr, normalGoldBitmap),
540 XtRString, NULL
541 },
542 {
543 "normalBishopBitmap", "normalBishopBitmap", XtRString,
544 sizeof(String), XtOffset(AppDataPtr, normalBishopBitmap),
545 XtRString, NULL
546 },
547 {
548 "normalRookBitmap", "normalRookBitmap", XtRString,
549 sizeof(String), XtOffset(AppDataPtr, normalRookBitmap),
550 XtRString, NULL
551 },
552 {
553 "normalPPawnBitmap", "normalPPawnBitmap", XtRString,
554 sizeof(String), XtOffset(AppDataPtr, normalPPawnBitmap),
555 XtRString, NULL
556 },
557 {
558 "normalPLanceBitmap", "normalPLanceBitmap", XtRString,
559 sizeof(String), XtOffset(AppDataPtr, normalPLanceBitmap),
560 XtRString, NULL
561 },
562 {
563 "normalPKnightBitmap", "normalPKnightBitmap", XtRString,
564 sizeof(String), XtOffset(AppDataPtr, normalPKnightBitmap),
565 XtRString, NULL
566 },
567 {
568 "normalPSilverBitmap", "normalPSilverBitmap", XtRString,
569 sizeof(String), XtOffset(AppDataPtr, normalPSilverBitmap),
570 XtRString, NULL
571 },
572 {
573 "normalPBishopBitmap", "normalPBishopBitmap", XtRString,
574 sizeof(String), XtOffset(AppDataPtr, normalPBishopBitmap),
575 XtRString, NULL
576 },
577 {
578 "normalPRookBitmap", "normalPRookBitmap", XtRString,
579 sizeof(String), XtOffset(AppDataPtr, normalPRookBitmap),
580 XtRString, NULL
581 },
582 {
583 "normalKingBitmap", "normalKingBitmap", XtRString,
584 sizeof(String), XtOffset(AppDataPtr, normalKingBitmap),
585 XtRString, NULL
586 },
587 {
588 "remoteShell", "remoteShell", XtRString, sizeof(String),
589 XtOffset(AppDataPtr, remoteShell), XtRString, "rsh"
590 },
591 {
592 "timeDelay", "timeDelay", XtRFloat, sizeof(float),
593 XtOffset(AppDataPtr, timeDelay), XtRString,
594 (XtPointer) TIME_DELAY
595 },
596 {
597 "timeControl", "timeControl", XtRString, sizeof(String),
598 XtOffset(AppDataPtr, timeControl), XtRString,
599 (XtPointer) TIME_CONTROL
600 },
601 {
602 "gameIn", "gameIn",
603 XtRBoolean, sizeof(Boolean),
604 XtOffset(AppDataPtr, gameIn), XtRImmediate,
605 (XtPointer) False
606 },
607 {
608 "autoSaveGames", "autoSaveGames", XtRBoolean,
609 sizeof(Boolean), XtOffset(AppDataPtr, autoSaveGames),
610 XtRImmediate, (XtPointer) False
611 },
612 {
613 "loadGameFile", "loadGameFile", XtRString, sizeof(String),
614 XtOffset(AppDataPtr, loadGameFile), XtRString, NULL
615 },
616 {
617 "loadPositionFile", "loadPositionFile", XtRString,
618 sizeof(String), XtOffset(AppDataPtr, loadPositionFile),
619 XtRString, NULL
620 },
621 {
622 "saveGameFile", "saveGameFile", XtRString, sizeof(String),
623 XtOffset(AppDataPtr, saveGameFile), XtRString, ""
624 },
625 {
626 "savePositionFile", "savePositionFile", XtRString,
627 sizeof(String), XtOffset(AppDataPtr, savePositionFile),
628 XtRString, ""
629 },
630 {
631 "challengeDisplay", "challengeDisplay", XtRString,
632 sizeof(String), XtOffset(AppDataPtr, challengeDisplay),
633 XtRString, NULL
634 },
635 {
636 "matchMode", "matchMode", XtRString, sizeof(String),
637 XtOffset(AppDataPtr, matchMode), XtRString, MATCH_MODE
638 },
639 {
640 "monoMode", "monoMode", XtRBoolean, sizeof(Boolean),
641 XtOffset(AppDataPtr, monoMode), XtRImmediate,
642 (XtPointer) False
643 },
644 {
645 "debugMode", "debugMode", XtRBoolean, sizeof(Boolean),
646 XtOffset(AppDataPtr, debugMode), XtRImmediate,
647 (XtPointer) False
648 },
649 {
650 "Iconic", "Iconic", XtRBoolean, sizeof(Boolean),
651 XtOffset(AppDataPtr, Iconic), XtRImmediate,
652 (XtPointer) False
653 },
654 {
655 "clockMode", "clockMode", XtRBoolean, sizeof(Boolean),
656 XtOffset(AppDataPtr, clockMode), XtRImmediate,
657 (XtPointer) True
658 },
659 {
660 "autoCallFlag", "autoCallFlag", XtRBoolean,
661 sizeof(Boolean), XtOffset(AppDataPtr, autoCallFlag),
662 XtRImmediate, (XtPointer) False
663 },
664 {
665 "boardSize", "boardSize", XtRString, sizeof(String),
666 XtOffset(AppDataPtr, boardSize), XtRString, DEFAULT_SIZE
667 },
668 {
669 "searchTime", "searchTime", XtRString, sizeof(String),
670 XtOffset(AppDataPtr, searchTime), XtRString,
671 (XtPointer) NULL
672 },
673 {
674 "searchDepth", "searchDepth", XtRInt, sizeof(int),
675 XtOffset(AppDataPtr, searchDepth), XtRImmediate,
676 (XtPointer) 0
677 },
678 {
679 "showCoords", "showCoords", XtRBoolean, sizeof(Boolean),
680 XtOffset(AppDataPtr, showCoords), XtRImmediate,
681 (XtPointer) False
682 },
683 {
684 "mainFont", "mainFont", XtRString, sizeof(String),
685 XtOffset(AppDataPtr, mainFont), XtRString, MAIN_FONT
686 },
687 {
688 "coordFont", "coordFont", XtRString, sizeof(String),
689 XtOffset(AppDataPtr, coordFont), XtRString, COORD_FONT
690 },
691 {
692 "ringBellAfterMoves", "ringBellAfterMoves",
693 XtRBoolean, sizeof(Boolean),
694 XtOffset(AppDataPtr, ringBellAfterMoves),
695 XtRImmediate, (XtPointer) False
696 },
697 {
698 "borderXoffset", "borderXoffset", XtRInt, sizeof(int),
699 XtOffset(AppDataPtr, borderXoffset), XtRImmediate,
700 (XtPointer) BORDER_X_OFFSET
701 },
702 {
703 "borderYoffset", "borderYOffset", XtRInt, sizeof(int),
704 XtOffset(AppDataPtr, borderYoffset), XtRImmediate,
705 (XtPointer) BORDER_Y_OFFSET
706 }
707 };
708
709
710 struct DisplayData
711 {
712 AppData appData;
713
714 Arg shellArgs[6];
715 Arg boardArgs[3];
716 Arg commandsArgs[7];
717 Arg messageArgs[3];
718 Arg timerArgs[2];
719 Arg titleArgs[2];
720
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;
736
737 Display *xDisplay;
738 int xScreen;
739 Window xBoardWindow;
740
741 GC squareGC, lineGC, pieceGC, oPieceGC, charPieceGC,
742 squareOffBoardGC, coordGC, dropPiece;
743
744 Font mainFontID, coordFontID;
745 XFontStruct *mainFontStruct, *coordFontStruct;
746
747 Widget shellWidget, formWidget, boardWidget,
748 commandsWidget, messageWidget,
749 blackTimerWidget, whiteTimerWidget,
750 titleWidget, widgetList[6],
751 promotionShell,
752 filemodeShell, challengeWidget;
753
754 XSegment gridSegments[(BOARD_SIZE + 1) * 2];
755
756 Pixel timerForegroundPixel, timerBackgroundPixel;
757
758 BoardSize boardSize;
759 int squareSize;
760 int black_pixel_is_zero;
761 int flipView;
762 int promotionUp;
763
764 Boolean monoMode, showCoords, Iconic;
765 };
766
767
768
769 struct DisplayData localPlayer, remotePlayer;
770
771
772 typedef struct
773 {
774 ShogiSquare piece;
775 int to_x, to_y;
776 } PromotionMoveInfo;
777
778 static PromotionMoveInfo pmi; /* making this global is gross */
779
780
781 Pixmap *pieceToReverse[2][28] =
782 {
783 {
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
812 },
813 {
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
842 }
843 };
844
845
846
847 Pixmap *pieceToNormal[2][28] =
848 {
849 {
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
878 },
879 {
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
908 }
909 };
910
911
912
913 Pixmap *pieceToReverseSolid[2][28] =
914 {
915 {
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
944 },
945 {
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
974 }
975 };
976
977
978
979 Pixmap *pieceToNormalSolid[2][28] =
980 {
981 {
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
1010 },
1011 {
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
1040 }
1041 };
1042
1043
1044
1045 int pieceIsPromoted[] =
1046 {
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
1052 };
1053
1054
1055 int piecePromotable[] =
1056 {
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
1062 };
1063
1064
1065 char pieceToChar[] =
1066 {
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',
1069 '.'
1070 };
1071
1072
1073 ShogiSquare pieceToPromoted[] =
1074 {
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
1083 };
1084
1085
1086
1087 XrmOptionDescRec shellOptions[] =
1088 {
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" }
1210 };
1211
1212
1213
1214 XtActionsRec boardActions[] =
1215 {
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 }
1230 };
1231
1232
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";
1256
1257
1258 char translationsTableReduced[] =
1259 "<Expose>: DrawPosition() \n \
1260 <Btn1Down>: HandleUserMove() \n \
1261 <Btn1Up>: HandleUserMove() \n \
1262 <Message>WM_PROTOCOLS: QuitProc() \n";
1263
1264
1265 char blackTranslations[] = "<BtnDown>: SetBlackToPlay()\n";
1266 char whiteTranslations[] = "<BtnDown>: SetWhiteToPlay()\n";
1267
1268 String xshogiResources[] =
1269 {
1270 DEFAULT_FONT,
1271 "*Dialog*value.translations: #override "
1272 "\\n <Key>Return: FileNameAction()",
1273 NULL
1274 };
1275
1276
1277 int global_argc; /* number of command args */
1278 char *global_argv[10]; /* pointers to up to 10 command args */
1279
1280
1281
1282 static struct DisplayData *player;
1283
1284
1285 typedef struct
1286 {
1287 char mode[2];
1288 char name[100];
1289 } FileModeInfo;
1290
1291 static FileModeInfo fmi;
1292
1293
1294 /*
1295 * This is a hack that allows the parser to tell the program
1296 * that the game it's loading has ended.
1297 */
1298
1299 int loaded_game_finished = 0;
1300
1301
1302 /**********************************************************************
1303 *
1304 * End of globals.
1305 *
1306 **********************************************************************/
1307
1308
1309 void
CreatePlayerWindow(void)1310 CreatePlayerWindow(void)
1311 {
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);
1320
1321 player->monoMode = player->appData.monoMode;
1322 player->showCoords = player->appData.showCoords;
1323
1324 /*
1325 * Parse timeControl resource.
1326 */
1327
1328 if (player->appData.timeControl != NULL)
1329 {
1330 matched = sscanf(player->appData.timeControl, "%d:%d", &min, &sec);
1331
1332 if (matched == 1)
1333 {
1334 timeControl = min * 60 * 1000;
1335 }
1336 else if (matched == 2)
1337 {
1338 timeControl = (min * 60 + sec) * 1000;
1339 }
1340 else
1341 {
1342 fprintf(stderr, "%s: bad timeControl option %s\n",
1343 programName, player->appData.timeControl);
1344 Usage();
1345 }
1346 }
1347
1348 /*
1349 * Parse searchTime resource
1350 */
1351
1352 if (player->appData.searchTime != NULL)
1353 {
1354 matched = sscanf(player->appData.searchTime, "%d:%d", &min, &sec);
1355
1356 if (matched == 1)
1357 {
1358 searchTime = min * 60;
1359 }
1360 else if (matched == 2)
1361 {
1362 searchTime = min * 60 + sec;
1363 }
1364 else
1365 {
1366 fprintf(stderr, "%s: bad searchTime option %s\n",
1367 programName, player->appData.searchTime);
1368 Usage();
1369 }
1370 }
1371
1372 if ((player->appData.searchTime != NULL)
1373 || (player->appData.searchDepth > 0)
1374 || player->appData.noShogiProgram)
1375 {
1376 player->appData.clockMode = False;
1377 }
1378
1379 player->Iconic = False;
1380 player->boardSize = Small;
1381 player->squareSize = SMALL_SQUARE_SIZE;
1382 player->flipView = (player == &remotePlayer);
1383 player->promotionUp = False;
1384
1385 /*
1386 * Determine boardSize.
1387 */
1388
1389 if (strcasecmp(player->appData.boardSize, "Large") == 0)
1390 {
1391 player->boardSize = Large;
1392 }
1393 else if (strcasecmp(player->appData.boardSize, "Medium") == 0)
1394 {
1395 player->boardSize = Medium;
1396 }
1397 else if (strcasecmp(player->appData.boardSize, "Small") == 0)
1398 {
1399 player->boardSize = Small;
1400 }
1401 else
1402 {
1403 fprintf(stderr, "%s: bad boardSize option %s\n",
1404 programName, player->appData.boardSize);
1405 Usage();
1406 }
1407
1408 if ((local = (player == &localPlayer)))
1409 {
1410 player->xDisplay = XtDisplay(player->shellWidget);
1411 player->xScreen = DefaultScreen(player->xDisplay);
1412 }
1413
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))
1419 {
1420 player->boardSize = Medium;
1421 }
1422 #endif
1423
1424 switch (player->boardSize)
1425 {
1426 case Small:
1427 player->squareSize = SMALL_SQUARE_SIZE;
1428 mainFontPxlSize = 11;
1429 coordFontPxlSize = 10;
1430 break;
1431
1432 case Medium:
1433 player->squareSize = MEDIUM_SQUARE_SIZE;
1434 mainFontPxlSize = 17;
1435 coordFontPxlSize = 12;
1436 break;
1437
1438 default:
1439 case Large:
1440 player->squareSize = LARGE_SQUARE_SIZE;
1441 mainFontPxlSize = 17;
1442 coordFontPxlSize = 14;
1443 break;
1444 }
1445
1446 /*
1447 * Detect if there are not enough colors are available and adapt.
1448 */
1449
1450 if (DefaultDepth(player->xDisplay, player->xScreen) <= 2)
1451 player->monoMode = True;
1452
1453 /*
1454 * Determine what fonts to use.
1455 */
1456
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);
1469
1470 /*
1471 * Set default arguments.
1472 */
1473
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);
1480
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));
1488
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);
1496
1497 XtSetArg(player->messageArgs[0], XtNborderWidth, 0);
1498 XtSetArg(player->messageArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1499 XtSetArg(player->messageArgs[2], XtNlabel, (XtArgVal) "starting...");
1500
1501 XtSetArg(player->timerArgs[0], XtNborderWidth, 0);
1502 XtSetArg(player->timerArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1503
1504 XtSetArg(player->titleArgs[0], XtNborderWidth, 0);
1505 XtSetArg(player->titleArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1506
1507 boardWidth = LINE_GAP
1508 + (BOARD_SIZE + 4) * (player->squareSize + LINE_GAP);
1509
1510 XtSetArg(player->boardArgs[1], XtNwidth, boardWidth);
1511 XtSetArg(player->boardArgs[2], XtNheight,
1512 LINE_GAP + BOARD_SIZE * (player->squareSize + LINE_GAP));
1513
1514 /*
1515 * widget hierarchy
1516 */
1517
1518 player->formWidget = XtCreateManagedWidget("form",
1519 formWidgetClass,
1520 player->shellWidget, NULL, 0);
1521
1522 player->widgetList[0] = player->blackTimerWidget
1523 = XtCreateWidget((local ? "black time:" : "rblack time:"),
1524 labelWidgetClass,
1525 player->formWidget, player->timerArgs,
1526 XtNumber(player->timerArgs));
1527
1528 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1529 XtSetValues(player->blackTimerWidget, args, 1);
1530
1531 player->widgetList[1] = player->whiteTimerWidget
1532 = XtCreateWidget((local ? "white time:" : "rwhite time:"),
1533 labelWidgetClass,
1534 player->formWidget, player->timerArgs,
1535 XtNumber(player->timerArgs));
1536
1537 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1538 XtSetValues(player->whiteTimerWidget, args, 1);
1539
1540 player->widgetList[2] = player->titleWidget
1541 = XtCreateWidget((local ? "" : "r"), labelWidgetClass,
1542 player->formWidget, player->titleArgs,
1543 XtNumber(player->titleArgs));
1544
1545 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1546 XtSetValues(player->titleWidget, args, 1);
1547
1548 player->widgetList[3] = player->messageWidget
1549 = XtCreateWidget((local ? "message" : "rmessage"),
1550 labelWidgetClass, player->formWidget,
1551 player->messageArgs,
1552 XtNumber(player->messageArgs));
1553
1554 XtSetArg(args[0], XtNfont, player->mainFontStruct);
1555 XtSetValues(player->messageWidget, args, 1);
1556
1557 player->widgetList[4] = player->commandsWidget
1558 = XtCreateWidget((local ? "commands" : "rcommand"),
1559 listWidgetClass, player->formWidget,
1560 player->commandsArgs,
1561 XtNumber(player->commandsArgs));
1562
1563 player->widgetList[5] = player->boardWidget
1564 = XtCreateWidget((local ? "board" : "rboard"),
1565 widgetClass, player->formWidget,
1566 player->boardArgs,
1567 XtNumber(player->boardArgs));
1568
1569 XtManageChildren(player->widgetList, XtNumber(player->widgetList));
1570
1571 /*
1572 * Calculate the width of the timer labels.
1573 */
1574
1575 XtSetArg(args[0], XtNfont, &player->mainFontStruct);
1576 XtGetValues(player->blackTimerWidget, args, 1);
1577
1578 if (player->appData.clockMode)
1579 {
1580 timerWidth = XTextWidth(player->mainFontStruct,
1581 "Black: 8:88:88 ", 15);
1582 }
1583 else
1584 {
1585 timerWidth = XTextWidth(player->mainFontStruct, "Black ", 7);
1586 }
1587
1588 XtSetArg(args[0], XtNwidth, timerWidth);
1589 XtSetValues(player->blackTimerWidget, args, 1);
1590 XtSetValues(player->whiteTimerWidget, args, 1);
1591
1592 XtSetArg(args[0], XtNbackground, &player->timerForegroundPixel);
1593 XtSetArg(args[1], XtNforeground, &player->timerBackgroundPixel);
1594 XtGetValues(player->blackTimerWidget, args, 2);
1595
1596 /*
1597 * Calculate the width of the name and message labels.
1598 */
1599
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);
1607
1608 /*
1609 * 'formWidget' uses these constraints but they are stored
1610 * in the children.
1611 */
1612
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);
1623
1624 XtRealizeWidget(player->shellWidget);
1625
1626 player->xBoardWindow = XtWindow(player->boardWidget);
1627
1628 /*
1629 * Create an icon.
1630 */
1631
1632 player->iconPixmap =
1633 XCreateBitmapFromData(player->xDisplay,
1634 XtWindow(player->shellWidget),
1635 (char *)icon_bits, icon_width, icon_height);
1636
1637 XtSetArg(args[0], XtNiconPixmap, player->iconPixmap);
1638 XtSetValues(player->shellWidget, args, 1);
1639
1640 /*
1641 * Create a cursor for the board widget.
1642 */
1643
1644 window_attributes.cursor = XCreateFontCursor(player->xDisplay, XC_hand2);
1645 XChangeWindowAttributes(player->xDisplay, player->xBoardWindow,
1646 CWCursor, &window_attributes);
1647
1648 /*
1649 * Inhibit shell resizing.
1650 */
1651
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);
1658
1659 /*
1660 * Determine value of black pixel.
1661 */
1662
1663 player->black_pixel_is_zero =
1664 (XBlackPixel(player->xDisplay, player->xScreen) == 0);
1665
1666 CreateGCs();
1667 CreateGrid();
1668 CreatePieces();
1669
1670 if (!fromRemotePlayer)
1671 CreatePieceMenus();
1672
1673 XtAddCallback(player->commandsWidget, XtNcallback, SelectCommand,
1674 (XtPointer)fromRemotePlayer);
1675
1676 if (!fromRemotePlayer)
1677 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1678
1679 if (fromRemotePlayer)
1680 {
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);
1687 }
1688 else
1689 {
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);
1699 }
1700
1701 XtAddEventHandler(player->boardWidget, ExposureMask | ButtonPressMask
1702 | ButtonReleaseMask | Button1MotionMask | KeyPressMask,
1703 False, (XtEventHandler)EventProc,
1704 (XtPointer)(player == &remotePlayer));
1705
1706 sprintf(buf, "xshogi version %s based on "
1707 "xboard version %s",
1708 PACKAGE_VERSION, XBOARD_VERSION);
1709
1710 /*
1711 * If there is to be a machine match, set it up.
1712 */
1713
1714 if (matchMode != MatchFalse && player != &remotePlayer)
1715 {
1716 if (player->appData.noShogiProgram)
1717 {
1718 fprintf(stderr,
1719 "%s: can't have a match with no shogi programs!\n",
1720 programName);
1721 exit(1);
1722 }
1723
1724 DisplayMessage(buf, fromRemotePlayer);
1725 TwoMachinesProc(NULL, NULL, NULL, NULL);
1726 }
1727 else
1728 {
1729 Reset(True);
1730 DisplayMessage(buf, fromRemotePlayer);
1731 }
1732 }
1733
1734
1735
1736
1737 int
main(int argc,char ** argv)1738 main(int argc, char **argv)
1739 {
1740 setbuf(stdout, NULL);
1741 setbuf(stderr, NULL);
1742
1743 /*
1744 * Copy pointers to command line arguments and number of such pointers.
1745 * (argc, argv will be destroyed by XtAppInitialize)
1746 */
1747
1748 for (global_argc = 0; global_argc < argc; global_argc++)
1749 global_argv[global_argc] = argv[global_argc];
1750
1751 programName = strrchr(argv[0], '/');
1752
1753 if (programName == NULL)
1754 programName = argv[0];
1755 else
1756 programName++;
1757
1758 localPlayer.shellWidget
1759 = XtAppInitialize(&appContext, "XShogi", shellOptions,
1760 XtNumber(shellOptions), &argc, argv,
1761 xshogiResources, NULL, 0);
1762
1763 if (argc > 1)
1764 Usage();
1765
1766 if ((shogiDir = (char *)getenv("SHOGIDIR")) == NULL)
1767 {
1768 shogiDir = ".";
1769 }
1770 else
1771 {
1772 if (chdir(shogiDir) != 0)
1773 {
1774 fprintf(stderr, "%s: can't cd to SHOGIDIR\n",
1775 programName);
1776 perror(shogiDir);
1777 exit(1);
1778 }
1779 }
1780
1781 XtGetApplicationResources(localPlayer.shellWidget,
1782 &localPlayer.appData, clientResources,
1783 XtNumber(clientResources), NULL, 0);
1784
1785 xshogiDebug = localPlayer.appData.debugMode;
1786
1787 /*
1788 * Determine matchMode state -- poor man's resource converter.
1789 */
1790
1791 if (strcasecmp(localPlayer.appData.matchMode, "Init") == 0)
1792 {
1793 matchMode = MatchInit;
1794 }
1795 else if (strcasecmp(localPlayer.appData.matchMode, "Position") == 0)
1796 {
1797 matchMode = MatchPosition;
1798 }
1799 else if (strcasecmp(localPlayer.appData.matchMode, "Opening") == 0)
1800 {
1801 matchMode = MatchOpening;
1802 }
1803 else if (strcasecmp(localPlayer.appData.matchMode, "False") == 0)
1804 {
1805 matchMode = MatchFalse;
1806 }
1807 else
1808 {
1809 fprintf(stderr, "%s: bad matchMode option %s\n",
1810 programName, localPlayer.appData.matchMode);
1811 Usage();
1812 }
1813
1814 buttonStrings = gnuButtonStrings;
1815 buttonProcs = gnuButtonProcs;
1816 buttonCount = XtNumber(gnuButtonStrings);
1817
1818 player = &localPlayer;
1819
1820 CreatePlayerWindow();
1821
1822 XtAppMainLoop(appContext);
1823
1824 return 0;
1825 }
1826
1827
1828
1829 /*
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.
1837 */
1838
1839 char *
FindFont(char * pattern,int targetPxlSize)1840 FindFont(char *pattern, int targetPxlSize)
1841 {
1842 char **fonts, *p, *best;
1843 int i, j, nfonts, minerr, err, pxlSize;
1844
1845 fonts = XListFonts(player->xDisplay, pattern, 999999, &nfonts);
1846
1847 if (nfonts < 1)
1848 {
1849 fprintf(stderr, "%s: No fonts match pattern %s\n",
1850 programName, pattern);
1851 exit(1);
1852 }
1853
1854 best = "";
1855 minerr = 999999;
1856
1857 for (i = 0; i < nfonts; i++)
1858 {
1859 j = 0;
1860 p = fonts[i];
1861
1862 if (*p != '-')
1863 continue;
1864
1865 while (j < 7)
1866 {
1867 if (*p == NULLCHAR)
1868 break;
1869
1870 if (*p++ == '-')
1871 j++;
1872 }
1873
1874 if (j < 7)
1875 continue;
1876
1877 pxlSize = atoi(p);
1878
1879 if (pxlSize == targetPxlSize)
1880 {
1881 best = fonts[i];
1882 break;
1883 }
1884
1885 err = pxlSize - targetPxlSize;
1886
1887 if (abs(err) < abs(minerr)
1888 || ((minerr > 0) && (err < 0) && (-err == minerr)))
1889 {
1890 best = fonts[i];
1891 minerr = err;
1892 }
1893 }
1894
1895 p = (char *)XtMalloc(strlen(best) + 1);
1896 strcpy(p, best);
1897 XFreeFontNames(fonts);
1898 return p;
1899 }
1900
1901
1902
1903
1904 void
CreateGCs(void)1905 CreateGCs(void)
1906 {
1907 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
1908 | GCBackground | GCFunction | GCPlaneMask;
1909 XGCValues gc_values;
1910
1911 gc_values.plane_mask = AllPlanes;
1912 gc_values.line_width = LINE_GAP;
1913 gc_values.line_style = LineSolid;
1914 gc_values.function = GXcopy;
1915
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);
1919
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);
1923
1924 if (player->monoMode)
1925 {
1926 gc_values.foreground
1927 = XWhitePixel(player->xDisplay, player->xScreen);
1928 gc_values.background
1929 = XWhitePixel(player->xDisplay, player->xScreen);
1930
1931 /* empty square off board */
1932 player->squareOffBoardGC
1933 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1934
1935 /* empty square on board */
1936 player->squareGC
1937 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1938 }
1939 else
1940 {
1941 Pixel bg; /* background color */
1942 Arg args[1];
1943
1944 /* Get background color. */
1945 XtSetArg(args[0], XtNbackground, &bg);
1946 XtGetValues(player->shellWidget, args, 1);
1947
1948 /* empty square off board */
1949 gc_values.foreground = gc_values.background = bg;
1950 player->squareOffBoardGC
1951 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1952
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);
1960
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);
1967
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);
1975
1976 /* piece symbol */
1977 /*
1978 * FIXME: charPieceColor seems to have no effect;
1979 * the bitmap is *always* black.
1980 */
1981 gc_values.function = (player->black_pixel_is_zero ? GXand : GXor);
1982
1983 gc_values.foreground
1984 = player->appData.charPieceColor;
1985 gc_values.background
1986 = player->appData.charPieceColor;
1987
1988 player->charPieceGC
1989 = XtGetGC(player->shellWidget, value_mask, &gc_values);
1990 }
1991 }
1992
1993
1994
1995
1996 void
CreatePieces(void)1997 CreatePieces(void)
1998 {
1999 XSynchronize(player->xDisplay, True); /* Work-around for xlib/xt
2000 buffering bug */
2001
2002 if (player->appData.westernPieceSet)
2003 {
2004 ReadBitmap(player->appData.reverseBigSolidBitmap,
2005 &player->reverseBigSolidBitmap,
2006 NULL,
2007 bigsolidR_bits, bigsolidR_m_bits, bigsolidR_l_bits);
2008
2009 ReadBitmap(player->appData.reverseSmallSolidBitmap,
2010 &player->reverseSmallSolidBitmap,
2011 NULL,
2012 smallsolidR_bits, smallsolidR_m_bits, smallsolidR_l_bits);
2013
2014 ReadBitmap(player->appData.normalBigSolidBitmap,
2015 &player->normalBigSolidBitmap,
2016 NULL,
2017 bigsolid_bits, bigsolid_m_bits, bigsolid_l_bits);
2018
2019 ReadBitmap(player->appData.normalSmallSolidBitmap,
2020 &player->normalSmallSolidBitmap,
2021 NULL,
2022 smallsolid_bits, smallsolid_m_bits, smallsolid_l_bits);
2023
2024 ReadBitmap(player->appData.reversePawnBitmap,
2025 &player->reversePawnBitmap,
2026 &player->reverseSmallSolidBitmap,
2027 pawnRW_bits, pawnRW_bits, pawnRW_bits);
2028
2029 ReadBitmap(player->appData.reverseLanceBitmap,
2030 &player->reverseLanceBitmap,
2031 &player->reverseSmallSolidBitmap,
2032 lanceRW_bits, lanceRW_bits, lanceRW_bits);
2033
2034 ReadBitmap(player->appData.reverseKnightBitmap,
2035 &player->reverseKnightBitmap,
2036 &player->reverseSmallSolidBitmap,
2037 knightRW_bits, knightRW_bits, knightRW_bits);
2038
2039 ReadBitmap(player->appData.reverseSilverBitmap,
2040 &player->reverseSilverBitmap,
2041 &player->reverseBigSolidBitmap,
2042 silverRW_bits, silverRW_bits, silverRW_bits);
2043
2044 ReadBitmap(player->appData.reverseGoldBitmap,
2045 &player->reverseGoldBitmap,
2046 &player->reverseBigSolidBitmap,
2047 goldRW_bits, goldRW_bits, goldRW_bits);
2048
2049 ReadBitmap(player->appData.reverseRookBitmap,
2050 &player->reverseRookBitmap,
2051 &player->reverseBigSolidBitmap,
2052 rookRW_bits, rookRW_bits, rookRW_bits);
2053
2054 ReadBitmap(player->appData.reverseBishopBitmap,
2055 &player->reverseBishopBitmap,
2056 &player->reverseBigSolidBitmap,
2057 bishopRW_bits, bishopRW_bits, bishopRW_bits);
2058
2059 ReadBitmap(player->appData.reversePPawnBitmap,
2060 &player->reversePPawnBitmap,
2061 &player->reverseSmallSolidBitmap,
2062 pawnPRW_bits, pawnPRW_bits, pawnPRW_bits);
2063
2064 ReadBitmap(player->appData.reversePLanceBitmap,
2065 &player->reversePLanceBitmap,
2066 &player->reverseSmallSolidBitmap,
2067 lancePRW_bits, lancePRW_bits, lancePRW_bits);
2068
2069 ReadBitmap(player->appData.reversePKnightBitmap,
2070 &player->reversePKnightBitmap,
2071 &player->reverseSmallSolidBitmap,
2072 knightPRW_bits, knightPRW_bits, knightPRW_bits);
2073
2074 ReadBitmap(player->appData.reversePSilverBitmap,
2075 &player->reversePSilverBitmap,
2076 &player->reverseBigSolidBitmap,
2077 silverPRW_bits, silverPRW_bits, silverPRW_bits);
2078
2079 ReadBitmap(player->appData.reversePRookBitmap,
2080 &player->reversePRookBitmap,
2081 &player->reverseBigSolidBitmap,
2082 rookPRW_bits, rookPRW_bits, rookPRW_bits);
2083
2084 ReadBitmap(player->appData.reversePBishopBitmap,
2085 &player->reversePBishopBitmap,
2086 &player->reverseBigSolidBitmap,
2087 bishopPRW_bits, bishopPRW_bits, bishopPRW_bits);
2088
2089 ReadBitmap(player->appData.reverseKingBitmap,
2090 &player->reverseKingBitmap,
2091 &player->reverseBigSolidBitmap,
2092 kingRW_bits, kingRW_bits, kingRW_bits);
2093
2094 ReadBitmap(player->appData.normalPawnBitmap,
2095 &player->normalPawnBitmap,
2096 &player->normalSmallSolidBitmap,
2097 pawnW_bits, pawnW_bits, pawnW_bits);
2098
2099 ReadBitmap(player->appData.normalLanceBitmap,
2100 &player->normalLanceBitmap,
2101 &player->normalSmallSolidBitmap,
2102 lanceW_bits, lanceW_bits, lanceW_bits);
2103
2104 ReadBitmap(player->appData.normalKnightBitmap,
2105 &player->normalKnightBitmap,
2106 &player->normalSmallSolidBitmap,
2107 knightW_bits, knightW_bits, knightW_bits);
2108
2109 ReadBitmap(player->appData.normalSilverBitmap,
2110 &player->normalSilverBitmap,
2111 &player->normalBigSolidBitmap,
2112 silverW_bits, silverW_bits, silverW_bits);
2113
2114 ReadBitmap(player->appData.normalGoldBitmap,
2115 &player->normalGoldBitmap,
2116 &player->normalBigSolidBitmap,
2117 goldW_bits, goldW_bits, goldW_bits);
2118
2119 ReadBitmap(player->appData.normalRookBitmap,
2120 &player->normalRookBitmap,
2121 &player->normalBigSolidBitmap,
2122 rookW_bits, rookW_bits, rookW_bits);
2123
2124 ReadBitmap(player->appData.normalBishopBitmap,
2125 &player->normalBishopBitmap,
2126 &player->normalBigSolidBitmap,
2127 bishopW_bits, bishopW_bits, bishopW_bits);
2128
2129 ReadBitmap(player->appData.normalPPawnBitmap,
2130 &player->normalPPawnBitmap,
2131 &player->normalSmallSolidBitmap,
2132 pawnPW_bits, pawnPW_bits, pawnPW_bits);
2133
2134 ReadBitmap(player->appData.normalPLanceBitmap,
2135 &player->normalPLanceBitmap,
2136 &player->normalSmallSolidBitmap,
2137 lancePW_bits, lancePW_bits, lancePW_bits);
2138
2139 ReadBitmap(player->appData.normalPKnightBitmap,
2140 &player->normalPKnightBitmap,
2141 &player->normalSmallSolidBitmap,
2142 knightPW_bits, knightPW_bits, knightPW_bits);
2143
2144 ReadBitmap(player->appData.normalPSilverBitmap,
2145 &player->normalPSilverBitmap,
2146 &player->normalBigSolidBitmap,
2147 silverPW_bits, silverPW_bits, silverPW_bits);
2148
2149 ReadBitmap(player->appData.normalPRookBitmap,
2150 &player->normalPRookBitmap,
2151 &player->normalBigSolidBitmap,
2152 rookPW_bits, rookPW_bits, rookPW_bits);
2153
2154 ReadBitmap(player->appData.normalPBishopBitmap,
2155 &player->normalPBishopBitmap,
2156 &player->normalBigSolidBitmap,
2157 bishopPW_bits, bishopPW_bits, bishopPW_bits);
2158
2159 ReadBitmap(player->appData.normalKingBitmap,
2160 &player->normalKingBitmap,
2161 &player->normalBigSolidBitmap,
2162 kingW_bits, kingW_bits, kingW_bits);
2163 }
2164 else
2165 {
2166 ReadBitmap(player->appData.reverseBigSolidBitmap,
2167 &player->reverseBigSolidBitmap,
2168 NULL,
2169 bigsolidR_bits, bigsolidR_m_bits, bigsolidR_l_bits);
2170
2171 ReadBitmap(player->appData.reverseSmallSolidBitmap,
2172 &player->reverseSmallSolidBitmap,
2173 NULL,
2174 smallsolidR_bits, smallsolidR_m_bits, smallsolidR_l_bits);
2175
2176 ReadBitmap(player->appData.normalBigSolidBitmap,
2177 &player->normalBigSolidBitmap,
2178 NULL,
2179 bigsolid_bits, bigsolid_m_bits, bigsolid_l_bits);
2180
2181 ReadBitmap(player->appData.normalSmallSolidBitmap,
2182 &player->normalSmallSolidBitmap,
2183 NULL,
2184 smallsolid_bits, smallsolid_m_bits, smallsolid_l_bits);
2185
2186 ReadBitmap(player->appData.reversePawnBitmap,
2187 &player->reversePawnBitmap,
2188 &player->reverseSmallSolidBitmap,
2189 pawnR_bits, pawnR_m_bits, pawnR_l_bits);
2190
2191 ReadBitmap(player->appData.reverseLanceBitmap,
2192 &player->reverseLanceBitmap,
2193 &player->reverseSmallSolidBitmap,
2194 lanceR_bits, lanceR_m_bits, lanceR_l_bits);
2195
2196 ReadBitmap(player->appData.reverseKnightBitmap,
2197 &player->reverseKnightBitmap,
2198 &player->reverseSmallSolidBitmap,
2199 knightR_bits, knightR_m_bits, knightR_l_bits);
2200
2201 ReadBitmap(player->appData.reverseSilverBitmap,
2202 &player->reverseSilverBitmap,
2203 &player->reverseBigSolidBitmap,
2204 silverR_bits, silverR_m_bits, silverR_l_bits);
2205
2206 ReadBitmap(player->appData.reverseGoldBitmap,
2207 &player->reverseGoldBitmap,
2208 &player->reverseBigSolidBitmap,
2209 goldR_bits, goldR_m_bits, goldR_l_bits);
2210
2211 ReadBitmap(player->appData.reverseRookBitmap,
2212 &player->reverseRookBitmap,
2213 &player->reverseBigSolidBitmap,
2214 rookR_bits, rookR_m_bits, rookR_l_bits);
2215
2216 ReadBitmap(player->appData.reverseBishopBitmap,
2217 &player->reverseBishopBitmap,
2218 &player->reverseBigSolidBitmap,
2219 bishopR_bits, bishopR_m_bits, bishopR_l_bits);
2220
2221 ReadBitmap(player->appData.reversePPawnBitmap,
2222 &player->reversePPawnBitmap,
2223 &player->reverseSmallSolidBitmap,
2224 pawnPR_bits, pawnPR_m_bits, pawnPR_l_bits);
2225
2226 ReadBitmap(player->appData.reversePLanceBitmap,
2227 &player->reversePLanceBitmap,
2228 &player->reverseSmallSolidBitmap,
2229 lancePR_bits, lancePR_m_bits, lancePR_l_bits);
2230
2231 ReadBitmap(player->appData.reversePKnightBitmap,
2232 &player->reversePKnightBitmap,
2233 &player->reverseSmallSolidBitmap,
2234 knightPR_bits, knightPR_m_bits, knightPR_l_bits);
2235
2236 ReadBitmap(player->appData.reversePSilverBitmap,
2237 &player->reversePSilverBitmap,
2238 &player->reverseBigSolidBitmap,
2239 silverPR_bits, silverPR_m_bits, silverPR_l_bits);
2240
2241 ReadBitmap(player->appData.reversePRookBitmap,
2242 &player->reversePRookBitmap,
2243 &player->reverseBigSolidBitmap,
2244 rookPR_bits, rookPR_m_bits, rookPR_l_bits);
2245
2246 ReadBitmap(player->appData.reversePBishopBitmap,
2247 &player->reversePBishopBitmap,
2248 &player->reverseBigSolidBitmap,
2249 bishopPR_bits, bishopPR_m_bits, bishopPR_l_bits);
2250
2251 ReadBitmap(player->appData.reverseKingBitmap,
2252 &player->reverseKingBitmap,
2253 &player->reverseBigSolidBitmap,
2254 kingR_bits, kingR_m_bits, kingR_l_bits);
2255
2256 ReadBitmap(player->appData.normalPawnBitmap,
2257 &player->normalPawnBitmap,
2258 &player->normalSmallSolidBitmap,
2259 pawn_bits, pawn_m_bits, pawn_l_bits);
2260
2261 ReadBitmap(player->appData.normalLanceBitmap,
2262 &player->normalLanceBitmap,
2263 &player->normalSmallSolidBitmap,
2264 lance_bits, lance_m_bits, lance_l_bits);
2265
2266 ReadBitmap(player->appData.normalKnightBitmap,
2267 &player->normalKnightBitmap,
2268 &player->normalSmallSolidBitmap,
2269 knight_bits, knight_m_bits, knight_l_bits);
2270
2271 ReadBitmap(player->appData.normalSilverBitmap,
2272 &player->normalSilverBitmap,
2273 &player->normalBigSolidBitmap,
2274 silver_bits, silver_m_bits, silver_l_bits);
2275
2276 ReadBitmap(player->appData.normalGoldBitmap,
2277 &player->normalGoldBitmap,
2278 &player->normalBigSolidBitmap,
2279 gold_bits, gold_m_bits, gold_l_bits);
2280
2281 ReadBitmap(player->appData.normalRookBitmap,
2282 &player->normalRookBitmap,
2283 &player->normalBigSolidBitmap,
2284 rook_bits, rook_m_bits, rook_l_bits);
2285
2286 ReadBitmap(player->appData.normalBishopBitmap,
2287 &player->normalBishopBitmap,
2288 &player->normalBigSolidBitmap,
2289 bishop_bits, bishop_m_bits, bishop_l_bits);
2290
2291 ReadBitmap(player->appData.normalPPawnBitmap,
2292 &player->normalPPawnBitmap,
2293 &player->normalSmallSolidBitmap,
2294 pawnP_bits, pawnP_m_bits, pawnP_l_bits);
2295
2296 ReadBitmap(player->appData.normalPLanceBitmap,
2297 &player->normalPLanceBitmap,
2298 &player->normalSmallSolidBitmap,
2299 lanceP_bits, lanceP_m_bits, lanceP_l_bits);
2300
2301 ReadBitmap(player->appData.normalPKnightBitmap,
2302 &player->normalPKnightBitmap,
2303 &player->normalSmallSolidBitmap,
2304 knightP_bits, knightP_m_bits, knightP_l_bits);
2305
2306 ReadBitmap(player->appData.normalPSilverBitmap,
2307 &player->normalPSilverBitmap,
2308 &player->normalBigSolidBitmap,
2309 silverP_bits, silverP_m_bits, silverP_l_bits);
2310
2311 ReadBitmap(player->appData.normalPRookBitmap,
2312 &player->normalPRookBitmap,
2313 &player->normalBigSolidBitmap,
2314 rookP_bits, rookP_m_bits, rookP_l_bits);
2315
2316 ReadBitmap(player->appData.normalPBishopBitmap,
2317 &player->normalPBishopBitmap,
2318 &player->normalBigSolidBitmap,
2319 bishopP_bits, bishopP_m_bits, bishopP_l_bits);
2320
2321 ReadBitmap(player->appData.normalKingBitmap,
2322 &player->normalKingBitmap,
2323 &player->normalBigSolidBitmap,
2324 king_bits, king_m_bits, king_l_bits);
2325
2326 }
2327
2328 XSynchronize(player->xDisplay, False); /* Work-around for xlib/xt
2329 buffering bug */
2330 }
2331
2332
2333
2334
2335 int
ReadBitmapFile(Display * display,Drawable d,char * filename,unsigned int * width_return,unsigned int * height_return,Pixmap * bitmap_return,int * x_hot_return,int * y_hot_return)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)
2341 {
2342 int n;
2343
2344 if ((n = XReadBitmapFile(display, d, filename,
2345 width_return, height_return,
2346 bitmap_return, x_hot_return, y_hot_return))
2347 != BitmapSuccess)
2348 {
2349 return n;
2350 }
2351 else
2352 {
2353 /* transform a 1 plane pixmap to a k plane pixmap */
2354 return BitmapSuccess;
2355 }
2356 }
2357
2358
2359
2360
2361 /*
2362 * Create the X pixmap from .xbm file bitmap data. This may
2363 * have to be revised considerably.
2364 */
2365
2366 void
ReadBitmap(String name,Pixmap * pm,Pixmap * qm,unsigned char * small_bits,unsigned char * medium_bits,unsigned char * large_bits)2367 ReadBitmap(String name, Pixmap *pm, Pixmap *qm,
2368 unsigned char *small_bits,
2369 unsigned char *medium_bits,
2370 unsigned char *large_bits)
2371 {
2372 int x_hot, y_hot;
2373 unsigned int w, h;
2374
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))
2380 {
2381 unsigned long fg, bg;
2382 unsigned int depth;
2383
2384 depth = DisplayPlanes(player->xDisplay, player->xScreen);
2385
2386 if (player->monoMode)
2387 {
2388 fg = XBlackPixel(player->xDisplay, player->xScreen);
2389 bg = XWhitePixel(player->xDisplay, player->xScreen);
2390 }
2391 else if (qm == NULL)
2392 {
2393 fg = player->appData.oneColor;
2394 bg = player->appData.zeroColor;
2395 }
2396 else
2397 {
2398 fg = (player->black_pixel_is_zero ? 0 : ~0);
2399 bg = (player->black_pixel_is_zero ? ~0 : 0);
2400 }
2401
2402 switch (player->boardSize)
2403 {
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;
2412
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;
2421
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;
2430 }
2431 }
2432 }
2433
2434
2435
2436
2437 void
CreateGrid(void)2438 CreateGrid(void)
2439 {
2440 int i, offset;
2441
2442 offset = 2 * (player->squareSize + LINE_GAP);
2443
2444 for (i = 0; i < BOARD_SIZE + 1; i++)
2445 {
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);
2457 }
2458 }
2459
2460
2461
2462
2463 void
CreatePieceMenus(void)2464 CreatePieceMenus(void)
2465 {
2466 int i;
2467 Widget entry;
2468 Arg args[1];
2469 ShogiSquare selection;
2470
2471 XtSetArg(args[0], XtNlabel, "Black");
2472 blackPieceMenu = XtCreatePopupShell("menuW", simpleMenuWidgetClass,
2473 localPlayer.boardWidget, args, 1);
2474
2475 for (i = 0; i < PIECE_MENU_SIZE; i++)
2476 {
2477 String item = pieceMenuStrings[i];
2478
2479 if (strcmp(item, "----") == 0)
2480 {
2481 entry = XtCreateManagedWidget(item, smeLineObjectClass,
2482 blackPieceMenu, NULL, 0);
2483 }
2484 else
2485 {
2486 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
2487 blackPieceMenu, NULL, 0);
2488 selection = pieceMenuTranslation[0][i];
2489 XtAddCallback(entry, XtNcallback,
2490 (XtCallbackProc)PieceMenuSelect,
2491 (XtPointer)selection);
2492
2493 if (selection == BlackPawn)
2494 {
2495 XtSetArg(args[0], XtNpopupOnEntry, entry);
2496 XtSetValues(blackPieceMenu, args, 1);
2497 }
2498 }
2499 }
2500
2501 XtSetArg(args[0], XtNlabel, "White");
2502 whitePieceMenu = XtCreatePopupShell("menuB", simpleMenuWidgetClass,
2503 localPlayer.boardWidget, args, 1);
2504
2505 for (i = 0; i < PIECE_MENU_SIZE; i++)
2506 {
2507 String item = pieceMenuStrings[i];
2508
2509 if (strcmp(item, "----") == 0)
2510 {
2511 entry = XtCreateManagedWidget(item, smeLineObjectClass,
2512 whitePieceMenu, NULL, 0);
2513 }
2514 else
2515 {
2516 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
2517 whitePieceMenu, NULL, 0);
2518 selection = pieceMenuTranslation[1][i];
2519 XtAddCallback(entry, XtNcallback,
2520 (XtCallbackProc)PieceMenuSelect,
2521 (XtPointer)selection);
2522
2523 if (selection == WhitePawn)
2524 {
2525 XtSetArg(args[0], XtNpopupOnEntry, entry);
2526 XtSetValues(whitePieceMenu, args, 1);
2527 }
2528 }
2529 }
2530
2531 XtRegisterGrabAction(PieceMenuPopup, True,
2532 (unsigned)(ButtonPressMask|ButtonReleaseMask),
2533 GrabModeAsync, GrabModeAsync);
2534 }
2535
2536
2537
2538
2539 void
PieceMenuPopup(Widget w,XEvent * event,String * params,Cardinal * num_params)2540 PieceMenuPopup(Widget w, XEvent *event, String *params, Cardinal *num_params)
2541 {
2542 if (event->type != ButtonPress)
2543 return;
2544
2545 if (gameMode != EditPosition)
2546 return;
2547
2548 if (((pmFromX = EventToXSquare(event->xbutton.x)) < 1)
2549 || (pmFromX > BOARD_SIZE + 2)
2550 || ((pmFromY = EventToSquare(event->xbutton.y)) < 0))
2551 {
2552 pmFromX = pmFromY = -1;
2553 return;
2554 }
2555
2556 if (localPlayer.flipView)
2557 pmFromX = BOARD_SIZE + 3 - pmFromX;
2558 else
2559 pmFromY = BOARD_SIZE - 1 - pmFromY;
2560
2561 XtPopupSpringLoaded(XtNameToWidget(localPlayer.boardWidget, params[0]));
2562 }
2563
2564
2565
2566
2567 static void
PieceMenuSelect(Widget w,ShogiSquare piece,char * junk)2568 PieceMenuSelect(Widget w, ShogiSquare piece, char *junk)
2569 {
2570 if ((pmFromX < 0) || (pmFromY < 0))
2571 return;
2572
2573 if (off_board(pmFromX))
2574 {
2575 int i, c;
2576 switch (piece)
2577 {
2578 case ClearBoard:
2579 break;
2580
2581 case BlackPlay:
2582 break;
2583
2584 case WhitePlay:
2585 break;
2586
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;
2594 }
2595 }
2596
2597 pmFromX -= 2;
2598
2599 switch (piece)
2600 {
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;
2605
2606 ClearCatches(catches[0]);
2607 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2608 break;
2609
2610 case BlackPlay: /* not currently on menu */
2611 SetBlackToPlay();
2612 break;
2613
2614 case WhitePlay: /* not currently on menu */
2615 SetWhiteToPlay();
2616 break;
2617
2618 default:
2619 boards[0][pmFromY][pmFromX] = piece;
2620 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2621 break;
2622 }
2623
2624 XSync(localPlayer.xDisplay, False);
2625 }
2626
2627
2628
2629
2630 static void
SetBlackToPlay(void)2631 SetBlackToPlay(void)
2632 {
2633 int saveCM;
2634
2635 if (gameMode != EditPosition)
2636 return;
2637
2638 whitePlaysFirst = False;
2639 saveCM = currentMove;
2640 currentMove = 0; /* kludge */
2641 DisplayClocks(ReDisplayTimers);
2642 currentMove = saveCM;
2643 }
2644
2645
2646
2647
2648 static void
SetWhiteToPlay(void)2649 SetWhiteToPlay(void)
2650 {
2651 int saveCM;
2652
2653 if (gameMode != EditPosition)
2654 return;
2655
2656 whitePlaysFirst = True;
2657 saveCM = currentMove;
2658 currentMove = 1; /* kludge */
2659 DisplayClocks(ReDisplayTimers);
2660 currentMove = saveCM;
2661 }
2662
2663
2664
2665
2666 /*
2667 * If the user selects on a border boundary or off the board, return failure.
2668 * Otherwise map the event coordinate to the square.
2669 */
2670
2671 int
EventToSquare(int x)2672 EventToSquare(int x)
2673 {
2674 if (x < LINE_GAP)
2675 return -1;
2676
2677 x -= LINE_GAP;
2678
2679 if ((x % (player->squareSize + LINE_GAP)) >= player->squareSize)
2680 return -1;
2681
2682 x /= (player->squareSize + LINE_GAP);
2683
2684 if (x >= BOARD_SIZE)
2685 return -1;
2686
2687 return x;
2688 }
2689
2690
2691
2692
2693 int
EventToXSquare(int x)2694 EventToXSquare(int x)
2695 {
2696 if (x < LINE_GAP)
2697 return -1;
2698
2699 x -= LINE_GAP;
2700
2701 if ((x % (player->squareSize + LINE_GAP)) >= player->squareSize)
2702 return -1;
2703
2704 x /= (player->squareSize + LINE_GAP);
2705
2706 if (x >= BOARD_SIZE + 4)
2707 return -1;
2708
2709 return x;
2710 }
2711
2712
2713
2714
2715 ShogiSquare
CharToPiece(int c,int p)2716 CharToPiece(int c, int p)
2717 {
2718 if (p)
2719 {
2720 switch (c)
2721 {
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;
2740 }
2741 }
2742 else
2743 {
2744 switch (c)
2745 {
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;
2764 }
2765 }
2766 }
2767
2768
2769
2770
2771 /*
2772 * Convert coordinates to normal algebraic notation.
2773 * promoPiece must be NULLCHAR if not a promotion.
2774 */
2775
2776 ShogiMove
MakeAlg(int fromX,int fromY,int toX,int toY,char promoPiece,int currentBoardIndex,char * out)2777 MakeAlg(int fromX, int fromY, int toX, int toY,
2778 char promoPiece, int currentBoardIndex, char *out)
2779 {
2780 ShogiSquare piece;
2781 char *outp = out;
2782
2783 if (fromX > 80)
2784 {
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);
2792 }
2793 else
2794 {
2795 *outp++ = '9' - fromX;
2796 *outp++ = 'i' - fromY;
2797 *outp++ = '9' - toX;
2798 *outp++ = 'i' - toY;
2799 *outp++ = promoPiece;
2800 *outp++ = NULLCHAR;
2801
2802 if (promoPiece == NULLCHAR)
2803 {
2804 return NormalMove;
2805 }
2806 else
2807 {
2808 return (BlackOnMove(forwardMostMove)
2809 ? BlackPromotion : WhitePromotion);
2810 }
2811 }
2812 }
2813
2814
2815
2816
2817 void
DrawSquare(int row,int column,ShogiSquare piece)2818 DrawSquare(int row, int column, ShogiSquare piece)
2819 {
2820 int square_color, x, y, direction, font_ascent, font_descent;
2821 char string[2];
2822 XCharStruct overall;
2823 struct DisplayData *player;
2824
2825 for (player = &localPlayer; True; player = &remotePlayer)
2826 {
2827 int offset, remote;
2828
2829 remote = (player == &remotePlayer);
2830 offset = 2 * (player->squareSize + LINE_GAP);
2831
2832 if (player->flipView)
2833 {
2834 x = LINE_GAP + ((BOARD_SIZE - 1) - column) *
2835 (player->squareSize + LINE_GAP) + offset;
2836 y = LINE_GAP + row * (player->squareSize + LINE_GAP);
2837 }
2838 else
2839 {
2840 x = LINE_GAP + column * (player->squareSize + LINE_GAP) + offset;
2841 y = LINE_GAP + ((BOARD_SIZE - 1) - row) *
2842 (player->squareSize + LINE_GAP);
2843 }
2844
2845 square_color = (((column + row) % 2) ? LIGHT : DARK);
2846
2847 if (piece == EmptySquare)
2848 {
2849 if (column < 0 || column >= BOARD_SIZE)
2850 {
2851 /* empty square off board */
2852 XFillRectangle(player->xDisplay, player->xBoardWindow,
2853 player->squareOffBoardGC,
2854 x, y, player->squareSize,
2855 player->squareSize);
2856 }
2857 else
2858 {
2859 /* empty square on board */
2860 XFillRectangle(player->xDisplay,
2861 player->xBoardWindow,
2862 player->squareGC,
2863 x, y,
2864 player->squareSize,
2865 player->squareSize);
2866 }
2867 }
2868 else if (player->monoMode) /* Draw a piece in mono mode. */
2869 {
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);
2881 }
2882 else /* Draw a piece in color mode. */
2883 {
2884 if ((column < 0) || (column >= BOARD_SIZE)) /* off board */
2885 {
2886 /* draw piece background */
2887
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);
2897
2898 /* draw piece bitmap */
2899
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);
2909 }
2910 else /* on board */
2911 {
2912 /* draw piece background */
2913
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);
2923
2924 /* draw piece bitmap */
2925
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);
2935 }
2936 }
2937
2938 string[1] = NULLCHAR;
2939
2940 if (player->showCoords
2941 && (column >= 0) && (column < 9)
2942 && (row == (player->flipView ? 8 : 0)))
2943 {
2944 string[0] = '9' - column;
2945 XTextExtents(player->coordFontStruct, string, 1, &direction,
2946 &font_ascent, &font_descent, &overall);
2947
2948 if (player->monoMode)
2949 {
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);
2955 }
2956 else
2957 {
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);
2963 }
2964 }
2965
2966 if (player->showCoords
2967 && (row >= 0) && (row < 9)
2968 && (column == (player->flipView ? 8 : 0)))
2969 {
2970 string[0] = 'i' - row;
2971 XTextExtents(player->coordFontStruct, string, 1, &direction,
2972 &font_ascent, &font_descent, &overall);
2973
2974 if (player->monoMode)
2975 {
2976 XDrawImageString(player->xDisplay,
2977 player->xBoardWindow, player->coordGC,
2978 x + 2, y + font_ascent + 1, string, 1);
2979 }
2980 else
2981 {
2982 XDrawString(player->xDisplay, player->xBoardWindow,
2983 player->coordGC,
2984 x + 2, y + font_ascent + 1, string, 1);
2985 }
2986 }
2987
2988 if (!updateRemotePlayer || (player == &remotePlayer))
2989 break;
2990 }
2991 }
2992
2993
2994
2995
2996 void
EventProc(Widget widget,XtPointer client_data,XEvent * event)2997 EventProc(Widget widget, XtPointer client_data, XEvent *event)
2998 {
2999 if (event->type == MappingNotify)
3000 {
3001 XRefreshKeyboardMapping((XMappingEvent *) event);
3002 return;
3003 }
3004
3005 if (!XtIsRealized(widget))
3006 return;
3007
3008 if ((event->type == ButtonPress) || (event->type == ButtonRelease))
3009 {
3010 if (event->xbutton.button != Button1)
3011 return;
3012 }
3013
3014 switch (event->type)
3015 {
3016 case Expose:
3017 DrawPosition(widget, event, NULL, NULL);
3018 break;
3019
3020 default:
3021 return;
3022 }
3023 }
3024
3025
3026
3027
3028 /*
3029 * event handler for redrawing the board
3030 */
3031
3032 void
DrawPosition(Widget w,XEvent * event,String * prms,Cardinal * nprms)3033 DrawPosition(Widget w, XEvent *event, String *prms, Cardinal *nprms)
3034 {
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;
3041
3042 if (!player->Iconic)
3043 {
3044 XtSetArg(args[0], XtNiconic, False);
3045 XtSetValues(localPlayer.shellWidget, args, 1);
3046 }
3047
3048 /*
3049 * It would be simpler to clear the window with XClearWindow()
3050 * but this causes a very distracting flicker.
3051 */
3052
3053 if ((w == localPlayer.boardWidget)
3054 && (event == NULL)
3055 && lastBoardValid
3056 && (lastFlipView == localPlayer.flipView)
3057 && (!updateRemotePlayer
3058 || (lastRemoteFlipView == remotePlayer.flipView)))
3059 {
3060 for (i = 0; i < BOARD_SIZE; i++)
3061 {
3062 for (j = 0; j < BOARD_SIZE; j++)
3063 {
3064 if (boards[currentMove][i][j] != lastBoard[i][j])
3065 DrawSquare(i, j, boards[currentMove][i][j]);
3066 }
3067 }
3068
3069 for (i = 0; i < 2; i++)
3070 {
3071 for (j = 0; j < 8; j++)
3072 {
3073 if (catches[currentMove][i][j] != lastCatches[i][j])
3074 {
3075 UpdateCatched(i, 0, False, True, currentMove);
3076 break;
3077 }
3078 }
3079 }
3080 }
3081 else
3082 {
3083 XDrawSegments(localPlayer.xDisplay,
3084 localPlayer.xBoardWindow, localPlayer.lineGC,
3085 localPlayer.gridSegments, (BOARD_SIZE + 1) * 2);
3086
3087 if (updateRemotePlayer)
3088 {
3089 XDrawSegments(remotePlayer.xDisplay,
3090 remotePlayer.xBoardWindow, remotePlayer.lineGC,
3091 remotePlayer.gridSegments, (BOARD_SIZE + 1) * 2);
3092 }
3093
3094 for (i = 0; i < BOARD_SIZE; i++)
3095 for (j = 0; j < BOARD_SIZE; j++)
3096 DrawSquare(i, j, boards[currentMove][i][j]);
3097
3098 UpdateCatched(0, 0, False, True, currentMove);
3099 UpdateCatched(1, 0, False, True, currentMove);
3100 }
3101
3102 CopyBoard(lastBoard, boards[currentMove]);
3103 CopyCatches(lastCatches, catches[currentMove]);
3104 lastBoardValid = 1;
3105 lastFlipView = localPlayer.flipView;
3106
3107 if (updateRemotePlayer)
3108 lastRemoteFlipView = remotePlayer.flipView;
3109
3110 XSync(localPlayer.xDisplay, False);
3111
3112 if (updateRemotePlayer)
3113 XSync(remotePlayer.xDisplay, False);
3114 }
3115
3116
3117
3118
3119 void
InitPosition(int redraw)3120 InitPosition(int redraw)
3121 {
3122 currentMove = forwardMostMove = backwardMostMove = 0;
3123 CopyBoard(boards[0], initialPosition);
3124 ClearCatches(catches[0]);
3125
3126 if (redraw)
3127 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3128 }
3129
3130
3131
3132
3133 void
CopyBoard(Board to,Board from)3134 CopyBoard(Board to, Board from)
3135 {
3136 int i, j;
3137
3138 for (i = 0; i < BOARD_SIZE; i++)
3139 for (j = 0; j < BOARD_SIZE; j++)
3140 to[i][j] = from[i][j];
3141 }
3142
3143
3144
3145
3146 void
CopyCatches(Catched to,Catched from)3147 CopyCatches(Catched to, Catched from)
3148 {
3149 int i, j;
3150
3151 for (i = 0; i < 2; i++)
3152 for (j = 0; j < 8; j++)
3153 to[i][j] = from[i][j];
3154 }
3155
3156
3157
3158
3159 void
SendCurrentBoard(FILE * fp)3160 SendCurrentBoard(FILE *fp)
3161 {
3162 SendBoard(fp, boards[currentMove], catches[currentMove]);
3163 }
3164
3165
3166
3167
3168 void
SendBoard(FILE * fp,Board board,Catched catches)3169 SendBoard(FILE *fp, Board board, Catched catches)
3170 {
3171 char message[MSG_SIZ];
3172 ShogiSquare *bp;
3173 int i, j;
3174
3175 SendToProgram("edit\n", fp);
3176 SendToProgram("#\n", fp);
3177
3178 for (i = BOARD_SIZE - 1; i >= 0; i--)
3179 {
3180 bp = &board[i][0];
3181
3182 for (j = 0; j < BOARD_SIZE; j++, bp++)
3183 {
3184 if (((int) *bp) < (int)WhitePawn)
3185 {
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);
3191 }
3192 }
3193 }
3194
3195 for (i = 0; i <= 7; i++)
3196 {
3197 int n;
3198
3199 for (n = catches[0][i]; n > 0; n--)
3200 {
3201 sprintf(message, "%c*\n",
3202 catchedIndexToChar[i]);
3203 SendToProgram(message, fp);
3204 }
3205 }
3206
3207 SendToProgram("c\n", fp);
3208
3209 for (i = BOARD_SIZE - 1; i >= 0; i--)
3210 {
3211 bp = &board[i][0];
3212
3213 for (j = 0; j < BOARD_SIZE; j++, bp++)
3214 {
3215 if ((((int) *bp) != ((int)EmptySquare))
3216 && (((int) *bp) >= ((int)WhitePawn)))
3217 {
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);
3223 }
3224 }
3225 }
3226
3227 for (i = 0; i <= 7; i++)
3228 {
3229 int n;
3230
3231 for (n = catches[1][i]; n > 0; n--)
3232 {
3233 sprintf(message, "%c*\n",
3234 catchedIndexToChar[i]);
3235 SendToProgram(message, fp);
3236 }
3237 }
3238
3239 SendToProgram(".\n", fp);
3240 }
3241
3242
3243
3244
3245 static int
PromotionPossible(int fromY,int toY,ShogiSquare piece)3246 PromotionPossible(int fromY, int toY, ShogiSquare piece)
3247 {
3248 if (((int)piece) < ((int)WhitePawn))
3249 {
3250 if ((fromY < 6) && (toY < 6))
3251 return False;
3252 }
3253 else
3254 {
3255 if ((fromY > 2) && (toY > 2))
3256 return False;
3257 }
3258
3259 return piecePromotable[(int)piece];
3260
3261 }
3262
3263
3264
3265
3266 static void
ShowCount(int row,int column,int n)3267 ShowCount(int row, int column, int n)
3268 {
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;
3274
3275 DrawSquare(row, column, EmptySquare);
3276
3277 if (n <= 1)
3278 return;
3279
3280 for (player = &localPlayer; True; player = &remotePlayer)
3281 {
3282 if (player->flipView)
3283 {
3284 x = LINE_GAP + ((BOARD_SIZE - 1) - column) *
3285 (player->squareSize + LINE_GAP) + offset;
3286 y = LINE_GAP + row * (player->squareSize + LINE_GAP);
3287 }
3288 else
3289 {
3290 x = LINE_GAP + column * (player->squareSize + LINE_GAP) + offset;
3291 y = LINE_GAP + ((BOARD_SIZE - 1) - row) *
3292 (player->squareSize + LINE_GAP);
3293 }
3294
3295 x -= player->squareSize / 2;
3296
3297 string[1] = NULLCHAR;
3298
3299 if (n > 9)
3300 string[0] = '*';
3301 else
3302 string[0] = '0' + n;
3303
3304 XTextExtents(player->coordFontStruct, string, 1, &direction,
3305 &font_ascent, &font_descent, &overall);
3306
3307 if (player->monoMode)
3308 {
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);
3314 }
3315 else
3316 {
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);
3322 }
3323
3324 if (!updateRemotePlayer || (player == &remotePlayer))
3325 break;
3326 }
3327 }
3328
3329
3330
3331
3332 void
UpdateCatched(int Color,int Figure,int Drop,int DropAll,int currentMove)3333 UpdateCatched(int Color, int Figure, int Drop, int DropAll, int currentMove)
3334 {
3335 int n, F;
3336 int x, y;
3337
3338 /* Determine first row and column. */
3339
3340 if (Color)
3341 {
3342 x = -1;
3343 y = BOARD_SIZE - 1;
3344 }
3345 else
3346 {
3347 x = BOARD_SIZE;
3348 y = 0;
3349 }
3350
3351 if (DropAll)
3352 n = 0;
3353 else
3354 n = catches[currentMove][Color][Figure];
3355
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. */
3360
3361 if (DropAll || (Drop && (n == 1)) || (!Drop && (n == 0)))
3362 {
3363 /* show all captured pieces */
3364 n = 0;
3365
3366 for (F = pawn; F <= king; F++)
3367 {
3368 int c;
3369
3370 if ((c = catches[currentMove][Color][F]) > 0)
3371 {
3372 n++;
3373 DrawSquare(y, x, catchedIndexToPiece[Color][F]);
3374 ShowCount(y, (Color ? (x - 1) : (x + 1)), c);
3375
3376 if (Color)
3377 y--;
3378 else
3379 y++;
3380 }
3381 }
3382
3383 if (DropAll)
3384 {
3385 for (; n < 9; n++)
3386 {
3387 DrawSquare(y, x, EmptySquare);
3388 ShowCount(y, (Color ? (x - 1) : (x + 1)), 0);
3389
3390 if (Color)
3391 y--;
3392 else
3393 y++;
3394 }
3395 }
3396 else if (!Drop)
3397 {
3398 /* remove one line! */
3399 DrawSquare(y, x, EmptySquare);
3400 ShowCount(y, (Color ? (x - 1) : (x + 1)), 0);
3401 }
3402 }
3403 else
3404 {
3405 /* show the actual count */
3406 for (F = pawn; F <= Figure - 1; F++)
3407 {
3408 if (catches[currentMove][Color][F] > 0)
3409 {
3410 if (Color)
3411 y--;
3412 else
3413 y++;
3414 }
3415 }
3416
3417 ShowCount(y, (Color ? (x - 1) : (x + 1)), n);
3418 }
3419 }
3420
3421
3422
3423
3424 #ifdef BLINK_COUNT
3425
3426 static int BlinkCount = 0;
3427 static int BlinkRow, BlinkCol;
3428 static ShogiSquare BlinkPiece;
3429
3430
3431 void
BlinkSquareProc(void)3432 BlinkSquareProc(void)
3433 {
3434 if (BlinkCount > 0)
3435 {
3436 BlinkCount--;
3437 DrawSquare (BlinkRow, BlinkCol,
3438 ((BlinkCount & 1) ? EmptySquare : BlinkPiece));
3439
3440 if (BlinkCount > 0)
3441 {
3442 blinkSquareXID
3443 = XtAppAddTimeOut(appContext,
3444 150,
3445 (XtTimerCallbackProc)BlinkSquareProc,
3446 NULL);
3447 }
3448 }
3449 else
3450 {
3451 BlinkCount = 0;
3452 }
3453 }
3454
3455
3456
3457
3458 void
BlinkSquare(int row,int col,ShogiSquare piece)3459 BlinkSquare(int row, int col, ShogiSquare piece)
3460 {
3461 BlinkCount = 2 * BLINK_COUNT + 1;
3462 BlinkRow = row;
3463 BlinkCol = col;
3464 BlinkPiece = piece;
3465 BlinkSquareProc();
3466 }
3467
3468
3469 #endif /* BLINK_COUNT */
3470
3471
3472
3473
3474 static int
PieceOfCatched(int color,int x,int y,int currentMove)3475 PieceOfCatched(int color, int x, int y, int currentMove)
3476 {
3477 int F, n;
3478
3479 if (color)
3480 {
3481 if (x != 1)
3482 return (no_piece);
3483
3484 y = 8 - y;
3485 }
3486 else
3487 {
3488 if (x != 11)
3489 return no_piece;
3490 }
3491
3492 for (F = pawn, n = 0; F <= king; F++)
3493 {
3494 if (catches[currentMove][color][F] > 0)
3495 {
3496 if (n == y)
3497 return F;
3498
3499 n++;
3500 }
3501 }
3502
3503 return no_piece;
3504 }
3505
3506
3507
3508
3509 /*
3510 * event handler for parsing user moves
3511 */
3512
3513 void
HandleUserMove(Widget w,XEvent * event)3514 HandleUserMove(Widget w, XEvent *event)
3515 {
3516 ShogiMove move_type;
3517 ShogiSquare from_piece;
3518 int to_x, to_y, fromRemotePlayer;
3519
3520 if (updateRemotePlayer)
3521 {
3522 if (((w != localPlayer.boardWidget)
3523 && (w != remotePlayer.boardWidget))
3524 || (matchMode != MatchFalse))
3525 {
3526 return;
3527 }
3528
3529 fromRemotePlayer = (w == remotePlayer.boardWidget);
3530 }
3531 else
3532 {
3533 if ((w != localPlayer.boardWidget) || (matchMode != MatchFalse))
3534 return;
3535
3536 fromRemotePlayer = False;
3537 }
3538
3539 player = (fromRemotePlayer ? &remotePlayer : &localPlayer);
3540
3541 if (player->promotionUp)
3542 {
3543 XtPopdown(player->promotionShell);
3544 XtDestroyWidget(player->promotionShell);
3545 player->promotionUp = False;
3546 fromX = fromY = -1;
3547 }
3548
3549 switch (gameMode)
3550 {
3551 case EndOfGame:
3552 case PlayFromGameFile:
3553 case TwoMachinesPlay:
3554 return;
3555
3556 case MachinePlaysBlack:
3557 if (BlackOnMove(forwardMostMove))
3558 {
3559 DisplayMessage("It is not your turn", fromRemotePlayer);
3560 return;
3561 }
3562
3563 break;
3564
3565 case MachinePlaysWhite:
3566 if (!BlackOnMove(forwardMostMove))
3567 {
3568 DisplayMessage("It is not your turn", fromRemotePlayer);
3569 return;
3570 }
3571
3572 break;
3573
3574 case ForceMoves:
3575 forwardMostMove = currentMove;
3576 break;
3577
3578 default:
3579 break;
3580 }
3581
3582 if (currentMove != forwardMostMove)
3583 {
3584 DisplayMessage("Displayed position is not current",
3585 fromRemotePlayer);
3586 return;
3587 }
3588
3589 switch (event->type)
3590 {
3591 case ButtonPress:
3592 if ((fromX >= 0) || (fromY >= 0))
3593 return;
3594
3595 if (((fromX = EventToXSquare(event->xbutton.x)) < 1)
3596 || (fromX > BOARD_SIZE + 2)
3597 || ((fromY = EventToSquare(event->xbutton.y)) < 0))
3598 {
3599 fromX = fromY = -1;
3600 return;
3601 }
3602
3603 if (player->flipView)
3604 fromX = BOARD_SIZE + 3 - fromX;
3605 else
3606 fromY = BOARD_SIZE - 1 - fromY;
3607
3608 break;
3609
3610 case ButtonRelease:
3611 if ((fromX < 0) || (fromY < 0))
3612 return;
3613
3614 if (((to_x = EventToXSquare(event->xbutton.x)) < 1)
3615 || (to_x > BOARD_SIZE + 2)
3616 || ((to_y = EventToSquare(event->xbutton.y)) < 0))
3617 {
3618 if (gameMode == EditPosition && !off_board(fromX))
3619 {
3620 fromX -= 2;
3621 boards[0][fromY][fromX] = EmptySquare;
3622 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3623 XSync(localPlayer.xDisplay, False);
3624
3625 if (updateRemotePlayer)
3626 XSync(remotePlayer.xDisplay, False);
3627 }
3628
3629 fromX = fromY = -1;
3630 return;
3631 }
3632
3633 if (player->flipView)
3634 to_x = BOARD_SIZE + 3 - to_x;
3635 else
3636 to_y = BOARD_SIZE - 1 - to_y;
3637
3638 if ((fromX == to_x) && (fromY == to_y))
3639 {
3640 fromX = fromY = -1;
3641 return;
3642 }
3643
3644 if (gameMode == EditPosition)
3645 {
3646 ShogiSquare piece;
3647
3648 if (off_board(fromX))
3649 {
3650 /* Remove a catched piece */
3651 int i, c;
3652 c = ((fromX < 5) ^ player->flipView);
3653 i = PieceOfCatched(c, fromX, fromY, 0);
3654
3655 if (i == no_piece)
3656 {
3657 fromX = fromY = -1;
3658 return;
3659 }
3660 else
3661 {
3662 piece = catchedIndexToPiece[c][i];
3663 catches[0][c][i]--;
3664 }
3665 }
3666 else
3667 {
3668 /* remove piece from board field */
3669 fromX -= 2;
3670 piece = boards[0][fromY][fromX];
3671 boards[0][fromY][fromX] = EmptySquare;
3672 }
3673
3674 if (!off_board(to_x))
3675 {
3676 /* drop piece to board field */
3677 ShogiSquare catched_piece;
3678 to_x -= 2;
3679 catched_piece = boards[0][to_y][to_x];
3680
3681 if (catched_piece != EmptySquare)
3682 {
3683 /* put piece to catched pieces */
3684 int i = pieceToCatchedIndex[catched_piece];
3685 int c = (catched_piece < WhitePawn);
3686 catches[0][c][i]++;
3687 }
3688
3689 /* place moved piece */
3690 boards[0][to_y][to_x] = piece;
3691 }
3692
3693 fromX = fromY = -1;
3694 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3695 XSync(localPlayer.xDisplay, False);
3696
3697 if (updateRemotePlayer)
3698 XSync(remotePlayer.xDisplay, False);
3699
3700 return;
3701 }
3702
3703 if (off_board(fromX))
3704 {
3705 int c = (BlackOnMove(forwardMostMove) ? 0 : 1);
3706 int piece = PieceOfCatched(c, fromX, fromY, currentMove);
3707
3708 if (piece == no_piece)
3709 {
3710 fromX = fromY = -1;
3711 return;
3712 }
3713 else
3714 {
3715 if (updateRemotePlayer
3716 && (BlackOnMove(forwardMostMove) == fromRemotePlayer))
3717 {
3718 DisplayMessage("Do not try to drop your opponent's pieces!",
3719 fromRemotePlayer);
3720 fromX = fromY = -1;
3721 return;
3722 }
3723
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);
3729
3730 #ifdef BLINK_COUNT
3731 if (updateRemotePlayer)
3732 BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
3733 #endif
3734
3735 FinishUserMove(move_type, to_x, to_y);
3736 break;
3737 }
3738 }
3739 else if (off_board(to_x))
3740 {
3741 fromX = fromY = -1;
3742 return;
3743 }
3744 else
3745 {
3746 fromX -= 2;
3747 to_x -= 2;
3748 from_piece = boards[currentMove][fromY][fromX];
3749
3750 if ((from_piece != EmptySquare)
3751 && updateRemotePlayer
3752 && ((from_piece < WhitePawn) == fromRemotePlayer))
3753 {
3754 DisplayMessage("Do not try to move your opponent's pieces!",
3755 fromRemotePlayer);
3756 fromX = fromY = -1;
3757 return;
3758 }
3759
3760 if (PromotionPossible(fromY, to_y, from_piece))
3761 {
3762 PromotionPopUp(from_piece, to_x, to_y, fromRemotePlayer);
3763 return;
3764 }
3765
3766 move_type = NormalMove;
3767 MakeMove(&move_type, fromX, fromY, to_x, to_y);
3768
3769 #ifdef BLINK_COUNT
3770 if (updateRemotePlayer)
3771 BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
3772 #endif
3773
3774 FinishUserMove(move_type, to_x, to_y);
3775 break;
3776 }
3777 }
3778 }
3779
3780
3781
3782
3783 void
FinishUserMove(ShogiMove move_type,int to_x,int to_y)3784 FinishUserMove(ShogiMove move_type, int to_x, int to_y)
3785 {
3786 char user_move[MSG_SIZ];
3787
3788 /* output move for gnushogi */
3789 switch (move_type)
3790 {
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;
3796
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;
3802
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;
3807
3808 default:
3809 fprintf(stderr, "%s: internal error; bad move_type\n",
3810 (char *)programName);
3811 break;
3812 }
3813
3814 Attention(firstProgramPID);
3815
3816 if (firstSendTime)
3817 SendTimeRemaining(toFirstProgFP);
3818
3819 SendToProgram(user_move, toFirstProgFP);
3820 strcpy(moveList[currentMove - 1], user_move);
3821
3822 fromX = fromY = -1;
3823
3824 if (gameMode == PauseGame)
3825 {
3826 /* a user move restarts a paused game*/
3827 PauseProc(NULL, NULL, NULL, NULL);
3828 }
3829
3830 switch (gameMode)
3831 {
3832 case ForceMoves:
3833 break;
3834
3835 case BeginningOfGame:
3836 if (localPlayer.appData.noShogiProgram)
3837 lastGameMode = gameMode = ForceMoves;
3838 else
3839 lastGameMode = gameMode = MachinePlaysWhite;
3840
3841 ModeHighlight();
3842 break;
3843
3844 case MachinePlaysWhite:
3845 case MachinePlaysBlack:
3846 default:
3847 break;
3848 }
3849 }
3850
3851
3852
3853
3854 /* Simple parser for moves from gnushogi. */
3855 void
ParseMachineMove(char * machine_move,ShogiMove * move_type,int * from_x,int * from_y,int * to_x,int * to_y)3856 ParseMachineMove(char *machine_move, ShogiMove *move_type,
3857 int *from_x, int *from_y, int *to_x, int *to_y)
3858 {
3859 #define no_digit(c) (c < '0' || c > '9')
3860 {
3861 if (no_digit(machine_move[0]))
3862 {
3863 switch (machine_move[0])
3864 {
3865 case 'P':
3866 *from_x = 81;
3867 break;
3868
3869 case 'L':
3870 *from_x = 82;
3871 break;
3872
3873 case 'N':
3874 *from_x = 83;
3875 break;
3876
3877 case 'S':
3878 *from_x = 84;
3879 break;
3880
3881 case 'G':
3882 *from_x = 85;
3883 break;
3884
3885 case 'B':
3886 *from_x = 86;
3887 break;
3888
3889 case 'R':
3890 *from_x = 87;
3891 break;
3892
3893 case 'K':
3894 *from_x = 88;
3895 break;
3896
3897 default:
3898 *from_x = -1;
3899 }
3900
3901 *from_y = *from_x;
3902 *to_x = '9' - machine_move[2];
3903 *to_y = 'i' - machine_move[3];
3904 }
3905 else
3906 {
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];
3911
3912 switch (machine_move[4])
3913 {
3914 case '+':
3915 *move_type = (BlackOnMove(forwardMostMove)
3916 ? BlackPromotion : WhitePromotion);
3917 break;
3918
3919 default:
3920 *move_type = NormalMove;
3921 break;
3922 }
3923 }
3924 }
3925 }
3926
3927
3928
3929
3930 void
SkipString(char ** mpr)3931 SkipString(char **mpr)
3932 {
3933 while (**mpr == ' ')
3934 (*mpr)++;
3935
3936 while ((**mpr != ' ') && (**mpr != NULLCHAR) && (**mpr != '\n'))
3937 (*mpr)++;
3938
3939 while (**mpr == ' ')
3940 (*mpr)++;
3941 }
3942
3943
3944
3945
3946 void
HandleMachineMove(char * message,FILE * fp)3947 HandleMachineMove(char *message, FILE *fp)
3948 {
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;
3953
3954 #ifdef SYNCHTIME
3955 long time_remaining;
3956 #endif
3957
3958 maybeThinking = False;
3959
3960 if (strncmp(message, "warning:", 8) == 0)
3961 {
3962 DisplayMessage(message, False);
3963
3964 if (updateRemotePlayer)
3965 DisplayMessage(message, True);
3966
3967 return;
3968 }
3969
3970 /*
3971 * If shogi program startup fails, exit with an error message.
3972 * Attempts to recover here are futile.
3973 */
3974
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))
3980 {
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);
3993 }
3994
3995 /*
3996 * If the move is illegal, cancel it and redraw the board.
3997 */
3998
3999 if (strncmp(message, "Illegal move", 12) == 0)
4000 {
4001 if (fp == fromFirstProgFP && firstSendTime == 2)
4002 {
4003 /* First program doesn't have the "time" command */
4004 firstSendTime = 0;
4005 return;
4006 }
4007 else if (fp == fromSecondProgFP && secondSendTime == 2)
4008 {
4009 /* Second program doesn't have the "time" command */
4010 secondSendTime = 0;
4011 return;
4012 }
4013
4014 if (forwardMostMove <= backwardMostMove)
4015 return;
4016
4017 if (gameMode == PauseGame)
4018 PauseProc(NULL, NULL, NULL, NULL);
4019
4020 if (gameMode == PlayFromGameFile)
4021 {
4022 /* Stop reading this game file */
4023 gameMode = ForceMoves;
4024 ModeHighlight();
4025 }
4026
4027 currentMove = --forwardMostMove;
4028
4029 if ((gameMode == PlayFromGameFile)
4030 || (gameMode == ForceMoves))
4031 DisplayClocks(ReDisplayTimers);
4032 else
4033 DisplayClocks(SwitchTimers);
4034
4035 sprintf(buf1, "Illegal move: %s", parseList[currentMove]);
4036 DisplayMessage(buf1, False);
4037
4038 if (updateRemotePlayer)
4039 DisplayMessage(buf1, True);
4040
4041 #ifdef BLINK_COUNT
4042 /*
4043 * Disable blinking of the target square.
4044 */
4045
4046 if (BlinkCount > 0)
4047 {
4048 /* If BlinkCount is even, the piece is currently displayed. */
4049 if (!(BlinkCount & 1))
4050 DrawSquare (BlinkRow, BlinkCol, EmptySquare);
4051
4052 /* BlinkCount = 0 will force the next blink timeout
4053 * to do nothing. */
4054 BlinkCount = 0;
4055 }
4056 #endif
4057
4058 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
4059
4060 XSync(localPlayer.xDisplay, False);
4061
4062 if (updateRemotePlayer)
4063 XSync(remotePlayer.xDisplay, False);
4064
4065 return;
4066 }
4067
4068 if (strstr(message, "GNU Shogi") != NULL)
4069 {
4070 at_least_gnushogi_1_2p03 = True;
4071 return;
4072 }
4073
4074 if (strncmp(message, "Hint:", 5) == 0)
4075 {
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);
4080
4081 if (move_type == WhitePromotion || move_type == BlackPromotion)
4082 promoPiece = '+';
4083 else
4084 promoPiece = NULLCHAR;
4085
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);
4090
4091 if (updateRemotePlayer)
4092 DisplayMessage(buf2, True);
4093
4094 return;
4095 }
4096
4097 if (strncmp(message, "Clocks:", 7) == 0)
4098 {
4099 sscanf(message, "Clocks: %ld %ld",
4100 &blackTimeRemaining, &whiteTimeRemaining);
4101 DisplayClocks(ReDisplayTimers);
4102
4103 return;
4104 }
4105
4106 /*
4107 * win, lose or draw
4108 */
4109
4110 if (strncmp(message, "Black", 5) == 0)
4111 {
4112 ShutdownShogiPrograms("Black wins");
4113 return;
4114 }
4115 else if (strncmp(message, "White", 5) == 0)
4116 {
4117 ShutdownShogiPrograms("White wins");
4118 return;
4119 }
4120 else if (strncmp(message, "Repetition", 10) == 0)
4121 {
4122 ShutdownShogiPrograms("Repetition");
4123 return;
4124 }
4125 else if (strncmp(message, "opponent mates!", 15) == 0)
4126 {
4127 switch ((gameMode == PauseGame) ? pausePreviousMode : gameMode)
4128 {
4129 case MachinePlaysWhite:
4130 ShutdownShogiPrograms("Black wins");
4131 break;
4132
4133 case MachinePlaysBlack:
4134 ShutdownShogiPrograms("White wins");
4135 break;
4136
4137 case TwoMachinesPlay:
4138 ShutdownShogiPrograms((fp == fromFirstProgFP)
4139 ? "Black wins" : "White wins");
4140 break;
4141
4142 default:
4143 /* can't happen */
4144 break;
4145 }
4146
4147 return;
4148 }
4149 else if (strncmp(message, "computer mates!", 15) == 0)
4150 {
4151 switch ((gameMode == PauseGame) ? pausePreviousMode : gameMode)
4152 {
4153 case MachinePlaysWhite:
4154 ShutdownShogiPrograms("White wins");
4155 break;
4156
4157 case MachinePlaysBlack:
4158 ShutdownShogiPrograms("Black wins");
4159 break;
4160
4161 case TwoMachinesPlay:
4162 ShutdownShogiPrograms((fp == fromFirstProgFP)
4163 ? "White wins" : "Black wins");
4164 break;
4165
4166 default:
4167 /* can't happen */
4168 break;
4169 }
4170
4171 return;
4172 }
4173 else if (strncmp(message, "Draw", 4) == 0)
4174 {
4175 ShutdownShogiPrograms("Draw");
4176 return;
4177 }
4178
4179 /*
4180 * normal machine reply move
4181 */
4182 maybeThinking = True;
4183
4184 if (strstr(message, "...") != NULL)
4185 {
4186 sscanf(message, "%s %s %s", buf1, buf2, machine_move);
4187
4188 #ifdef SYNCHTIME
4189 mpr = message;
4190 SkipString(&mpr); /* skip move number */
4191 SkipString(&mpr); /* skip ... */
4192 SkipString(&mpr); /* skip move */
4193
4194 if ((gameMode != TwoMachinesPlay) && (gameMode != ForceMoves)
4195 && ((*mpr == '-') || ((*mpr >= '0') && (*mpr <= '9'))))
4196 {
4197 /* synchronize with shogi program clock */
4198 sscanf(mpr, "%ld", &time_remaining);
4199
4200 if (xshogiDebug)
4201 {
4202 printf("from '%s' synchronize %s clock %ld\n",
4203 message,
4204 (BlackOnMove(forwardMostMove)
4205 ? "Black's"
4206 : "White's"),
4207 time_remaining);
4208 }
4209
4210 if (BlackOnMove(forwardMostMove))
4211 blackTimeRemaining = time_remaining;
4212 else
4213 whiteTimeRemaining = time_remaining;
4214 }
4215 #endif
4216
4217 if (machine_move[0] == NULLCHAR)
4218 return;
4219 }
4220 else
4221 {
4222 mpr = message;
4223
4224 #ifdef SYNCHTIME
4225 if (strstr(message, "time") == NULL)
4226 {
4227 /* remaining time will be determined from move */
4228 SkipString(&mpr); /* skip move number */
4229 SkipString(&mpr); /* skip move */
4230 }
4231
4232 if ((gameMode != TwoMachinesPlay) && (gameMode != ForceMoves)
4233 && ((*mpr == '-') || ((*mpr >= '0') && (*mpr <= '9'))))
4234 {
4235 /* synchronize with shogi program clock */
4236 sscanf(mpr, "%ld", &time_remaining);
4237
4238 if (xshogiDebug)
4239 {
4240 printf("from '%s' synchronize %s clock %ld\n",
4241 message,
4242 ((!BlackOnMove(forwardMostMove))
4243 ? "Black's" : "White's"),
4244 time_remaining);
4245 }
4246
4247 if (!BlackOnMove(forwardMostMove))
4248 blackTimeRemaining = time_remaining;
4249 else
4250 whiteTimeRemaining = time_remaining;
4251 }
4252 else
4253 #endif
4254
4255 if (xshogiDebug)
4256 printf("ignore noise: '%s'\n", message);
4257
4258 return; /* ignore noise */
4259 }
4260
4261 strcpy(moveList[forwardMostMove], machine_move);
4262
4263 ParseMachineMove(machine_move, &move_type, &from_x, &from_y,
4264 &to_x, &to_y);
4265
4266 if (gameMode != PauseGame)
4267 currentMove = forwardMostMove; /* display latest move */
4268
4269 MakeMove(&move_type, from_x, from_y, to_x, to_y);
4270
4271 #ifdef BLINK_COUNT
4272 if (gameMode != TwoMachinesPlay)
4273 BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
4274 #endif
4275
4276 if ((gameMode != PauseGame) && localPlayer.appData.ringBellAfterMoves)
4277 putc(BELLCHAR, stderr);
4278
4279 if ((gameMode == TwoMachinesPlay)
4280 || ((gameMode == PauseGame)
4281 && (pausePreviousMode == TwoMachinesPlay)))
4282 {
4283 strcat(machine_move, "\n");
4284
4285 if (BlackOnMove(forwardMostMove))
4286 {
4287 Attention(secondProgramPID);
4288
4289 if (secondSendTime)
4290 SendTimeRemaining(toSecondProgFP);
4291
4292 SendToProgram(machine_move, toSecondProgFP);
4293
4294 if (firstMove)
4295 {
4296 firstMove = False;
4297 SendToProgram(localPlayer.appData.blackString,
4298 toSecondProgFP);
4299 }
4300 }
4301 else
4302 {
4303 Attention(firstProgramPID);
4304
4305 if (firstSendTime)
4306 SendTimeRemaining(toFirstProgFP);
4307
4308 SendToProgram(machine_move, toFirstProgFP);
4309
4310 if (firstMove)
4311 {
4312 firstMove = False;
4313 SendToProgram(localPlayer.appData.blackString,
4314 toFirstProgFP);
4315 }
4316 }
4317 }
4318 }
4319
4320
4321
4322
4323 void
ReadGameFile(void)4324 ReadGameFile(void)
4325 {
4326 for (;;)
4327 {
4328 if (!ReadGameFileProc())
4329 return;
4330
4331 if (matchMode == MatchOpening)
4332 continue;
4333
4334 readGameXID
4335 = XtAppAddTimeOut(appContext,
4336 (int)(1000 * localPlayer.appData.timeDelay),
4337 (XtTimerCallbackProc) ReadGameFile, NULL);
4338 break;
4339 }
4340 }
4341
4342
4343
4344 /*
4345 * FIXME: there is a naming inconsistency: here ReadGameFileProc() is
4346 * called by ReadGameFile() while in other places XXXProc() calls XXX().
4347 */
4348
4349 int
ReadGameFileProc(void)4350 ReadGameFileProc(void)
4351 {
4352 ShogiMove move_type;
4353 char move[MSG_SIZ], buf[MSG_SIZ];
4354
4355 if (gameFileFP == NULL)
4356 return (int)False;
4357
4358 if (gameMode == PauseGame)
4359 return True;
4360
4361 if (gameMode != PlayFromGameFile)
4362 {
4363 fclose(gameFileFP);
4364 gameFileFP = NULL;
4365 return (int)False;
4366 }
4367
4368 if (commentUp)
4369 {
4370 XtPopdown(commentShell);
4371 XtDestroyWidget(commentShell);
4372 commentUp = False;
4373 }
4374
4375 fgets(move, MSG_SIZ, gameFileFP);
4376 move[strlen(move) - 1] = NULLCHAR;
4377 sprintf(buf, "# %s game file", programName);
4378
4379 if (strncmp(move, buf, strlen(buf)))
4380 {
4381 strcat(move, ": no xshogi game file");
4382 DisplayMessage(move, False);
4383 return (int)False;
4384 }
4385
4386 DisplayName(move);
4387 rewind(gameFileFP);
4388
4389 parseGameFile();
4390
4391 move_type = (ShogiMove)0;
4392
4393 lastGameMode = gameMode;
4394 gameMode = ForceMoves;
4395 ModeHighlight();
4396
4397 if (!loaded_game_finished)
4398 DisplayMessage("End of game file", False);
4399
4400 if (readGameXID != 0)
4401 {
4402 XtRemoveTimeOut(readGameXID);
4403 readGameXID = 0;
4404 }
4405
4406 fclose(gameFileFP);
4407 gameFileFP = NULL;
4408
4409 return (int)False;
4410 }
4411
4412
4413
4414
4415 /*
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.
4419 */
4420
4421 void
ApplyMove(ShogiMove * move_type,int from_x,int from_y,int to_x,int to_y,int currentMove)4422 ApplyMove(ShogiMove *move_type, int from_x, int from_y,
4423 int to_x, int to_y, int currentMove)
4424 {
4425 ShogiSquare piece, cpiece;
4426 char pieceChar;
4427 int i, c;
4428
4429 if (from_x > 80)
4430 {
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]--;
4436 }
4437 else if (PromotionPossible(from_y, to_y,
4438 piece = boards[currentMove][from_y][from_x]))
4439 {
4440 cpiece = boards[currentMove][to_y][to_x];
4441
4442 if (cpiece != EmptySquare)
4443 {
4444 i = pieceToCatchedIndex[cpiece];
4445 c = (cpiece < WhitePawn);
4446 catches[currentMove][c][i]++;
4447 }
4448
4449 if (*move_type == NormalMove)
4450 {
4451 boards[currentMove][to_y][to_x] = piece;
4452 }
4453 else
4454 {
4455 boards[currentMove][to_y][to_x] = piece = pieceToPromoted[piece];
4456 pieceChar = '+';
4457 }
4458
4459 boards[currentMove][from_y][from_x] = EmptySquare;
4460 }
4461 else
4462 {
4463 ShogiSquare piece = boards[currentMove][to_y][to_x];
4464
4465 if (piece != EmptySquare)
4466 {
4467 i = pieceToCatchedIndex[piece];
4468 c = (piece < WhitePawn);
4469 catches[currentMove][c][i]++;
4470 }
4471
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;
4476 }
4477 }
4478
4479
4480
4481
4482 /*
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.
4486 */
4487
4488 void
MakeMove(ShogiMove * move_type,int from_x,int from_y,int to_x,int to_y)4489 MakeMove(ShogiMove *move_type, int from_x, int from_y, int to_x, int to_y)
4490 {
4491 char message[MSG_SIZ], movestr[MSG_SIZ];
4492 char promoPiece = NULLCHAR;
4493
4494 forwardMostMove++;
4495
4496 CopyBoard(boards[forwardMostMove], boards[forwardMostMove - 1]);
4497 CopyCatches(catches[forwardMostMove], catches[forwardMostMove - 1]);
4498
4499 ApplyMove(move_type, from_x, from_y, to_x, to_y, forwardMostMove);
4500
4501 endMessage[0] = NULLCHAR;
4502
4503 timeRemaining[0][forwardMostMove] = blackTimeRemaining;
4504 timeRemaining[1][forwardMostMove] = whiteTimeRemaining;
4505
4506 if ((gameMode == PauseGame) && (pausePreviousMode != PlayFromGameFile))
4507 return;
4508
4509 currentMove = forwardMostMove;
4510
4511 if (gameMode == PlayFromGameFile)
4512 {
4513 sprintf(message, "%d. %s%s",
4514 ((currentMove + 1) / 2),
4515 (BlackOnMove(currentMove) ? "... " : ""),
4516 currentMoveString);
4517 strcpy(parseList[currentMove - 1], currentMoveString);
4518 }
4519 else
4520 {
4521 if ((*move_type == WhitePromotion) || (*move_type == BlackPromotion))
4522 promoPiece = '+';
4523 else
4524 promoPiece = NULLCHAR;
4525
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);
4533 }
4534
4535 DisplayMessage(message, False);
4536
4537 if ((gameMode == PlayFromGameFile) || (gameMode == ForceMoves)
4538 || ((gameMode == PauseGame)
4539 && (pausePreviousMode == PlayFromGameFile)))
4540 {
4541 DisplayClocks(ReDisplayTimers);
4542 }
4543 else
4544 {
4545 DisplayClocks(SwitchTimers);
4546 }
4547
4548 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
4549
4550 XSync(localPlayer.xDisplay, False);
4551
4552 if (updateRemotePlayer)
4553 {
4554 DisplayMessage(message, True);
4555 XSync(remotePlayer.xDisplay, False);
4556 }
4557 }
4558
4559
4560
4561
4562 void
InitShogiProgram(char * host_name,char * program_name,int * pid,FILE ** to,FILE ** from,XtIntervalId * xid,int * sendTime)4563 InitShogiProgram(char *host_name, char *program_name, int *pid,
4564 FILE **to, FILE **from, XtIntervalId *xid, int *sendTime)
4565 {
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;
4572
4573 if (localPlayer.appData.noShogiProgram)
4574 return;
4575
4576 signal(SIGPIPE, CatchPipeSignal);
4577 pipe(to_prog);
4578 pipe(from_prog);
4579
4580 if ((*pid = fork()) == 0)
4581 {
4582 signal(SIGPIPE, CatchPipeSignal);
4583
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 */
4591
4592 if (localPlayer.appData.searchTime != NULL)
4593 {
4594 sprintf(arg_buf, "%d", searchTime);
4595 arg1 = arg_buf;
4596 arg2 = (char *)NULL;
4597 }
4598 else if (localPlayer.appData.searchDepth > 0)
4599 {
4600 sprintf(arg_buf, "%d", localPlayer.appData.searchDepth);
4601 arg1 = "1";
4602 arg2 = "9999";
4603 }
4604 else
4605 {
4606 sprintf(arg_buf, "%d", localPlayer.appData.movesPerSession);
4607 arg1 = arg_buf;
4608 arg2 = localPlayer.appData.timeControl;
4609 }
4610
4611 if (strcmp(host_name, "localhost") == 0)
4612 {
4613 execlp(program_name, program_name, arg1, arg2,
4614 (char *)NULL);
4615 }
4616 else
4617 {
4618 execlp(localPlayer.appData.remoteShell,
4619 localPlayer.appData.remoteShell,
4620 host_name, program_name, arg1, arg2,
4621 (char *)NULL);
4622 }
4623
4624 perror(program_name);
4625 exit(1);
4626 }
4627
4628 close(to_prog[0]);
4629 close(from_prog[1]);
4630
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);
4635
4636 ReceiveFromProgram(from_fp, &dummy_source, &dummy_id); /* "GNU Shogi"*/
4637
4638 if (!at_least_gnushogi_1_2p03)
4639 {
4640 fprintf(stderr, "you must have at least gnushogi-1.2p03\n");
4641 exit(1);
4642 }
4643
4644 if (*pid == 0)
4645 return;
4646
4647 *xid = XtAppAddInput(appContext, fileno(from_fp),
4648 (XtPointer)XtInputReadMask,
4649 (XtInputCallbackProc)ReceiveFromProgram,
4650 (XtPointer)from_fp);
4651
4652 SendToProgram(localPlayer.appData.initString, *to);
4653
4654 if (localPlayer.appData.gameIn)
4655 SendToProgram("gamein\n", *to);
4656
4657 SendSearchDepth(*to);
4658
4659 if (*sendTime == 2)
4660 {
4661 /* Does program have "time" command? */
4662 char buf[MSG_SIZ];
4663
4664 sprintf(buf, "time %ld\n", blackTimeRemaining / 10);
4665 SendToProgram(buf, to_fp);
4666 ReceiveFromProgram(from_fp, &dummy_source, &dummy_id);
4667
4668 if (*sendTime == 2)
4669 {
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);
4674 }
4675 }
4676 }
4677
4678
4679
4680
4681 void
ShutdownShogiPrograms(char * why)4682 ShutdownShogiPrograms(char *why)
4683 {
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);
4693
4694 if (readGameXID != 0)
4695 XtRemoveTimeOut(readGameXID);
4696
4697 readGameXID = 0;
4698
4699 if (firstProgramPID != 0)
4700 {
4701 fclose(fromFirstProgFP);
4702 fclose(toFirstProgFP);
4703 fromFirstProgFP = toFirstProgFP = NULL;
4704
4705 if (kill(firstProgramPID, SIGTERM) == 0)
4706 WAIT0;
4707 }
4708
4709 firstProgramPID = 0;
4710
4711 if (firstProgramXID != 0)
4712 XtRemoveInput(firstProgramXID);
4713
4714 firstProgramXID = 0;
4715
4716 if (secondProgramPID != 0)
4717 {
4718 fclose(fromSecondProgFP);
4719 fclose(toSecondProgFP);
4720 fromSecondProgFP = toSecondProgFP = NULL;
4721
4722 if (kill(secondProgramPID, SIGTERM) == 0)
4723 WAIT0;
4724 }
4725
4726 secondProgramPID = 0;
4727
4728 if (secondProgramXID != 0)
4729 XtRemoveInput(secondProgramXID);
4730
4731 secondProgramXID = 0;
4732
4733 DisplayClocks(StopTimers);
4734
4735 if (matchMode != MatchFalse)
4736 {
4737 if (localPlayer.appData.saveGameFile[0] != NULLCHAR)
4738 SaveGame(localPlayer.appData.saveGameFile);
4739
4740 exit(0);
4741 }
4742 }
4743
4744
4745
4746
4747 void
CommentPopUp(char * label)4748 CommentPopUp(char *label)
4749 {
4750 Arg args[2];
4751 Position x, y;
4752 Dimension bw_width, pw_width;
4753
4754 if (commentUp)
4755 {
4756 XtPopdown(commentShell);
4757 XtDestroyWidget(commentShell);
4758 commentUp = False;
4759 }
4760
4761 DisplayMessage("Comment", False);
4762
4763 XtSetArg(args[0], XtNwidth, &bw_width);
4764 XtGetValues(localPlayer.formWidget, args, 1);
4765
4766 XtSetArg(args[0], XtNresizable, True);
4767 XtSetArg(args[1], XtNwidth, bw_width - 8);
4768
4769 commentShell = XtCreatePopupShell("Comment",
4770 transientShellWidgetClass,
4771 localPlayer.commandsWidget, args, 2);
4772
4773 XtSetArg(args[0], XtNlabel, label);
4774
4775 (void)XtCreateManagedWidget("commentLabel", labelWidgetClass,
4776 commentShell, args, 1);
4777
4778 XtRealizeWidget(commentShell);
4779
4780 XtSetArg(args[0], XtNwidth, &pw_width);
4781 XtGetValues(commentShell, args, 1);
4782
4783 XtTranslateCoords(localPlayer.shellWidget,
4784 (bw_width - pw_width) / 2, -50, &x, &y);
4785
4786 XtSetArg(args[0], XtNx, x);
4787 XtSetArg(args[1], XtNy, y);
4788 XtSetValues(commentShell, args, 2);
4789
4790 XtPopup(commentShell, XtGrabNone);
4791 commentUp = True;
4792 }
4793
4794
4795
4796
4797 void
FileNamePopUp(char * label,Boolean (* proc)(char *))4798 FileNamePopUp(char *label, Boolean (*proc) (char *))
4799 {
4800 Arg args[2];
4801 Widget popup, dialog;
4802 Position x, y;
4803 Dimension bw_width, pw_width;
4804
4805 fileProc = proc;
4806
4807 XtSetArg(args[0], XtNwidth, &bw_width);
4808 XtGetValues(localPlayer.boardWidget, args, 1);
4809
4810 XtSetArg(args[0], XtNresizable, True);
4811 XtSetArg(args[1], XtNwidth, DIALOG_SIZE);
4812
4813 popup = XtCreatePopupShell("File Name Prompt",
4814 transientShellWidgetClass,
4815 localPlayer.commandsWidget, args, 2);
4816
4817 XtSetArg(args[0], XtNlabel, label);
4818 XtSetArg(args[1], XtNvalue, "");
4819
4820 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
4821 popup, args, 2);
4822
4823 XawDialogAddButton(dialog, "ok", FileNameCallback, (XtPointer) dialog);
4824 XawDialogAddButton(dialog, "cancel", FileNameCallback,
4825 (XtPointer) dialog);
4826
4827 XtRealizeWidget(popup);
4828
4829 XtSetArg(args[0], XtNwidth, &pw_width);
4830 XtGetValues(popup, args, 1);
4831
4832 XtTranslateCoords(localPlayer.boardWidget,
4833 (bw_width - pw_width) / 2, 10, &x, &y);
4834
4835 XtSetArg(args[0], XtNx, x);
4836 XtSetArg(args[1], XtNy, y);
4837 XtSetValues(popup, args, 2);
4838
4839 XtPopup(popup, XtGrabExclusive);
4840 filenameUp = True;
4841
4842 XtSetKeyboardFocus(localPlayer.shellWidget, popup);
4843 }
4844
4845
4846
4847
4848 void
FileNameCallback(Widget w,XtPointer client_data,XtPointer call_data)4849 FileNameCallback(Widget w, XtPointer client_data, XtPointer call_data)
4850 {
4851 String name;
4852 Arg args[1];
4853
4854 XtSetArg(args[0], XtNlabel, &name);
4855 XtGetValues(w, args, 1);
4856
4857 if (strcmp(name, "cancel") == 0)
4858 {
4859 XtPopdown(w = XtParent(XtParent(w)));
4860 XtDestroyWidget(w);
4861 filenameUp = False;
4862 ModeHighlight();
4863 return;
4864 }
4865
4866 FileNameAction(w, NULL, NULL, NULL);
4867 }
4868
4869
4870
4871
4872 void
FileNameAction(Widget w,XEvent * event,String * prms,Cardinal * nprms)4873 FileNameAction(Widget w, XEvent *event, String *prms, Cardinal *nprms)
4874 {
4875 char buf[MSG_SIZ];
4876 String name;
4877
4878 name = XawDialogGetValueString(w = XtParent(w));
4879
4880 if ((name != NULL) && (*name != NULLCHAR))
4881 {
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;
4890 }
4891
4892 XtPopdown(w = XtParent(w));
4893 XtDestroyWidget(w);
4894 filenameUp = False;
4895 ModeHighlight();
4896 }
4897
4898
4899
4900
4901 void
PromotionPopUp(ShogiSquare piece,int to_x,int to_y,int fromRemotePlayer)4902 PromotionPopUp(ShogiSquare piece, int to_x, int to_y, int fromRemotePlayer)
4903 {
4904 Arg args[2];
4905 Widget dialog;
4906 Position x, y;
4907 Dimension bw_width, bw_height, pw_width, pw_height;
4908
4909 player = (fromRemotePlayer ? &remotePlayer : &localPlayer);
4910
4911 pmi.piece = piece;
4912 pmi.to_x = to_x;
4913 pmi.to_y = to_y;
4914
4915 XtSetArg(args[0], XtNwidth, &bw_width);
4916 XtSetArg(args[1], XtNheight, &bw_height);
4917 XtGetValues(player->boardWidget, args, 2);
4918
4919 XtSetArg(args[0], XtNresizable, True);
4920
4921 player->promotionShell
4922 = XtCreatePopupShell("Promotion",
4923 transientShellWidgetClass,
4924 player->commandsWidget, args, 1);
4925
4926 XtSetArg(args[0], XtNlabel, "Promote piece?");
4927 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
4928 player->promotionShell, args, 1);
4929
4930 XawDialogAddButton(dialog, "Yes", PromotionCallback,
4931 (XtPointer) dialog);
4932 XawDialogAddButton(dialog, "No", PromotionCallback,
4933 (XtPointer) dialog);
4934 XawDialogAddButton(dialog, "cancel", PromotionCallback,
4935 (XtPointer) dialog);
4936
4937 XtRealizeWidget(player->promotionShell);
4938
4939 XtSetArg(args[0], XtNwidth, &pw_width);
4940 XtSetArg(args[1], XtNheight, &pw_height);
4941 XtGetValues(player->promotionShell, args, 2);
4942
4943 XtTranslateCoords(player->boardWidget,
4944 ((bw_width - pw_width) / 2),
4945 (LINE_GAP
4946 + player->squareSize / 3
4947 + (((piece == BlackPawn) ^ (player->flipView))
4948 ? 0
4949 : (6 * (player->squareSize + LINE_GAP)))),
4950 &x, &y);
4951
4952 XtSetArg(args[0], XtNx, x);
4953 XtSetArg(args[1], XtNy, y);
4954 XtSetValues(player->promotionShell, args, 2);
4955
4956 XtPopup(player->promotionShell, XtGrabNone);
4957
4958 player->promotionUp = True;
4959 }
4960
4961
4962
4963
4964 void
PromotionCallback(Widget w,XtPointer client_data,XtPointer call_data)4965 PromotionCallback(Widget w, XtPointer client_data, XtPointer call_data)
4966 {
4967 String name;
4968 Arg args[1];
4969 ShogiMove move_type;
4970 struct DisplayData *player;
4971
4972 XtSetArg(args[0], XtNlabel, &name);
4973 XtGetValues(w, args, 1);
4974
4975 w = XtParent(XtParent(w));
4976 player = ((w == remotePlayer.promotionShell)
4977 ? &remotePlayer : &localPlayer);
4978 XtPopdown(w);
4979 XtDestroyWidget(w);
4980 player->promotionUp = False;
4981
4982 if (fromX == -1)
4983 return;
4984
4985 if (strcmp(name, "Yes") == 0)
4986 {
4987 if ((int)pmi.piece < (int)WhitePawn)
4988 move_type = BlackPromotion;
4989 else
4990 move_type = WhitePromotion;
4991 }
4992 else if (strcmp(name, "No") == 0)
4993 {
4994 move_type = NormalMove;
4995 }
4996 else /* strcmp(name, "cancel") == 0 */
4997 {
4998 fromX = fromY = -1;
4999 return;
5000 }
5001
5002 MakeMove(&move_type, fromX, fromY, pmi.to_x, pmi.to_y);
5003
5004 #ifdef BLINK_COUNT
5005 if (updateRemotePlayer)
5006 {
5007 BlinkSquare(pmi.to_y, pmi.to_x,
5008 boards[currentMove][pmi.to_y][pmi.to_x]);
5009 }
5010 #endif
5011
5012 FinishUserMove(move_type, pmi.to_x, pmi.to_y);
5013 }
5014
5015
5016
5017
5018 void
FileModePopUp(char * name)5019 FileModePopUp(char *name)
5020 {
5021 Arg args[2];
5022 Widget dialog;
5023 Position x, y;
5024 Dimension bw_width, bw_height, pw_width, pw_height;
5025
5026 struct DisplayData *player = &localPlayer;
5027
5028 strcpy(fmi.name, name);
5029
5030 XtSetArg(args[0], XtNwidth, &bw_width);
5031 XtSetArg(args[1], XtNheight, &bw_height);
5032 XtGetValues(player->boardWidget, args, 2);
5033
5034 XtSetArg(args[0], XtNresizable, True);
5035 player->filemodeShell
5036 = XtCreatePopupShell("FileMode",
5037 transientShellWidgetClass,
5038 player->commandsWidget, args, 1);
5039
5040 XtSetArg(args[0], XtNlabel, "Append to existing file?");
5041 dialog = XtCreateManagedWidget("filemode", dialogWidgetClass,
5042 player->filemodeShell, args, 1);
5043
5044 XawDialogAddButton(dialog, "Yes", FileModeCallback,
5045 (XtPointer) dialog);
5046 XawDialogAddButton(dialog, "No", FileModeCallback,
5047 (XtPointer) dialog);
5048 XawDialogAddButton(dialog, "cancel", FileModeCallback,
5049 (XtPointer) dialog);
5050
5051 XtRealizeWidget(player->filemodeShell);
5052
5053 XtSetArg(args[0], XtNwidth, &pw_width);
5054 XtSetArg(args[1], XtNheight, &pw_height);
5055 XtGetValues(player->filemodeShell, args, 2);
5056
5057 XtTranslateCoords(player->boardWidget, (bw_width - pw_width) / 2,
5058 LINE_GAP + player->squareSize/3 +
5059 (6*(player->squareSize + LINE_GAP)),
5060 &x, &y);
5061
5062 XtSetArg(args[0], XtNx, x);
5063 XtSetArg(args[1], XtNy, y);
5064 XtSetValues(player->filemodeShell, args, 2);
5065
5066 XtPopup(player->filemodeShell, XtGrabNone);
5067
5068 filemodeUp = True;
5069 }
5070
5071
5072
5073
5074 void
FileModeCallback(Widget w,XtPointer client_data,XtPointer call_data)5075 FileModeCallback(Widget w, XtPointer client_data, XtPointer call_data)
5076 {
5077 String name;
5078 Arg args[1];
5079
5080 XtSetArg(args[0], XtNlabel, &name);
5081 XtGetValues(w, args, 1);
5082
5083 XtPopdown(w = XtParent(XtParent(w)));
5084 XtDestroyWidget(w);
5085
5086 if (strcmp(name, "Yes") == 0)
5087 {
5088 strcpy(fmi.mode, "a");
5089 }
5090 else if (strcmp(name, "No") == 0)
5091 {
5092 strcpy(fmi.mode, "w");
5093 }
5094 else /* strcmp(name, "cancel") == 0 */
5095 {
5096 filemodeUp = False;
5097 return;
5098 }
5099
5100 XtPopdown(localPlayer.filemodeShell);
5101 XtDestroyWidget(localPlayer.filemodeShell);
5102
5103 SaveGame(fmi.name);
5104
5105 filemodeUp = False;
5106 }
5107
5108
5109
5110
5111 void
SelectCommand(Widget w,XtPointer client_data,XtPointer call_data)5112 SelectCommand(Widget w, XtPointer client_data, XtPointer call_data)
5113 {
5114 Cardinal fromRemotePlayer = (Cardinal)client_data;
5115
5116 XawListReturnStruct *list_return = XawListShowCurrent(w);
5117
5118 player = fromRemotePlayer ? &remotePlayer : &localPlayer;
5119
5120 fromX = fromY = -1;
5121
5122 if (player->promotionUp)
5123 {
5124 XtPopdown(player->promotionShell);
5125 XtDestroyWidget(player->promotionShell);
5126 player->promotionUp = False;
5127 }
5128
5129 (*buttonProcs[list_return->list_index])
5130 (w, NULL, NULL, &fromRemotePlayer);
5131
5132 if (!filenameUp)
5133 ModeHighlight();
5134 }
5135
5136
5137
5138
5139 void
HighlightProcButton(XtActionProc proc)5140 HighlightProcButton(XtActionProc proc)
5141 {
5142 int i = 0;
5143
5144 if (proc == NULL)
5145 {
5146 XawListUnhighlight(localPlayer.commandsWidget);
5147
5148 if (updateRemotePlayer)
5149 XawListUnhighlight(remotePlayer.commandsWidget);
5150
5151 return;
5152 }
5153
5154 for (;;)
5155 {
5156 if (buttonProcs[i] == NULL)
5157 {
5158 XawListUnhighlight(localPlayer.commandsWidget);
5159
5160 if (updateRemotePlayer)
5161 XawListUnhighlight(remotePlayer.commandsWidget);
5162
5163 return;
5164 }
5165
5166 if (buttonProcs[i] == proc)
5167 {
5168 XawListHighlight(localPlayer.commandsWidget, i);
5169
5170 if (updateRemotePlayer)
5171 XawListHighlight(remotePlayer.commandsWidget, i);
5172
5173 return;
5174 }
5175
5176 i++;
5177 }
5178 }
5179
5180
5181
5182
5183 void
ModeHighlight(void)5184 ModeHighlight(void)
5185 {
5186 switch (gameMode)
5187 {
5188 case BeginningOfGame:
5189 if (localPlayer.appData.noShogiProgram)
5190 HighlightProcButton(ForceProc);
5191 else
5192 HighlightProcButton(MachineBlackProc);
5193
5194 break;
5195
5196 case MachinePlaysBlack:
5197 HighlightProcButton(MachineBlackProc);
5198 break;
5199
5200 case MachinePlaysWhite:
5201 HighlightProcButton(MachineWhiteProc);
5202 break;
5203
5204 case TwoMachinesPlay:
5205 HighlightProcButton(TwoMachinesProc);
5206 break;
5207
5208 case ForceMoves:
5209 HighlightProcButton(ForceProc);
5210
5211 break;
5212
5213 case PlayFromGameFile:
5214 HighlightProcButton(LoadGameProc);
5215 break;
5216
5217 case PauseGame:
5218 HighlightProcButton(PauseProc);
5219 break;
5220
5221 case EditPosition:
5222 HighlightProcButton(EditPositionProc);
5223 break;
5224
5225 case EndOfGame:
5226 default:
5227 HighlightProcButton(NULL);
5228 break;
5229 }
5230 }
5231
5232
5233
5234
5235 /*
5236 * Button procedures
5237 */
5238
5239 void
QuitRemotePlayerProc(void)5240 QuitRemotePlayerProc(void)
5241 {
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;
5248 }
5249
5250
5251
5252 void
QuitProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5253 QuitProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5254 {
5255 if (updateRemotePlayer)
5256 QuitRemotePlayerProc();
5257
5258 ShutdownShogiPrograms("Quitting");
5259 exit(0);
5260 }
5261
5262
5263
5264 void
LoadGameProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5265 LoadGameProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5266 {
5267 int fromRemotePlayer = *nprms;
5268
5269 if (fromRemotePlayer)
5270 {
5271 DisplayMessage("only opponent may load game", fromRemotePlayer);
5272 return;
5273 }
5274
5275 if (gameMode != BeginningOfGame)
5276 {
5277 DisplayMessage("Press Reset first.", False);
5278 return;
5279 }
5280
5281 if (localPlayer.appData.loadGameFile == NULL)
5282 FileNamePopUp("Game file name?", LoadGame);
5283 else
5284 (void) LoadGame(localPlayer.appData.loadGameFile);
5285 }
5286
5287
5288
5289
5290 Boolean
LoadGame(char * name)5291 LoadGame(char *name)
5292 {
5293 char buf[MSG_SIZ];
5294
5295 loaded_game_finished = 0;
5296
5297 if (gameMode != BeginningOfGame)
5298 {
5299 DisplayMessage("Press Reset first", False);
5300 return (int)False;
5301 }
5302
5303 if (localPlayer.appData.loadGameFile != name)
5304 {
5305 if (localPlayer.appData.loadGameFile)
5306 XtFree(localPlayer.appData.loadGameFile);
5307
5308 localPlayer.appData.loadGameFile = XtMalloc(strlen(name) + 1);
5309 strcpy(localPlayer.appData.loadGameFile, name);
5310 }
5311
5312 if ((gameFileFP = fopen(name, "r")) == NULL)
5313 {
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;
5319 }
5320
5321 lastGameMode = gameMode = PlayFromGameFile;
5322 ModeHighlight();
5323 InitPosition(True);
5324 DisplayClocks(StopTimers);
5325
5326 if (firstProgramXID == 0)
5327 {
5328 InitShogiProgram(localPlayer.appData.firstHost,
5329 localPlayer.appData.firstShogiProgram,
5330 &firstProgramPID, &toFirstProgFP,
5331 &fromFirstProgFP, &firstProgramXID,
5332 &firstSendTime);
5333 }
5334
5335 SendToProgram(localPlayer.appData.initString, toFirstProgFP);
5336 SendSearchDepth(toFirstProgFP);
5337 SendToProgram("force\n", toFirstProgFP);
5338
5339 currentMove = forwardMostMove = backwardMostMove = 0;
5340
5341 ReadGameFile();
5342
5343 return True;
5344 }
5345
5346
5347
5348
5349 /*
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.
5353 */
5354
5355 void
ResurrectShogiProgram(void)5356 ResurrectShogiProgram(void)
5357 {
5358 char buf[MSG_SIZ];
5359 int i;
5360
5361 if (currentMove > 0)
5362 currentMove--; /* delete "Black wins" or the like */
5363
5364 InitShogiProgram(localPlayer.appData.firstHost,
5365 localPlayer.appData.firstShogiProgram,
5366 &firstProgramPID, &toFirstProgFP, &fromFirstProgFP,
5367 &firstProgramXID, &firstSendTime);
5368
5369 SendToProgram(localPlayer.appData.initString, toFirstProgFP);
5370 SendSearchDepth(toFirstProgFP);
5371 SendToProgram("force\n", toFirstProgFP);
5372 gameMode = lastGameMode = ForceMoves;
5373 ModeHighlight();
5374
5375 i = (whitePlaysFirst ? 1 : 0);
5376
5377 if (startedFromSetupPosition)
5378 SendBoard(toFirstProgFP, boards[i], catches[i]);
5379
5380 for (; i < currentMove; i++)
5381 {
5382 strcpy(buf, moveList[i]);
5383 SendToProgram(buf, toFirstProgFP);
5384 }
5385
5386 if (!firstSendTime)
5387 {
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;
5393 }
5394 }
5395
5396
5397
5398
5399 void
MachineWhiteProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5400 MachineWhiteProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5401 {
5402 int fromRemotePlayer = *nprms;
5403
5404 if (updateRemotePlayer)
5405 {
5406 DisplayMessage("no machine moves in challenge mode",
5407 fromRemotePlayer);
5408
5409 return;
5410 }
5411
5412 if (gameMode == PauseGame)
5413 PauseProc(w, event, prms, nprms);
5414
5415 if (gameMode == PlayFromGameFile)
5416 ForceProc(w, event, prms, nprms);
5417
5418 if (gameMode == EditPosition)
5419 EditPositionDone();
5420
5421 if ((gameMode == EndOfGame)
5422 || (gameMode == PlayFromGameFile)
5423 || (gameMode == TwoMachinesPlay)
5424 || localPlayer.appData.noShogiProgram
5425 || (gameMode == MachinePlaysWhite))
5426 {
5427 return;
5428 }
5429
5430 if (BlackOnMove((gameMode == ForceMoves)
5431 ? currentMove
5432 : forwardMostMove))
5433 {
5434 DisplayMessage("It is not White's turn.", False);
5435 return;
5436 }
5437
5438 if (gameMode == ForceMoves)
5439 forwardMostMove = currentMove;
5440
5441 lastGameMode = gameMode = MachinePlaysWhite;
5442 ModeHighlight();
5443 SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
5444 DisplayClocks(StartTimers);
5445 }
5446
5447
5448
5449
5450 void
MachineBlackProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5451 MachineBlackProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5452 {
5453 int fromRemotePlayer = *nprms;
5454
5455 if (updateRemotePlayer)
5456 {
5457 DisplayMessage("no machine moves in challenge mode",
5458 fromRemotePlayer);
5459 return;
5460 }
5461
5462 if (gameMode == PauseGame)
5463 PauseProc(w, event, prms, nprms);
5464
5465 if (gameMode == PlayFromGameFile)
5466 ForceProc(w, event, prms, nprms);
5467
5468 if (gameMode == EditPosition)
5469 EditPositionDone();
5470
5471 if ((gameMode == EndOfGame)
5472 || (gameMode == PlayFromGameFile)
5473 || (gameMode == TwoMachinesPlay)
5474 || localPlayer.appData.noShogiProgram
5475 || (gameMode == MachinePlaysBlack))
5476 {
5477 return;
5478 }
5479
5480 if (!BlackOnMove((gameMode == ForceMoves)
5481 ? currentMove
5482 : forwardMostMove))
5483 {
5484 DisplayMessage("It is not Black's turn.", False);
5485 return;
5486 }
5487
5488 if (gameMode == ForceMoves)
5489 forwardMostMove = currentMove;
5490
5491 lastGameMode = gameMode = MachinePlaysBlack;
5492 ModeHighlight();
5493 SendToProgram(localPlayer.appData.blackString, toFirstProgFP);
5494 DisplayClocks(StartTimers);
5495 }
5496
5497
5498
5499
5500 void
ForwardProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5501 ForwardProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5502 {
5503 char buf[MSG_SIZ];
5504 int target;
5505 unsigned int state;
5506
5507 int fromRemotePlayer = *nprms;
5508
5509 if (updateRemotePlayer)
5510 {
5511 DisplayMessage("Forward button disabled.", fromRemotePlayer);
5512 return;
5513 }
5514
5515 if ((gameMode == EndOfGame) || (gameMode == EditPosition))
5516 return;
5517
5518 if (gameMode == PlayFromGameFile)
5519 PauseProc(w, event, prms, nprms);
5520
5521 if (currentMove >= forwardMostMove)
5522 return;
5523
5524 if (event == NULL)
5525 {
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);
5533 }
5534 else
5535 {
5536 state = event->xkey.state;
5537 }
5538
5539 if (state & ShiftMask)
5540 target = forwardMostMove;
5541 else
5542 target = currentMove + 1;
5543
5544 if (gameMode == ForceMoves)
5545 {
5546 while (currentMove < target)
5547 {
5548 strcpy(buf, moveList[currentMove++]);
5549 SendToProgram(buf, toFirstProgFP);
5550 }
5551 }
5552 else
5553 {
5554 currentMove = target;
5555 }
5556
5557 if (gameMode == ForceMoves)
5558 {
5559 blackTimeRemaining = timeRemaining[0][currentMove];
5560 whiteTimeRemaining = timeRemaining[1][currentMove];
5561 }
5562
5563 DisplayClocks(ReDisplayTimers);
5564 DisplayMove(currentMove - 1);
5565 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
5566 }
5567
5568
5569
5570
5571 void
ResetFileProc(void)5572 ResetFileProc(void)
5573 {
5574 char *buf = "";
5575
5576 if (updateRemotePlayer)
5577 return;
5578
5579 if (localPlayer.appData.loadGameFile)
5580 XtFree(localPlayer.appData.loadGameFile);
5581
5582 if (localPlayer.appData.loadPositionFile)
5583 XtFree(localPlayer.appData.loadPositionFile);
5584
5585 localPlayer.appData.loadGameFile
5586 = localPlayer.appData.loadPositionFile = NULL;
5587 DisplayName(buf);
5588
5589 if (gameFileFP != NULL)
5590 {
5591 fclose(gameFileFP);
5592 gameFileFP = NULL;
5593 }
5594 }
5595
5596
5597
5598
5599 void
ResetChallenge(void)5600 ResetChallenge(void)
5601 {
5602 char *buf = "";
5603
5604 if (localPlayer.appData.challengeDisplay)
5605 XtFree(localPlayer.appData.challengeDisplay);
5606
5607 localPlayer.appData.challengeDisplay = NULL;
5608 DisplayName(buf);
5609 }
5610
5611
5612
5613
5614 void
ResetProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5615 ResetProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5616 {
5617 int fromRemotePlayer = *nprms;
5618
5619 if (fromRemotePlayer)
5620 {
5621 DisplayMessage("Only your opponent may reset the game.",
5622 fromRemotePlayer);
5623 return;
5624 }
5625
5626 Reset(True);
5627 }
5628
5629
5630
5631
5632 void
Reset(int redraw)5633 Reset(int redraw) /* Boolean */
5634 {
5635 ResetFileProc();
5636 ResetChallenge();
5637
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;
5645
5646 endMessage[0] = NULLCHAR;
5647
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);
5660
5661 if (commentUp)
5662 {
5663 XtPopdown(commentShell);
5664 XtDestroyWidget(commentShell);
5665 commentUp = False;
5666 }
5667
5668 if (localPlayer.promotionUp)
5669 {
5670 XtPopdown(localPlayer.promotionShell);
5671 XtDestroyWidget(localPlayer.promotionShell);
5672 localPlayer.promotionUp = False;
5673 }
5674
5675 if (updateRemotePlayer && remotePlayer.promotionUp)
5676 {
5677 XtPopdown(remotePlayer.promotionShell);
5678 XtDestroyWidget(remotePlayer.promotionShell);
5679 remotePlayer.promotionUp = False;
5680 }
5681 }
5682
5683
5684
5685
5686 void
ClearCatches(int (* catches)[8])5687 ClearCatches(int (*catches)[8])
5688 {
5689 int c, p;
5690
5691 for (c = 0; c <= 1; c++)
5692 for (p = 0; p <= 7; p++)
5693 catches[c][p] = 0;
5694 }
5695
5696
5697
5698
5699 Boolean
Challenge(char * name)5700 Challenge(char *name)
5701 {
5702 char buf[MSG_SIZ];
5703 int argc;
5704 char **argv;
5705 XrmDatabase database;
5706
5707 if (gameMode != BeginningOfGame)
5708 {
5709 DisplayMessage("Press Reset first.", False);
5710 return (int)False;
5711 }
5712
5713 if (localPlayer.appData.challengeDisplay != name)
5714 {
5715 if (localPlayer.appData.challengeDisplay)
5716 XtFree(localPlayer.appData.challengeDisplay);
5717
5718 localPlayer.appData.challengeDisplay = XtMalloc(strlen(name) + 1);
5719 strcpy(localPlayer.appData.challengeDisplay, name);
5720 }
5721
5722 sprintf(buf, "trying to connect to %s.....", name);
5723 DisplayMessage(buf, False);
5724
5725 argc = global_argc;
5726 argv = global_argv;
5727
5728 if ((remotePlayer.xDisplay
5729 = XtOpenDisplay(appContext, name, "XShogi",
5730 "XShogi", 0, 0, &argc, argv)) == NULL)
5731 {
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;
5737 }
5738
5739 DisplayMessage("connected! creating remote window...", False);
5740
5741 remotePlayer.xScreen = DefaultScreen(remotePlayer.xDisplay);
5742
5743 remotePlayer.shellWidget
5744 = XtAppCreateShell(NULL, "XShogi",
5745 applicationShellWidgetClass,
5746 remotePlayer.xDisplay, NULL, 0);
5747
5748 database = XtDatabase(remotePlayer.xDisplay);
5749
5750 XrmParseCommand(&database,
5751 shellOptions, XtNumber(shellOptions),
5752 "XShogi", &argc, argv);
5753
5754 XtGetApplicationResources(remotePlayer.shellWidget,
5755 &remotePlayer.appData, clientResources,
5756 XtNumber(clientResources), NULL, 0);
5757
5758 player = &remotePlayer;
5759
5760 CreatePlayerWindow();
5761
5762 updateRemotePlayer = True;
5763
5764 DisplayName("REMOTE");
5765 DrawPosition(remotePlayer.boardWidget, NULL, NULL, NULL);
5766 DisplayClocks(ReDisplayTimers);
5767
5768 DisplayMessage("ready to play", False);
5769 DisplayMessage("ready to play", True);
5770
5771 return True;
5772 }
5773
5774
5775
5776
5777 void
ChallengeProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5778 ChallengeProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5779 {
5780 int fromRemotePlayer = *nprms;
5781
5782 if (updateRemotePlayer)
5783 {
5784 DisplayMessage("You are already in challenge mode.",
5785 fromRemotePlayer);
5786 return;
5787 }
5788
5789 if (gameMode != BeginningOfGame)
5790 {
5791 DisplayMessage("Press Reset first.", False);
5792 return;
5793 }
5794
5795 if (localPlayer.appData.challengeDisplay == NULL)
5796 FileNamePopUp("Challenge display?", Challenge);
5797 else
5798 (void) Challenge(localPlayer.appData.challengeDisplay);
5799 }
5800
5801
5802
5803
5804 Boolean
SelectLevel(char * command)5805 SelectLevel(char *command)
5806 {
5807 char buf[MSG_SIZ];
5808
5809 sprintf(buf, "level %s\n", command);
5810 SendToProgram(buf, toFirstProgFP);
5811
5812 return True;
5813 }
5814
5815
5816
5817
5818 void
SelectLevelProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5819 SelectLevelProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5820 {
5821 if ((BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysBlack))
5822 || (!BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysWhite)))
5823 {
5824 DisplayMessage("Wait until your turn.", False);
5825 }
5826 else
5827 {
5828 FileNamePopUp("#moves #minutes", SelectLevel);
5829 }
5830 }
5831
5832
5833
5834
5835 void
MoveNowProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5836 MoveNowProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5837 {
5838 if ((!BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysBlack))
5839 || (BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysWhite)))
5840 {
5841 DisplayMessage("Wait until machine's turn.", False);
5842 }
5843 else
5844 {
5845 Attention(firstProgramPID);
5846 }
5847 }
5848
5849
5850
5851
5852 void
LoadPositionProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5853 LoadPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5854 {
5855 int fromRemotePlayer = *nprms;
5856
5857 if (fromRemotePlayer)
5858 {
5859 DisplayMessage("only opponent may load position", fromRemotePlayer);
5860 return;
5861 }
5862
5863 if (gameMode != BeginningOfGame)
5864 {
5865 DisplayMessage("Press Reset first.", False);
5866 return;
5867 }
5868
5869 FileNamePopUp("Position file name?", LoadPosition);
5870 }
5871
5872
5873
5874
5875 Boolean
LoadPosition(char * name)5876 LoadPosition(char *name)
5877 {
5878 char *p, line[MSG_SIZ], buf[MSG_SIZ];
5879 Board initial_position;
5880 Catched initial_catches;
5881 FILE *fp;
5882 int i, j;
5883
5884 if (gameMode != BeginningOfGame)
5885 {
5886 DisplayMessage("Press Reset first.", False);
5887 return False;
5888 }
5889
5890 if (localPlayer.appData.loadPositionFile != name)
5891 {
5892 if (localPlayer.appData.loadPositionFile)
5893 XtFree(localPlayer.appData.loadPositionFile);
5894
5895 localPlayer.appData.loadPositionFile = XtMalloc(strlen(name) + 1);
5896 strcpy(localPlayer.appData.loadPositionFile, name);
5897 }
5898
5899 if ((fp = fopen(name, "r")) == NULL)
5900 {
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;
5906 }
5907
5908 lastGameMode = gameMode = ForceMoves;
5909 ModeHighlight();
5910 startedFromSetupPosition = True;
5911
5912 if (firstProgramXID == 0)
5913 {
5914 InitShogiProgram(localPlayer.appData.firstHost,
5915 localPlayer.appData.firstShogiProgram,
5916 &firstProgramPID, &toFirstProgFP,
5917 &fromFirstProgFP, &firstProgramXID,
5918 &firstSendTime);
5919 }
5920
5921 /*
5922 * Check and skip header information in position file.
5923 */
5924
5925 fgets(line, MSG_SIZ, fp);
5926 line[strlen(line) - 1] = NULLCHAR;
5927 sprintf(buf, "# %s position file", programName);
5928
5929 if (strncmp(line, buf, strlen(buf)))
5930 {
5931 strcat(line, ": no xshogi position file");
5932 DisplayMessage(line, False);
5933 return False;
5934 }
5935
5936 DisplayName(line);
5937 fgets(line, MSG_SIZ, fp); /* skip opponents */
5938
5939 for (i = BOARD_SIZE - 1; i >= 0; i--)
5940 {
5941 fgets(line, MSG_SIZ, fp);
5942
5943 for (p = line, j = 0; j < BOARD_SIZE; p++)
5944 {
5945 int promoted = False; /* CHECKME: is this valid? */
5946
5947 if (*p == '+')
5948 promoted = True;
5949
5950 if (*p == ' ')
5951 promoted = False;
5952
5953 p++;
5954 initial_position[i][j++] = CharToPiece(*p, promoted);
5955 }
5956 }
5957
5958 {
5959 int color;
5960
5961 for (color = 0; color <= 1; color++)
5962 {
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]);
5972 }
5973 }
5974
5975 whitePlaysFirst = False;
5976
5977 if (!feof(fp))
5978 {
5979 fgets(line, MSG_SIZ, fp);
5980
5981 if (strncmp(line, "white", strlen("white")) == 0)
5982 whitePlaysFirst = True;
5983 }
5984
5985 fclose(fp);
5986
5987 if (whitePlaysFirst)
5988 {
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);
6000 }
6001 else
6002 {
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);
6009 }
6010
6011 DisplayClocks(ResetTimers);
6012 timeRemaining[0][1] = blackTimeRemaining;
6013 timeRemaining[1][1] = whiteTimeRemaining;
6014
6015 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6016 return True;
6017 }
6018
6019
6020
6021
6022 void
EditPositionProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6023 EditPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6024 {
6025 int fromRemotePlayer = *nprms;
6026
6027 if (updateRemotePlayer)
6028 {
6029 DisplayMessage("Edit button disabled", fromRemotePlayer);
6030 return;
6031 }
6032
6033 if (gameMode == EditPosition)
6034 return;
6035
6036 ForceProc(w, event, prms, nprms);
6037
6038 if (gameMode != ForceMoves)
6039 return;
6040
6041 DisplayName("<-- Press to set side to play next");
6042 DisplayMessage("Mouse: 1=drag, 2=black, 3=white", False);
6043
6044 lastGameMode = gameMode = EditPosition;
6045 ModeHighlight();
6046
6047 if (currentMove > 0)
6048 CopyBoard(boards[0], boards[currentMove]);
6049
6050 whitePlaysFirst = !BlackOnMove(forwardMostMove);
6051 currentMove = forwardMostMove = backwardMostMove = 0;
6052 }
6053
6054
6055
6056
6057 void
EditPositionDone(void)6058 EditPositionDone(void)
6059 {
6060 startedFromSetupPosition = True;
6061 SendToProgram(localPlayer.appData.initString, toFirstProgFP);
6062 SendSearchDepth(toFirstProgFP);
6063
6064 if (whitePlaysFirst)
6065 {
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);
6075 }
6076 else
6077 {
6078 currentMove = forwardMostMove = backwardMostMove = 0;
6079 SendCurrentBoard(toFirstProgFP);
6080 SendToProgram("force\n", toFirstProgFP);
6081 DisplayName(" ");
6082 DisplayMessage("Black to play", False);
6083 }
6084
6085 lastGameMode = gameMode = ForceMoves;
6086 }
6087
6088
6089
6090 /*
6091 * FUNCTION
6092 * BackwardProc
6093 *
6094 * DESCRIPTION
6095 * This function executes when undoing a move.
6096 * FIXME: this function is totally hosed!!!
6097 *
6098 * ARGUMENTS
6099 * Widget w
6100 * XEvent *event
6101 * String *prms
6102 * Cardinal *nprms
6103 *
6104 * RETURN VALUE
6105 * void
6106 *
6107 */
6108
6109 void
BackwardProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6110 BackwardProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6111 {
6112 int target;
6113 unsigned int state;
6114
6115 int fromRemotePlayer = *nprms;
6116
6117 if (updateRemotePlayer)
6118 {
6119 DisplayMessage("Backward button disabled", fromRemotePlayer);
6120 return;
6121 }
6122
6123 /*
6124 * Why do we need this here?
6125 */
6126
6127 ForceProc(w, event, prms, nprms);
6128
6129 if ((currentMove <= backwardMostMove) || (gameMode == EditPosition))
6130 return;
6131
6132 if (gameMode == EndOfGame)
6133 ResurrectShogiProgram();
6134
6135 if (gameMode == PlayFromGameFile)
6136 PauseProc(w, event, prms, nprms);
6137
6138 if (event == NULL)
6139 {
6140 /* Kludge */
6141 Window root, child;
6142 int root_x, root_y;
6143 int win_x, win_y;
6144
6145 XQueryPointer(localPlayer.xDisplay, localPlayer.xBoardWindow,
6146 &root, &child, &root_x, &root_y,
6147 &win_x, &win_y, &state);
6148 }
6149 else
6150 {
6151 state = event->xkey.state;
6152 }
6153
6154 if (state & ShiftMask)
6155 {
6156 target = backwardMostMove;
6157 }
6158 else
6159 {
6160 target = currentMove - 1;
6161 }
6162
6163 if (gameMode == ForceMoves)
6164 {
6165 Attention(firstProgramPID);
6166
6167 while (currentMove > target)
6168 {
6169 SendToProgram("undo\n", toFirstProgFP);
6170 currentMove--;
6171 }
6172 }
6173 else
6174 {
6175 currentMove = target;
6176 }
6177
6178 if (gameMode == ForceMoves)
6179 {
6180 whiteTimeRemaining = timeRemaining[0][currentMove];
6181 blackTimeRemaining = timeRemaining[1][currentMove];
6182 }
6183
6184 DisplayClocks(ReDisplayTimers);
6185 DisplayMove(currentMove - 1);
6186 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6187 }
6188
6189
6190
6191
6192 void
FlipViewProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6193 FlipViewProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6194 {
6195 struct DisplayData *player = (*nprms ? &remotePlayer : &localPlayer);
6196
6197 player->flipView = !player->flipView;
6198 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6199 }
6200
6201
6202
6203
6204 void
SaveGameProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6205 SaveGameProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6206 {
6207 char def[MSG_SIZ];
6208
6209 int fromRemotePlayer = *nprms;
6210
6211 if (fromRemotePlayer)
6212 {
6213 DisplayMessage("only opponent may save game", fromRemotePlayer);
6214 return;
6215 }
6216
6217 def[0] = NULLCHAR;
6218
6219 FileNamePopUp("Filename for saved game?", SaveGame);
6220 }
6221
6222
6223
6224
6225 Boolean
SaveGame(char * name)6226 SaveGame(char *name)
6227 {
6228 char buf[MSG_SIZ];
6229 int i, len, move = 0;
6230 time_t tm;
6231
6232 if (!filemodeUp) /* if called via FileModeCallback avoid recursion */
6233 {
6234 if ((gameFileFP = fopen(name, "r")) == NULL)
6235 {
6236 strcpy(fmi.mode, "w");
6237 }
6238 else
6239 {
6240 fclose(gameFileFP);
6241 FileModePopUp(name);
6242 return False; /* CHECKME: what should the return value be? */
6243 }
6244 }
6245
6246 if ((gameFileFP = fopen(name, fmi.mode)) == NULL)
6247 {
6248 sprintf(buf, "Can't open %s (mode %s)", name, fmi.mode);
6249 DisplayMessage(buf, False);
6250 return False;
6251 }
6252
6253 tm = time((time_t *) NULL);
6254
6255 fprintf(gameFileFP, "# %s game file -- %s", programName, ctime(&tm));
6256 PrintOpponents(gameFileFP);
6257
6258 for (i = 0; i < currentMove;)
6259 {
6260 if ((i % 5) == 0)
6261 fprintf(gameFileFP, "\n");
6262
6263 fprintf(gameFileFP, "%d. %s ", ++move, parseList[i++]);
6264
6265 if (i >= currentMove)
6266 {
6267 fprintf(gameFileFP, "\n");
6268 break;
6269 }
6270
6271 if ((len = strlen(parseList[i])) == 0)
6272 break;
6273
6274 fprintf(gameFileFP, "%s ", parseList[i++]);
6275 }
6276
6277 fprintf(gameFileFP, "\n");
6278
6279 fclose(gameFileFP);
6280 gameFileFP = NULL;
6281
6282 return True;
6283 }
6284
6285
6286
6287
6288 void
SwitchProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6289 SwitchProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6290 {
6291 if (localPlayer.appData.noShogiProgram)
6292 return;
6293
6294 switch (gameMode)
6295 {
6296 default:
6297 return;
6298
6299 case MachinePlaysBlack:
6300 if (BlackOnMove(forwardMostMove))
6301 {
6302 DisplayMessage("Wait until your turn", False);
6303 return;
6304 }
6305
6306 lastGameMode = gameMode = MachinePlaysWhite;
6307 ModeHighlight();
6308 break;
6309
6310 case BeginningOfGame:
6311
6312 case MachinePlaysWhite:
6313 if (!BlackOnMove(forwardMostMove))
6314 {
6315 DisplayMessage("Wait until your turn", False);
6316 return;
6317 }
6318
6319 if (forwardMostMove == 0)
6320 {
6321 MachineBlackProc(w, event, prms, nprms);
6322 return;
6323 }
6324
6325 lastGameMode = gameMode = MachinePlaysBlack;
6326 ModeHighlight();
6327 break;
6328 }
6329
6330 Attention(firstProgramPID);
6331 SendToProgram("switch\n", toFirstProgFP);
6332 }
6333
6334
6335
6336
6337 void
ForceProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6338 ForceProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6339 {
6340 int i;
6341
6342 switch (gameMode)
6343 {
6344 case MachinePlaysBlack:
6345 if (BlackOnMove(forwardMostMove))
6346 {
6347 DisplayMessage("Wait until your turn", False);
6348 return;
6349 }
6350
6351 Attention(firstProgramPID);
6352 SendToProgram("force\n", toFirstProgFP);
6353 break;
6354
6355 case MachinePlaysWhite:
6356 if (!BlackOnMove(forwardMostMove))
6357 {
6358 DisplayMessage("Wait until your turn", False);
6359 return;
6360 }
6361
6362 Attention(firstProgramPID);
6363 SendToProgram("force\n", toFirstProgFP);
6364 break;
6365
6366 case BeginningOfGame:
6367 SendToProgram("force\n", toFirstProgFP);
6368 break;
6369
6370 case PlayFromGameFile:
6371 if (readGameXID != 0)
6372 {
6373 XtRemoveTimeOut(readGameXID);
6374 readGameXID = 0;
6375 }
6376
6377 if (gameFileFP != NULL)
6378 {
6379 fclose(gameFileFP);
6380 gameFileFP = NULL;
6381 }
6382
6383 break;
6384
6385 case EndOfGame:
6386 ResurrectShogiProgram();
6387 break;
6388
6389 case EditPosition:
6390 EditPositionDone();
6391 break;
6392
6393 case TwoMachinesPlay:
6394 ShutdownShogiPrograms("");
6395 ResurrectShogiProgram();
6396 return;
6397
6398 default:
6399 return;
6400 }
6401
6402 if ((gameMode == MachinePlaysWhite)
6403 || (gameMode == MachinePlaysBlack)
6404 || (gameMode == TwoMachinesPlay)
6405 || (gameMode == PlayFromGameFile))
6406 {
6407 i = forwardMostMove;
6408
6409 while (i > currentMove)
6410 {
6411 SendToProgram("undo\n", toFirstProgFP);
6412 i--;
6413 }
6414
6415 blackTimeRemaining = timeRemaining[0][currentMove];
6416 whiteTimeRemaining = timeRemaining[1][currentMove];
6417
6418 if (whiteFlag || blackFlag)
6419 {
6420 whiteFlag = blackFlag = 0;
6421 }
6422
6423 DisplayTitle("");
6424 }
6425
6426 lastGameMode = gameMode = ForceMoves;
6427 ModeHighlight();
6428 DisplayClocks(StopTimers);
6429 }
6430
6431
6432
6433 void
HintProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6434 HintProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6435 {
6436 int fromRemotePlayer = *nprms;
6437
6438 if (updateRemotePlayer)
6439 {
6440 DisplayMessage("no hints in challenge mode", fromRemotePlayer);
6441 return;
6442 }
6443
6444 if (localPlayer.appData.noShogiProgram)
6445 return;
6446
6447 switch (gameMode)
6448 {
6449 case MachinePlaysBlack:
6450 if (BlackOnMove(forwardMostMove))
6451 {
6452 DisplayMessage("Wait until your turn", False);
6453 return;
6454 }
6455
6456 break;
6457
6458 case BeginningOfGame:
6459 case MachinePlaysWhite:
6460 if (!BlackOnMove(forwardMostMove))
6461 {
6462 DisplayMessage("Wait until your turn", False);
6463 return;
6464 }
6465
6466 break;
6467
6468 default:
6469 DisplayMessage("No hint available", False);
6470 return;
6471 }
6472
6473 Attention(firstProgramPID);
6474 SendToProgram("hint\n", toFirstProgFP);
6475 }
6476
6477
6478
6479
6480 void
PrintPosition(FILE * fp,int move)6481 PrintPosition(FILE *fp, int move)
6482 {
6483 int i, j, color;
6484
6485 for (i = BOARD_SIZE - 1; i >= 0; i--)
6486 {
6487 for (j = 0; j < BOARD_SIZE; j++)
6488 {
6489 if (pieceIsPromoted[(int)boards[currentMove][i][j]])
6490 fprintf(fp, "%c", '+');
6491 else
6492 fprintf(fp, "%c", ' ');
6493
6494 fprintf(fp, "%c",
6495 pieceToChar[(int)boards[currentMove][i][j]]);
6496
6497 if (j == BOARD_SIZE - 1)
6498 fputc('\n', fp);
6499 }
6500 }
6501
6502 for (color = 0; color <= 1; color++)
6503 {
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]);
6513 }
6514
6515 if ((gameMode == EditPosition)
6516 ? !whitePlaysFirst
6517 : BlackOnMove(forwardMostMove))
6518 {
6519 fprintf(fp, "black to play\n");
6520 }
6521 else
6522 {
6523 fprintf(fp, "white to play\n");
6524 }
6525 }
6526
6527
6528
6529
6530 void
PrintOpponents(FILE * fp)6531 PrintOpponents(FILE *fp)
6532 {
6533 char host_name[MSG_SIZ];
6534
6535 #ifdef HAVE_GETHOSTNAME
6536 gethostname(host_name, MSG_SIZ);
6537 #else
6538 strncpy(host_name, "hostname not available", MSG_SIZ);
6539 #endif
6540
6541 switch (lastGameMode)
6542 {
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;
6550
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;
6558
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;
6566
6567 default:
6568 fprintf(fp, "#\n");
6569 break;
6570 }
6571 }
6572
6573
6574
6575
6576 void
SavePositionProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6577 SavePositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6578 {
6579 char def[MSG_SIZ];
6580
6581 int fromRemotePlayer = *nprms;
6582
6583 if (fromRemotePlayer)
6584 {
6585 DisplayMessage("only opponent may save game", fromRemotePlayer);
6586 return;
6587 }
6588
6589 def[0] = NULLCHAR;
6590
6591 FileNamePopUp("Filename for saved position?", SavePosition);
6592 }
6593
6594
6595
6596
6597 Boolean
SavePosition(char * name)6598 SavePosition(char *name)
6599 {
6600 char buf[MSG_SIZ];
6601 FILE *fp;
6602 time_t tm;
6603
6604 if ((fp = fopen(name, "w")) == NULL)
6605 {
6606 sprintf(buf, "Can't open %s", name);
6607 DisplayMessage(buf, False);
6608 return False;
6609 }
6610
6611 tm = time((time_t *) NULL);
6612
6613 fprintf(fp, "# %s position file -- %s", programName, ctime(&tm));
6614 PrintOpponents(fp);
6615 PrintPosition(fp, currentMove);
6616 fclose(fp);
6617
6618 return True;
6619 }
6620
6621
6622
6623
6624 void
TwoMachinesProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6625 TwoMachinesProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6626 {
6627 int i;
6628 MatchMode matchKind;
6629
6630 int fromRemotePlayer = *nprms;
6631
6632 if (updateRemotePlayer)
6633 {
6634 DisplayMessage("no machine moves in challenge mode",
6635 fromRemotePlayer);
6636 return;
6637 }
6638
6639 if (gameMode == PauseGame)
6640 PauseProc(w, event, prms, nprms);
6641
6642 if (gameMode == PlayFromGameFile)
6643 ForceProc(w, event, prms, nprms);
6644
6645 if ((gameMode == EndOfGame)
6646 || (gameMode == TwoMachinesPlay)
6647 || localPlayer.appData.noShogiProgram)
6648 {
6649 return;
6650 }
6651
6652 if (matchMode == MatchFalse)
6653 {
6654 switch (gameMode)
6655 {
6656 case PauseGame:
6657 case PlayFromGameFile:
6658 return;
6659
6660 case MachinePlaysBlack:
6661 case MachinePlaysWhite:
6662 ForceProc(w, event, prms, nprms);
6663
6664 if (gameMode != ForceMoves)
6665 return;
6666
6667 matchKind = MatchOpening;
6668 break;
6669
6670 case ForceMoves:
6671 matchKind = MatchOpening;
6672 break;
6673
6674 case EditPosition:
6675 EditPositionDone();
6676 matchKind = MatchPosition;
6677 break;
6678
6679 case BeginningOfGame:
6680 default:
6681 matchKind = MatchInit;
6682 break;
6683 }
6684 }
6685 else
6686 {
6687 matchKind = matchMode;
6688 }
6689
6690 forwardMostMove = currentMove;
6691
6692 localPlayer.flipView = False;
6693 remotePlayer.flipView = True;
6694 firstMove = False;
6695 DisplayClocks(ResetTimers);
6696 DisplayClocks(StartTimers);
6697
6698 switch (matchKind)
6699 {
6700 case MatchOpening:
6701 if (firstProgramXID == 0)
6702 {
6703 if (localPlayer.appData.loadGameFile == NULL)
6704 {
6705 DisplayMessage("Select game file first", False);
6706 return;
6707 }
6708
6709 InitShogiProgram(localPlayer.appData.firstHost,
6710 localPlayer.appData.firstShogiProgram,
6711 &firstProgramPID, &toFirstProgFP,
6712 &fromFirstProgFP, &firstProgramXID,
6713 &firstSendTime);
6714
6715 if (!LoadGame(localPlayer.appData.loadGameFile))
6716 {
6717 ShutdownShogiPrograms("Bad game file");
6718 return;
6719 }
6720
6721 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6722 }
6723
6724 InitShogiProgram(localPlayer.appData.secondHost,
6725 localPlayer.appData.secondShogiProgram,
6726 &secondProgramPID, &toSecondProgFP,
6727 &fromSecondProgFP, &secondProgramXID,
6728 &secondSendTime);
6729
6730 if (startedFromSetupPosition)
6731 {
6732 if (whitePlaysFirst)
6733 {
6734 i = 1;
6735 SendToProgram("force\n", toSecondProgFP);
6736 SendBoard(toSecondProgFP, boards[i], catches[i]);
6737 }
6738 else
6739 {
6740 i = 0;
6741 SendBoard(toSecondProgFP, boards[i], catches[i]);
6742 SendToProgram("force\n", toSecondProgFP);
6743 }
6744 }
6745 else
6746 {
6747 i = 0;
6748 SendToProgram("force\n", toSecondProgFP);
6749 }
6750
6751 for (i = backwardMostMove; i < forwardMostMove; i++)
6752 SendToProgram(moveList[i], toSecondProgFP);
6753
6754 lastGameMode = gameMode = TwoMachinesPlay;
6755 ModeHighlight();
6756 firstMove = True;
6757
6758 if (BlackOnMove(forwardMostMove))
6759 SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6760 else
6761 SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
6762
6763 break;
6764
6765 case MatchPosition:
6766 if (firstProgramXID == 0)
6767 {
6768 if (localPlayer.appData.loadPositionFile == NULL)
6769 {
6770 DisplayMessage("Select position file first", False);
6771 return;
6772 }
6773
6774 InitShogiProgram(localPlayer.appData.firstHost,
6775 localPlayer.appData.firstShogiProgram,
6776 &firstProgramPID, &toFirstProgFP,
6777 &fromFirstProgFP, &firstProgramXID,
6778 &firstSendTime);
6779
6780 if (!LoadPosition(localPlayer.appData.loadPositionFile))
6781 return;
6782 }
6783
6784 InitShogiProgram(localPlayer.appData.secondHost,
6785 localPlayer.appData.secondShogiProgram,
6786 &secondProgramPID, &toSecondProgFP,
6787 &fromSecondProgFP, &secondProgramXID,
6788 &secondSendTime);
6789
6790 if (whitePlaysFirst)
6791 SendToProgram("force\n", toSecondProgFP);
6792
6793 SendCurrentBoard(toSecondProgFP);
6794 lastGameMode = gameMode = TwoMachinesPlay;
6795 ModeHighlight();
6796 firstMove = True;
6797
6798 if (BlackOnMove(forwardMostMove))
6799 SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6800 else
6801 SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
6802
6803 break;
6804
6805 case MatchInit:
6806 InitPosition(True);
6807
6808 if (firstProgramXID == 0)
6809 {
6810 InitShogiProgram(localPlayer.appData.firstHost,
6811 localPlayer.appData.firstShogiProgram,
6812 &firstProgramPID, &toFirstProgFP,
6813 &fromFirstProgFP, &firstProgramXID,
6814 &firstSendTime);
6815 }
6816
6817 InitShogiProgram(localPlayer.appData.secondHost,
6818 localPlayer.appData.secondShogiProgram,
6819 &secondProgramPID, &toSecondProgFP,
6820 &fromSecondProgFP, &secondProgramXID,
6821 &secondSendTime);
6822
6823 lastGameMode = gameMode = TwoMachinesPlay;
6824 ModeHighlight();
6825 SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6826
6827 default:
6828 break;
6829 }
6830
6831 if (!firstSendTime || !secondSendTime)
6832 {
6833 DisplayClocks(ResetTimers);
6834 timeRemaining[0][forwardMostMove] = blackTimeRemaining;
6835 timeRemaining[1][forwardMostMove] = whiteTimeRemaining;
6836 }
6837
6838 DisplayClocks(StartTimers);
6839 }
6840
6841
6842
6843
6844 void
PauseProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6845 PauseProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6846 {
6847 static GameMode previous_mode = PauseGame;
6848
6849 switch (gameMode)
6850 {
6851 case ForceMoves:
6852 case EndOfGame:
6853 case EditPosition:
6854 default:
6855 return;
6856
6857 case PauseGame:
6858 gameMode = previous_mode;
6859 ModeHighlight();
6860 previous_mode = PauseGame;
6861 DisplayClocks(StartTimers);
6862 DisplayMessage("", False);
6863
6864 if (updateRemotePlayer)
6865 DisplayMessage("", True);
6866 break;
6867
6868 case PlayFromGameFile:
6869 if (readGameXID == 0)
6870 {
6871 readGameXID =
6872 XtAppAddTimeOut(appContext,
6873 (int)(1000 * localPlayer.appData.timeDelay),
6874 (XtTimerCallbackProc) ReadGameFile, NULL);
6875 }
6876 else
6877 {
6878 XtRemoveTimeOut(readGameXID);
6879 readGameXID = 0;
6880 }
6881
6882 DisplayMessage("Pausing", False);
6883
6884 if (updateRemotePlayer)
6885 DisplayMessage("Pausing", True);
6886
6887 break;
6888
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;
6895
6896 if (((gameMode == MachinePlaysWhite)
6897 && !BlackOnMove(forwardMostMove))
6898 || ((gameMode == MachinePlaysBlack) &&
6899 BlackOnMove(forwardMostMove)))
6900 {
6901 DisplayClocks(StopTimers);
6902 }
6903
6904 previous_mode = gameMode;
6905 gameMode = PauseGame;
6906 ModeHighlight();
6907 DisplayClocks(StopTimers);
6908 DisplayMessage("Pausing", False);
6909
6910 if (updateRemotePlayer)
6911 DisplayMessage("Pausing", True);
6912
6913 break;
6914 }
6915 }
6916
6917
6918
6919
6920 void
Iconify(Widget w,XEvent * event,String * prms,Cardinal * nprms)6921 Iconify(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6922 {
6923 Arg args[1];
6924
6925 fromX = fromY = -1;
6926
6927 XtSetArg(args[0], XtNiconic, True);
6928 XtSetValues(localPlayer.shellWidget, args, 1);
6929 }
6930
6931
6932
6933
6934 void
SendToProgram(char * message,FILE * fp)6935 SendToProgram(char *message, FILE *fp)
6936 {
6937 if (fp == NULL)
6938 return;
6939
6940 lastMsgFP = fp;
6941
6942 if (xshogiDebug)
6943 {
6944 fprintf(stderr, "Sending to %s: %s\n",
6945 ((fp == toFirstProgFP) ? "first" : "second"), message);
6946 }
6947
6948 if (message[strlen(message) - 1] != '\n')
6949 fprintf(fp, "\n%s\n", message);
6950 else
6951 fputs(message, fp);
6952
6953 fflush(fp);
6954 }
6955
6956
6957
6958
6959 void
ReceiveFromProgram(FILE * fp,int * source,XtInputId * id)6960 ReceiveFromProgram(FILE *fp, int *source, XtInputId *id)
6961 {
6962 char message[MSG_SIZ], *end_str, *number, *name;
6963
6964 if (fgets(message, MSG_SIZ, fp) == NULL)
6965 {
6966 if (fp == fromFirstProgFP)
6967 {
6968 number = "first";
6969 name = localPlayer.appData.firstShogiProgram;
6970 }
6971 else if (fp == fromSecondProgFP)
6972 {
6973 number = "second";
6974 name = localPlayer.appData.secondShogiProgram;
6975 }
6976 else
6977 {
6978 return;
6979 }
6980
6981 if (ferror(fp) == 0)
6982 {
6983 sprintf(message, "%s shogi program (%s) exited unexpectedly",
6984 number, name);
6985 fprintf(stderr, "%s: %s\n", programName, message);
6986 }
6987 else
6988 {
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);
6993 }
6994
6995 return;
6996 }
6997
6998 if ((end_str = (char *)strchr(message, '\r')) != NULL)
6999 *end_str = NULLCHAR;
7000
7001 if ((end_str = (char *)strchr(message, '\n')) != NULL)
7002 *end_str = NULLCHAR;
7003
7004 if (xshogiDebug || localPlayer.appData.debugMode)
7005 {
7006 fprintf(stderr, "Received from %s: %s\n",
7007 ((fp == fromFirstProgFP) ? "first" : "second"), message);
7008 }
7009
7010 HandleMachineMove(message, fp);
7011 }
7012
7013
7014
7015
7016 void
SendSearchDepth(FILE * fp)7017 SendSearchDepth(FILE *fp)
7018 {
7019 char message[MSG_SIZ];
7020
7021 if (localPlayer.appData.searchDepth <= 0)
7022 return;
7023
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);
7028 }
7029
7030
7031
7032
7033 void
DisplayMessage(char * message,int toRemotePlayer)7034 DisplayMessage(char *message, int toRemotePlayer)
7035 {
7036 Arg arg;
7037
7038 XtSetArg(arg, XtNlabel, message);
7039
7040 if (!toRemotePlayer)
7041 XtSetValues(localPlayer.messageWidget, &arg, 1);
7042
7043 if (updateRemotePlayer && toRemotePlayer)
7044 XtSetValues(remotePlayer.messageWidget, &arg, 1);
7045 }
7046
7047
7048
7049
7050 void
DisplayName(char * name)7051 DisplayName(char *name)
7052 {
7053 Arg arg;
7054
7055 XtSetArg(arg, XtNlabel, name);
7056 XtSetValues(localPlayer.titleWidget, &arg, 1);
7057
7058 if (updateRemotePlayer)
7059 XtSetValues(remotePlayer.titleWidget, &arg, 1);
7060 }
7061
7062
7063
7064
SendTimeRemaining(FILE * fp)7065 void SendTimeRemaining(FILE *fp)
7066 {
7067 char message[MSG_SIZ];
7068 long comtime, opptime;
7069
7070 if (BlackOnMove(forwardMostMove) == (fp == toFirstProgFP))
7071 {
7072 comtime = blackTimeRemaining;
7073 opptime = whiteTimeRemaining;
7074 }
7075 else
7076 {
7077 comtime = whiteTimeRemaining;
7078 opptime = blackTimeRemaining;
7079 }
7080
7081 if (comtime <= 0)
7082 comtime = 1000;
7083
7084 if (opptime <= 0)
7085 opptime = 1000;
7086
7087 sprintf(message, "time %ld\n", comtime / 10);
7088 SendToProgram(message, fp);
7089 sprintf(message, "otime %ld\n", opptime / 10);
7090 SendToProgram(message, fp);
7091 }
7092
7093
7094
7095
DisplayMove(int moveNumber)7096 void DisplayMove(int moveNumber)
7097 {
7098 char message[MSG_SIZ];
7099
7100 if (moveNumber < 0)
7101 {
7102 if (moveNumber == forwardMostMove - 1)
7103 DisplayMessage(endMessage, False);
7104 else
7105 DisplayMessage("", False);
7106 }
7107 else
7108 {
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);
7115 }
7116 }
7117
7118
7119
7120
DisplayTitle(char * title)7121 void DisplayTitle(char *title)
7122 {
7123 Arg arg;
7124
7125 XtSetArg(arg, XtNlabel, title);
7126 XtSetValues(localPlayer.titleWidget, &arg, 1);
7127 }
7128
7129
7130
7131
7132 /*
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.
7138 *
7139 * Now gnushogi periodically checks for user input without a need for
7140 * this hack.
7141 */
7142
7143 void
Attention(int pid)7144 Attention(int pid)
7145 {
7146 #if 0
7147 if (localPlayer.appData.noShogiProgram || (pid == 0))
7148 return;
7149
7150 switch (gameMode)
7151 {
7152 case MachinePlaysBlack:
7153 case MachinePlaysWhite:
7154 case TwoMachinesPlay:
7155 if ((forwardMostMove > backwardMostMove + 1) && maybeThinking)
7156 {
7157 if (xshogiDebug || localPlayer.appData.debugMode)
7158 {
7159 fprintf(stderr, "Sending SIGINT to %s\n",
7160 ((pid == firstProgramPID) ? "first" : "second"));
7161 }
7162
7163 (void)kill(pid, SIGINT); /* stop it thinking */
7164 }
7165 break;
7166
7167 default:
7168 break; /* CHECKME: is this OK? */
7169 }
7170 #endif /* !defined(FIONREAD) */
7171 }
7172
7173
7174
7175
7176 void
CheckFlags(void)7177 CheckFlags(void)
7178 {
7179 if (blackTimeRemaining <= 0)
7180 {
7181 if (!blackFlag)
7182 {
7183 blackFlag = True;
7184
7185 if (whiteFlag)
7186 DisplayName(" Both flags have fallen");
7187 else
7188 DisplayName(" Black's flag has fallen");
7189 }
7190 }
7191
7192 if (whiteTimeRemaining <= 0)
7193 {
7194 if (!whiteFlag)
7195 {
7196 whiteFlag = True;
7197
7198 if (blackFlag)
7199 DisplayName(" Both flags have fallen");
7200 else
7201 DisplayName(" White's flag has fallen");
7202 }
7203 }
7204 }
7205
7206
7207
7208
7209 void
CheckTimeControl(void)7210 CheckTimeControl(void)
7211 {
7212 if (!localPlayer.appData.clockMode)
7213 return;
7214
7215 if (forwardMostMove == 0)
7216 return;
7217
7218 /*
7219 * Add time to clocks when time control is achieved.
7220 */
7221
7222 if ((forwardMostMove % (localPlayer.appData.movesPerSession * 2)) == 0)
7223 {
7224 blackTimeRemaining += timeControl;
7225 whiteTimeRemaining += timeControl;
7226 }
7227 }
7228
7229
7230
7231
7232 void
DisplayLabels(void)7233 DisplayLabels(void)
7234 {
7235 DisplayTimerLabel(localPlayer.blackTimerWidget, "Black",
7236 blackTimeRemaining);
7237 DisplayTimerLabel(localPlayer.whiteTimerWidget, "White",
7238 whiteTimeRemaining);
7239
7240 if (updateRemotePlayer)
7241 {
7242 DisplayTimerLabel(remotePlayer.blackTimerWidget, "Black",
7243 blackTimeRemaining);
7244 DisplayTimerLabel(remotePlayer.whiteTimerWidget, "White",
7245 whiteTimeRemaining);
7246 }
7247 }
7248
7249
7250
7251
7252 #ifdef HAVE_GETTIMEOFDAY
7253 static struct timeval tickStartTV;
7254 static int tickLength;
7255
7256 int
PartialTickLength(void)7257 PartialTickLength(void)
7258 {
7259 struct timeval tv;
7260 int ptl;
7261
7262 gettimeofday(&tv, NULL);
7263 ptl = ((tv.tv_sec - tickStartTV.tv_sec) * 1000000 +
7264 (tv.tv_usec - tickStartTV.tv_usec) + 500) / 1000;
7265
7266 if (ptl > tickLength)
7267 ptl = tickLength;
7268
7269 return ptl;
7270 }
7271 #else /* !HAVE_GETTIMEOFDAY */
7272 #define tickLength 1000
7273 #endif /* HAVE_GETTIMEOFDAY */
7274
7275
7276
7277
7278 /*
7279 * DisplayClocks manages the game clocks.
7280 *
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.
7286 */
7287
7288 void
DisplayClocks(int clock_mode)7289 DisplayClocks(int clock_mode)
7290 {
7291 long timeRemaining;
7292
7293 switch (clock_mode)
7294 {
7295 case ResetTimers:
7296 /* Stop clocks and reset to a fresh time control */
7297 if (timerXID != 0)
7298 {
7299 XtRemoveTimeOut(timerXID);
7300 timerXID = 0;
7301 }
7302
7303 blackTimeRemaining = timeControl;
7304 whiteTimeRemaining = timeControl;
7305
7306 if (blackFlag || whiteFlag)
7307 {
7308 DisplayName("");
7309 blackFlag = whiteFlag = False;
7310 }
7311
7312 DisplayLabels();
7313 break;
7314
7315 case DecrementTimers:
7316 /* Decrement running clock to next 1-second boundary */
7317 if (gameMode == PauseGame)
7318 return;
7319
7320 timerXID = 0;
7321
7322 if (!localPlayer.appData.clockMode)
7323 return;
7324
7325 if (BlackOnMove(forwardMostMove))
7326 {
7327 timeRemaining = (blackTimeRemaining -= tickLength);
7328 }
7329 else
7330 {
7331 timeRemaining = (whiteTimeRemaining -= tickLength);
7332 }
7333
7334 DisplayLabels();
7335 CheckFlags();
7336
7337 #ifdef HAVE_GETTIMEOFDAY
7338 tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7339 ? 100 : 1000);
7340 gettimeofday(&tickStartTV, NULL);
7341 #endif /* HAVE_GETTIMEOFDAY */
7342
7343 timerXID =
7344 XtAppAddTimeOut(appContext, tickLength,
7345 (XtTimerCallbackProc) DisplayClocks,
7346 (XtPointer) DecrementTimers);
7347 break;
7348
7349 case SwitchTimers:
7350 /* A player has just moved, so stop the previously running
7351 clock and start the other one. */
7352
7353 if (timerXID != 0)
7354 {
7355 XtRemoveTimeOut(timerXID);
7356 timerXID = 0;
7357
7358 #ifdef HAVE_GETTIMEOFDAY
7359 if (localPlayer.appData.clockMode)
7360 {
7361 if (BlackOnMove(forwardMostMove))
7362 whiteTimeRemaining -= PartialTickLength();
7363 else
7364 blackTimeRemaining -= PartialTickLength();
7365 CheckFlags();
7366 }
7367 #endif /* HAVE_GETTIMEOFDAY */
7368 }
7369
7370 CheckTimeControl();
7371 DisplayLabels();
7372
7373 if (!localPlayer.appData.clockMode)
7374 return;
7375
7376 if ((gameMode == PauseGame)
7377 && ((pausePreviousMode == MachinePlaysBlack)
7378 || (pausePreviousMode == MachinePlaysWhite)))
7379 {
7380 return;
7381 }
7382
7383 timeRemaining = (BlackOnMove(forwardMostMove)
7384 ? blackTimeRemaining : whiteTimeRemaining);
7385
7386 #ifdef HAVE_GETTIMEOFDAY
7387 tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7388 ? (((timeRemaining - 1) % 100) + 1)
7389 : (((timeRemaining - 1) % 1000) + 1));
7390
7391 if (tickLength <= 0)
7392 tickLength += 1000;
7393
7394 gettimeofday(&tickStartTV, NULL);
7395
7396 #endif /* HAVE_GETTIMEOFDAY */
7397 timerXID =
7398 XtAppAddTimeOut(appContext, tickLength,
7399 (XtTimerCallbackProc) DisplayClocks,
7400 (XtPointer) DecrementTimers);
7401 break;
7402
7403 case ReDisplayTimers:
7404 /* Display current clock values */
7405 DisplayLabels();
7406 break;
7407
7408 case StopTimers:
7409 /* Stop both clocks */
7410 if (timerXID == 0)
7411 return;
7412
7413 XtRemoveTimeOut(timerXID);
7414 timerXID = 0;
7415
7416 if (!localPlayer.appData.clockMode)
7417 return;
7418
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;
7428
7429 case StartTimers:
7430 /* Start clock of player on move, if not already running. */
7431 if (timerXID != 0)
7432 return;
7433
7434 DisplayLabels();
7435
7436 if (!localPlayer.appData.clockMode)
7437 return;
7438
7439 timeRemaining = (BlackOnMove(forwardMostMove)
7440 ? blackTimeRemaining : whiteTimeRemaining);
7441
7442 if (timeRemaining == 0)
7443 return;
7444
7445 #ifdef HAVE_GETTIMEOFDAY
7446 tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7447 ? (((timeRemaining - 1) % 100) + 1)
7448 : (((timeRemaining - 1) % 1000) + 1));
7449
7450 if (tickLength <= 0)
7451 tickLength += 1000;
7452
7453 gettimeofday(&tickStartTV, NULL);
7454 #endif /* HAVE_GETTIMEOFDAY */
7455
7456 timerXID =
7457 XtAppAddTimeOut(appContext, tickLength,
7458 (XtTimerCallbackProc) DisplayClocks,
7459 (XtPointer)DecrementTimers);
7460 break;
7461 }
7462 }
7463
7464
7465
7466
7467 void
DisplayTimerLabel(Widget w,char * color,long int timer)7468 DisplayTimerLabel(Widget w, char *color, long int timer)
7469 {
7470 char buf[MSG_SIZ];
7471 Arg args[3];
7472 struct DisplayData *player;
7473
7474 player = (((w == localPlayer.blackTimerWidget)
7475 || (w == localPlayer.whiteTimerWidget))
7476 ? &localPlayer : &remotePlayer);
7477
7478 if (localPlayer.appData.clockMode)
7479 {
7480 sprintf(buf, "%s: %s", color, TimeString(timer));
7481 XtSetArg(args[0], XtNlabel, buf);
7482 }
7483 else
7484 {
7485 XtSetArg(args[0], XtNlabel, color);
7486 }
7487
7488 if (((color[0] == 'W') && BlackOnMove(forwardMostMove))
7489 || ((color[0] == 'B') && !BlackOnMove(forwardMostMove)))
7490 {
7491 XtSetArg(args[1], XtNbackground, player->timerForegroundPixel);
7492 XtSetArg(args[2], XtNforeground, player->timerBackgroundPixel);
7493 }
7494 else
7495 {
7496 XtSetArg(args[1], XtNbackground, player->timerBackgroundPixel);
7497 XtSetArg(args[2], XtNforeground, player->timerForegroundPixel);
7498 }
7499
7500 XtSetValues(w, args, 3);
7501 }
7502
7503
7504
7505
7506 char *
TimeString(long tm)7507 TimeString(long tm)
7508 {
7509 int second, minute, hour, day;
7510 char *sign = "";
7511 static char buf[32];
7512
7513 if ((tm > 0) && (tm <= 900))
7514 {
7515 /* convert milliseconds to tenths, rounding up */
7516 sprintf(buf, " 0.%1ld ", (tm + 99) / 100);
7517 return buf;
7518 }
7519
7520 /* convert milliseconds to seconds, rounding up */
7521 tm = (tm + 999) / 1000;
7522
7523 if (tm < 0)
7524 {
7525 sign = "-";
7526 tm = -tm;
7527 }
7528
7529 if (tm >= (60 * 60 * 24))
7530 {
7531 day = (int)(tm / (60 * 60 * 24));
7532 tm -= day * 60 * 60 * 24;
7533 }
7534 else
7535 {
7536 day = 0;
7537 }
7538
7539 if (tm >= (60 * 60))
7540 {
7541 hour = (int)(tm / (60 * 60));
7542 tm -= hour * 60 * 60;
7543 }
7544 else
7545 {
7546 hour = 0;
7547 }
7548
7549 if (tm >= 60)
7550 {
7551 minute = (int)(tm / 60);
7552 tm -= minute * 60;
7553 }
7554 else
7555 {
7556 minute = 0;
7557 }
7558
7559 second = tm % 60;
7560
7561 if (day > 0)
7562 {
7563 sprintf(buf, " %s%d:%02d:%02d:%02d ",
7564 sign, day, hour, minute, second);
7565 }
7566 else if (hour > 0)
7567 {
7568 sprintf(buf, " %s%d:%02d:%02d ",
7569 sign, hour, minute, second);
7570 }
7571 else
7572 {
7573 sprintf(buf, " %s%2d:%02d ",
7574 sign, minute, second);
7575 }
7576
7577 return buf;
7578 }
7579
7580
7581
7582
7583 void
Usage(void)7584 Usage(void)
7585 {
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");
7596
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);
7617 }
7618
7619
7620
7621 void
CatchPipeSignal(int dummy)7622 CatchPipeSignal(int dummy)
7623 {
7624 char message[MSG_SIZ];
7625
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;
7635 }
7636
7637