Warnings: correctly use #ifdef for declarations.
[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         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;
1424
1425     t = (int)strtol(time, &time, 10);
1426
1427     if (*time == ':')
1428     {
1429         time++;
1430         /* FIXME: sec is parsed but ignored */
1431         (void)strtol(time, &time, 10);
1432     }
1433
1434     m = (int)strtol(time, &time, 10);
1435
1436     if (t)
1437         TimeControl.clock[opponent] = t;
1438
1439     if (m)
1440         TimeControl.moves[opponent] = m;
1441
1442     ElapsedTime(COMPUTE_AND_INIT_MODE);
1443
1444     if (XSHOGI)
1445     {
1446         /* just to inform xshogi about availability of otime command */
1447         printf("otime %d %d\n", t, m);
1448     }
1449 }
1450
1451
1452 static void
1453 SetMachineTime(char *time)
1454 {
1455     int m, t;
1456
1457     t = (int)strtol(time, &time, 10);
1458
1459     if (*time == ':')
1460     {
1461         time++;
1462         /* FIXME: sec is parsed but ignored */
1463         (void)strtol(time, &time, 10);
1464     }
1465
1466     m = (int)strtol(time, &time, 10);
1467
1468     if (t)
1469         TimeControl.clock[computer] = t;
1470
1471     if (m)
1472         TimeControl.moves[computer] = m;
1473
1474     ElapsedTime(COMPUTE_AND_INIT_MODE);
1475
1476     if (XSHOGI)
1477     {
1478         /* just to inform xshogi about availability of time command */
1479         printf("time %d %d\n", t, m);
1480     }
1481 }
1482
1483
1484 /* FIXME!  This is truly the function from hell! */
1485
1486 /*
1487  * Process the user's command. If easy mode is OFF (the computer is thinking
1488  * on opponents time) and the program is out of book, then make the 'hint'
1489  * move on the board and call SelectMove() to find a response. The user
1490  * terminates the search by entering a command. If the opponent does not make
1491  * the hint move, then set Sdepth to zero.
1492  */
1493
1494 void
1495 InputCommand(char *command)
1496 {
1497 #ifdef QUIETBACKGROUND
1498     short have_shown_prompt = false;
1499 #endif
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, "xboard") == 0)
1636         {
1637             xboard = true;
1638             strcpy(ColorStr[0], "White");
1639             strcpy(ColorStr[1], "Black");
1640         }
1641         else if (strcmp(s, "protover") == 0)
1642         {
1643             printf("feature myname=\"GNU %sShogi %s\" variants=\"%sshogi\" debug=1 setboard=0 sigint=0 done=1\n",
1644 #ifdef MINISHOGI
1645                                        "mini", PACKAGE_VERSION, "5x5+5_"
1646 #else
1647                                          "",   PACKAGE_VERSION, ""
1648 #endif
1649                   );
1650         }
1651         else if ((strcmp(s, "set") == 0)
1652                  || (strcmp(s, "edit") == 0))
1653         {
1654             dsp->EditBoard();
1655         }
1656         else if (strcmp(s, "setup") == 0)
1657         {
1658             dsp->SetupBoard();
1659         }
1660         else if (strcmp(s, "first") == 0)
1661         {
1662             ok = true;
1663         }
1664         else if (strcmp(s, "go") == 0)
1665         {
1666             ok = true;
1667             flag.force = false;
1668
1669             if (computer == black)
1670             {
1671                 computer = white;
1672                 opponent = black;
1673             }
1674             else
1675             {
1676                 computer = black;
1677                 opponent = white;
1678             }
1679         }
1680         else if (strcmp(s, "help") == 0)
1681         {
1682             dsp->help();
1683         }
1684         else if (strcmp(s, "material") == 0)
1685         {
1686             flag.material = !flag.material;
1687         }
1688         else if (strcmp(s, "force") == 0)
1689         {
1690             if (XSHOGI)
1691             {
1692                 flag.force = true;
1693                 flag.bothsides = false;
1694             }
1695             else
1696             {
1697                 flag.force = !flag.force;
1698                 flag.bothsides = false;
1699             }
1700         }
1701         else if (strcmp(s, "book") == 0)
1702         {
1703             Book = Book ? 0 : BOOKFAIL;
1704         }
1705         else if (strcmp(s, "new") == 0)
1706         {
1707             NewGame();
1708             dsp->UpdateDisplay(0, 0, 1, 0);
1709         }
1710         else if (strcmp(s, "list") == 0)
1711         {
1712             ListGame();
1713         }
1714         else if (strcmp(s, "level") == 0)
1715         {
1716             dsp->SelectLevel(sx + strlen("level"));
1717         }
1718         else if (strcmp(s, "clock") == 0)
1719         {
1720             dsp->SelectLevel(sx + strlen("clock"));
1721         }
1722         else if (strcmp(s, "hash") == 0)
1723         {
1724             flag.hash = !flag.hash;
1725         }
1726         else if (strcmp(s, "gamein") == 0)
1727         {
1728             flag.gamein = !flag.gamein;
1729         }
1730         else if (strcmp(s, "beep") == 0)
1731         {
1732             flag.beep = !flag.beep;
1733         }
1734         else if (strcmp(s, "time") == 0)
1735         {
1736             SetMachineTime(sx + strlen("time"));
1737         }
1738         else if ((strcmp(s, "otime") == 0) ||
1739                  (xboard && (strcmp(s, "otim")) == 0))
1740         {
1741             SetOppTime(sx + strlen("otime"));
1742         }
1743         else if (strcmp(s, "Awindow") == 0)
1744         {
1745             dsp->ChangeAlphaWindow();
1746         }
1747         else if (strcmp(s, "Bwindow") == 0)
1748         {
1749             dsp->ChangeBetaWindow();
1750         }
1751         else if (strcmp(s, "rcptr") == 0)
1752         {
1753             flag.rcptr = !flag.rcptr;
1754         }
1755         else if (strcmp(s, "hint") == 0)
1756         {
1757             dsp->GiveHint();
1758         }
1759         else if (strcmp(s, "both") == 0)
1760         {
1761             flag.bothsides = !flag.bothsides;
1762             flag.force = false;
1763             Sdepth = 0;
1764             ElapsedTime(COMPUTE_AND_INIT_MODE);
1765             SelectMove(opponent, FOREGROUND_MODE);
1766             ok = true;
1767         }
1768         else if (strcmp(s, "reverse") == 0)
1769         {
1770             flag.reverse = !flag.reverse;
1771             dsp->ClearScreen();
1772             dsp->UpdateDisplay(0, 0, 1, 0);
1773         }
1774         else if (strcmp(s, "switch") == 0)
1775         {
1776             computer = computer ^ 1;
1777             opponent = opponent ^ 1;
1778             xwndw = (computer == black) ? WXWNDW : BXWNDW;
1779             flag.force = false;
1780             Sdepth = 0;
1781             ok = true;
1782             dsp->UpdateDisplay(0, 0, 1, 0);
1783         }
1784         else if (xboard ? strcmp(s, "white") == 0 : strcmp(s, "black") == 0)
1785         {
1786             computer = white;
1787             opponent = black;
1788             xwndw = WXWNDW;
1789             flag.force = false;
1790             Sdepth = 0;
1791
1792             /*
1793              * ok = true; don't automatically start with black command
1794              */
1795         }
1796         else if (xboard ? strcmp(s, "black") == 0 : strcmp(s, "white") == 0)
1797         {
1798             computer = black;
1799             opponent = white;
1800             xwndw = BXWNDW;
1801             flag.force = false;
1802             Sdepth = 0;
1803
1804             /*
1805              * ok = true; don't automatically start with white command
1806              */
1807         }
1808         else if (strcmp(s, "undo") == 0 && GameCnt > 0)
1809         {
1810             Undo();
1811         }
1812         else if (strcmp(s, "remove") == 0 && GameCnt > 1)
1813         {
1814             Undo();
1815             Undo();
1816         }
1817         /* CHECKME: are these next three correct? */
1818         else if (!XSHOGI && strcmp(s, "xget") == 0)
1819         {
1820             GetXGame();
1821         }
1822         else if (!XSHOGI && strcmp(s, "xsave") == 0)
1823         {
1824             SaveXGame();
1825         }
1826         else if (!XSHOGI && strcmp(s, "bsave") == 0)
1827         {
1828             BookSave();
1829         }
1830 #ifdef EASY_OPENINGS
1831         else if ((strcmp(s, "?") == 0)
1832                  || (strcmp(s, "!") == 0)
1833                  || (strcmp(s, "~") == 0))
1834 #else
1835         else if ((strcmp(s, "?") == 0)
1836                  || (strcmp(s, "!") == 0))
1837 #endif
1838         {
1839             FlagMove(*s);
1840         }
1841         else if (strcmp(s, "get") == 0)
1842         {
1843             GetGame();
1844         }
1845         else if (strcmp(s, "save") == 0)
1846         {
1847             SaveGame();
1848         }
1849         else if (strcmp(s, "depth") == 0)
1850         {
1851             dsp->ChangeSearchDepth(sx + strlen("depth"));
1852         }
1853         else if (strcmp(s, "sd") == 0)
1854         {
1855             dsp->ChangeSearchDepth(sx + strlen("sd"));
1856         }
1857         else if (strcmp(s, "hashdepth") == 0)
1858         {
1859             dsp->ChangeHashDepth();
1860         }
1861         else if (strcmp(s, "random") == 0)
1862         {
1863             dither = DITHER;
1864         }
1865         else if (strcmp(s, "hard") == 0)
1866         {
1867             flag.easy = false;
1868         }
1869         else if (strcmp(s, "easy") == 0)
1870         {
1871             flag.easy = !flag.easy;
1872         }
1873         else if (strcmp(s, "tsume") == 0)
1874         {
1875             flag.tsume = !flag.tsume;
1876         }
1877         else if (strcmp(s, "contempt") == 0)
1878         {
1879             dsp->SetContempt();
1880         }
1881         else if (strcmp(s, "xwndw") == 0)
1882         {
1883             dsp->ChangeXwindow();
1884         }
1885         else if (strcmp(s, "rv") == 0)
1886         {
1887             flag.rv = !flag.rv;
1888             dsp->UpdateDisplay(0, 0, 1, 0);
1889         }
1890         else if (strcmp(s, "coords") == 0)
1891         {
1892             flag.coords = !flag.coords;
1893             dsp->UpdateDisplay(0, 0, 1, 0);
1894         }
1895         else if (strcmp(s, "stars") == 0)
1896         {
1897             flag.stars = !flag.stars;
1898             dsp->UpdateDisplay(0, 0, 1, 0);
1899         }
1900         else if (!XSHOGI && strcmp(s, "moves") == 0)
1901         {
1902             short temp;
1903
1904 #if MAXDEPTH > 3
1905             if (GameCnt > 0)
1906             {
1907                 extern unsigned short PrVar[MAXDEPTH];
1908
1909                 SwagHt = (GameList[GameCnt].gmove == PrVar[1])
1910                     ? PrVar[2] : 0;
1911             }
1912             else
1913 #endif
1914                 SwagHt = 0;
1915
1916             dsp->ShowMessage("Testing MoveList Speed");
1917             temp = generate_move_flags;
1918             generate_move_flags = true;
1919             TestSpeed(MoveList, 1);
1920             generate_move_flags = temp;
1921             dsp->ShowMessage("Testing CaptureList Speed");
1922             TestSpeed(CaptureList, 1);
1923             dsp->ShowMessage("Testing Eval Speed");
1924             ExaminePosition(opponent);
1925             TestPSpeed(ScorePosition, 1);
1926         }
1927         else if (!XSHOGI && strcmp(s, "test") == 0)
1928         {
1929 #ifdef SLOW_CPU
1930             dsp->ShowMessage("Testing MoveList Speed");
1931             TestSpeed(MoveList, 2000);
1932             dsp->ShowMessage("Testing CaptureList Speed");
1933             TestSpeed(CaptureList, 3000);
1934             dsp->ShowMessage("Testing Eval Speed");
1935             ExaminePosition(opponent);
1936             TestPSpeed(ScorePosition, 1500);
1937 #else
1938             dsp->ShowMessage("Testing MoveList Speed");
1939             TestSpeed(MoveList, 20000);
1940             dsp->ShowMessage("Testing CaptureList Speed");
1941             TestSpeed(CaptureList, 30000);
1942             dsp->ShowMessage("Testing Eval Speed");
1943             ExaminePosition(opponent);
1944             TestPSpeed(ScorePosition, 15000);
1945 #endif
1946         }
1947         else if (!XSHOGI && strcmp(s, "p") == 0)
1948         {
1949             dsp->ShowPostnValues();
1950         }
1951         else if (!XSHOGI && strcmp(s, "debug") == 0)
1952         {
1953             dsp->DoDebug();
1954         }
1955         else
1956         {
1957             if (flag.mate)
1958             {
1959                 ok = true;
1960             }
1961             else if ((ok = VerifyMove(s, VERIFY_AND_MAKE_MODE, &mv)))
1962             {
1963                 /* check for repetition */
1964                 short rpt = repetition();
1965
1966                 if (rpt >= 3)
1967                 {
1968                     DRAW = DRAW_REPETITION;
1969                     dsp->ShowMessage(DRAW);
1970                     GameList[GameCnt].flags |= draw;
1971
1972                         flag.mate = true;
1973                 }
1974                 else
1975                 {
1976                     is_move = true;
1977                 }
1978             }
1979
1980             Sdepth = 0;
1981         }
1982     }
1983
1984     ElapsedTime(COMPUTE_AND_INIT_MODE);
1985
1986     if (flag.force)
1987     {
1988         computer = opponent;
1989         opponent = computer ^ 1;
1990     }
1991
1992     if (XSHOGI)
1993     {
1994         /* add remaining time in milliseconds for xshogi */
1995         if (is_move)
1996         {
1997             printf("%d. %s %ld\n",
1998                    ++mycnt2, s, TimeControl.clock[player] * 10);
1999         }
2000     }
2001 }