8fc4b32b7639b37a64f8fc0ac07f7ec34e7fe8de
[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] = '*';
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         return;
1044
1045     if ((fd = fopen(fname, "a")) != NULL)
1046     {
1047         fprintf(fd, "#\n");
1048
1049         for (i = 1; i <= GameCnt; i++)
1050         {
1051             struct GameRec  *g = &GameList[i];
1052             char mvnr[20], mvs[20];
1053
1054             if (i % 2)
1055                 sprintf(mvnr, "%d.", (i + 1)/2);
1056             else
1057                 strcpy(mvnr, "");
1058
1059             f = g->gmove >> 8;
1060             t = (g->gmove & 0xFF);
1061             algbr(f, t, g->flags);
1062             j = 0;
1063
1064             /* determine move quality string */
1065             if (g->flags & goodmove)
1066                 sflags[j++] = '!';
1067
1068             if (g->flags & badmove)
1069                 sflags[j++] = '?';
1070
1071 #ifdef EASY_OPENINGS
1072             if (g->flags & difficult)
1073                 sflags[j++] = '~';
1074 #endif
1075
1076             sflags[j] = '\0';
1077
1078             /* determine move string */
1079             if (f > NO_SQUARES)
1080             {
1081                 sprintf(mvs, "%s%s ", &mvstr[0][1], sflags);
1082             }
1083             else
1084             {
1085                 sprintf(mvs, "%c%c%c%c%c%s%s ",
1086                         mvstr[0][0], mvstr[0][1],
1087                         (g->flags & capture) ? 'x' : '-',
1088                         mvstr[0][2], mvstr[0][3],
1089                         (mvstr[0][4] == '+') ? "+" : "",
1090                         sflags);
1091             }
1092
1093             fprintf(fd, "%s%s%c%s",
1094                     mvnr,
1095                     (f > NO_SQUARES
1096                      ? ""
1097                      : (is_promoted[g->fpiece] ? "+" : "")),
1098                     pxx[g->fpiece],
1099                     mvs);
1100
1101             if ((i % 10) == 0)
1102                 fprintf(fd, "\n");
1103         }
1104
1105         if ((i % 10) != 1)
1106             fprintf(fd, "\n");
1107
1108         fclose(fd);
1109
1110         dsp->ShowMessage("Game saved");
1111     }
1112     else
1113     {
1114         dsp->ShowMessage("Could not open file");
1115     }
1116 }
1117
1118
1119 void
1120 ListGame(void)
1121 {
1122     FILE *fd;
1123     short i, f, t;
1124     time_t when;
1125     char fname[256], dbuf[256];
1126
1127     if (listfile[0])
1128     {
1129         strcpy(fname, listfile);
1130     }
1131     else
1132     {
1133         time(&when);
1134         strncpy(dbuf, ctime(&when), 20);
1135         dbuf[7]  = '\0';
1136         dbuf[10] = '\0';
1137         dbuf[13] = '\0';
1138         dbuf[16] = '\0';
1139         dbuf[19] = '\0';
1140
1141         /* use format "CL.Jan01-020304B" when
1142            date is Jan 1
1143            time is 02:03:04
1144            program played white */
1145
1146         sprintf(fname, "CL.%s%s-%s%s%s%c",
1147                 dbuf + 4, dbuf + 8, dbuf + 11, dbuf + 14,
1148                 dbuf + 17, ColorStr[computer][0]);
1149
1150         /* replace space padding with 0 */
1151         for (i = 0; fname[i] != '\0'; i++)
1152         {
1153             if (fname[i] == ' ')
1154                 fname[i] = '0';
1155         }
1156     }
1157
1158     fd = fopen(fname, "w");
1159
1160     if (!fd)
1161     {
1162         printf("Open failure for file: %s", fname);
1163         exit(1);
1164     }
1165
1166     fprintf(fd, "gnushogi %s game\n", PACKAGE_VERSION);
1167     fputs("         score  depth   nodes  time         ", fd);
1168     fputs("         score  depth   nodes  time\n", fd);
1169
1170     for (i = 1; i <= GameCnt; i++)
1171     {
1172         f = GameList[i].gmove >> 8;
1173         t = (GameList[i].gmove & 0xFF);
1174         algbr(f, t, GameList[i].flags);
1175
1176         if (GameList[i].flags & book)
1177         {
1178             fprintf(fd, "%c%c%-5s  %5d    Book%7ld %5ld",
1179                     ((f > NO_SQUARES)
1180                      ? ' '
1181                      : (is_promoted[GameList[i].fpiece] ? '+' : ' ')),
1182                     pxx[GameList[i].fpiece],
1183                     ((f > NO_SQUARES)
1184                      ? &mvstr[0][1] : mvstr[0]),
1185                     GameList[i].score,
1186                     GameList[i].nodes,
1187                     GameList[i].time);
1188         }
1189         else
1190         {
1191             fprintf(fd, "%c%c%-5s  %5d     %2d %7ld %5ld",
1192                     (f > NO_SQUARES
1193                      ? ' '
1194                      : (is_promoted[GameList[i].fpiece] ? '+' : ' ')),
1195                     pxx[GameList[i].fpiece],
1196                     (f > NO_SQUARES ? &mvstr[0][1] : mvstr[0]),
1197                     GameList[i].score, GameList[i].depth,
1198                     GameList[i].nodes, GameList[i].time);
1199         }
1200
1201         if ((i % 2) == 0)
1202         {
1203             fprintf(fd, "\n");
1204         }
1205         else
1206         {
1207             fprintf(fd, "         ");
1208         }
1209     }
1210
1211     fprintf(fd, "\n\n");
1212
1213     if (GameList[GameCnt].flags & draw)
1214     {
1215         fprintf(fd, "Draw %s\n", DRAW);
1216
1217         if (DRAW == DRAW_REPETITION)
1218         {
1219             short j;
1220
1221             fprintf(fd, "repetition by positions ");
1222
1223             for (j = GameCnt - 1; j >= Game50; j -= 2)
1224             {
1225                 if (GameList[j].hashkey == hashkey &&
1226                     GameList[j].hashbd == hashbd)
1227                     fprintf(fd, "%d ", j);
1228             }
1229
1230             fprintf(fd, "\n");
1231         }
1232     }
1233     else if (GameList[GameCnt].score == -(SCORE_LIMIT + 999))
1234     {
1235         fprintf(fd, "%s\n", ColorStr[player ]);
1236     }
1237     else if (GameList[GameCnt].score == (SCORE_LIMIT + 998))
1238     {
1239         fprintf(fd, "%s\n", ColorStr[player ^ 1]);
1240     }
1241
1242     fclose(fd);
1243 }
1244
1245
1246 static void
1247 FlagMove(char c)
1248 {
1249     switch(c)
1250     {
1251     case '?' :
1252         GameList[GameCnt].flags |= badmove;
1253         break;
1254
1255     case '!' :
1256         GameList[GameCnt].flags |= goodmove;
1257         break;
1258
1259 #ifdef EASY_OPENINGS
1260     case '~' :
1261         GameList[GameCnt].flags |= difficult;
1262         break;
1263 #endif
1264     }
1265 }
1266
1267
1268 /*
1269  * Undo the most recent half-move.
1270  */
1271
1272 static void
1273 Undo(void)
1274 {
1275     short f, t;
1276
1277     f = GameList[GameCnt].gmove >> 8;
1278     t = GameList[GameCnt].gmove & 0x7F;
1279
1280     if (f > NO_SQUARES)
1281     {
1282         /* the move was a drop */
1283         Captured[color[t]][board[t]]++;
1284         board[t] = no_piece;
1285         color[t] = neutral;
1286         Mvboard[t]--;
1287     }
1288     else
1289     {
1290         if (GameList[GameCnt].flags & promote)
1291             board[f] = unpromoted[board[t]];
1292         else
1293             board[f] = board[t];
1294
1295         color[f] = color[t];
1296         board[t] = GameList[GameCnt].piece;
1297         color[t] = GameList[GameCnt].color;
1298
1299         if (board[t] != no_piece)
1300             Captured[color[f]][unpromoted[board[t]]]--;
1301
1302         if (color[t] != neutral)
1303             Mvboard[t]--;
1304
1305         Mvboard[f]--;
1306     }
1307
1308     InitializeStats();
1309
1310     if (TCflag && (TCmoves > 1))
1311         ++TimeControl.moves[color[f]];
1312
1313     hashkey = GameList[GameCnt].hashkey;
1314     hashbd = GameList[GameCnt].hashbd;
1315     GameCnt--;
1316     computer = computer ^ 1;
1317     opponent = opponent ^ 1;
1318     flag.mate = false;
1319     Sdepth = 0;
1320     player = player ^ 1;
1321     dsp->ShowSidetoMove();
1322     dsp->UpdateDisplay(0, 0, 1, 0);
1323
1324     if (flag.regularstart)
1325         Book = false;
1326 }
1327
1328
1329 static void
1330 TestSpeed(void(*f)(short side, short ply,
1331                    short in_check, short blockable),
1332           unsigned j)
1333 {
1334 #ifdef test
1335     unsigned jj;
1336 #endif
1337
1338     unsigned i;
1339     long cnt, t1, t2;
1340
1341 #ifdef HAVE_GETTIMEOFDAY
1342     struct timeval tv;
1343 #endif
1344
1345 #ifdef HAVE_GETTIMEOFDAY
1346     gettimeofday(&tv, NULL);
1347     t1 = (tv.tv_sec*100 + (tv.tv_usec/10000));
1348 #else
1349     t1 = time(0);
1350 #endif
1351
1352     for (i = 0; i < j; i++)
1353     {
1354         f(opponent, 2, -1, true);
1355
1356 #ifdef test
1357         for (jj = TrPnt[2]; i < TrPnt[3]; jj++)
1358         {
1359             if (!pick(jj, TrPnt[3] - 1))
1360                 break;
1361         }
1362 #endif
1363     }
1364
1365 #ifdef HAVE_GETTIMEOFDAY
1366     gettimeofday(&tv, NULL);
1367     t2 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1368 #else
1369     t2 = time(0);
1370 #endif
1371
1372     cnt = j * (TrPnt[3] - TrPnt[2]);
1373
1374     if (t2 - t1)
1375         et = (t2 - t1);
1376     else
1377         et = 1;
1378
1379     dsp->ShowNodeCnt(cnt);
1380 }
1381
1382
1383 static void
1384 TestPSpeed(short(*f) (short side), unsigned j)
1385 {
1386     unsigned i;
1387     long cnt, t1, t2;
1388 #ifdef HAVE_GETTIMEOFDAY
1389     struct timeval tv;
1390 #endif
1391
1392 #ifdef HAVE_GETTIMEOFDAY
1393     gettimeofday(&tv, NULL);
1394     t1 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1395 #else
1396     t1 = time(0);
1397 #endif
1398
1399     for (i = 0; i < j; i++)
1400         (void) f(opponent);
1401
1402 #ifdef HAVE_GETTIMEOFDAY
1403     gettimeofday(&tv, NULL);
1404     t2 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1405 #else
1406     t2 = time(0);
1407 #endif
1408
1409     cnt = j;
1410
1411     if (t2 - t1)
1412         et = (t2 - t1);
1413     else
1414         et = 1;
1415
1416     dsp->ShowNodeCnt(cnt);
1417 }
1418
1419
1420 static void
1421 SetOppTime(char *time)
1422 {
1423     int m, t, sec;
1424
1425     sec = 0;
1426     t = (int)strtol(time, &time, 10);
1427
1428     if (*time == ':')
1429     {
1430         time++;
1431         /* FIXME: sec is parsed but ignored */
1432         sec = (int)strtol(time, &time, 10);
1433     }
1434
1435     m = (int)strtol(time, &time, 10);
1436
1437     if (t)
1438         TimeControl.clock[opponent] = t;
1439
1440     if (m)
1441         TimeControl.moves[opponent] = m;
1442
1443     ElapsedTime(COMPUTE_AND_INIT_MODE);
1444
1445     if (XSHOGI)
1446     {
1447         /* just to inform xshogi about availability of otime command */
1448         printf("otime %d %d\n", t, m);
1449     }
1450 }
1451
1452
1453 static void
1454 SetMachineTime(char *time)
1455 {
1456     int m, t, sec;
1457
1458     sec = 0;
1459     t = (int)strtol(time, &time, 10);
1460
1461     if (*time == ':')
1462     {
1463         time++;
1464         /* FIXME: sec is parsed but ignored */
1465         sec = (int)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 void
1497 InputCommand(char *command)
1498 {
1499     short have_shown_prompt = false;
1500     short ok, done, is_move = false;
1501     unsigned short mv;
1502     char s[80], sx[80];
1503
1504     ok = flag.quit = done = false;
1505     player = opponent;
1506
1507 #if ttblsz
1508     if (TTadd > ttbllimit)
1509         ZeroTTable();
1510 #endif
1511
1512     if ((hint > 0) && !flag.easy && !flag.force)
1513     {
1514         /*
1515          * A hint move for the player is available.  Compute a move for the
1516          * opponent in background mode assuming that the hint move will be
1517          * selected by the player.
1518          */
1519
1520         ft = time0; /* Save reference time for the player. */
1521         fflush(stdout);
1522         algbr((short) hint >> 8, (short) hint & 0xff, false);
1523         strcpy(s, mvstr[0]);
1524
1525         if (flag.post)
1526             dsp->GiveHint();
1527
1528         /* do the hint move */
1529         if (VerifyMove(s, VERIFY_AND_TRY_MODE, &mv))
1530         {
1531             Sdepth = 0;
1532
1533 #ifdef QUIETBACKGROUND
1534             dsp->ShowPrompt();
1535             have_shown_prompt = true;
1536 #endif /* QUIETBACKGROUND */
1537
1538             /* Start computing a move until the search is interrupted. */
1539
1540 #ifdef INTERRUPT_TEST
1541             itime0 = 0;
1542 #endif
1543
1544             /* would love to put null move in here */
1545             /* after we make the hint move make a 2 ply search
1546              * with both plys our moves */
1547             /* think on opponents time */
1548             SelectMove(computer, BACKGROUND_MODE);
1549
1550 #ifdef INTERRUPT_TEST
1551             ElapsedTime(COMPUTE_INTERRUPT_MODE);
1552
1553             if (itime0 == 0)
1554             {
1555                 printf("searching not terminated by interrupt!\n");
1556             }
1557             else
1558             {
1559                 printf("elapsed time from interrupt to "
1560                        "terminating search: %ld\n", it);
1561             }
1562 #endif
1563
1564             /* undo the hint and carry on */
1565             VerifyMove(s, UNMAKE_MODE, &mv);
1566             Sdepth = 0;
1567         }
1568
1569         time0 = ft; /* Restore reference time for the player. */
1570     }
1571
1572     while(!(ok || flag.quit || done))
1573     {
1574         player = opponent;
1575
1576 #ifdef QUIETBACKGROUND
1577         if (!have_shown_prompt)
1578         {
1579 #endif /* QUIETBACKGROUND */
1580
1581             dsp->ShowPrompt();
1582
1583 #ifdef QUIETBACKGROUND
1584         }
1585
1586         have_shown_prompt = false;
1587 #endif /* QUIETBACKGROUND */
1588
1589         if (command == NULL) {
1590             int eof = dsp->GetString(sx);
1591             if (eof)
1592                 dsp->ExitShogi();
1593         } else {
1594             strcpy(sx, command);
1595             done = true;
1596         }
1597
1598         /* extract first word */
1599         if (sscanf(sx, "%s", s) < 1)
1600             continue;
1601
1602         if (strcmp(s, "bd") == 0)   /* bd -- display board */
1603         {
1604             /* FIXME: Hack alert! */
1605             short old_xshogi = XSHOGI;
1606
1607             if (old_xshogi)
1608                 display_type = DISPLAY_RAW;
1609
1610             dsp->ClearScreen();
1611             dsp->UpdateDisplay(0, 0, 1, 0);
1612
1613             if (old_xshogi)
1614                 display_type = DISPLAY_X;
1615         }
1616         else if (strcmp(s, "post") == 0)
1617         {
1618             flag.post = (xboard ? 1 : !flag.post);
1619         }
1620         else if (strcmp(s, "nopost") == 0)
1621         {
1622             flag.post = 0;
1623         }
1624         else if (strcmp(s, "alg") == 0 ||
1625                  strcmp(s, "accepted") == 0 || strcmp(s, "rejected") == 0 ||
1626                  strcmp(s, "variant") == 0 || strcmp(s, "computer") == 0)
1627         {
1628             /* noop */ ;
1629         }
1630         else if ((strcmp(s, "quit") == 0)
1631                  || (strcmp(s, "exit") == 0))
1632         {
1633             flag.quit = true;
1634         }
1635         else if (strcmp(s, "protover") == 0)
1636         {
1637             printf("feature myname=\"GNU %sShogi %s\" variants=\"%sshogi\" debug=1 setboard=0 done=1\n",
1638 #ifdef MINISHOGI
1639                                        "mini", PACKAGE_VERSION, "5x5+5_"
1640 #else
1641                                          "",   PACKAGE_VERSION, ""
1642 #endif
1643                   );
1644         }
1645         else if ((strcmp(s, "set") == 0)
1646                  || (strcmp(s, "edit") == 0))
1647         {
1648             dsp->EditBoard();
1649         }
1650         else if (strcmp(s, "setup") == 0)
1651         {
1652             dsp->SetupBoard();
1653         }
1654         else if (strcmp(s, "first") == 0)
1655         {
1656             ok = true;
1657         }
1658         else if (strcmp(s, "go") == 0)
1659         {
1660             ok = true;
1661             flag.force = false;
1662
1663             if (computer == black)
1664             {
1665                 computer = white;
1666                 opponent = black;
1667             }
1668             else
1669             {
1670                 computer = black;
1671                 opponent = white;
1672             }
1673         }
1674         else if (strcmp(s, "help") == 0)
1675         {
1676             dsp->help();
1677         }
1678         else if (strcmp(s, "material") == 0)
1679         {
1680             flag.material = !flag.material;
1681         }
1682         else if (strcmp(s, "force") == 0)
1683         {
1684             if (XSHOGI)
1685             {
1686                 flag.force = true;
1687                 flag.bothsides = false;
1688             }
1689             else
1690             {
1691                 flag.force = !flag.force;
1692                 flag.bothsides = false;
1693             }
1694         }
1695         else if (strcmp(s, "book") == 0)
1696         {
1697             Book = Book ? 0 : BOOKFAIL;
1698         }
1699         else if (strcmp(s, "new") == 0)
1700         {
1701             NewGame();
1702             dsp->UpdateDisplay(0, 0, 1, 0);
1703         }
1704         else if (strcmp(s, "list") == 0)
1705         {
1706             ListGame();
1707         }
1708         else if (strcmp(s, "level") == 0)
1709         {
1710             dsp->SelectLevel(sx + strlen("level"));
1711         }
1712         else if (strcmp(s, "clock") == 0)
1713         {
1714             dsp->SelectLevel(sx + strlen("clock"));
1715         }
1716         else if (strcmp(s, "hash") == 0)
1717         {
1718             flag.hash = !flag.hash;
1719         }
1720         else if (strcmp(s, "gamein") == 0)
1721         {
1722             flag.gamein = !flag.gamein;
1723         }
1724         else if (strcmp(s, "beep") == 0)
1725         {
1726             flag.beep = !flag.beep;
1727         }
1728         else if (strcmp(s, "time") == 0)
1729         {
1730             SetMachineTime(sx + strlen("time"));
1731         }
1732         else if (strcmp(s, "otime") == 0 ||
1733                  (xboard && strcmp(s, "otim")) == 0)
1734         {
1735             SetOppTime(sx + strlen("otime"));
1736         }
1737         else if (strcmp(s, "Awindow") == 0)
1738         {
1739             dsp->ChangeAlphaWindow();
1740         }
1741         else if (strcmp(s, "Bwindow") == 0)
1742         {
1743             dsp->ChangeBetaWindow();
1744         }
1745         else if (strcmp(s, "rcptr") == 0)
1746         {
1747             flag.rcptr = !flag.rcptr;
1748         }
1749         else if (strcmp(s, "hint") == 0)
1750         {
1751             dsp->GiveHint();
1752         }
1753         else if (strcmp(s, "both") == 0)
1754         {
1755             flag.bothsides = !flag.bothsides;
1756             flag.force = false;
1757             Sdepth = 0;
1758             ElapsedTime(COMPUTE_AND_INIT_MODE);
1759             SelectMove(opponent, FOREGROUND_MODE);
1760             ok = true;
1761         }
1762         else if (strcmp(s, "reverse") == 0)
1763         {
1764             flag.reverse = !flag.reverse;
1765             dsp->ClearScreen();
1766             dsp->UpdateDisplay(0, 0, 1, 0);
1767         }
1768         else if (strcmp(s, "switch") == 0)
1769         {
1770             computer = computer ^ 1;
1771             opponent = opponent ^ 1;
1772             xwndw = (computer == black) ? WXWNDW : BXWNDW;
1773             flag.force = false;
1774             Sdepth = 0;
1775             ok = true;
1776             dsp->UpdateDisplay(0, 0, 1, 0);
1777         }
1778         else if (strcmp(s, "black") == 0)
1779         {
1780             computer = white;
1781             opponent = black;
1782             xwndw = WXWNDW;
1783             flag.force = false;
1784             Sdepth = 0;
1785
1786             /*
1787              * ok = true; don't automatically start with black command
1788              */
1789         }
1790         else if (strcmp(s, "white") == 0)
1791         {
1792             computer = black;
1793             opponent = white;
1794             xwndw = BXWNDW;
1795             flag.force = false;
1796             Sdepth = 0;
1797
1798             /*
1799              * ok = true; don't automatically start with white command
1800              */
1801         }
1802         else if (strcmp(s, "undo") == 0 && GameCnt > 0)
1803         {
1804             Undo();
1805         }
1806         else if (strcmp(s, "remove") == 0 && GameCnt > 1)
1807         {
1808             Undo();
1809             Undo();
1810         }
1811         /* CHECKME: are these next three correct? */
1812         else if (!XSHOGI && strcmp(s, "xget") == 0)
1813         {
1814             GetXGame();
1815         }
1816         else if (!XSHOGI && strcmp(s, "xsave") == 0)
1817         {
1818             SaveXGame();
1819         }
1820         else if (!XSHOGI && strcmp(s, "bsave") == 0)
1821         {
1822             BookSave();
1823         }
1824 #ifdef EASY_OPENINGS
1825         else if ((strcmp(s, "?") == 0)
1826                  || (strcmp(s, "!") == 0)
1827                  || (strcmp(s, "~") == 0))
1828 #else
1829         else if ((strcmp(s, "?") == 0)
1830                  || (strcmp(s, "!") == 0))
1831 #endif
1832         {
1833             FlagMove(*s);
1834         }
1835         else if (strcmp(s, "get") == 0)
1836         {
1837             GetGame();
1838         }
1839         else if (strcmp(s, "save") == 0)
1840         {
1841             SaveGame();
1842         }
1843         else if (strcmp(s, "depth") == 0)
1844         {
1845             dsp->ChangeSearchDepth(sx + strlen("depth"));
1846         }
1847         else if (strcmp(s, "sd") == 0)
1848         {
1849             dsp->ChangeSearchDepth(sx + strlen("sd"));
1850         }
1851         else if (strcmp(s, "hashdepth") == 0)
1852         {
1853             dsp->ChangeHashDepth();
1854         }
1855         else if (strcmp(s, "random") == 0)
1856         {
1857             dither = DITHER;
1858         }
1859         else if (strcmp(s, "hard") == 0)
1860         {
1861             flag.easy = false;
1862         }
1863         else if (strcmp(s, "easy") == 0)
1864         {
1865             flag.easy = !flag.easy;
1866         }
1867         else if (strcmp(s, "tsume") == 0)
1868         {
1869             flag.tsume = !flag.tsume;
1870         }
1871         else if (strcmp(s, "contempt") == 0)
1872         {
1873             dsp->SetContempt();
1874         }
1875         else if (strcmp(s, "xwndw") == 0)
1876         {
1877             dsp->ChangeXwindow();
1878         }
1879         else if (strcmp(s, "rv") == 0)
1880         {
1881             flag.rv = !flag.rv;
1882             dsp->UpdateDisplay(0, 0, 1, 0);
1883         }
1884         else if (strcmp(s, "coords") == 0)
1885         {
1886             flag.coords = !flag.coords;
1887             dsp->UpdateDisplay(0, 0, 1, 0);
1888         }
1889         else if (strcmp(s, "stars") == 0)
1890         {
1891             flag.stars = !flag.stars;
1892             dsp->UpdateDisplay(0, 0, 1, 0);
1893         }
1894         else if (!XSHOGI && strcmp(s, "moves") == 0)
1895         {
1896             short temp;
1897
1898 #if MAXDEPTH > 3
1899             if (GameCnt > 0)
1900             {
1901                 extern unsigned short PrVar[MAXDEPTH];
1902
1903                 SwagHt = (GameList[GameCnt].gmove == PrVar[1])
1904                     ? PrVar[2] : 0;
1905             }
1906             else
1907 #endif
1908                 SwagHt = 0;
1909
1910             dsp->ShowMessage("Testing MoveList Speed");
1911             temp = generate_move_flags;
1912             generate_move_flags = true;
1913             TestSpeed(MoveList, 1);
1914             generate_move_flags = temp;
1915             dsp->ShowMessage("Testing CaptureList Speed");
1916             TestSpeed(CaptureList, 1);
1917             dsp->ShowMessage("Testing Eval Speed");
1918             ExaminePosition(opponent);
1919             TestPSpeed(ScorePosition, 1);
1920         }
1921         else if (!XSHOGI && strcmp(s, "test") == 0)
1922         {
1923 #ifdef SLOW_CPU
1924             dsp->ShowMessage("Testing MoveList Speed");
1925             TestSpeed(MoveList, 2000);
1926             dsp->ShowMessage("Testing CaptureList Speed");
1927             TestSpeed(CaptureList, 3000);
1928             dsp->ShowMessage("Testing Eval Speed");
1929             ExaminePosition(opponent);
1930             TestPSpeed(ScorePosition, 1500);
1931 #else
1932             dsp->ShowMessage("Testing MoveList Speed");
1933             TestSpeed(MoveList, 20000);
1934             dsp->ShowMessage("Testing CaptureList Speed");
1935             TestSpeed(CaptureList, 30000);
1936             dsp->ShowMessage("Testing Eval Speed");
1937             ExaminePosition(opponent);
1938             TestPSpeed(ScorePosition, 15000);
1939 #endif
1940         }
1941         else if (!XSHOGI && strcmp(s, "p") == 0)
1942         {
1943             dsp->ShowPostnValues();
1944         }
1945         else if (!XSHOGI && strcmp(s, "debug") == 0)
1946         {
1947             dsp->DoDebug();
1948         }
1949         else
1950         {
1951             if (flag.mate)
1952             {
1953                 ok = true;
1954             }
1955             else if ((ok = VerifyMove(s, VERIFY_AND_MAKE_MODE, &mv)))
1956             {
1957                 /* check for repetition */
1958                 short rpt = repetition();
1959
1960                 if (rpt >= 3)
1961                 {
1962                     DRAW = DRAW_REPETITION;
1963                     dsp->ShowMessage(DRAW);
1964                     GameList[GameCnt].flags |= draw;
1965
1966                         flag.mate = true;
1967                 }
1968                 else
1969                 {
1970                     is_move = true;
1971                 }
1972             }
1973
1974             Sdepth = 0;
1975         }
1976     }
1977
1978     ElapsedTime(COMPUTE_AND_INIT_MODE);
1979
1980     if (flag.force)
1981     {
1982         computer = opponent;
1983         opponent = computer ^ 1;
1984     }
1985
1986     if (XSHOGI)
1987     {
1988         /* add remaining time in milliseconds for xshogi */
1989         if (is_move)
1990         {
1991             printf("%d. %s %ld\n",
1992                    ++mycnt2, s, TimeControl.clock[player] * 10);
1993         }
1994     }
1995 }