6272918582850ee47d3d4f3aae38dccd00b64ff3
[gnushogi.git] / gnushogi / commondsp.c
1 /*
2  * FILE: commondsp.c
3  *
4  *     Common display routines for GNU Shogi.
5  *
6  * ----------------------------------------------------------------------
7  * Copyright (c) 1993, 1994, 1995 Matthias Mutz
8  * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
9  * Copyright (c) 2008, 2013, 2014 Yann Dirson and the Free Software Foundation
10  *
11  * GNU SHOGI is based on GNU CHESS
12  *
13  * Copyright (c) 1988, 1989, 1990 John Stanback
14  * Copyright (c) 1992 Free Software Foundation
15  *
16  * This file is part of GNU SHOGI.
17  *
18  * GNU Shogi is free software; you can redistribute it and/or modify it
19  * under the terms of the GNU General Public License as published by the
20  * Free Software Foundation; either version 3 of the License,
21  * or (at your option) any later version.
22  *
23  * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
24  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
26  * for more details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with GNU Shogi; see the file COPYING. If not, see
30  * <http://www.gnu.org/licenses/>.
31  * ----------------------------------------------------------------------
32  *
33  */
34
35 /* request *snprintf prototypes */
36 #define _POSIX_C_SOURCE 200112L
37 #include <stdio.h>
38
39 #if defined HAVE_GETTIMEOFDAY
40 #include <sys/time.h>
41 #endif
42
43 #include <ctype.h>
44 #include <signal.h>
45
46 #include <sys/param.h>
47 #include <sys/types.h>
48 #include <sys/file.h>
49
50 #include "gnushogi.h"
51
52 char mvstr[4][6];
53 int mycnt1, mycnt2;
54 static char *InPtr;
55 struct display *dsp = &raw_display;
56
57 short xboard = false;
58
59 #if defined(BOOKTEST)
60
61 void
62 movealgbr(short m, char *s)
63 {
64     unsigned int f, t;
65     short piece = 0, flag = 0;
66
67     if (m == 0)
68     {
69         strcpy(s, "none");
70         return;
71     }
72
73     f = (m >> 8) & 0x7f;
74     t = m & 0xff;
75
76     if (f > NO_SQUARES)
77     {
78         piece = f - NO_SQUARES;
79
80         if (piece > NO_PIECES)
81             piece -= NO_PIECES;
82
83         flag = (dropmask | piece);
84     }
85
86     if (t & 0x80)
87     {
88         flag |= promote;
89         t &= 0x7f;
90     }
91
92     if (flag & dropmask)
93     {
94         *s = pxx[piece];
95         s++;
96         *s = '*';
97         s++;
98         *s = COL_NAME(column(t));
99         s++;
100         *s = ROW_NAME(row(t));
101         s++;
102     }
103     else
104     {
105         *s = COL_NAME(column(f));
106         s++;
107         *s = ROW_NAME(row(f));
108         s++;
109         *s = COL_NAME(column(t));
110         s++;
111         *s = ROW_NAME(row(t));
112         s++;
113
114         if (flag & promote)
115         {
116             *s = '+';
117             s++;
118         }
119     }
120
121     if (m & 0x8000)
122     {
123         *s = '?';
124         s++;
125     }
126
127     *s = '\0';
128 }
129
130 #endif /* BOOKTEST */
131
132
133 /*
134  * Generate move strings in different formats.
135  *
136  * INPUT:
137  * - f                                  piece to be moved
138  *   - 0 < f < NO_SQUARES                               source square
139  *   - NO_SQUARES <= f NO_SQUARES + 2*NO_PIECES         dropped piece modulo NO_PIECES
140  * - t & 0x7f                           target square
141  * - t & 0x80                           promotion flag
142  * - flag
143  *   - if flag & dropmask, piece type encoded in flag & pmask
144  *
145  * FIXME: that makes 2 ways to specify drops and promotions, why ?
146  *
147  * OUTPUT:
148  * - GLOBAL mvstr
149  */
150
151 void
152 algbr(short f, short t, short flag)
153 {
154     if (f > NO_SQUARES)
155     {
156         short piece;
157
158         piece = f - NO_SQUARES;
159
160         if (f > (NO_SQUARES + NO_PIECES))
161             piece -= NO_PIECES;
162
163         flag = (dropmask | piece);
164     }
165
166     if ((t & 0x80) != 0)
167     {
168         flag |= promote;
169         t &= 0x7f;
170     }
171
172     if ((f == t) && ((f != 0) || (t != 0)))
173     {
174         if (!XSHOGI) {
175             dsp->Printf("error in algbr: FROM=TO=%d, flag=0x%4x\n", t, flag);
176         }
177
178         mvstr[0][0] = mvstr[1][0] = mvstr[2][0] = mvstr[3][0] = '\0';
179     }
180     else if ((flag & dropmask) != 0)
181     {
182         short piece = flag & pmask;
183
184         mvstr[0][0] = pxx[piece];
185         mvstr[0][1] = xboard ? '@' : '*';
186         mvstr[0][2] = COL_NAME(column(t));
187         mvstr[0][3] = ROW_NAME(row(t));
188         mvstr[0][4] = '\0';
189         strcpy(mvstr[1], mvstr[0]);
190         strcpy(mvstr[2], mvstr[0]);
191         strcpy(mvstr[3], mvstr[0]);
192     }
193     else if ((f != 0) || (t != 0))
194     {
195         /* pure coordinates notation */
196         mvstr[0][0] = COL_NAME(column(f));
197         mvstr[0][1] = ROW_NAME(row(f));
198         mvstr[0][2] = COL_NAME(column(t));
199         mvstr[0][3] = ROW_NAME(row(t));
200         mvstr[0][4] = '\0';
201
202         /* algebraic notation without disambiguation */
203         mvstr[1][0] = pxx[board[f]];
204         mvstr[1][1] = mvstr[0][2];    /* to column */
205         mvstr[1][2] = mvstr[0][3];    /* to row */
206         mvstr[1][3] = '\0';
207
208         /* algebraic notation with row disambiguation */
209         mvstr[2][0] = mvstr[1][0];
210         mvstr[2][1] = mvstr[0][1];
211         mvstr[2][2] = mvstr[0][2];    /* to column */
212         mvstr[2][3] = mvstr[0][3];    /* to row */
213         mvstr[2][4] = '\0';
214
215         /* algebraic notation with column disambiguation */
216         strcpy(mvstr[3], mvstr[2]);
217         mvstr[3][1] = mvstr[0][0];
218
219         if (flag & promote)
220         {
221             strcat(mvstr[0], "+");
222             strcat(mvstr[1], "+");
223             strcat(mvstr[2], "+");
224             strcat(mvstr[3], "+");
225         }
226     }
227     else
228     {
229         mvstr[0][0] = mvstr[1][0] = mvstr[2][0] = mvstr[3][0] = '\0';
230     }
231 }
232
233
234 /*
235  * Compare the string 's' to the list of legal moves available for the
236  * opponent. If a match is found, make the move on the board.
237  */
238
239 int
240 VerifyMove(char *s, VerifyMove_mode iop, unsigned short *mv)
241 {
242     static short pnt, tempb, tempc, tempsf, tempst, cnt;
243     static struct leaf xnode;
244     struct leaf  *node;
245     short i, l, local_flags;
246     char buffer[60];
247
248     /* check and remove quality flags */
249     for (i = local_flags = 0, l = strlen(s); i < l; i++)
250     {
251         switch(s[i])
252         {
253         case '?':
254             local_flags |= badmove;
255             s[i] = '\0';
256             break;
257
258         case '!':
259             local_flags |= goodmove;
260             s[i] = '\0';
261             break;
262
263 #ifdef EASY_OPENINGS
264         case '~':
265             local_flags |= difficult;
266             s[i] = '\0';
267             break;
268 #endif
269         }
270     }
271
272     *mv = 0;
273
274     if (iop == UNMAKE_MODE)
275     {
276         UnmakeMove(opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
277         return false;
278     }
279
280     cnt = 0;
281
282     if (iop == VERIFY_AND_MAKE_MODE)
283         generate_move_flags = true;
284
285     MoveList(opponent, 2, -1, true);
286     generate_move_flags = false;
287     pnt = TrPnt[2];
288     if(s[4] == '=') s[4] = '\0'; /* deferral is implied */
289
290     while (pnt < TrPnt[3])
291     {
292         node = &Tree[pnt++];
293         algbr(node->f, node->t, (short) node->flags);
294
295         if ((strcmp(s, mvstr[0]) == 0)
296             || (strcmp(s, mvstr[1]) == 0)
297             || (strcmp(s, mvstr[2]) == 0)
298             || (strcmp(s, mvstr[3]) == 0))
299         {
300             cnt++;
301             xnode = *node;
302         }
303     }
304
305     if ((cnt == 1) && (xnode.score > DONTUSE))
306     {
307         short blocked;
308
309         MakeMove(opponent, &xnode, &tempb, &tempc,
310                  &tempsf, &tempst, &INCscore);
311
312         if (SqAttacked(PieceList[opponent][0], computer, &blocked))
313         {
314             UnmakeMove(opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
315             dsp->AlwaysShowMessage("Illegal move (in check): %s", s);
316             return false;
317         }
318         else
319         {
320             if (iop == VERIFY_AND_TRY_MODE)
321                 return true;
322
323             dsp->UpdateDisplay(xnode.f, xnode.t, 0, (short) xnode.flags);
324             GameList[GameCnt].depth = GameList[GameCnt].score = 0;
325             GameList[GameCnt].nodes = 0;
326             ElapsedTime(COMPUTE_AND_INIT_MODE);
327             GameList[GameCnt].time = (short) (et + 50)/100;
328             GameList[GameCnt].flags |= local_flags;
329
330             if (TCflag)
331             {
332                 TimeControl.clock[opponent] -= et;
333                 timeopp[oppptr] = et;
334                 --TimeControl.moves[opponent];
335             }
336
337             *mv = (xnode.f << 8) | xnode.t;
338             algbr(xnode.f, xnode.t, false);
339
340             /* in force mode, check for mate conditions */
341             if (flag.force)
342             {
343                 if (IsCheckmate(opponent ^ 1, -1, -1))
344                 {
345                     char buf[20];
346
347                     sprintf(buf, "%s mates!\n", ColorStr[opponent]);
348                     dsp->ShowMessage(buf);
349                     flag.mate = true;
350                 }
351             }
352
353             return true;
354         }
355     }
356
357     dsp->AlwaysShowMessage("Illegal move (no match): %s", s);
358
359     if (!XSHOGI && (cnt > 1))
360     {
361         sprintf(buffer, "Ambiguous Move %s!", s);
362         dsp->ShowMessage(buffer);
363     }
364
365     return false;
366 }
367
368
369 static int
370 parser(char *f, short *fpiece)
371 {
372     int c1, r1, c2, r2;
373     short i, p = false;
374
375     if (*f == '+')
376         f++, p = true;
377
378     for (i = 1, *fpiece = no_piece; i < NO_PIECES; i++)
379     {
380         if (f[0] == pxx[i] || f[0] == qxx[i])
381         {
382             *fpiece = (p ? promoted[i] : unpromoted[i]);
383             break;
384         }
385     }
386
387     if (f[1] == '*' || f[1] == '\'')
388     {
389         c2 = COL_NUM(f[2]);
390         r2 = ROW_NUM(f[3]);
391
392         return ((NO_SQUARES + *fpiece) << 8) | locn(r2, c2);
393     }
394     else
395     {
396         c1 = COL_NUM(f[1]);
397         r1 = ROW_NUM(f[2]);
398         c2 = COL_NUM(f[3]);
399         r2 = ROW_NUM(f[4]);
400         p = (f[5] == '+') ? 0x80 : 0;
401
402         return (locn(r1, c1) << 8) | locn(r2, c2) | p;
403     }
404 }
405
406
407 void
408 skip()
409 {
410     while (*InPtr != ' ')
411         InPtr++;
412
413     while (*InPtr == ' ')
414         InPtr++;
415 }
416
417
418 void
419 skipb()
420 {
421     while (*InPtr == ' ')
422         InPtr++;
423 }
424
425
426 void RequestInputString(char* buffer, unsigned bufsize)
427 {
428     static char fmt[10];
429     int ret = snprintf(fmt, sizeof(fmt), "%%%us", bufsize);
430     if (ret < 0 ) {
431         perror("RequestInputString snprintf");
432         exit(1);
433     }
434     if (ret >= sizeof(fmt)) {
435         fprintf(stderr,
436                 "Insufficient format-buffer size in %s for bufsize=%u\n",
437                 __FUNCTION__, bufsize);
438         exit(1);
439     }
440     dsp->doRequestInputString(fmt, buffer);
441 }
442
443
444 static void
445 GetGame(void)
446 {
447     FILE *fd;
448     char fname[256], *p;
449     int c, i, j;
450     short sq;
451     short side, isp;
452
453     if (savefile[0]) {
454         strcpy(fname, savefile);
455     } else {
456         dsp->ShowMessage("Enter file name: ");
457         RequestInputString(fname, sizeof(fname)-1);
458     }
459
460     if (fname[0] == '\0')
461         strcpy(fname, "shogi.000");
462
463     if ((fd = fopen(fname, "r")) != NULL)
464     {
465         NewGame();
466         fgets(fname, 256, fd);
467         computer = opponent = black;
468         InPtr = fname;
469         skip();
470
471         if (*InPtr == 'c')
472             computer = white;
473         else
474             opponent = white;
475
476         /* FIXME: write a skipn() function so that we can get
477          * 3 skips by doing skipn(3) */
478         skip();
479         skip();
480         skip();
481         Game50 = atoi(InPtr);
482         skip();
483         flag.force = (*InPtr == 'f');
484         fgets(fname, 256, fd); /* empty */
485         fgets(fname, 256, fd);
486         InPtr = &fname[11];
487         skipb();
488         TCflag = atoi(InPtr);
489         skip();
490         InPtr += 14;
491         skipb();
492         OperatorTime = atoi(InPtr);
493         fgets(fname, 256, fd);
494         InPtr = &fname[11];
495         skipb();
496         TimeControl.clock[black] = atol(InPtr);
497         skip();
498         skip();
499         TimeControl.moves[black] = atoi(InPtr);
500         fgets(fname, 256, fd);
501         InPtr = &fname[11];
502         skipb();
503         TimeControl.clock[white] = atol(InPtr);
504         skip();
505         skip();
506         TimeControl.moves[white] = atoi(InPtr);
507         fgets(fname, 256, fd); /* empty */
508
509         for (i = NO_ROWS - 1; i > -1; i--)
510         {
511             fgets(fname, 256, fd);
512             p = &fname[2];
513             InPtr = &fname[23];
514
515             for (j = 0; j < NO_COLS; j++)
516             {
517                 sq = i * NO_COLS + j;
518                 isp = (*p == '+');
519                 p++;
520
521                 if (*p == '-')
522                 {
523                     board[sq] = no_piece;
524                     color[sq] = neutral;
525                 }
526                 else
527                 {
528                     for (c = 0; c < NO_PIECES; c++)
529                     {
530                         if (*p == pxx[c])
531                         {
532                             if (isp)
533                                 board[sq] = promoted[c];
534                             else
535                                 board[sq] = unpromoted[c];
536
537                             color[sq] = white;
538                         }
539                     }
540
541                     for (c = 0; c < NO_PIECES; c++)
542                     {
543                         if (*p == qxx[c])
544                         {
545                             if (isp)
546                                 board[sq] = promoted[c];
547                             else
548                                 board[sq] = unpromoted[c];
549
550                             color[sq] = black;
551                         }
552                     }
553                 }
554
555                 p++;
556                 Mvboard[sq] = atoi(InPtr);
557                 skip();
558             }
559         }
560
561         fgets(fname, 256, fd);  /* empty */
562         fgets(fname, 256, fd);  /* 9 8 7 ... */
563         fgets(fname, 256, fd);  /* empty */
564         fgets(fname, 256, fd);  /* p l n ... */
565         ClearCaptured();
566
567         for (side = 0; side <= 1; side++)
568         {
569             fgets(fname, 256, fd);
570             InPtr = fname;
571             skip();
572             skipb();
573             Captured[side][pawn] = atoi(InPtr);
574             skip();
575 #ifndef MINISHOGI
576             Captured[side][lance] = atoi(InPtr);
577             skip();
578             Captured[side][knight] = atoi(InPtr);
579             skip();
580 #endif
581             Captured[side][silver] = atoi(InPtr);
582             skip();
583             Captured[side][gold] = atoi(InPtr);
584             skip();
585             Captured[side][bishop] = atoi(InPtr);
586             skip();
587             Captured[side][rook] = atoi(InPtr);
588             skip();
589             Captured[side][king] = atoi(InPtr);
590         }
591
592         GameCnt = 0;
593         flag.regularstart = true;
594         Book = BOOKFAIL;
595         fgets(fname, 256, fd); /* empty */
596         fgets(fname, 256, fd);   /*  move score ... */
597
598         while (fgets(fname, 256, fd))
599         {
600             struct GameRec  *g;
601             int side = computer;
602
603             side = side ^ 1;
604             ++GameCnt;
605             InPtr = fname;
606             skipb();
607             g = &GameList[GameCnt];
608             g->gmove = parser(InPtr, &g->fpiece);
609             skip();
610             g->score = atoi(InPtr);
611             skip();
612             g->depth = atoi(InPtr);
613             skip();
614             g->nodes = atol(InPtr);
615             skip();
616             g->time = atol(InPtr);
617             skip();
618             g->flags = c = atoi(InPtr);
619             skip();
620             g->hashkey = strtol(InPtr, (char **) NULL, 16);
621             skip();
622             g->hashbd = strtol(InPtr, (char **) NULL, 16);
623
624             if (c & capture)
625             {
626                 short i, piece;
627
628                 skip();
629
630                 for (piece = no_piece, i = 0; i < NO_PIECES; i++)
631                 {
632                     if (pxx[i] == *InPtr)
633                     {
634                         piece = i;
635                         break;
636                     }
637                 }
638
639                 skip();
640                 g->color = ((*InPtr == 'W') ? white : black);
641                 skip();
642                 g->piece = (*InPtr == '+'
643                             ? promoted[piece]
644                             : unpromoted[piece]);
645             }
646             else
647             {
648                 g->color = neutral;
649                 g->piece = no_piece;
650             }
651         }
652
653         if (TimeControl.clock[black] > 0)
654             TCflag = true;
655
656         fclose(fd);
657     }
658
659     ZeroRPT();
660     InitializeStats();
661     dsp->UpdateDisplay(0, 0, 1, 0);
662     Sdepth = 0;
663     hint = 0;
664 }
665
666
667 static void
668 SaveGame(void)
669 {
670     FILE *fd;
671     char fname[256];
672     short sq, i, c, f, t;
673     char p;
674     short side, piece;
675     char empty[2] = "\n";
676
677     if (savefile[0]) {
678         strcpy(fname, savefile);
679     } else {
680         dsp->ShowMessage("Enter file name: ");
681         RequestInputString(fname, sizeof(fname)-1);
682     }
683
684     if (fname[0] == '\0')
685         strcpy(fname, "shogi.000");
686
687     if ((fd = fopen(fname, "w")) != NULL)
688     {
689         char *b, *w;
690         b = w = "Human   ";
691
692         if (computer == white)
693             w = "computer";
694
695         if (computer == black)
696             b = "computer";
697
698         fprintf(fd, "White %s Black %s %d %s\n", w, b, Game50,
699                 flag.force ? "force" : "");
700         fputs(empty, fd);
701         fprintf(fd, "TimeControl %d Operator Time %d\n", TCflag, OperatorTime);
702         fprintf(fd, "Black Clock %ld Moves %d\nWhite Clock %ld Moves %d\n",
703                 TimeControl.clock[black], TimeControl.moves[black],
704                 TimeControl.clock[white], TimeControl.moves[white]);
705         fputs(empty, fd);
706
707         for (i = NO_ROWS - 1; i > -1; i--)
708         {
709             fprintf(fd, "%c ", ROW_NAME(i));
710
711             for (c = 0; c < NO_COLS; c++)
712             {
713                 sq = i * NO_COLS + c;
714                 piece = board[sq];
715                 p = is_promoted[piece] ? '+' : ' ';
716                 fprintf(fd, "%c", p);
717
718                 switch(color[sq])
719                 {
720                 case white:
721                     p = pxx[piece];
722                     break;
723
724                 case black:
725                     p = qxx[piece];
726                     break;
727
728                 default:
729                     p = '-';
730                 }
731
732                 fprintf(fd, "%c", p);
733             }
734
735             fprintf(fd, "  ");
736
737             for (f = i * NO_COLS; f < i * NO_COLS + NO_ROWS; f++)
738                 fprintf(fd, " %d", Mvboard[f]);
739
740             fprintf(fd, "\n");
741         }
742
743         fputs(empty, fd);
744 #ifndef MINISHOGI
745         fprintf(fd, "   9 8 7 6 5 4 3 2 1\n");
746         fputs(empty, fd);
747         fprintf(fd, "   p  l  n  s  g  b  r  k\n");
748 #else
749         fprintf(fd, "   5 4 3 2 1\n");
750         fputs(empty, fd);
751         fprintf(fd, "   p  s  g  b  r  k\n");
752 #endif
753
754         for (side = 0; side <= 1; side++)
755         {
756             fprintf(fd, "%c", (side == black) ? 'B' : 'W');
757             fprintf(fd, " %2d", Captured[side][pawn]);
758 #ifndef MINISHOGI
759             fprintf(fd, " %2d", Captured[side][lance]);
760             fprintf(fd, " %2d", Captured[side][knight]);
761 #endif
762             fprintf(fd, " %2d", Captured[side][silver]);
763             fprintf(fd, " %2d", Captured[side][gold]);
764             fprintf(fd, " %2d", Captured[side][bishop]);
765             fprintf(fd, " %2d", Captured[side][rook]);
766             fprintf(fd, " %2d", Captured[side][king]);
767             fprintf(fd, "\n");
768         }
769
770         fputs(empty, fd);
771         fputs("  move   score depth   nodes   time flags                         capture\n", fd);
772
773         for (i = 1; i <= GameCnt; i++)
774         {
775             struct GameRec  *g = &GameList[i];
776
777             f = g->gmove >> 8;
778             t = (g->gmove & 0xFF);
779             algbr(f, t, g->flags);
780
781             fprintf(fd, "%c%c%-5s %6d %5d %7ld %6ld %5d  0x%08lx 0x%08lx",
782                     ((f > NO_SQUARES)
783                      ? ' '
784                      : (is_promoted[g->fpiece] ? '+' : ' ')),
785                     pxx[g->fpiece],
786                     ((f > NO_SQUARES) ? &mvstr[0][1] : mvstr[0]),
787                     g->score, g->depth,
788                     g->nodes, g->time, g->flags,
789                     g->hashkey, g->hashbd);
790
791             if (g->piece != no_piece)
792             {
793                 fprintf(fd, "  %c %s %c\n",
794                         pxx[g->piece], ColorStr[g->color],
795                         (is_promoted[g->piece] ? '+' : ' '));
796             }
797             else
798             {
799                 fprintf(fd, "\n");
800             }
801         }
802
803         fclose(fd);
804
805         dsp->ShowMessage("Game saved");
806     }
807     else
808     {
809         dsp->ShowMessage("Could not open file");
810     }
811 }
812
813
814 /*
815  * GetXGame, SaveXGame and BookGame used to only be defined if
816  * xshogi wasn't defined -- wonder why?
817  */
818
819 static void
820 GetXGame(void)
821 {
822     FILE *fd;
823     char fname[256], *p;
824     int c, i, j;
825     short sq;
826     short side, isp;
827
828     dsp->ShowMessage("Enter file name: ");
829     RequestInputString(fname, sizeof(fname)-1);
830
831     if (fname[0] == '\0')
832         strcpy(fname, "xshogi.position.read");
833
834     if ((fd = fopen(fname, "r")) != NULL)
835     {
836         NewGame();
837         flag.regularstart = false;
838         Book = false;
839
840         /* xshogi position file ... */
841         fgets(fname, 256, fd);
842
843 #ifdef notdef
844         fname[6] = '\0';
845
846         if (strcmp(fname, "xshogi"))
847             return;
848 #endif
849
850         /* -- empty line -- */
851         fgets(fname, 256, fd);
852         /* -- empty line -- */
853         fgets(fname, 256, fd);
854
855         for (i = NO_ROWS - 1; i > -1; i--)
856         {
857             fgets(fname, 256, fd);
858             p = fname;
859
860             for (j = 0; j < NO_COLS; j++)
861             {
862                 sq = i * NO_COLS + j;
863                 isp = (*p == '+');
864                 p++;
865
866                 if (*p == '.')
867                 {
868                     board[sq] = no_piece;
869                     color[sq] = neutral;
870                 }
871                 else
872                 {
873                     for (c = 0; c < NO_PIECES; c++)
874                     {
875                         if (*p == qxx[c])
876                         {
877                             if (isp)
878                                 board[sq] = promoted[c];
879                             else
880                                 board[sq] = unpromoted[c];
881
882                             color[sq] = white;
883                         }
884                     }
885
886                     for (c = 0; c < NO_PIECES; c++)
887                     {
888                         if (*p == pxx[c])
889                         {
890                             if (isp)
891                                 board[sq] = promoted[c];
892                             else
893                                 board[sq] = unpromoted[c];
894
895                             color[sq] = black;
896                         }
897                     }
898                 }
899
900                 p++;
901             }
902         }
903
904         ClearCaptured();
905
906         for (side = 0; side <= 1; side++)
907         {
908             fgets(fname, 256, fd);
909             InPtr = fname;
910             Captured[side][pawn]   = atoi(InPtr);
911             skip();
912 #ifndef MINISHOGI
913             Captured[side][lance]  = atoi(InPtr);
914             skip();
915             Captured[side][knight] = atoi(InPtr);
916             skip();
917 #endif
918             Captured[side][silver] = atoi(InPtr);
919             skip();
920             Captured[side][gold]   = atoi(InPtr);
921             skip();
922             Captured[side][bishop] = atoi(InPtr);
923             skip();
924             Captured[side][rook]   = atoi(InPtr);
925             skip();
926             Captured[side][king]   = atoi(InPtr);
927         }
928
929         if (fgets(fname, 256, fd) != NULL && strncmp(fname, "white", 5) == 0)
930         {
931             computer = black;
932             opponent = white;
933             xwndw = BXWNDW;
934         }
935
936         fclose(fd);
937     }
938
939     Game50 = 1;
940     ZeroRPT();
941     InitializeStats();
942     dsp->UpdateDisplay(0, 0, 1, 0);
943     Sdepth = 0;
944     hint = 0;
945 }
946
947
948 static void
949 SaveXGame(void)
950 {
951     FILE *fd;
952     char fname[256], *p;
953     int i, j;
954     short sq, piece;
955     short side, isp;
956
957     dsp->ShowMessage("Enter file name: ");
958     RequestInputString(fname, sizeof(fname)-1);
959
960     if (fname[0] == '\0')
961         strcpy(fname, "xshogi.position.read");
962
963     if ((fd = fopen(fname, "w")) != NULL)
964     {
965         fputs("# xshogi position file -- \n", fd);
966         fputs("\n", fd);
967         fputs("\n", fd);
968
969         for (i = NO_ROWS - 1; i > -1; i--)
970         {
971             p = fname;
972
973             for (j = 0; j < NO_COLS; j++)
974             {
975                 sq = i * NO_COLS + j;
976                 piece = board[sq];
977                 isp = is_promoted[piece];
978                 *p = (isp ? '+' : ' ');
979                 p++;
980
981                 if (piece == no_piece)
982                     *p = '.';
983                 else if (color[sq] == white)
984                     *p = qxx[piece];
985                 else
986                     *p = pxx[piece];
987
988                 p++;
989             }
990
991             *p++ = '\n';
992             *p++ = '\0';
993             fputs(fname, fd);
994         }
995
996         for (side = 0; side <= 1; side++)
997         {
998             sprintf(fname,
999 #ifndef MINISHOGI
1000                     "%d %d %d %d %d %d %d %d\n",
1001 #else
1002                     "%d %d %d %d %d %d\n",
1003 #endif
1004                     Captured[side][pawn],
1005 #ifndef MINISHOGI
1006                     Captured[side][lance],
1007                     Captured[side][knight],
1008 #endif
1009                     Captured[side][silver],
1010                     Captured[side][gold],
1011                     Captured[side][bishop],
1012                     Captured[side][rook],
1013                     Captured[side][king]);
1014
1015             fputs(fname, fd);
1016         }
1017
1018         if (computer == black)
1019             fputs("white to play\n", fd);
1020         else
1021             fputs("black to play\n", fd);
1022
1023         fclose(fd);
1024     }
1025 }
1026
1027
1028 static void
1029 BookSave(void)
1030 {
1031     FILE *fd;
1032     char fname[256], sflags[4];
1033     short i, j, f, t;
1034
1035     if (savefile[0]) {
1036         strcpy(fname, savefile);
1037     } else {
1038         /* Enter file name */
1039         dsp->ShowMessage("Enter file name: ");
1040         RequestInputString(fname, sizeof(fname)-1);
1041     }
1042
1043     if (fname[0] == '\0') {
1044         dsp->AlwaysShowMessage("aborting book save");
1045         return;
1046     }
1047
1048     if ((fd = fopen(fname, "a")) != NULL)
1049     {
1050         fprintf(fd, "#\n");
1051
1052         for (i = 1; i <= GameCnt; i++)
1053         {
1054             struct GameRec  *g = &GameList[i];
1055             char mvnr[20], mvs[20];
1056
1057             if (i % 2)
1058                 sprintf(mvnr, "%d.", (i + 1)/2);
1059             else
1060                 strcpy(mvnr, "");
1061
1062             f = g->gmove >> 8;
1063             t = (g->gmove & 0xFF);
1064             algbr(f, t, g->flags);
1065             j = 0;
1066
1067             /* determine move quality string */
1068             if (g->flags & goodmove)
1069                 sflags[j++] = '!';
1070
1071             if (g->flags & badmove)
1072                 sflags[j++] = '?';
1073
1074 #ifdef EASY_OPENINGS
1075             if (g->flags & difficult)
1076                 sflags[j++] = '~';
1077 #endif
1078
1079             sflags[j] = '\0';
1080
1081             /* determine move string */
1082             if (f > NO_SQUARES)
1083             {
1084                 sprintf(mvs, "%s%s ", &mvstr[0][1], sflags);
1085             }
1086             else
1087             {
1088                 sprintf(mvs, "%c%c%c%c%c%s%s ",
1089                         mvstr[0][0], mvstr[0][1],
1090                         (g->flags & capture) ? 'x' : '-',
1091                         mvstr[0][2], mvstr[0][3],
1092                         (mvstr[0][4] == '+') ? "+" : "",
1093                         sflags);
1094             }
1095
1096             fprintf(fd, "%s%s%c%s",
1097                     mvnr,
1098                     (f > NO_SQUARES
1099                      ? ""
1100                      : (is_promoted[g->fpiece] ? "+" : "")),
1101                     pxx[g->fpiece],
1102                     mvs);
1103
1104             if ((i % 10) == 0)
1105                 fprintf(fd, "\n");
1106         }
1107
1108         if ((i % 10) != 1)
1109             fprintf(fd, "\n");
1110
1111         fclose(fd);
1112
1113         dsp->ShowMessage("Game saved");
1114     }
1115     else
1116     {
1117         dsp->ShowMessage("Could not open file");
1118     }
1119 }
1120
1121
1122 void
1123 ListGame(void)
1124 {
1125     FILE *fd;
1126     short i, f, t;
1127     time_t when;
1128     char fname[256], dbuf[256];
1129
1130     if (listfile[0])
1131     {
1132         strcpy(fname, listfile);
1133     }
1134     else
1135     {
1136         time(&when);
1137         strncpy(dbuf, ctime(&when), 20);
1138         dbuf[7]  = '\0';
1139         dbuf[10] = '\0';
1140         dbuf[13] = '\0';
1141         dbuf[16] = '\0';
1142         dbuf[19] = '\0';
1143
1144         /* use format "CL.Jan01-020304B" when
1145            date is Jan 1
1146            time is 02:03:04
1147            program played white */
1148
1149         sprintf(fname, "CL.%s%s-%s%s%s%c",
1150                 dbuf + 4, dbuf + 8, dbuf + 11, dbuf + 14,
1151                 dbuf + 17, ColorStr[computer][0]);
1152
1153         /* replace space padding with 0 */
1154         for (i = 0; fname[i] != '\0'; i++)
1155         {
1156             if (fname[i] == ' ')
1157                 fname[i] = '0';
1158         }
1159     }
1160
1161     fd = fopen(fname, "w");
1162
1163     if (!fd)
1164     {
1165         printf("Open failure for file: %s", fname);
1166         exit(1);
1167     }
1168
1169     fprintf(fd, "gnushogi %s game\n", PACKAGE_VERSION);
1170     fputs("         score  depth   nodes  time         ", fd);
1171     fputs("         score  depth   nodes  time\n", fd);
1172
1173     for (i = 1; i <= GameCnt; i++)
1174     {
1175         f = GameList[i].gmove >> 8;
1176         t = (GameList[i].gmove & 0xFF);
1177         algbr(f, t, GameList[i].flags);
1178
1179         if (GameList[i].flags & book)
1180         {
1181             fprintf(fd, "%c%c%-5s  %5d    Book%7ld %5ld",
1182                     ((f > NO_SQUARES)
1183                      ? ' '
1184                      : (is_promoted[GameList[i].fpiece] ? '+' : ' ')),
1185                     pxx[GameList[i].fpiece],
1186                     ((f > NO_SQUARES)
1187                      ? &mvstr[0][1] : mvstr[0]),
1188                     GameList[i].score,
1189                     GameList[i].nodes,
1190                     GameList[i].time);
1191         }
1192         else
1193         {
1194             fprintf(fd, "%c%c%-5s  %5d     %2d %7ld %5ld",
1195                     (f > NO_SQUARES
1196                      ? ' '
1197                      : (is_promoted[GameList[i].fpiece] ? '+' : ' ')),
1198                     pxx[GameList[i].fpiece],
1199                     (f > NO_SQUARES ? &mvstr[0][1] : mvstr[0]),
1200                     GameList[i].score, GameList[i].depth,
1201                     GameList[i].nodes, GameList[i].time);
1202         }
1203
1204         if ((i % 2) == 0)
1205         {
1206             fprintf(fd, "\n");
1207         }
1208         else
1209         {
1210             fprintf(fd, "         ");
1211         }
1212     }
1213
1214     fprintf(fd, "\n\n");
1215
1216     if (GameList[GameCnt].flags & draw)
1217     {
1218         fprintf(fd, "Draw %s\n", DRAW);
1219
1220         if (DRAW == DRAW_REPETITION)
1221         {
1222             short j;
1223
1224             fprintf(fd, "repetition by positions ");
1225
1226             for (j = GameCnt - 1; j >= Game50; j -= 2)
1227             {
1228                 if (GameList[j].hashkey == hashkey &&
1229                     GameList[j].hashbd == hashbd)
1230                     fprintf(fd, "%d ", j);
1231             }
1232
1233             fprintf(fd, "\n");
1234         }
1235     }
1236     else if (GameList[GameCnt].score == -(SCORE_LIMIT + 999))
1237     {
1238         fprintf(fd, "%s\n", ColorStr[player ]);
1239     }
1240     else if (GameList[GameCnt].score == (SCORE_LIMIT + 998))
1241     {
1242         fprintf(fd, "%s\n", ColorStr[player ^ 1]);
1243     }
1244
1245     fclose(fd);
1246 }
1247
1248
1249 static void
1250 FlagMove(char c)
1251 {
1252     switch(c)
1253     {
1254     case '?' :
1255         GameList[GameCnt].flags |= badmove;
1256         break;
1257
1258     case '!' :
1259         GameList[GameCnt].flags |= goodmove;
1260         break;
1261
1262 #ifdef EASY_OPENINGS
1263     case '~' :
1264         GameList[GameCnt].flags |= difficult;
1265         break;
1266 #endif
1267     }
1268 }
1269
1270
1271 /*
1272  * Undo the most recent half-move.
1273  */
1274
1275 static void
1276 Undo(void)
1277 {
1278     short f, t;
1279
1280     f = GameList[GameCnt].gmove >> 8;
1281     t = GameList[GameCnt].gmove & 0x7F;
1282
1283     if (f > NO_SQUARES)
1284     {
1285         /* the move was a drop */
1286         Captured[color[t]][board[t]]++;
1287         board[t] = no_piece;
1288         color[t] = neutral;
1289         Mvboard[t]--;
1290     }
1291     else
1292     {
1293         if (GameList[GameCnt].flags & promote)
1294             board[f] = unpromoted[board[t]];
1295         else
1296             board[f] = board[t];
1297
1298         color[f] = color[t];
1299         board[t] = GameList[GameCnt].piece;
1300         color[t] = GameList[GameCnt].color;
1301
1302         if (board[t] != no_piece)
1303             Captured[color[f]][unpromoted[board[t]]]--;
1304
1305         if (color[t] != neutral)
1306             Mvboard[t]--;
1307
1308         Mvboard[f]--;
1309     }
1310
1311     InitializeStats();
1312
1313     if (TCflag && (TCmoves > 1))
1314         ++TimeControl.moves[color[f]];
1315
1316     hashkey = GameList[GameCnt].hashkey;
1317     hashbd = GameList[GameCnt].hashbd;
1318     GameCnt--;
1319     computer = computer ^ 1;
1320     opponent = opponent ^ 1;
1321     flag.mate = false;
1322     Sdepth = 0;
1323     player = player ^ 1;
1324     dsp->ShowSidetoMove();
1325     dsp->UpdateDisplay(0, 0, 1, 0);
1326
1327     if (flag.regularstart)
1328         Book = false;
1329 }
1330
1331
1332 static void
1333 TestSpeed(void(*f)(short side, short ply,
1334                    short in_check, short blockable),
1335           unsigned j)
1336 {
1337 #ifdef test
1338     unsigned jj;
1339 #endif
1340
1341     unsigned i;
1342     long cnt, t1, t2;
1343
1344 #ifdef HAVE_GETTIMEOFDAY
1345     struct timeval tv;
1346 #endif
1347
1348 #ifdef HAVE_GETTIMEOFDAY
1349     gettimeofday(&tv, NULL);
1350     t1 = (tv.tv_sec*100 + (tv.tv_usec/10000));
1351 #else
1352     t1 = time(0);
1353 #endif
1354
1355     for (i = 0; i < j; i++)
1356     {
1357         f(opponent, 2, -1, true);
1358
1359 #ifdef test
1360         for (jj = TrPnt[2]; i < TrPnt[3]; jj++)
1361         {
1362             if (!pick(jj, TrPnt[3] - 1))
1363                 break;
1364         }
1365 #endif
1366     }
1367
1368 #ifdef HAVE_GETTIMEOFDAY
1369     gettimeofday(&tv, NULL);
1370     t2 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1371 #else
1372     t2 = time(0);
1373 #endif
1374
1375     cnt = j * (TrPnt[3] - TrPnt[2]);
1376
1377     if (t2 - t1)
1378         et = (t2 - t1);
1379     else
1380         et = 1;
1381
1382     dsp->ShowNodeCnt(cnt);
1383 }
1384
1385
1386 static void
1387 TestPSpeed(short(*f) (short side), unsigned j)
1388 {
1389     unsigned i;
1390     long cnt, t1, t2;
1391 #ifdef HAVE_GETTIMEOFDAY
1392     struct timeval tv;
1393 #endif
1394
1395 #ifdef HAVE_GETTIMEOFDAY
1396     gettimeofday(&tv, NULL);
1397     t1 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1398 #else
1399     t1 = time(0);
1400 #endif
1401
1402     for (i = 0; i < j; i++)
1403         (void) f(opponent);
1404
1405 #ifdef HAVE_GETTIMEOFDAY
1406     gettimeofday(&tv, NULL);
1407     t2 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1408 #else
1409     t2 = time(0);
1410 #endif
1411
1412     cnt = j;
1413
1414     if (t2 - t1)
1415         et = (t2 - t1);
1416     else
1417         et = 1;
1418
1419     dsp->ShowNodeCnt(cnt);
1420 }
1421
1422
1423 static void
1424 SetOppTime(char *time)
1425 {
1426     int m, t;
1427
1428     t = (int)strtol(time, &time, 10);
1429
1430     if (*time == ':')
1431     {
1432         time++;
1433         /* FIXME: sec is parsed but ignored */
1434         (void)strtol(time, &time, 10);
1435     }
1436
1437     m = (int)strtol(time, &time, 10);
1438
1439     if (t)
1440         TimeControl.clock[opponent] = t;
1441
1442     if (m)
1443         TimeControl.moves[opponent] = m;
1444
1445     ElapsedTime(COMPUTE_AND_INIT_MODE);
1446
1447     if (XSHOGI)
1448     {
1449         /* just to inform xshogi about availability of otime command */
1450         printf("otime %d %d\n", t, m);
1451     }
1452 }
1453
1454
1455 static void
1456 SetMachineTime(char *time)
1457 {
1458     int m, t;
1459
1460     t = (int)strtol(time, &time, 10);
1461
1462     if (*time == ':')
1463     {
1464         time++;
1465         /* FIXME: sec is parsed but ignored */
1466         (void)strtol(time, &time, 10);
1467     }
1468
1469     m = (int)strtol(time, &time, 10);
1470
1471     if (t)
1472         TimeControl.clock[computer] = t;
1473
1474     if (m)
1475         TimeControl.moves[computer] = m;
1476
1477     ElapsedTime(COMPUTE_AND_INIT_MODE);
1478
1479     if (XSHOGI)
1480     {
1481         /* just to inform xshogi about availability of time command */
1482         printf("time %d %d\n", t, m);
1483     }
1484 }
1485
1486 /*
1487  * Set up a board position. Pieces are entered by typing the piece followed
1488  * by the location. For example, Nf3 will place a knight on square f3.
1489  */
1490 static void
1491 ReadFEN(char *fen)
1492 {
1493     short a = white, r, c, sq, i, error = 0;
1494     char s[80];
1495
1496     flag.regularstart = true;
1497     Book = BOOKFAIL;
1498
1499     for (sq = 0; sq < NO_SQUARES; sq++)
1500     {
1501         board[sq] = no_piece;
1502         color[sq] = neutral;
1503     }
1504
1505     ClearCaptured();
1506
1507     /* read board */
1508     r = NO_ROWS-1; c = 0;
1509     while(*fen)
1510     {
1511         if (isdigit(*fen))
1512         {
1513             c += *fen++ - '0'; /* assumes single digit! */
1514         }
1515         else if (*fen == '/')
1516         {   /* next rank */
1517             if (c != NO_COLS) error++;
1518             c = 0; fen++;
1519             if (--r < 0) break;
1520         }
1521         else
1522         {
1523             int promo = 0, found = 0;
1524             if (*fen == '+')
1525             {
1526                 promo++; fen++;
1527             }
1528
1529             if (!isalpha(*fen)) break;
1530
1531             for (i = no_piece; i <= king; i++)
1532             {
1533                 if ((*fen == pxx[i]) || (*fen == qxx[i]))
1534                 {
1535                     sq = locn(r, c);
1536                     color[sq] = (islower(*fen) ? white : black);
1537                     if (promo)
1538                         board[sq] = promoted[i];
1539                     else
1540                         board[sq] = i;
1541
1542                     found = 1;
1543                     break;
1544                 }
1545             }
1546
1547             if (!found) error++;
1548             c++; fen++;
1549         }
1550     }
1551     if(r || c != NO_COLS) error++;
1552
1553     while (*fen == ' ') fen++;
1554
1555     /* read holdings */
1556     if(!strncmp(fen, "[-]", 3)) fen += 3; /* empty holdings */
1557     else if(*fen == '[')
1558     {
1559         fen++;
1560         while(isalpha(*fen))
1561         {
1562             int found = 0;
1563             for (i = pawn; i <= king; i++)
1564             {
1565                 if ((*fen == pxx[i]) || (*fen == qxx[i]))
1566                 {
1567                     Captured[islower(*fen) ? white : black][i]++;
1568                     found = 1;
1569                     break;
1570                 }
1571             }
1572             if (!found) error++;
1573             fen++;
1574         }
1575         if(*fen == ']') fen++; else error++;
1576     }
1577
1578     while (*fen == ' ') fen++;
1579
1580     if (*fen == 'w')
1581         a = black;
1582     else if (*fen == 'b')
1583         a = white;
1584     else
1585         error++;
1586
1587     if (error) printf("tellusererror bad FEN\n");
1588
1589     for (sq = 0; sq < NO_SQUARES; sq++)
1590         Mvboard[sq] = ((board[sq] != Stboard[sq]) ? 10 : 0);
1591
1592     computer = otherside[a];
1593     opponent = a;
1594     flag.force = true;
1595     GameCnt = 0;
1596     Game50 = 1;
1597     ZeroRPT();
1598     Sdepth = 0;
1599     InitializeStats();
1600 }
1601
1602
1603 /*
1604  * Process the user's command. If easy mode is OFF (the computer is thinking
1605  * on opponents time) and the program is out of book, then make the 'hint'
1606  * move on the board and call SelectMove() to find a response. The user
1607  * terminates the search by entering a command. If the opponent does not make
1608  * the hint move, then set Sdepth to zero.
1609  */
1610
1611 static char ponderString[20];
1612
1613 void
1614 PonderOnHintMove(void)
1615 {
1616 #ifdef QUIETBACKGROUND
1617     short have_shown_prompt = false;
1618 #endif
1619     unsigned short mv;
1620
1621         /*
1622          * A hint move for the player is available.  Compute a move for the
1623          * opponent in background mode assuming that the hint move will be
1624          * selected by the player.
1625          */
1626
1627         ft = time0; /* Save reference time for the player. */
1628         fflush(stdout);
1629         algbr((short) hint >> 8, (short) hint & 0xff, false);
1630         strcpy(ponderString, mvstr[0]);
1631
1632         if (flag.post)
1633             dsp->GiveHint();
1634
1635         /* do the hint move */
1636         if (VerifyMove(ponderString, VERIFY_AND_TRY_MODE, &mv))
1637         {
1638             Sdepth = 0;
1639
1640 #ifdef QUIETBACKGROUND
1641             dsp->ShowPrompt();
1642             have_shown_prompt = true;
1643 #endif /* QUIETBACKGROUND */
1644
1645             /* Start computing a move until the search is interrupted. */
1646
1647 #ifdef INTERRUPT_TEST
1648             itime0 = 0;
1649 #endif
1650
1651             /* would love to put null move in here */
1652             /* after we make the hint move make a 2 ply search
1653              * with both plys our moves */
1654             /* think on opponents time */
1655             SelectMove(computer, BACKGROUND_MODE);
1656
1657 #ifdef INTERRUPT_TEST
1658             ElapsedTime(COMPUTE_INTERRUPT_MODE);
1659
1660             if (itime0 == 0)
1661             {
1662                 printf("searching not terminated by interrupt!\n");
1663             }
1664             else
1665             {
1666                 printf("elapsed time from interrupt to "
1667                        "terminating search: %ld\n", it);
1668             }
1669 #endif
1670
1671             if (strcmp(ponderString, "hit"))
1672             {   /* undo the hint and carry on */
1673                 VerifyMove(ponderString, UNMAKE_MODE, &mv);
1674             }
1675             else
1676             {   /* otherwise SelectMove will have played the computer's reply */ 
1677                 /* update ponder-move stats, which was skipped in TRY_MODE    */
1678                 GameList[GameCnt-1].depth = GameList[GameCnt].score = 0;
1679                 GameList[GameCnt-1].nodes = 0;
1680                 ElapsedTime(COMPUTE_AND_INIT_MODE);
1681                 GameList[GameCnt-1].time = (short) (et + 50)/100; /* FIXME: this is wrong */
1682
1683                 RenewTimeControl(computer); /* add time for next session */
1684             }
1685             Sdepth = 0;
1686         }
1687
1688         time0 = ft; /* Restore reference time for the player. */
1689         ponderString[0] = '\0';
1690 }
1691
1692 /*
1693  * Recognize the command s from input line sx, and perform the action it specifies.
1694  * Returns whether the command could cause it to be out turn to move.
1695  */
1696 int
1697 ParseAndExecuteCommand(char *s, char *sx)
1698 {
1699     short ok;
1700     unsigned short mv;
1701
1702         if (strcmp(s, "bd") == 0)   /* bd -- display board */
1703         {
1704             /* FIXME: Hack alert! */
1705             short old_xshogi = XSHOGI;
1706
1707             if (old_xshogi)
1708                 display_type = DISPLAY_RAW;
1709
1710             dsp->ClearScreen();
1711             dsp->UpdateDisplay(0, 0, 1, 0);
1712
1713             if (old_xshogi)
1714                 display_type = DISPLAY_X;
1715         }
1716         else if (strcmp(s, "post") == 0)
1717         {
1718             flag.post = (xboard ? 1 : !flag.post);
1719         }
1720         else if (strcmp(s, "nopost") == 0)
1721         {
1722             flag.post = 0;
1723         }
1724 #ifdef MINISHOGI
1725         else if (strcmp(s, "variant") == 0)
1726         {   /* only variant we play is minishogi */
1727             printf("setup (P.BR.S...G.+.++.+Kp.br.s...g.+.++.+k) 5x5+5_shogi rbsgk/4p/5/P4/KGSBR [-] w 0 1\n");
1728         }
1729 #endif
1730         else if (strcmp(s, "alg") == 0 ||
1731                  strcmp(s, "accepted") == 0 || strcmp(s, "rejected") == 0 ||
1732                  strcmp(s, "variant") == 0 || strcmp(s, "computer") == 0)
1733         {
1734             /* noop */ ;
1735         }
1736         else if ((strcmp(s, "quit") == 0) ||
1737                  (strcmp(s, "exit") == 0) && !xboard)
1738         {
1739             flag.quit = true;
1740         }
1741         else if (strcmp(s, "xboard") == 0)
1742         {
1743             xboard = true;
1744             strcpy(ColorStr[0], "White");
1745             strcpy(ColorStr[1], "Black");
1746         }
1747         else if (strcmp(s, "protover") == 0)
1748         {
1749             printf("feature option=\"tsume -check 0\"\n");
1750             printf("feature option=\"contempt -spin %d -1000 1000\"\n", contempt);
1751             printf("feature option=\"Hash-file search depth -spin %d 0 100\"\n", HashDepth);
1752             printf("feature option=\"Hash-file move number -spin %d 0 100\"\n", HashMoveLimit);
1753             printf("feature myname=\"GNU %s %s\" ",
1754 #ifdef MINISHOGI
1755                    "MiniShogi",
1756 #else
1757                    "Shogi",
1758 #endif
1759                    PACKAGE_VERSION
1760                 );
1761             printf("variants=\"%s\" ",
1762 #ifdef MINISHOGI
1763                    "5x5+5_shogi,minishogi"
1764 #else
1765                    "shogi"
1766 #endif
1767                 );
1768             printf("debug=1 setboard=1 sigint=0 memory=1 usermove=1 done=1\n");
1769         }
1770         else if (strcmp(s, ".") == 0)
1771         {   // periodic update request of analysis info: send stat01 info
1772             ElapsedTime(2);
1773             algbr((short)(currentMove >> 8), (short)(currentMove & 0xFF), 0);
1774             printf("stat01: %4ld %8ld %2d %2d %2d %s\n",
1775                     et, NodeCnt, Sdepth, movesLeft, TrPnt[2]-TrPnt[1], mvstr[0]);
1776             fflush(stdout);
1777             if (!root) return false; /* signal no abort needed */
1778         }
1779         else if (strcmp(s, "exit") == 0)
1780         {
1781             flag.analyze = false;
1782             flag.force = true;
1783         }
1784         else if (strcmp(s, "analyze") == 0)
1785         {
1786             flag.analyze = true;
1787             flag.force = true;
1788         }
1789         else if ((strcmp(s, "set") == 0) ||
1790                  (strcmp(s, "edit") == 0))
1791         {
1792             dsp->EditBoard();
1793         }
1794         else if (strcmp(s, "setup") == 0)
1795         {
1796             dsp->SetupBoard();
1797         }
1798         else if (strcmp(s, "first") == 0)
1799         {
1800             ok = true;
1801         }
1802 #if ttblsz
1803         else if (strcmp(s, "memory") == 0)
1804         {
1805             unsigned int mem, size, t = 1;
1806             sscanf(sx, "memory %d", &mem);
1807             if(mem > 2048) mem = 2048; /* prevent integer overflow for > 2GB hash */
1808             size = (mem << 20) / sizeof(struct hashentry) - rehash;
1809             while(t <= size/4) t <<= 1;
1810             AllocateTT(t);
1811         }
1812 #endif
1813         else if (strcmp(s, "go") == 0)
1814         {
1815             ok = true;
1816             flag.force = false;
1817
1818             if (computer == black)
1819             {
1820                 computer = white;
1821                 opponent = black;
1822             }
1823             else
1824             {
1825                 computer = black;
1826                 opponent = white;
1827             }
1828         }
1829         else if (strcmp(s, "help") == 0)
1830         {
1831             dsp->help();
1832         }
1833         else if (strcmp(s, "material") == 0)
1834         {
1835             flag.material = !flag.material;
1836         }
1837         else if (strcmp(s, "force") == 0)
1838         {
1839             if (XSHOGI)
1840             {
1841                 flag.force = true;
1842                 flag.bothsides = false;
1843             }
1844             else
1845             {
1846                 flag.force = !flag.force;
1847                 flag.bothsides = false;
1848             }
1849         }
1850         else if (strcmp(s, "book") == 0)
1851         {
1852             Book = Book ? 0 : BOOKFAIL;
1853         }
1854         else if (strcmp(s, "new") == 0)
1855         {
1856             NewGame();
1857             dsp->UpdateDisplay(0, 0, 1, 0);
1858         }
1859         else if (strcmp(s, "setboard") == 0)
1860         {
1861             ReadFEN(sx + 9);
1862         }
1863         else if (strcmp(s, "list") == 0)
1864         {
1865             ListGame();
1866         }
1867         else if (strcmp(s, "level") == 0)
1868         {
1869             dsp->SelectLevel(sx + strlen("level"));
1870         }
1871         else if (strcmp(s, "clock") == 0)
1872         {
1873             dsp->SelectLevel(sx + strlen("clock"));
1874         }
1875         else if (strcmp(s, "hash") == 0)
1876         {
1877             flag.hash = !flag.hash;
1878         }
1879         else if (strcmp(s, "gamein") == 0)
1880         {
1881             flag.gamein = !flag.gamein;
1882         }
1883         else if (strcmp(s, "beep") == 0)
1884         {
1885             flag.beep = !flag.beep;
1886         }
1887         else if (strcmp(s, "time") == 0)
1888         {
1889             SetMachineTime(sx + strlen("time"));
1890         }
1891         else if ((strcmp(s, "otime") == 0) ||
1892                  (xboard && (strcmp(s, "otim")) == 0))
1893         {
1894             SetOppTime(sx + strlen("otime"));
1895         }
1896         else if (strcmp(s, "Awindow") == 0)
1897         {
1898             dsp->ChangeAlphaWindow();
1899         }
1900         else if (strcmp(s, "Bwindow") == 0)
1901         {
1902             dsp->ChangeBetaWindow();
1903         }
1904         else if (strcmp(s, "rcptr") == 0)
1905         {
1906             flag.rcptr = !flag.rcptr;
1907         }
1908         else if (strcmp(s, "hint") == 0)
1909         {
1910             dsp->GiveHint();
1911         }
1912         else if (strcmp(s, "both") == 0)
1913         {
1914             flag.bothsides = !flag.bothsides;
1915             flag.force = false;
1916             Sdepth = 0;
1917             ElapsedTime(COMPUTE_AND_INIT_MODE);
1918             SelectMove(opponent, FOREGROUND_MODE);
1919             ok = true;
1920         }
1921         else if (strcmp(s, "reverse") == 0)
1922         {
1923             flag.reverse = !flag.reverse;
1924             dsp->ClearScreen();
1925             dsp->UpdateDisplay(0, 0, 1, 0);
1926         }
1927         else if (strcmp(s, "switch") == 0)
1928         {
1929             computer = computer ^ 1;
1930             opponent = opponent ^ 1;
1931             xwndw = (computer == black) ? WXWNDW : BXWNDW;
1932             flag.force = false;
1933             Sdepth = 0;
1934             ok = true;
1935             dsp->UpdateDisplay(0, 0, 1, 0);
1936         }
1937         else if (xboard ? strcmp(s, "white") == 0 : strcmp(s, "black") == 0)
1938         {
1939             computer = white;
1940             opponent = black;
1941             xwndw = WXWNDW;
1942             flag.force = false;
1943             Sdepth = 0;
1944
1945             /*
1946              * ok = true; don't automatically start with black command
1947              */
1948         }
1949         else if (xboard ? strcmp(s, "black") == 0 : strcmp(s, "white") == 0)
1950         {
1951             computer = black;
1952             opponent = white;
1953             xwndw = BXWNDW;
1954             flag.force = false;
1955             Sdepth = 0;
1956
1957             /*
1958              * ok = true; don't automatically start with white command
1959              */
1960         }
1961         else if (strcmp(s, "undo") == 0 && GameCnt > 0)
1962         {
1963             Undo();
1964         }
1965         else if (strcmp(s, "remove") == 0 && GameCnt > 1)
1966         {
1967             Undo();
1968             Undo();
1969         }
1970         /* CHECKME: are these next three correct? */
1971         else if (!XSHOGI && strcmp(s, "xget") == 0)
1972         {
1973             GetXGame();
1974         }
1975         else if (!XSHOGI && strcmp(s, "xsave") == 0)
1976         {
1977             SaveXGame();
1978         }
1979         else if (!XSHOGI && strcmp(s, "bsave") == 0)
1980         {
1981             BookSave();
1982         }
1983 #ifdef EASY_OPENINGS
1984         else if ((strcmp(s, "?") == 0) ||
1985                  (strcmp(s, "!") == 0) ||
1986                  (strcmp(s, "~") == 0))
1987 #else
1988         else if ((strcmp(s, "?") == 0) ||
1989                  (strcmp(s, "!") == 0))
1990 #endif
1991         {
1992             FlagMove(*s);
1993         }
1994         else if (strcmp(s, "get") == 0)
1995         {
1996             GetGame();
1997         }
1998         else if (strcmp(s, "save") == 0)
1999         {
2000             SaveGame();
2001         }
2002         else if (strcmp(s, "depth") == 0)
2003         {
2004             dsp->ChangeSearchDepth(sx + strlen("depth"));
2005         }
2006         else if (strcmp(s, "sd") == 0)
2007         {
2008             dsp->ChangeSearchDepth(sx + strlen("sd"));
2009         }
2010         else if (strcmp(s, "hashdepth") == 0)
2011         {
2012             dsp->ChangeHashDepth();
2013         }
2014         else if (strcmp(s, "random") == 0)
2015         {
2016             dither = DITHER;
2017         }
2018         else if (strcmp(s, "hard") == 0)
2019         {
2020             flag.easy = false;
2021         }
2022         else if (strcmp(s, "easy") == 0)
2023         {
2024             flag.easy = !flag.easy;
2025         }
2026         else if (strcmp(s, "option") == 0)
2027         {
2028             sscanf(sx, "option tsume=%hd", &flag.tsume) ||
2029             sscanf(sx, "option hash=%hd",  &flag.hash)  ||
2030             sscanf(sx, "option Hash-file search depth=%hd", &HashDepth)    ||
2031             sscanf(sx, "option Hash-file move number=%hd", &HashMoveLimit) ||
2032             sscanf(sx, "option contempt=%hd", &contempt);
2033         }
2034         else if (strcmp(s, "tsume") == 0)
2035         {
2036             flag.tsume = !flag.tsume;
2037         }
2038         else if (strcmp(s, "contempt") == 0)
2039         {
2040             dsp->SetContempt();
2041         }
2042         else if (strcmp(s, "xwndw") == 0)
2043         {
2044             dsp->ChangeXwindow();
2045         }
2046         else if (strcmp(s, "rv") == 0)
2047         {
2048             flag.rv = !flag.rv;
2049             dsp->UpdateDisplay(0, 0, 1, 0);
2050         }
2051         else if (strcmp(s, "coords") == 0)
2052         {
2053             flag.coords = !flag.coords;
2054             dsp->UpdateDisplay(0, 0, 1, 0);
2055         }
2056         else if (strcmp(s, "stars") == 0)
2057         {
2058             flag.stars = !flag.stars;
2059             dsp->UpdateDisplay(0, 0, 1, 0);
2060         }
2061         else if (!XSHOGI && strcmp(s, "moves") == 0)
2062         {
2063             short temp;
2064
2065 #if MAXDEPTH > 3
2066             if (GameCnt > 0)
2067             {
2068                 extern unsigned short PrVar[MAXDEPTH];
2069
2070                 SwagHt = (GameList[GameCnt].gmove == PrVar[1])
2071                     ? PrVar[2] : 0;
2072             }
2073             else
2074 #endif
2075                 SwagHt = 0;
2076
2077             dsp->ShowMessage("Testing MoveList Speed");
2078             temp = generate_move_flags;
2079             generate_move_flags = true;
2080             TestSpeed(MoveList, 1);
2081             generate_move_flags = temp;
2082             dsp->ShowMessage("Testing CaptureList Speed");
2083             TestSpeed(CaptureList, 1);
2084             dsp->ShowMessage("Testing Eval Speed");
2085             ExaminePosition(opponent);
2086             TestPSpeed(ScorePosition, 1);
2087         }
2088         else if (!XSHOGI && strcmp(s, "test") == 0)
2089         {
2090 #ifdef SLOW_CPU
2091             dsp->ShowMessage("Testing MoveList Speed");
2092             TestSpeed(MoveList, 2000);
2093             dsp->ShowMessage("Testing CaptureList Speed");
2094             TestSpeed(CaptureList, 3000);
2095             dsp->ShowMessage("Testing Eval Speed");
2096             ExaminePosition(opponent);
2097             TestPSpeed(ScorePosition, 1500);
2098 #else
2099             dsp->ShowMessage("Testing MoveList Speed");
2100             TestSpeed(MoveList, 20000);
2101             dsp->ShowMessage("Testing CaptureList Speed");
2102             TestSpeed(CaptureList, 30000);
2103             dsp->ShowMessage("Testing Eval Speed");
2104             ExaminePosition(opponent);
2105             TestPSpeed(ScorePosition, 15000);
2106 #endif
2107         }
2108         else if (!XSHOGI && strcmp(s, "p") == 0)
2109         {
2110             dsp->ShowPostnValues();
2111         }
2112         else if (!XSHOGI && strcmp(s, "debug") == 0)
2113         {
2114             dsp->DoDebug();
2115         }
2116         else
2117         {
2118             if (strcmp(s, "usermove") == 0)
2119                 sscanf(sx + 9, "%s", s);
2120
2121             if (flag.mate)
2122             {
2123                 ok = true;
2124             }
2125             else if ((ok = VerifyMove(s, VERIFY_AND_MAKE_MODE, &mv)))
2126             {
2127                 /* check for repetition */
2128                 short rpt = repetition();
2129
2130                 if (rpt >= 3)
2131                 {
2132                     DRAW = DRAW_REPETITION;
2133                     dsp->ShowMessage(DRAW);
2134                     GameList[GameCnt].flags |= draw;
2135
2136                         flag.mate = true;
2137                 }
2138                 else if (XSHOGI)
2139                 {
2140                     /* add remaining time in milliseconds for xshogi */
2141                     printf("%d. %s %ld\n",
2142                            ++mycnt2, s, TimeControl.clock[player] * 10);
2143                  }
2144             }
2145
2146             Sdepth = 0;
2147         }
2148
2149     return ok;
2150 }
2151
2152 /*
2153  * Read commands from input, and execute them, until it becomes our turn to move.
2154  * When called during a background search (root = false) it just backlogs the
2155  * input command without executing it, and returns immediately. Unless the command 
2156  * was the move on which the search was pondering. In that case we turn the ongoing
2157  * search into a foreground search. To judge this, it is also necessary to process
2158  * the 'time' and 'otim' commands that preceed the move. The '.' command is also
2159  * always processed, to prevent it from aborting an analysis search.
2160  * The time spent waiting for input can be filled with background searches for
2161  * pondering or analysis. (In !root mode input is guaranteed to be pending already!)
2162  */
2163 int
2164 InputCommand(int root)
2165 {
2166 #ifdef QUIETBACKGROUND
2167     short have_shown_prompt = false;
2168 #endif
2169     short ok;
2170     char s[200], sx[200], s2[200];
2171     static char backlog[200];
2172
2173     ok = flag.quit = false;
2174     player = opponent;
2175
2176 #if ttblsz
2177     /* CHECKME: should this also be done in the following while loop? */
2178     if (TTadd > ttbllimit)
2179         ZeroTTable();
2180 #endif
2181
2182     while ((hint > 0) && !flag.easy && !flag.force && !backlog[0] && root)
2183     {
2184         /*
2185          * A hint move for the player is available.  Compute a move for the
2186          * opponent in background mode assuming that the hint move will be
2187          * selected by the player.
2188          * Terminate this search on input, which will then be saved in backlog[].
2189          * Unless the input was the hint move ('ponder hit'). Then that move will
2190          * be played (after the search times out) in addition to the hint. There
2191          * will then be no backlog, and we start pondering on the new hint move.
2192          */
2193
2194         PonderOnHintMove();
2195     }
2196
2197     while(!(ok || flag.quit))
2198     {   /* process input commands until our it becomes our turn to move */
2199         player = opponent;
2200
2201         /* in analysis mode we do a background search while waiting for input */
2202         if (flag.analyze && !backlog[0] && root) {
2203             SelectMove(opponent, BACKGROUND_MODE);
2204         }
2205
2206 #ifdef QUIETBACKGROUND
2207         if (!have_shown_prompt)
2208         {
2209 #endif /* QUIETBACKGROUND */
2210
2211             dsp->ShowPrompt();
2212
2213 #ifdef QUIETBACKGROUND
2214         }
2215
2216         have_shown_prompt = false;
2217 #endif /* QUIETBACKGROUND */
2218
2219         if (!backlog[0]) {    /* read new input line */
2220             int eof = dsp->GetString(sx);
2221             if (eof)
2222                 dsp->ExitShogi();
2223         } else {              /* or use backlogged input line */
2224             strcpy(sx, backlog);
2225             backlog[0]= '\0'; /* make sure no backlog is left */
2226         }
2227
2228         /* extract first word */
2229         if (sscanf(sx, "%s %s", s, s2) < 1)
2230             continue;
2231
2232         if (!root && (strcmp(s, "usermove") == 0)
2233                   && (strcmp(s2, ponderString) == 0))
2234         {   /* ponder hit; switch to normal search  */
2235             background = false;
2236             hint = 0;
2237             if (TCflag)
2238             {   /* account opponent time and moves */
2239                 TimeControl.clock[opponent] -= et;
2240                 timeopp[oppptr] = et;
2241                 if (--TimeControl.moves[opponent] == 0)
2242                     TimeControl.moves[opponent] = TCmoves; /* assumes uni-TC! */
2243             }
2244             SetResponseTime(computer);
2245             strcpy(ponderString, "hit");
2246             return false;        /* no search abort */
2247         }
2248
2249         if (!root && strcmp(s, ".") && strcmp(s, "time") && strcmp(s, "otim"))
2250         {   /* during search most commands can only be done after abort */
2251             strcpy(backlog, sx); /* backlog the command    */
2252             return true;         /* and order search abort */
2253         }
2254
2255         ok = ParseAndExecuteCommand(s, sx); /* returns whether turn changed */
2256     }
2257
2258     ElapsedTime(COMPUTE_AND_INIT_MODE);
2259
2260     /* kludge alert: change the side we play to prevent starting a search   */
2261     if (flag.force)
2262     {
2263         computer = opponent;
2264         opponent = computer ^ 1;
2265     }
2266
2267     return true;
2268 }