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