Fix InputCommand patch
[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 /* FIXME!  This is truly the function from hell! */
1604
1605 /*
1606  * Process the user's command. If easy mode is OFF (the computer is thinking
1607  * on opponents time) and the program is out of book, then make the 'hint'
1608  * move on the board and call SelectMove() to find a response. The user
1609  * terminates the search by entering a command. If the opponent does not make
1610  * the hint move, then set Sdepth to zero.
1611  */
1612
1613 int
1614 InputCommand(char *command, int root)
1615 {
1616 #ifdef QUIETBACKGROUND
1617     short have_shown_prompt = false;
1618 #endif
1619     short ok, done, is_move = false;
1620     unsigned short mv;
1621     char s[200], sx[200];
1622     static char backlog[200];
1623
1624     ok = flag.quit = done = false;
1625     player = opponent;
1626
1627 #if ttblsz
1628     if (TTadd > ttbllimit)
1629         ZeroTTable();
1630 #endif
1631
1632     if ((hint > 0) && !flag.easy && !flag.force && !command && !backlog[0] && root)
1633     {
1634         /*
1635          * A hint move for the player is available.  Compute a move for the
1636          * opponent in background mode assuming that the hint move will be
1637          * selected by the player.
1638          */
1639
1640         ft = time0; /* Save reference time for the player. */
1641         fflush(stdout);
1642         algbr((short) hint >> 8, (short) hint & 0xff, false);
1643         strcpy(s, mvstr[0]);
1644
1645         if (flag.post)
1646             dsp->GiveHint();
1647
1648         /* do the hint move */
1649         if (VerifyMove(s, VERIFY_AND_TRY_MODE, &mv))
1650         {
1651             Sdepth = 0;
1652
1653 #ifdef QUIETBACKGROUND
1654             dsp->ShowPrompt();
1655             have_shown_prompt = true;
1656 #endif /* QUIETBACKGROUND */
1657
1658             /* Start computing a move until the search is interrupted. */
1659
1660 #ifdef INTERRUPT_TEST
1661             itime0 = 0;
1662 #endif
1663
1664             /* would love to put null move in here */
1665             /* after we make the hint move make a 2 ply search
1666              * with both plys our moves */
1667             /* think on opponents time */
1668             SelectMove(computer, BACKGROUND_MODE);
1669
1670 #ifdef INTERRUPT_TEST
1671             ElapsedTime(COMPUTE_INTERRUPT_MODE);
1672
1673             if (itime0 == 0)
1674             {
1675                 printf("searching not terminated by interrupt!\n");
1676             }
1677             else
1678             {
1679                 printf("elapsed time from interrupt to "
1680                        "terminating search: %ld\n", it);
1681             }
1682 #endif
1683
1684             /* undo the hint and carry on */
1685             VerifyMove(s, UNMAKE_MODE, &mv);
1686             Sdepth = 0;
1687         }
1688
1689         time0 = ft; /* Restore reference time for the player. */
1690     }
1691
1692     while(!(ok || flag.quit || done))
1693     {
1694         player = opponent;
1695
1696         if (flag.analyze && !command && !backlog[0] && root) {
1697             SelectMove(opponent, BACKGROUND_MODE);
1698         }
1699
1700 #ifdef QUIETBACKGROUND
1701         if (!have_shown_prompt)
1702         {
1703 #endif /* QUIETBACKGROUND */
1704
1705             dsp->ShowPrompt();
1706
1707 #ifdef QUIETBACKGROUND
1708         }
1709
1710         have_shown_prompt = false;
1711 #endif /* QUIETBACKGROUND */
1712
1713         if (!command && backlog[0]) command = backlog; /* pick up backlogged command */
1714
1715         if (command == NULL) {
1716             int eof = dsp->GetString(sx);
1717             if (eof)
1718                 dsp->ExitShogi();
1719         } else {
1720             strcpy(sx, command);
1721             backlog[0]= '\0'; /* make sure no backlog is left */
1722             command = NULL;
1723         }
1724
1725         /* extract first word */
1726         if (sscanf(sx, "%s", s) < 1)
1727             continue;
1728
1729         if (!root && strcmp(s, "."))
1730         {   /* during search most commands can only be done after abort */
1731             strcpy(backlog, sx); /* backlog the command    */
1732             return true;         /* and order search abort */
1733         }
1734
1735         if (strcmp(s, "bd") == 0)   /* bd -- display board */
1736         {
1737             /* FIXME: Hack alert! */
1738             short old_xshogi = XSHOGI;
1739
1740             if (old_xshogi)
1741                 display_type = DISPLAY_RAW;
1742
1743             dsp->ClearScreen();
1744             dsp->UpdateDisplay(0, 0, 1, 0);
1745
1746             if (old_xshogi)
1747                 display_type = DISPLAY_X;
1748         }
1749         else if (strcmp(s, "post") == 0)
1750         {
1751             flag.post = (xboard ? 1 : !flag.post);
1752         }
1753         else if (strcmp(s, "nopost") == 0)
1754         {
1755             flag.post = 0;
1756         }
1757 #ifdef MINISHOGI
1758         else if (strcmp(s, "variant") == 0)
1759         {   /* only variant we play is minishogi */
1760             printf("setup (P.BR.S...G.+.++.+Kp.br.s...g.+.++.+k) 5x5+5_shogi rbsgk/4p/5/P4/KGSBR [-] w 0 1\n");
1761         }
1762 #endif
1763         else if (strcmp(s, "alg") == 0 ||
1764                  strcmp(s, "accepted") == 0 || strcmp(s, "rejected") == 0 ||
1765                  strcmp(s, "variant") == 0 || strcmp(s, "computer") == 0)
1766         {
1767             /* noop */ ;
1768         }
1769         else if ((strcmp(s, "quit") == 0) ||
1770                  (strcmp(s, "exit") == 0) && !xboard)
1771         {
1772             flag.quit = true;
1773         }
1774         else if (strcmp(s, "xboard") == 0)
1775         {
1776             xboard = true;
1777             strcpy(ColorStr[0], "White");
1778             strcpy(ColorStr[1], "Black");
1779         }
1780         else if (strcmp(s, "protover") == 0)
1781         {
1782             printf("feature option=\"tsume -check 0\"\n");
1783             printf("feature option=\"contempt -spin %d -1000 1000\"\n", contempt);
1784             printf("feature option=\"Hash-file search depth -spin %d 0 100\"\n", HashDepth);
1785             printf("feature option=\"Hash-file move number -spin %d 0 100\"\n", HashMoveLimit);
1786             printf("feature myname=\"GNU %s %s\" ",
1787 #ifdef MINISHOGI
1788                    "MiniShogi",
1789 #else
1790                    "Shogi",
1791 #endif
1792                    PACKAGE_VERSION
1793                 );
1794             printf("variants=\"%s\" ",
1795 #ifdef MINISHOGI
1796                    "5x5+5_shogi,minishogi"
1797 #else
1798                    "shogi"
1799 #endif
1800                 );
1801             printf("debug=1 setboard=1 sigint=0 memory=1 done=1\n");
1802         }
1803         else if (strcmp(s, ".") == 0)
1804         {   // periodic update request of analysis info: send stat01 info
1805             ElapsedTime(2);
1806             algbr((short)(currentMove >> 8), (short)(currentMove & 0xFF), 0);
1807             printf("stat01: %4ld %8ld %2d %2d %2d %s\n",
1808                     et, NodeCnt, Sdepth, movesLeft, TrPnt[2]-TrPnt[1], mvstr[0]);
1809             fflush(stdout);
1810             if (!root) return false; /* signal no abort needed */
1811         }
1812         else if (strcmp(s, "exit") == 0)
1813         {
1814             flag.analyze = false;
1815             flag.force = true;
1816         }
1817         else if (strcmp(s, "analyze") == 0)
1818         {
1819             flag.analyze = true;
1820             flag.force = true;
1821         }
1822         else if ((strcmp(s, "set") == 0) ||
1823                  (strcmp(s, "edit") == 0))
1824         {
1825             dsp->EditBoard();
1826         }
1827         else if (strcmp(s, "setup") == 0)
1828         {
1829             dsp->SetupBoard();
1830         }
1831         else if (strcmp(s, "first") == 0)
1832         {
1833             ok = true;
1834         }
1835 #if ttblsz
1836         else if (strcmp(s, "memory") == 0)
1837         {
1838             unsigned int mem, size, t = 1;
1839             sscanf(sx, "memory %d", &mem);
1840             if(mem > 2048) mem = 2048; /* prevent integer overflow for > 2GB hash */
1841             size = (mem << 20) / sizeof(struct hashentry) - rehash;
1842             while(t <= size/4) t <<= 1;
1843             AllocateTT(t);
1844         }
1845 #endif
1846         else if (strcmp(s, "go") == 0)
1847         {
1848             ok = true;
1849             flag.force = false;
1850
1851             if (computer == black)
1852             {
1853                 computer = white;
1854                 opponent = black;
1855             }
1856             else
1857             {
1858                 computer = black;
1859                 opponent = white;
1860             }
1861         }
1862         else if (strcmp(s, "help") == 0)
1863         {
1864             dsp->help();
1865         }
1866         else if (strcmp(s, "material") == 0)
1867         {
1868             flag.material = !flag.material;
1869         }
1870         else if (strcmp(s, "force") == 0)
1871         {
1872             if (XSHOGI)
1873             {
1874                 flag.force = true;
1875                 flag.bothsides = false;
1876             }
1877             else
1878             {
1879                 flag.force = !flag.force;
1880                 flag.bothsides = false;
1881             }
1882         }
1883         else if (strcmp(s, "book") == 0)
1884         {
1885             Book = Book ? 0 : BOOKFAIL;
1886         }
1887         else if (strcmp(s, "new") == 0)
1888         {
1889             NewGame();
1890             dsp->UpdateDisplay(0, 0, 1, 0);
1891         }
1892         else if (strcmp(s, "setboard") == 0)
1893         {
1894             ReadFEN(sx + 9);
1895         }
1896         else if (strcmp(s, "list") == 0)
1897         {
1898             ListGame();
1899         }
1900         else if (strcmp(s, "level") == 0)
1901         {
1902             dsp->SelectLevel(sx + strlen("level"));
1903         }
1904         else if (strcmp(s, "clock") == 0)
1905         {
1906             dsp->SelectLevel(sx + strlen("clock"));
1907         }
1908         else if (strcmp(s, "hash") == 0)
1909         {
1910             flag.hash = !flag.hash;
1911         }
1912         else if (strcmp(s, "gamein") == 0)
1913         {
1914             flag.gamein = !flag.gamein;
1915         }
1916         else if (strcmp(s, "beep") == 0)
1917         {
1918             flag.beep = !flag.beep;
1919         }
1920         else if (strcmp(s, "time") == 0)
1921         {
1922             SetMachineTime(sx + strlen("time"));
1923         }
1924         else if ((strcmp(s, "otime") == 0) ||
1925                  (xboard && (strcmp(s, "otim")) == 0))
1926         {
1927             SetOppTime(sx + strlen("otime"));
1928         }
1929         else if (strcmp(s, "Awindow") == 0)
1930         {
1931             dsp->ChangeAlphaWindow();
1932         }
1933         else if (strcmp(s, "Bwindow") == 0)
1934         {
1935             dsp->ChangeBetaWindow();
1936         }
1937         else if (strcmp(s, "rcptr") == 0)
1938         {
1939             flag.rcptr = !flag.rcptr;
1940         }
1941         else if (strcmp(s, "hint") == 0)
1942         {
1943             dsp->GiveHint();
1944         }
1945         else if (strcmp(s, "both") == 0)
1946         {
1947             flag.bothsides = !flag.bothsides;
1948             flag.force = false;
1949             Sdepth = 0;
1950             ElapsedTime(COMPUTE_AND_INIT_MODE);
1951             SelectMove(opponent, FOREGROUND_MODE);
1952             ok = true;
1953         }
1954         else if (strcmp(s, "reverse") == 0)
1955         {
1956             flag.reverse = !flag.reverse;
1957             dsp->ClearScreen();
1958             dsp->UpdateDisplay(0, 0, 1, 0);
1959         }
1960         else if (strcmp(s, "switch") == 0)
1961         {
1962             computer = computer ^ 1;
1963             opponent = opponent ^ 1;
1964             xwndw = (computer == black) ? WXWNDW : BXWNDW;
1965             flag.force = false;
1966             Sdepth = 0;
1967             ok = true;
1968             dsp->UpdateDisplay(0, 0, 1, 0);
1969         }
1970         else if (xboard ? strcmp(s, "white") == 0 : strcmp(s, "black") == 0)
1971         {
1972             computer = white;
1973             opponent = black;
1974             xwndw = WXWNDW;
1975             flag.force = false;
1976             Sdepth = 0;
1977
1978             /*
1979              * ok = true; don't automatically start with black command
1980              */
1981         }
1982         else if (xboard ? strcmp(s, "black") == 0 : strcmp(s, "white") == 0)
1983         {
1984             computer = black;
1985             opponent = white;
1986             xwndw = BXWNDW;
1987             flag.force = false;
1988             Sdepth = 0;
1989
1990             /*
1991              * ok = true; don't automatically start with white command
1992              */
1993         }
1994         else if (strcmp(s, "undo") == 0 && GameCnt > 0)
1995         {
1996             Undo();
1997         }
1998         else if (strcmp(s, "remove") == 0 && GameCnt > 1)
1999         {
2000             Undo();
2001             Undo();
2002         }
2003         /* CHECKME: are these next three correct? */
2004         else if (!XSHOGI && strcmp(s, "xget") == 0)
2005         {
2006             GetXGame();
2007         }
2008         else if (!XSHOGI && strcmp(s, "xsave") == 0)
2009         {
2010             SaveXGame();
2011         }
2012         else if (!XSHOGI && strcmp(s, "bsave") == 0)
2013         {
2014             BookSave();
2015         }
2016 #ifdef EASY_OPENINGS
2017         else if ((strcmp(s, "?") == 0) ||
2018                  (strcmp(s, "!") == 0) ||
2019                  (strcmp(s, "~") == 0))
2020 #else
2021         else if ((strcmp(s, "?") == 0) ||
2022                  (strcmp(s, "!") == 0))
2023 #endif
2024         {
2025             FlagMove(*s);
2026         }
2027         else if (strcmp(s, "get") == 0)
2028         {
2029             GetGame();
2030         }
2031         else if (strcmp(s, "save") == 0)
2032         {
2033             SaveGame();
2034         }
2035         else if (strcmp(s, "depth") == 0)
2036         {
2037             dsp->ChangeSearchDepth(sx + strlen("depth"));
2038         }
2039         else if (strcmp(s, "sd") == 0)
2040         {
2041             dsp->ChangeSearchDepth(sx + strlen("sd"));
2042         }
2043         else if (strcmp(s, "hashdepth") == 0)
2044         {
2045             dsp->ChangeHashDepth();
2046         }
2047         else if (strcmp(s, "random") == 0)
2048         {
2049             dither = DITHER;
2050         }
2051         else if (strcmp(s, "hard") == 0)
2052         {
2053             flag.easy = false;
2054         }
2055         else if (strcmp(s, "easy") == 0)
2056         {
2057             flag.easy = !flag.easy;
2058         }
2059         else if (strcmp(s, "option") == 0)
2060         {
2061             sscanf(sx, "option tsume=%hd", &flag.tsume) ||
2062             sscanf(sx, "option hash=%hd",  &flag.hash)  ||
2063             sscanf(sx, "option Hash-file search depth=%hd", &HashDepth)    ||
2064             sscanf(sx, "option Hash-file move number=%hd", &HashMoveLimit) ||
2065             sscanf(sx, "option contempt=%hd", &contempt);
2066         }
2067         else if (strcmp(s, "tsume") == 0)
2068         {
2069             flag.tsume = !flag.tsume;
2070         }
2071         else if (strcmp(s, "contempt") == 0)
2072         {
2073             dsp->SetContempt();
2074         }
2075         else if (strcmp(s, "xwndw") == 0)
2076         {
2077             dsp->ChangeXwindow();
2078         }
2079         else if (strcmp(s, "rv") == 0)
2080         {
2081             flag.rv = !flag.rv;
2082             dsp->UpdateDisplay(0, 0, 1, 0);
2083         }
2084         else if (strcmp(s, "coords") == 0)
2085         {
2086             flag.coords = !flag.coords;
2087             dsp->UpdateDisplay(0, 0, 1, 0);
2088         }
2089         else if (strcmp(s, "stars") == 0)
2090         {
2091             flag.stars = !flag.stars;
2092             dsp->UpdateDisplay(0, 0, 1, 0);
2093         }
2094         else if (!XSHOGI && strcmp(s, "moves") == 0)
2095         {
2096             short temp;
2097
2098 #if MAXDEPTH > 3
2099             if (GameCnt > 0)
2100             {
2101                 extern unsigned short PrVar[MAXDEPTH];
2102
2103                 SwagHt = (GameList[GameCnt].gmove == PrVar[1])
2104                     ? PrVar[2] : 0;
2105             }
2106             else
2107 #endif
2108                 SwagHt = 0;
2109
2110             dsp->ShowMessage("Testing MoveList Speed");
2111             temp = generate_move_flags;
2112             generate_move_flags = true;
2113             TestSpeed(MoveList, 1);
2114             generate_move_flags = temp;
2115             dsp->ShowMessage("Testing CaptureList Speed");
2116             TestSpeed(CaptureList, 1);
2117             dsp->ShowMessage("Testing Eval Speed");
2118             ExaminePosition(opponent);
2119             TestPSpeed(ScorePosition, 1);
2120         }
2121         else if (!XSHOGI && strcmp(s, "test") == 0)
2122         {
2123 #ifdef SLOW_CPU
2124             dsp->ShowMessage("Testing MoveList Speed");
2125             TestSpeed(MoveList, 2000);
2126             dsp->ShowMessage("Testing CaptureList Speed");
2127             TestSpeed(CaptureList, 3000);
2128             dsp->ShowMessage("Testing Eval Speed");
2129             ExaminePosition(opponent);
2130             TestPSpeed(ScorePosition, 1500);
2131 #else
2132             dsp->ShowMessage("Testing MoveList Speed");
2133             TestSpeed(MoveList, 20000);
2134             dsp->ShowMessage("Testing CaptureList Speed");
2135             TestSpeed(CaptureList, 30000);
2136             dsp->ShowMessage("Testing Eval Speed");
2137             ExaminePosition(opponent);
2138             TestPSpeed(ScorePosition, 15000);
2139 #endif
2140         }
2141         else if (!XSHOGI && strcmp(s, "p") == 0)
2142         {
2143             dsp->ShowPostnValues();
2144         }
2145         else if (!XSHOGI && strcmp(s, "debug") == 0)
2146         {
2147             dsp->DoDebug();
2148         }
2149         else
2150         {
2151             if (flag.mate)
2152             {
2153                 ok = true;
2154             }
2155             else if ((ok = VerifyMove(s, VERIFY_AND_MAKE_MODE, &mv)))
2156             {
2157                 /* check for repetition */
2158                 short rpt = repetition();
2159
2160                 if (rpt >= 3)
2161                 {
2162                     DRAW = DRAW_REPETITION;
2163                     dsp->ShowMessage(DRAW);
2164                     GameList[GameCnt].flags |= draw;
2165
2166                         flag.mate = true;
2167                 }
2168                 else
2169                 {
2170                     is_move = true;
2171                 }
2172             }
2173
2174             Sdepth = 0;
2175         }
2176     }
2177
2178     ElapsedTime(COMPUTE_AND_INIT_MODE);
2179
2180     if (flag.force)
2181     {
2182         computer = opponent;
2183         opponent = computer ^ 1;
2184     }
2185
2186     if (XSHOGI)
2187     {
2188         /* add remaining time in milliseconds for xshogi */
2189         if (is_move)
2190         {
2191             printf("%d. %s %ld\n",
2192                    ++mycnt2, s, TimeControl.clock[player] * 10);
2193         }
2194     }
2195
2196     return true;
2197 }