e35698d4a69f876c00e5fb5e50d6458be09f0480
[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
289     while (pnt < TrPnt[3])
290     {
291         node = &Tree[pnt++];
292         algbr(node->f, node->t, (short) node->flags);
293
294         if ((strcmp(s, mvstr[0]) == 0)
295             || (strcmp(s, mvstr[1]) == 0)
296             || (strcmp(s, mvstr[2]) == 0)
297             || (strcmp(s, mvstr[3]) == 0))
298         {
299             cnt++;
300             xnode = *node;
301         }
302     }
303
304     if ((cnt == 1) && (xnode.score > DONTUSE))
305     {
306         short blocked;
307
308         MakeMove(opponent, &xnode, &tempb, &tempc,
309                  &tempsf, &tempst, &INCscore);
310
311         if (SqAttacked(PieceList[opponent][0], computer, &blocked))
312         {
313             UnmakeMove(opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
314             dsp->AlwaysShowMessage("Illegal move (in check): %s", s);
315             return false;
316         }
317         else
318         {
319             if (iop == VERIFY_AND_TRY_MODE)
320                 return true;
321
322             dsp->UpdateDisplay(xnode.f, xnode.t, 0, (short) xnode.flags);
323             GameList[GameCnt].depth = GameList[GameCnt].score = 0;
324             GameList[GameCnt].nodes = 0;
325             ElapsedTime(COMPUTE_AND_INIT_MODE);
326             GameList[GameCnt].time = (short) (et + 50)/100;
327             GameList[GameCnt].flags |= local_flags;
328
329             if (TCflag)
330             {
331                 TimeControl.clock[opponent] -= et;
332                 timeopp[oppptr] = et;
333                 --TimeControl.moves[opponent];
334             }
335
336             *mv = (xnode.f << 8) | xnode.t;
337             algbr(xnode.f, xnode.t, false);
338
339             /* in force mode, check for mate conditions */
340             if (flag.force)
341             {
342                 if (IsCheckmate(opponent ^ 1, -1, -1))
343                 {
344                     char buf[20];
345
346                     sprintf(buf, "%s mates!\n", ColorStr[opponent]);
347                     dsp->ShowMessage(buf);
348                     flag.mate = true;
349                 }
350             }
351
352             return true;
353         }
354     }
355
356     dsp->AlwaysShowMessage("Illegal move (no match): %s", s);
357
358     if (!XSHOGI && (cnt > 1))
359     {
360         sprintf(buffer, "Ambiguous Move %s!", s);
361         dsp->ShowMessage(buffer);
362     }
363
364     return false;
365 }
366
367
368 static int
369 parser(char *f, short *fpiece)
370 {
371     int c1, r1, c2, r2;
372     short i, p = false;
373
374     if (*f == '+')
375         f++, p = true;
376
377     for (i = 1, *fpiece = no_piece; i < NO_PIECES; i++)
378     {
379         if (f[0] == pxx[i] || f[0] == qxx[i])
380         {
381             *fpiece = (p ? promoted[i] : unpromoted[i]);
382             break;
383         }
384     }
385
386     if (f[1] == '*' || f[1] == '\'')
387     {
388         c2 = COL_NUM(f[2]);
389         r2 = ROW_NUM(f[3]);
390
391         return ((NO_SQUARES + *fpiece) << 8) | locn(r2, c2);
392     }
393     else
394     {
395         c1 = COL_NUM(f[1]);
396         r1 = ROW_NUM(f[2]);
397         c2 = COL_NUM(f[3]);
398         r2 = ROW_NUM(f[4]);
399         p = (f[5] == '+') ? 0x80 : 0;
400
401         return (locn(r1, c1) << 8) | locn(r2, c2) | p;
402     }
403 }
404
405
406 void
407 skip()
408 {
409     while (*InPtr != ' ')
410         InPtr++;
411
412     while (*InPtr == ' ')
413         InPtr++;
414 }
415
416
417 void
418 skipb()
419 {
420     while (*InPtr == ' ')
421         InPtr++;
422 }
423
424
425 void RequestInputString(char* buffer, unsigned bufsize)
426 {
427     static char fmt[10];
428     int ret = snprintf(fmt, sizeof(fmt), "%%%us", bufsize);
429     if (ret < 0 ) {
430         perror("RequestInputString snprintf");
431         exit(1);
432     }
433     if (ret >= sizeof(fmt)) {
434         fprintf(stderr,
435                 "Insufficient format-buffer size in %s for bufsize=%u\n",
436                 __FUNCTION__, bufsize);
437         exit(1);
438     }
439     dsp->doRequestInputString(fmt, buffer);
440 }
441
442
443 static void
444 GetGame(void)
445 {
446     FILE *fd;
447     char fname[256], *p;
448     int c, i, j;
449     short sq;
450     short side, isp;
451
452     if (savefile[0]) {
453         strcpy(fname, savefile);
454     } else {
455         dsp->ShowMessage("Enter file name: ");
456         RequestInputString(fname, sizeof(fname)-1);
457     }
458
459     if (fname[0] == '\0')
460         strcpy(fname, "shogi.000");
461
462     if ((fd = fopen(fname, "r")) != NULL)
463     {
464         NewGame();
465         fgets(fname, 256, fd);
466         computer = opponent = black;
467         InPtr = fname;
468         skip();
469
470         if (*InPtr == 'c')
471             computer = white;
472         else
473             opponent = white;
474
475         /* FIXME: write a skipn() function so that we can get
476          * 3 skips by doing skipn(3) */
477         skip();
478         skip();
479         skip();
480         Game50 = atoi(InPtr);
481         skip();
482         flag.force = (*InPtr == 'f');
483         fgets(fname, 256, fd); /* empty */
484         fgets(fname, 256, fd);
485         InPtr = &fname[11];
486         skipb();
487         TCflag = atoi(InPtr);
488         skip();
489         InPtr += 14;
490         skipb();
491         OperatorTime = atoi(InPtr);
492         fgets(fname, 256, fd);
493         InPtr = &fname[11];
494         skipb();
495         TimeControl.clock[black] = atol(InPtr);
496         skip();
497         skip();
498         TimeControl.moves[black] = atoi(InPtr);
499         fgets(fname, 256, fd);
500         InPtr = &fname[11];
501         skipb();
502         TimeControl.clock[white] = atol(InPtr);
503         skip();
504         skip();
505         TimeControl.moves[white] = atoi(InPtr);
506         fgets(fname, 256, fd); /* empty */
507
508         for (i = NO_ROWS - 1; i > -1; i--)
509         {
510             fgets(fname, 256, fd);
511             p = &fname[2];
512             InPtr = &fname[23];
513
514             for (j = 0; j < NO_COLS; j++)
515             {
516                 sq = i * NO_COLS + j;
517                 isp = (*p == '+');
518                 p++;
519
520                 if (*p == '-')
521                 {
522                     board[sq] = no_piece;
523                     color[sq] = neutral;
524                 }
525                 else
526                 {
527                     for (c = 0; c < NO_PIECES; c++)
528                     {
529                         if (*p == pxx[c])
530                         {
531                             if (isp)
532                                 board[sq] = promoted[c];
533                             else
534                                 board[sq] = unpromoted[c];
535
536                             color[sq] = white;
537                         }
538                     }
539
540                     for (c = 0; c < NO_PIECES; c++)
541                     {
542                         if (*p == qxx[c])
543                         {
544                             if (isp)
545                                 board[sq] = promoted[c];
546                             else
547                                 board[sq] = unpromoted[c];
548
549                             color[sq] = black;
550                         }
551                     }
552                 }
553
554                 p++;
555                 Mvboard[sq] = atoi(InPtr);
556                 skip();
557             }
558         }
559
560         fgets(fname, 256, fd);  /* empty */
561         fgets(fname, 256, fd);  /* 9 8 7 ... */
562         fgets(fname, 256, fd);  /* empty */
563         fgets(fname, 256, fd);  /* p l n ... */
564         ClearCaptured();
565
566         for (side = 0; side <= 1; side++)
567         {
568             fgets(fname, 256, fd);
569             InPtr = fname;
570             skip();
571             skipb();
572             Captured[side][pawn] = atoi(InPtr);
573             skip();
574 #ifndef MINISHOGI
575             Captured[side][lance] = atoi(InPtr);
576             skip();
577             Captured[side][knight] = atoi(InPtr);
578             skip();
579 #endif
580             Captured[side][silver] = atoi(InPtr);
581             skip();
582             Captured[side][gold] = atoi(InPtr);
583             skip();
584             Captured[side][bishop] = atoi(InPtr);
585             skip();
586             Captured[side][rook] = atoi(InPtr);
587             skip();
588             Captured[side][king] = atoi(InPtr);
589         }
590
591         GameCnt = 0;
592         flag.regularstart = true;
593         Book = BOOKFAIL;
594         fgets(fname, 256, fd); /* empty */
595         fgets(fname, 256, fd);   /*  move score ... */
596
597         while (fgets(fname, 256, fd))
598         {
599             struct GameRec  *g;
600             int side = computer;
601
602             side = side ^ 1;
603             ++GameCnt;
604             InPtr = fname;
605             skipb();
606             g = &GameList[GameCnt];
607             g->gmove = parser(InPtr, &g->fpiece);
608             skip();
609             g->score = atoi(InPtr);
610             skip();
611             g->depth = atoi(InPtr);
612             skip();
613             g->nodes = atol(InPtr);
614             skip();
615             g->time = atol(InPtr);
616             skip();
617             g->flags = c = atoi(InPtr);
618             skip();
619             g->hashkey = strtol(InPtr, (char **) NULL, 16);
620             skip();
621             g->hashbd = strtol(InPtr, (char **) NULL, 16);
622
623             if (c & capture)
624             {
625                 short i, piece;
626
627                 skip();
628
629                 for (piece = no_piece, i = 0; i < NO_PIECES; i++)
630                 {
631                     if (pxx[i] == *InPtr)
632                     {
633                         piece = i;
634                         break;
635                     }
636                 }
637
638                 skip();
639                 g->color = ((*InPtr == 'W') ? white : black);
640                 skip();
641                 g->piece = (*InPtr == '+'
642                             ? promoted[piece]
643                             : unpromoted[piece]);
644             }
645             else
646             {
647                 g->color = neutral;
648                 g->piece = no_piece;
649             }
650         }
651
652         if (TimeControl.clock[black] > 0)
653             TCflag = true;
654
655         fclose(fd);
656     }
657
658     ZeroRPT();
659     InitializeStats();
660     dsp->UpdateDisplay(0, 0, 1, 0);
661     Sdepth = 0;
662     hint = 0;
663 }
664
665
666 static void
667 SaveGame(void)
668 {
669     FILE *fd;
670     char fname[256];
671     short sq, i, c, f, t;
672     char p;
673     short side, piece;
674     char empty[2] = "\n";
675
676     if (savefile[0]) {
677         strcpy(fname, savefile);
678     } else {
679         dsp->ShowMessage("Enter file name: ");
680         RequestInputString(fname, sizeof(fname)-1);
681     }
682
683     if (fname[0] == '\0')
684         strcpy(fname, "shogi.000");
685
686     if ((fd = fopen(fname, "w")) != NULL)
687     {
688         char *b, *w;
689         b = w = "Human   ";
690
691         if (computer == white)
692             w = "computer";
693
694         if (computer == black)
695             b = "computer";
696
697         fprintf(fd, "White %s Black %s %d %s\n", w, b, Game50,
698                 flag.force ? "force" : "");
699         fputs(empty, fd);
700         fprintf(fd, "TimeControl %d Operator Time %d\n", TCflag, OperatorTime);
701         fprintf(fd, "Black Clock %ld Moves %d\nWhite Clock %ld Moves %d\n",
702                 TimeControl.clock[black], TimeControl.moves[black],
703                 TimeControl.clock[white], TimeControl.moves[white]);
704         fputs(empty, fd);
705
706         for (i = NO_ROWS - 1; i > -1; i--)
707         {
708             fprintf(fd, "%c ", ROW_NAME(i));
709
710             for (c = 0; c < NO_COLS; c++)
711             {
712                 sq = i * NO_COLS + c;
713                 piece = board[sq];
714                 p = is_promoted[piece] ? '+' : ' ';
715                 fprintf(fd, "%c", p);
716
717                 switch(color[sq])
718                 {
719                 case white:
720                     p = pxx[piece];
721                     break;
722
723                 case black:
724                     p = qxx[piece];
725                     break;
726
727                 default:
728                     p = '-';
729                 }
730
731                 fprintf(fd, "%c", p);
732             }
733
734             fprintf(fd, "  ");
735
736             for (f = i * NO_COLS; f < i * NO_COLS + NO_ROWS; f++)
737                 fprintf(fd, " %d", Mvboard[f]);
738
739             fprintf(fd, "\n");
740         }
741
742         fputs(empty, fd);
743 #ifndef MINISHOGI
744         fprintf(fd, "   9 8 7 6 5 4 3 2 1\n");
745         fputs(empty, fd);
746         fprintf(fd, "   p  l  n  s  g  b  r  k\n");
747 #else
748         fprintf(fd, "   5 4 3 2 1\n");
749         fputs(empty, fd);
750         fprintf(fd, "   p  s  g  b  r  k\n");
751 #endif
752
753         for (side = 0; side <= 1; side++)
754         {
755             fprintf(fd, "%c", (side == black) ? 'B' : 'W');
756             fprintf(fd, " %2d", Captured[side][pawn]);
757 #ifndef MINISHOGI
758             fprintf(fd, " %2d", Captured[side][lance]);
759             fprintf(fd, " %2d", Captured[side][knight]);
760 #endif
761             fprintf(fd, " %2d", Captured[side][silver]);
762             fprintf(fd, " %2d", Captured[side][gold]);
763             fprintf(fd, " %2d", Captured[side][bishop]);
764             fprintf(fd, " %2d", Captured[side][rook]);
765             fprintf(fd, " %2d", Captured[side][king]);
766             fprintf(fd, "\n");
767         }
768
769         fputs(empty, fd);
770         fputs("  move   score depth   nodes   time flags                         capture\n", fd);
771
772         for (i = 1; i <= GameCnt; i++)
773         {
774             struct GameRec  *g = &GameList[i];
775
776             f = g->gmove >> 8;
777             t = (g->gmove & 0xFF);
778             algbr(f, t, g->flags);
779
780             fprintf(fd, "%c%c%-5s %6d %5d %7ld %6ld %5d  0x%08lx 0x%08lx",
781                     ((f > NO_SQUARES)
782                      ? ' '
783                      : (is_promoted[g->fpiece] ? '+' : ' ')),
784                     pxx[g->fpiece],
785                     ((f > NO_SQUARES) ? &mvstr[0][1] : mvstr[0]),
786                     g->score, g->depth,
787                     g->nodes, g->time, g->flags,
788                     g->hashkey, g->hashbd);
789
790             if (g->piece != no_piece)
791             {
792                 fprintf(fd, "  %c %s %c\n",
793                         pxx[g->piece], ColorStr[g->color],
794                         (is_promoted[g->piece] ? '+' : ' '));
795             }
796             else
797             {
798                 fprintf(fd, "\n");
799             }
800         }
801
802         fclose(fd);
803
804         dsp->ShowMessage("Game saved");
805     }
806     else
807     {
808         dsp->ShowMessage("Could not open file");
809     }
810 }
811
812
813 /*
814  * GetXGame, SaveXGame and BookGame used to only be defined if
815  * xshogi wasn't defined -- wonder why?
816  */
817
818 static void
819 GetXGame(void)
820 {
821     FILE *fd;
822     char fname[256], *p;
823     int c, i, j;
824     short sq;
825     short side, isp;
826
827     dsp->ShowMessage("Enter file name: ");
828     RequestInputString(fname, sizeof(fname)-1);
829
830     if (fname[0] == '\0')
831         strcpy(fname, "xshogi.position.read");
832
833     if ((fd = fopen(fname, "r")) != NULL)
834     {
835         NewGame();
836         flag.regularstart = false;
837         Book = false;
838
839         /* xshogi position file ... */
840         fgets(fname, 256, fd);
841
842 #ifdef notdef
843         fname[6] = '\0';
844
845         if (strcmp(fname, "xshogi"))
846             return;
847 #endif
848
849         /* -- empty line -- */
850         fgets(fname, 256, fd);
851         /* -- empty line -- */
852         fgets(fname, 256, fd);
853
854         for (i = NO_ROWS - 1; i > -1; i--)
855         {
856             fgets(fname, 256, fd);
857             p = fname;
858
859             for (j = 0; j < NO_COLS; j++)
860             {
861                 sq = i * NO_COLS + j;
862                 isp = (*p == '+');
863                 p++;
864
865                 if (*p == '.')
866                 {
867                     board[sq] = no_piece;
868                     color[sq] = neutral;
869                 }
870                 else
871                 {
872                     for (c = 0; c < NO_PIECES; c++)
873                     {
874                         if (*p == qxx[c])
875                         {
876                             if (isp)
877                                 board[sq] = promoted[c];
878                             else
879                                 board[sq] = unpromoted[c];
880
881                             color[sq] = white;
882                         }
883                     }
884
885                     for (c = 0; c < NO_PIECES; c++)
886                     {
887                         if (*p == pxx[c])
888                         {
889                             if (isp)
890                                 board[sq] = promoted[c];
891                             else
892                                 board[sq] = unpromoted[c];
893
894                             color[sq] = black;
895                         }
896                     }
897                 }
898
899                 p++;
900             }
901         }
902
903         ClearCaptured();
904
905         for (side = 0; side <= 1; side++)
906         {
907             fgets(fname, 256, fd);
908             InPtr = fname;
909             Captured[side][pawn]   = atoi(InPtr);
910             skip();
911 #ifndef MINISHOGI
912             Captured[side][lance]  = atoi(InPtr);
913             skip();
914             Captured[side][knight] = atoi(InPtr);
915             skip();
916 #endif
917             Captured[side][silver] = atoi(InPtr);
918             skip();
919             Captured[side][gold]   = atoi(InPtr);
920             skip();
921             Captured[side][bishop] = atoi(InPtr);
922             skip();
923             Captured[side][rook]   = atoi(InPtr);
924             skip();
925             Captured[side][king]   = atoi(InPtr);
926         }
927
928         if (fgets(fname, 256, fd) != NULL && strncmp(fname, "white", 5) == 0)
929         {
930             computer = black;
931             opponent = white;
932             xwndw = BXWNDW;
933         }
934
935         fclose(fd);
936     }
937
938     Game50 = 1;
939     ZeroRPT();
940     InitializeStats();
941     dsp->UpdateDisplay(0, 0, 1, 0);
942     Sdepth = 0;
943     hint = 0;
944 }
945
946
947 static void
948 SaveXGame(void)
949 {
950     FILE *fd;
951     char fname[256], *p;
952     int i, j;
953     short sq, piece;
954     short side, isp;
955
956     dsp->ShowMessage("Enter file name: ");
957     RequestInputString(fname, sizeof(fname)-1);
958
959     if (fname[0] == '\0')
960         strcpy(fname, "xshogi.position.read");
961
962     if ((fd = fopen(fname, "w")) != NULL)
963     {
964         fputs("# xshogi position file -- \n", fd);
965         fputs("\n", fd);
966         fputs("\n", fd);
967
968         for (i = NO_ROWS - 1; i > -1; i--)
969         {
970             p = fname;
971
972             for (j = 0; j < NO_COLS; j++)
973             {
974                 sq = i * NO_COLS + j;
975                 piece = board[sq];
976                 isp = is_promoted[piece];
977                 *p = (isp ? '+' : ' ');
978                 p++;
979
980                 if (piece == no_piece)
981                     *p = '.';
982                 else if (color[sq] == white)
983                     *p = qxx[piece];
984                 else
985                     *p = pxx[piece];
986
987                 p++;
988             }
989
990             *p++ = '\n';
991             *p++ = '\0';
992             fputs(fname, fd);
993         }
994
995         for (side = 0; side <= 1; side++)
996         {
997             sprintf(fname,
998 #ifndef MINISHOGI
999                     "%d %d %d %d %d %d %d %d\n",
1000 #else
1001                     "%d %d %d %d %d %d\n",
1002 #endif
1003                     Captured[side][pawn],
1004 #ifndef MINISHOGI
1005                     Captured[side][lance],
1006                     Captured[side][knight],
1007 #endif
1008                     Captured[side][silver],
1009                     Captured[side][gold],
1010                     Captured[side][bishop],
1011                     Captured[side][rook],
1012                     Captured[side][king]);
1013
1014             fputs(fname, fd);
1015         }
1016
1017         if (computer == black)
1018             fputs("white to play\n", fd);
1019         else
1020             fputs("black to play\n", fd);
1021
1022         fclose(fd);
1023     }
1024 }
1025
1026
1027 static void
1028 BookSave(void)
1029 {
1030     FILE *fd;
1031     char fname[256], sflags[4];
1032     short i, j, f, t;
1033
1034     if (savefile[0]) {
1035         strcpy(fname, savefile);
1036     } else {
1037         /* Enter file name */
1038         dsp->ShowMessage("Enter file name: ");
1039         RequestInputString(fname, sizeof(fname)-1);
1040     }
1041
1042     if (fname[0] == '\0') {
1043         dsp->AlwaysShowMessage("aborting book save");
1044         return;
1045     }
1046
1047     if ((fd = fopen(fname, "a")) != NULL)
1048     {
1049         fprintf(fd, "#\n");
1050
1051         for (i = 1; i <= GameCnt; i++)
1052         {
1053             struct GameRec  *g = &GameList[i];
1054             char mvnr[20], mvs[20];
1055
1056             if (i % 2)
1057                 sprintf(mvnr, "%d.", (i + 1)/2);
1058             else
1059                 strcpy(mvnr, "");
1060
1061             f = g->gmove >> 8;
1062             t = (g->gmove & 0xFF);
1063             algbr(f, t, g->flags);
1064             j = 0;
1065
1066             /* determine move quality string */
1067             if (g->flags & goodmove)
1068                 sflags[j++] = '!';
1069
1070             if (g->flags & badmove)
1071                 sflags[j++] = '?';
1072
1073 #ifdef EASY_OPENINGS
1074             if (g->flags & difficult)
1075                 sflags[j++] = '~';
1076 #endif
1077
1078             sflags[j] = '\0';
1079
1080             /* determine move string */
1081             if (f > NO_SQUARES)
1082             {
1083                 sprintf(mvs, "%s%s ", &mvstr[0][1], sflags);
1084             }
1085             else
1086             {
1087                 sprintf(mvs, "%c%c%c%c%c%s%s ",
1088                         mvstr[0][0], mvstr[0][1],
1089                         (g->flags & capture) ? 'x' : '-',
1090                         mvstr[0][2], mvstr[0][3],
1091                         (mvstr[0][4] == '+') ? "+" : "",
1092                         sflags);
1093             }
1094
1095             fprintf(fd, "%s%s%c%s",
1096                     mvnr,
1097                     (f > NO_SQUARES
1098                      ? ""
1099                      : (is_promoted[g->fpiece] ? "+" : "")),
1100                     pxx[g->fpiece],
1101                     mvs);
1102
1103             if ((i % 10) == 0)
1104                 fprintf(fd, "\n");
1105         }
1106
1107         if ((i % 10) != 1)
1108             fprintf(fd, "\n");
1109
1110         fclose(fd);
1111
1112         dsp->ShowMessage("Game saved");
1113     }
1114     else
1115     {
1116         dsp->ShowMessage("Could not open file");
1117     }
1118 }
1119
1120
1121 void
1122 ListGame(void)
1123 {
1124     FILE *fd;
1125     short i, f, t;
1126     time_t when;
1127     char fname[256], dbuf[256];
1128
1129     if (listfile[0])
1130     {
1131         strcpy(fname, listfile);
1132     }
1133     else
1134     {
1135         time(&when);
1136         strncpy(dbuf, ctime(&when), 20);
1137         dbuf[7]  = '\0';
1138         dbuf[10] = '\0';
1139         dbuf[13] = '\0';
1140         dbuf[16] = '\0';
1141         dbuf[19] = '\0';
1142
1143         /* use format "CL.Jan01-020304B" when
1144            date is Jan 1
1145            time is 02:03:04
1146            program played white */
1147
1148         sprintf(fname, "CL.%s%s-%s%s%s%c",
1149                 dbuf + 4, dbuf + 8, dbuf + 11, dbuf + 14,
1150                 dbuf + 17, ColorStr[computer][0]);
1151
1152         /* replace space padding with 0 */
1153         for (i = 0; fname[i] != '\0'; i++)
1154         {
1155             if (fname[i] == ' ')
1156                 fname[i] = '0';
1157         }
1158     }
1159
1160     fd = fopen(fname, "w");
1161
1162     if (!fd)
1163     {
1164         printf("Open failure for file: %s", fname);
1165         exit(1);
1166     }
1167
1168     fprintf(fd, "gnushogi %s game\n", PACKAGE_VERSION);
1169     fputs("         score  depth   nodes  time         ", fd);
1170     fputs("         score  depth   nodes  time\n", fd);
1171
1172     for (i = 1; i <= GameCnt; i++)
1173     {
1174         f = GameList[i].gmove >> 8;
1175         t = (GameList[i].gmove & 0xFF);
1176         algbr(f, t, GameList[i].flags);
1177
1178         if (GameList[i].flags & book)
1179         {
1180             fprintf(fd, "%c%c%-5s  %5d    Book%7ld %5ld",
1181                     ((f > NO_SQUARES)
1182                      ? ' '
1183                      : (is_promoted[GameList[i].fpiece] ? '+' : ' ')),
1184                     pxx[GameList[i].fpiece],
1185                     ((f > NO_SQUARES)
1186                      ? &mvstr[0][1] : mvstr[0]),
1187                     GameList[i].score,
1188                     GameList[i].nodes,
1189                     GameList[i].time);
1190         }
1191         else
1192         {
1193             fprintf(fd, "%c%c%-5s  %5d     %2d %7ld %5ld",
1194                     (f > NO_SQUARES
1195                      ? ' '
1196                      : (is_promoted[GameList[i].fpiece] ? '+' : ' ')),
1197                     pxx[GameList[i].fpiece],
1198                     (f > NO_SQUARES ? &mvstr[0][1] : mvstr[0]),
1199                     GameList[i].score, GameList[i].depth,
1200                     GameList[i].nodes, GameList[i].time);
1201         }
1202
1203         if ((i % 2) == 0)
1204         {
1205             fprintf(fd, "\n");
1206         }
1207         else
1208         {
1209             fprintf(fd, "         ");
1210         }
1211     }
1212
1213     fprintf(fd, "\n\n");
1214
1215     if (GameList[GameCnt].flags & draw)
1216     {
1217         fprintf(fd, "Draw %s\n", DRAW);
1218
1219         if (DRAW == DRAW_REPETITION)
1220         {
1221             short j;
1222
1223             fprintf(fd, "repetition by positions ");
1224
1225             for (j = GameCnt - 1; j >= Game50; j -= 2)
1226             {
1227                 if (GameList[j].hashkey == hashkey &&
1228                     GameList[j].hashbd == hashbd)
1229                     fprintf(fd, "%d ", j);
1230             }
1231
1232             fprintf(fd, "\n");
1233         }
1234     }
1235     else if (GameList[GameCnt].score == -(SCORE_LIMIT + 999))
1236     {
1237         fprintf(fd, "%s\n", ColorStr[player ]);
1238     }
1239     else if (GameList[GameCnt].score == (SCORE_LIMIT + 998))
1240     {
1241         fprintf(fd, "%s\n", ColorStr[player ^ 1]);
1242     }
1243
1244     fclose(fd);
1245 }
1246
1247
1248 static void
1249 FlagMove(char c)
1250 {
1251     switch(c)
1252     {
1253     case '?' :
1254         GameList[GameCnt].flags |= badmove;
1255         break;
1256
1257     case '!' :
1258         GameList[GameCnt].flags |= goodmove;
1259         break;
1260
1261 #ifdef EASY_OPENINGS
1262     case '~' :
1263         GameList[GameCnt].flags |= difficult;
1264         break;
1265 #endif
1266     }
1267 }
1268
1269
1270 /*
1271  * Undo the most recent half-move.
1272  */
1273
1274 static void
1275 Undo(void)
1276 {
1277     short f, t;
1278
1279     f = GameList[GameCnt].gmove >> 8;
1280     t = GameList[GameCnt].gmove & 0x7F;
1281
1282     if (f > NO_SQUARES)
1283     {
1284         /* the move was a drop */
1285         Captured[color[t]][board[t]]++;
1286         board[t] = no_piece;
1287         color[t] = neutral;
1288         Mvboard[t]--;
1289     }
1290     else
1291     {
1292         if (GameList[GameCnt].flags & promote)
1293             board[f] = unpromoted[board[t]];
1294         else
1295             board[f] = board[t];
1296
1297         color[f] = color[t];
1298         board[t] = GameList[GameCnt].piece;
1299         color[t] = GameList[GameCnt].color;
1300
1301         if (board[t] != no_piece)
1302             Captured[color[f]][unpromoted[board[t]]]--;
1303
1304         if (color[t] != neutral)
1305             Mvboard[t]--;
1306
1307         Mvboard[f]--;
1308     }
1309
1310     InitializeStats();
1311
1312     if (TCflag && (TCmoves > 1))
1313         ++TimeControl.moves[color[f]];
1314
1315     hashkey = GameList[GameCnt].hashkey;
1316     hashbd = GameList[GameCnt].hashbd;
1317     GameCnt--;
1318     computer = computer ^ 1;
1319     opponent = opponent ^ 1;
1320     flag.mate = false;
1321     Sdepth = 0;
1322     player = player ^ 1;
1323     dsp->ShowSidetoMove();
1324     dsp->UpdateDisplay(0, 0, 1, 0);
1325
1326     if (flag.regularstart)
1327         Book = false;
1328 }
1329
1330
1331 static void
1332 TestSpeed(void(*f)(short side, short ply,
1333                    short in_check, short blockable),
1334           unsigned j)
1335 {
1336 #ifdef test
1337     unsigned jj;
1338 #endif
1339
1340     unsigned i;
1341     long cnt, t1, t2;
1342
1343 #ifdef HAVE_GETTIMEOFDAY
1344     struct timeval tv;
1345 #endif
1346
1347 #ifdef HAVE_GETTIMEOFDAY
1348     gettimeofday(&tv, NULL);
1349     t1 = (tv.tv_sec*100 + (tv.tv_usec/10000));
1350 #else
1351     t1 = time(0);
1352 #endif
1353
1354     for (i = 0; i < j; i++)
1355     {
1356         f(opponent, 2, -1, true);
1357
1358 #ifdef test
1359         for (jj = TrPnt[2]; i < TrPnt[3]; jj++)
1360         {
1361             if (!pick(jj, TrPnt[3] - 1))
1362                 break;
1363         }
1364 #endif
1365     }
1366
1367 #ifdef HAVE_GETTIMEOFDAY
1368     gettimeofday(&tv, NULL);
1369     t2 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1370 #else
1371     t2 = time(0);
1372 #endif
1373
1374     cnt = j * (TrPnt[3] - TrPnt[2]);
1375
1376     if (t2 - t1)
1377         et = (t2 - t1);
1378     else
1379         et = 1;
1380
1381     dsp->ShowNodeCnt(cnt);
1382 }
1383
1384
1385 static void
1386 TestPSpeed(short(*f) (short side), unsigned j)
1387 {
1388     unsigned i;
1389     long cnt, t1, t2;
1390 #ifdef HAVE_GETTIMEOFDAY
1391     struct timeval tv;
1392 #endif
1393
1394 #ifdef HAVE_GETTIMEOFDAY
1395     gettimeofday(&tv, NULL);
1396     t1 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1397 #else
1398     t1 = time(0);
1399 #endif
1400
1401     for (i = 0; i < j; i++)
1402         (void) f(opponent);
1403
1404 #ifdef HAVE_GETTIMEOFDAY
1405     gettimeofday(&tv, NULL);
1406     t2 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1407 #else
1408     t2 = time(0);
1409 #endif
1410
1411     cnt = j;
1412
1413     if (t2 - t1)
1414         et = (t2 - t1);
1415     else
1416         et = 1;
1417
1418     dsp->ShowNodeCnt(cnt);
1419 }
1420
1421
1422 static void
1423 SetOppTime(char *time)
1424 {
1425     int m, t;
1426
1427     t = (int)strtol(time, &time, 10);
1428
1429     if (*time == ':')
1430     {
1431         time++;
1432         /* FIXME: sec is parsed but ignored */
1433         (void)strtol(time, &time, 10);
1434     }
1435
1436     m = (int)strtol(time, &time, 10);
1437
1438     if (t)
1439         TimeControl.clock[opponent] = t;
1440
1441     if (m)
1442         TimeControl.moves[opponent] = m;
1443
1444     ElapsedTime(COMPUTE_AND_INIT_MODE);
1445
1446     if (XSHOGI)
1447     {
1448         /* just to inform xshogi about availability of otime command */
1449         printf("otime %d %d\n", t, m);
1450     }
1451 }
1452
1453
1454 static void
1455 SetMachineTime(char *time)
1456 {
1457     int m, t;
1458
1459     t = (int)strtol(time, &time, 10);
1460
1461     if (*time == ':')
1462     {
1463         time++;
1464         /* FIXME: sec is parsed but ignored */
1465         (void)strtol(time, &time, 10);
1466     }
1467
1468     m = (int)strtol(time, &time, 10);
1469
1470     if (t)
1471         TimeControl.clock[computer] = t;
1472
1473     if (m)
1474         TimeControl.moves[computer] = m;
1475
1476     ElapsedTime(COMPUTE_AND_INIT_MODE);
1477
1478     if (XSHOGI)
1479     {
1480         /* just to inform xshogi about availability of time command */
1481         printf("time %d %d\n", t, m);
1482     }
1483 }
1484
1485
1486 /* FIXME!  This is truly the function from hell! */
1487
1488 /*
1489  * Process the user's command. If easy mode is OFF (the computer is thinking
1490  * on opponents time) and the program is out of book, then make the 'hint'
1491  * move on the board and call SelectMove() to find a response. The user
1492  * terminates the search by entering a command. If the opponent does not make
1493  * the hint move, then set Sdepth to zero.
1494  */
1495
1496 int
1497 InputCommand(char *command, int root)
1498 {
1499 #ifdef QUIETBACKGROUND
1500     short have_shown_prompt = false;
1501 #endif
1502     short ok, done, is_move = false;
1503     unsigned short mv;
1504     char s[80], sx[80];
1505     static char backlog[80];
1506
1507     ok = flag.quit = done = false;
1508     player = opponent;
1509
1510 #if ttblsz
1511     if (TTadd > ttbllimit)
1512         ZeroTTable();
1513 #endif
1514
1515     if ((hint > 0) && !flag.easy && !flag.force && !command && !backlog[0] && root)
1516     {
1517         /*
1518          * A hint move for the player is available.  Compute a move for the
1519          * opponent in background mode assuming that the hint move will be
1520          * selected by the player.
1521          */
1522
1523         ft = time0; /* Save reference time for the player. */
1524         fflush(stdout);
1525         algbr((short) hint >> 8, (short) hint & 0xff, false);
1526         strcpy(s, mvstr[0]);
1527
1528         if (flag.post)
1529             dsp->GiveHint();
1530
1531         /* do the hint move */
1532         if (VerifyMove(s, VERIFY_AND_TRY_MODE, &mv))
1533         {
1534             Sdepth = 0;
1535
1536 #ifdef QUIETBACKGROUND
1537             dsp->ShowPrompt();
1538             have_shown_prompt = true;
1539 #endif /* QUIETBACKGROUND */
1540
1541             /* Start computing a move until the search is interrupted. */
1542
1543 #ifdef INTERRUPT_TEST
1544             itime0 = 0;
1545 #endif
1546
1547             /* would love to put null move in here */
1548             /* after we make the hint move make a 2 ply search
1549              * with both plys our moves */
1550             /* think on opponents time */
1551             SelectMove(computer, BACKGROUND_MODE);
1552
1553 #ifdef INTERRUPT_TEST
1554             ElapsedTime(COMPUTE_INTERRUPT_MODE);
1555
1556             if (itime0 == 0)
1557             {
1558                 printf("searching not terminated by interrupt!\n");
1559             }
1560             else
1561             {
1562                 printf("elapsed time from interrupt to "
1563                        "terminating search: %ld\n", it);
1564             }
1565 #endif
1566
1567             /* undo the hint and carry on */
1568             VerifyMove(s, UNMAKE_MODE, &mv);
1569             Sdepth = 0;
1570         }
1571
1572         time0 = ft; /* Restore reference time for the player. */
1573     }
1574
1575     while(!(ok || flag.quit || done))
1576     {
1577         player = opponent;
1578
1579         if (flag.analyze && !command && !backlog[0] && root) {
1580             SelectMove(opponent, BACKGROUND_MODE);
1581         }
1582
1583 #ifdef QUIETBACKGROUND
1584         if (!have_shown_prompt)
1585         {
1586 #endif /* QUIETBACKGROUND */
1587
1588             dsp->ShowPrompt();
1589
1590 #ifdef QUIETBACKGROUND
1591         }
1592
1593         have_shown_prompt = false;
1594 #endif /* QUIETBACKGROUND */
1595
1596         if (!command && backlog[0]) command = backlog; /* pick up backlogged command */
1597
1598         if (command == NULL) {
1599             int eof = dsp->GetString(sx);
1600             if (eof)
1601                 dsp->ExitShogi();
1602         } else {
1603             strcpy(sx, command);
1604             backlog[0]= '\0'; /* make sure no backlog is left */
1605             done = true;
1606         }
1607
1608         /* extract first word */
1609         if (sscanf(sx, "%s", s) < 1)
1610             continue;
1611
1612         if (!root && strcmp(s, "."))
1613         {   /* during search most commands can only be done after abort */
1614             strcpy(backlog, sx); /* backlog the command    */
1615             return true;         /* and order search abort */
1616         }
1617
1618         if (strcmp(s, "bd") == 0)   /* bd -- display board */
1619         {
1620             /* FIXME: Hack alert! */
1621             short old_xshogi = XSHOGI;
1622
1623             if (old_xshogi)
1624                 display_type = DISPLAY_RAW;
1625
1626             dsp->ClearScreen();
1627             dsp->UpdateDisplay(0, 0, 1, 0);
1628
1629             if (old_xshogi)
1630                 display_type = DISPLAY_X;
1631         }
1632         else if (strcmp(s, "post") == 0)
1633         {
1634             flag.post = (xboard ? 1 : !flag.post);
1635         }
1636         else if (strcmp(s, "nopost") == 0)
1637         {
1638             flag.post = 0;
1639         }
1640 #ifdef MINISHOGI
1641         else if (strcmp(s, "variant") == 0)
1642         {   /* only variant we play is minishogi */
1643             printf("setup (P.BR.S...G.+.++.+Kp.br.s...g.+.++.+k) 5x5+5_shogi rbsgk/4p/5/P4/KGSBR [-] w 0 1\n");
1644         }
1645 #endif
1646         else if (strcmp(s, "alg") == 0 ||
1647                  strcmp(s, "accepted") == 0 || strcmp(s, "rejected") == 0 ||
1648                  strcmp(s, "variant") == 0 || strcmp(s, "computer") == 0)
1649         {
1650             /* noop */ ;
1651         }
1652         else if ((strcmp(s, "quit") == 0) ||
1653                  (strcmp(s, "exit") == 0) && !xboard)
1654         {
1655             flag.quit = true;
1656         }
1657         else if (strcmp(s, "xboard") == 0)
1658         {
1659             xboard = true;
1660             strcpy(ColorStr[0], "White");
1661             strcpy(ColorStr[1], "Black");
1662         }
1663         else if (strcmp(s, "protover") == 0)
1664         {
1665             printf("feature myname=\"GNU %s %s\" ",
1666 #ifdef MINISHOGI
1667                    "MiniShogi",
1668 #else
1669                    "Shogi",
1670 #endif
1671                    PACKAGE_VERSION
1672                 );
1673             printf("variants=\"%s\" ",
1674 #ifdef MINISHOGI
1675                    "5x5+5_shogi,minishogi"
1676 #else
1677                    "shogi"
1678 #endif
1679                 );
1680             printf("debug=1 setboard=0 sigint=0 done=1\n");
1681         }
1682         else if (strcmp(s, ".") == 0)
1683         {   // periodic update request of analysis info: send stat01 info
1684             ElapsedTime(2);
1685             algbr((short)(currentMove >> 8), (short)(currentMove & 0xFF), 0);
1686             printf("stat01: %4ld %8ld %2d %2d %2d %s\n",
1687                     et, NodeCnt, Sdepth, movesLeft, TrPnt[2]-TrPnt[1], mvstr[0]);
1688             fflush(stdout);
1689             if (!root) return false; /* signal no abort needed */
1690         }
1691         else if (strcmp(s, "exit") == 0)
1692         {
1693             flag.analyze = false;
1694             flag.force = true;
1695         }
1696         else if (strcmp(s, "analyze") == 0)
1697         {
1698             flag.analyze = true;
1699             flag.force = true;
1700         }
1701         else if ((strcmp(s, "set") == 0) ||
1702                  (strcmp(s, "edit") == 0))
1703         {
1704             dsp->EditBoard();
1705         }
1706         else if (strcmp(s, "setup") == 0)
1707         {
1708             dsp->SetupBoard();
1709         }
1710         else if (strcmp(s, "first") == 0)
1711         {
1712             ok = true;
1713         }
1714         else if (strcmp(s, "go") == 0)
1715         {
1716             ok = true;
1717             flag.force = false;
1718
1719             if (computer == black)
1720             {
1721                 computer = white;
1722                 opponent = black;
1723             }
1724             else
1725             {
1726                 computer = black;
1727                 opponent = white;
1728             }
1729         }
1730         else if (strcmp(s, "help") == 0)
1731         {
1732             dsp->help();
1733         }
1734         else if (strcmp(s, "material") == 0)
1735         {
1736             flag.material = !flag.material;
1737         }
1738         else if (strcmp(s, "force") == 0)
1739         {
1740             if (XSHOGI)
1741             {
1742                 flag.force = true;
1743                 flag.bothsides = false;
1744             }
1745             else
1746             {
1747                 flag.force = !flag.force;
1748                 flag.bothsides = false;
1749             }
1750         }
1751         else if (strcmp(s, "book") == 0)
1752         {
1753             Book = Book ? 0 : BOOKFAIL;
1754         }
1755         else if (strcmp(s, "new") == 0)
1756         {
1757             NewGame();
1758             dsp->UpdateDisplay(0, 0, 1, 0);
1759         }
1760         else if (strcmp(s, "list") == 0)
1761         {
1762             ListGame();
1763         }
1764         else if (strcmp(s, "level") == 0)
1765         {
1766             dsp->SelectLevel(sx + strlen("level"));
1767         }
1768         else if (strcmp(s, "clock") == 0)
1769         {
1770             dsp->SelectLevel(sx + strlen("clock"));
1771         }
1772         else if (strcmp(s, "hash") == 0)
1773         {
1774             flag.hash = !flag.hash;
1775         }
1776         else if (strcmp(s, "gamein") == 0)
1777         {
1778             flag.gamein = !flag.gamein;
1779         }
1780         else if (strcmp(s, "beep") == 0)
1781         {
1782             flag.beep = !flag.beep;
1783         }
1784         else if (strcmp(s, "time") == 0)
1785         {
1786             SetMachineTime(sx + strlen("time"));
1787         }
1788         else if ((strcmp(s, "otime") == 0) ||
1789                  (xboard && (strcmp(s, "otim")) == 0))
1790         {
1791             SetOppTime(sx + strlen("otime"));
1792         }
1793         else if (strcmp(s, "Awindow") == 0)
1794         {
1795             dsp->ChangeAlphaWindow();
1796         }
1797         else if (strcmp(s, "Bwindow") == 0)
1798         {
1799             dsp->ChangeBetaWindow();
1800         }
1801         else if (strcmp(s, "rcptr") == 0)
1802         {
1803             flag.rcptr = !flag.rcptr;
1804         }
1805         else if (strcmp(s, "hint") == 0)
1806         {
1807             dsp->GiveHint();
1808         }
1809         else if (strcmp(s, "both") == 0)
1810         {
1811             flag.bothsides = !flag.bothsides;
1812             flag.force = false;
1813             Sdepth = 0;
1814             ElapsedTime(COMPUTE_AND_INIT_MODE);
1815             SelectMove(opponent, FOREGROUND_MODE);
1816             ok = true;
1817         }
1818         else if (strcmp(s, "reverse") == 0)
1819         {
1820             flag.reverse = !flag.reverse;
1821             dsp->ClearScreen();
1822             dsp->UpdateDisplay(0, 0, 1, 0);
1823         }
1824         else if (strcmp(s, "switch") == 0)
1825         {
1826             computer = computer ^ 1;
1827             opponent = opponent ^ 1;
1828             xwndw = (computer == black) ? WXWNDW : BXWNDW;
1829             flag.force = false;
1830             Sdepth = 0;
1831             ok = true;
1832             dsp->UpdateDisplay(0, 0, 1, 0);
1833         }
1834         else if (xboard ? strcmp(s, "white") == 0 : strcmp(s, "black") == 0)
1835         {
1836             computer = white;
1837             opponent = black;
1838             xwndw = WXWNDW;
1839             flag.force = false;
1840             Sdepth = 0;
1841
1842             /*
1843              * ok = true; don't automatically start with black command
1844              */
1845         }
1846         else if (xboard ? strcmp(s, "black") == 0 : strcmp(s, "white") == 0)
1847         {
1848             computer = black;
1849             opponent = white;
1850             xwndw = BXWNDW;
1851             flag.force = false;
1852             Sdepth = 0;
1853
1854             /*
1855              * ok = true; don't automatically start with white command
1856              */
1857         }
1858         else if (strcmp(s, "undo") == 0 && GameCnt > 0)
1859         {
1860             Undo();
1861         }
1862         else if (strcmp(s, "remove") == 0 && GameCnt > 1)
1863         {
1864             Undo();
1865             Undo();
1866         }
1867         /* CHECKME: are these next three correct? */
1868         else if (!XSHOGI && strcmp(s, "xget") == 0)
1869         {
1870             GetXGame();
1871         }
1872         else if (!XSHOGI && strcmp(s, "xsave") == 0)
1873         {
1874             SaveXGame();
1875         }
1876         else if (!XSHOGI && strcmp(s, "bsave") == 0)
1877         {
1878             BookSave();
1879         }
1880 #ifdef EASY_OPENINGS
1881         else if ((strcmp(s, "?") == 0) ||
1882                  (strcmp(s, "!") == 0) ||
1883                  (strcmp(s, "~") == 0))
1884 #else
1885         else if ((strcmp(s, "?") == 0) ||
1886                  (strcmp(s, "!") == 0))
1887 #endif
1888         {
1889             FlagMove(*s);
1890         }
1891         else if (strcmp(s, "get") == 0)
1892         {
1893             GetGame();
1894         }
1895         else if (strcmp(s, "save") == 0)
1896         {
1897             SaveGame();
1898         }
1899         else if (strcmp(s, "depth") == 0)
1900         {
1901             dsp->ChangeSearchDepth(sx + strlen("depth"));
1902         }
1903         else if (strcmp(s, "sd") == 0)
1904         {
1905             dsp->ChangeSearchDepth(sx + strlen("sd"));
1906         }
1907         else if (strcmp(s, "hashdepth") == 0)
1908         {
1909             dsp->ChangeHashDepth();
1910         }
1911         else if (strcmp(s, "random") == 0)
1912         {
1913             dither = DITHER;
1914         }
1915         else if (strcmp(s, "hard") == 0)
1916         {
1917             flag.easy = false;
1918         }
1919         else if (strcmp(s, "easy") == 0)
1920         {
1921             flag.easy = !flag.easy;
1922         }
1923         else if (strcmp(s, "tsume") == 0)
1924         {
1925             flag.tsume = !flag.tsume;
1926         }
1927         else if (strcmp(s, "contempt") == 0)
1928         {
1929             dsp->SetContempt();
1930         }
1931         else if (strcmp(s, "xwndw") == 0)
1932         {
1933             dsp->ChangeXwindow();
1934         }
1935         else if (strcmp(s, "rv") == 0)
1936         {
1937             flag.rv = !flag.rv;
1938             dsp->UpdateDisplay(0, 0, 1, 0);
1939         }
1940         else if (strcmp(s, "coords") == 0)
1941         {
1942             flag.coords = !flag.coords;
1943             dsp->UpdateDisplay(0, 0, 1, 0);
1944         }
1945         else if (strcmp(s, "stars") == 0)
1946         {
1947             flag.stars = !flag.stars;
1948             dsp->UpdateDisplay(0, 0, 1, 0);
1949         }
1950         else if (!XSHOGI && strcmp(s, "moves") == 0)
1951         {
1952             short temp;
1953
1954 #if MAXDEPTH > 3
1955             if (GameCnt > 0)
1956             {
1957                 extern unsigned short PrVar[MAXDEPTH];
1958
1959                 SwagHt = (GameList[GameCnt].gmove == PrVar[1])
1960                     ? PrVar[2] : 0;
1961             }
1962             else
1963 #endif
1964                 SwagHt = 0;
1965
1966             dsp->ShowMessage("Testing MoveList Speed");
1967             temp = generate_move_flags;
1968             generate_move_flags = true;
1969             TestSpeed(MoveList, 1);
1970             generate_move_flags = temp;
1971             dsp->ShowMessage("Testing CaptureList Speed");
1972             TestSpeed(CaptureList, 1);
1973             dsp->ShowMessage("Testing Eval Speed");
1974             ExaminePosition(opponent);
1975             TestPSpeed(ScorePosition, 1);
1976         }
1977         else if (!XSHOGI && strcmp(s, "test") == 0)
1978         {
1979 #ifdef SLOW_CPU
1980             dsp->ShowMessage("Testing MoveList Speed");
1981             TestSpeed(MoveList, 2000);
1982             dsp->ShowMessage("Testing CaptureList Speed");
1983             TestSpeed(CaptureList, 3000);
1984             dsp->ShowMessage("Testing Eval Speed");
1985             ExaminePosition(opponent);
1986             TestPSpeed(ScorePosition, 1500);
1987 #else
1988             dsp->ShowMessage("Testing MoveList Speed");
1989             TestSpeed(MoveList, 20000);
1990             dsp->ShowMessage("Testing CaptureList Speed");
1991             TestSpeed(CaptureList, 30000);
1992             dsp->ShowMessage("Testing Eval Speed");
1993             ExaminePosition(opponent);
1994             TestPSpeed(ScorePosition, 15000);
1995 #endif
1996         }
1997         else if (!XSHOGI && strcmp(s, "p") == 0)
1998         {
1999             dsp->ShowPostnValues();
2000         }
2001         else if (!XSHOGI && strcmp(s, "debug") == 0)
2002         {
2003             dsp->DoDebug();
2004         }
2005         else
2006         {
2007             if (flag.mate)
2008             {
2009                 ok = true;
2010             }
2011             else if ((ok = VerifyMove(s, VERIFY_AND_MAKE_MODE, &mv)))
2012             {
2013                 /* check for repetition */
2014                 short rpt = repetition();
2015
2016                 if (rpt >= 3)
2017                 {
2018                     DRAW = DRAW_REPETITION;
2019                     dsp->ShowMessage(DRAW);
2020                     GameList[GameCnt].flags |= draw;
2021
2022                         flag.mate = true;
2023                 }
2024                 else
2025                 {
2026                     is_move = true;
2027                 }
2028             }
2029
2030             Sdepth = 0;
2031         }
2032     }
2033
2034     ElapsedTime(COMPUTE_AND_INIT_MODE);
2035
2036     if (flag.force)
2037     {
2038         computer = opponent;
2039         opponent = computer ^ 1;
2040     }
2041
2042     if (XSHOGI)
2043     {
2044         /* add remaining time in milliseconds for xshogi */
2045         if (is_move)
2046         {
2047             printf("%d. %s %ld\n",
2048                    ++mycnt2, s, TimeControl.clock[player] * 10);
2049         }
2050     }
2051
2052     return true;
2053 }