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