Stop hardcoding filenames inside pat2inc, use commandline parameters.
[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  *
10  * GNU SHOGI is based on GNU CHESS
11  *
12  * Copyright (c) 1988, 1989, 1990 John Stanback
13  * Copyright (c) 1992 Free Software Foundation
14  *
15  * This file is part of GNU SHOGI.
16  *
17  * GNU Shogi is free software; you can redistribute it and/or modify it
18  * under the terms of the GNU General Public License as published by the
19  * Free Software Foundation; either version 3 of the License,
20  * or (at your option) any later version.
21  *
22  * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
23  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with GNU Shogi; see the file COPYING. If not, see
29  * <http://www.gnu.org/licenses/>.
30  * ----------------------------------------------------------------------
31  *
32  */
33
34 /* request *snprintf prototypes */
35 #define _POSIX_C_SOURCE 200112L
36 #include <stdio.h>
37
38 #if defined HAVE_GETTIMEOFDAY
39 #include <sys/time.h>
40 #endif
41
42 #include <ctype.h>
43 #include <signal.h>
44
45 #include <sys/param.h>
46 #include <sys/types.h>
47 #include <sys/file.h>
48
49 #include "gnushogi.h"
50
51 char mvstr[4][6];
52 char *InPtr;
53 int InBackground = false;
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 (!barebones) {
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 (!barebones && (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 void
1318 FlagString(unsigned short flags, char *s)
1319 {
1320     short l, piece;
1321     *s = '\0';
1322
1323     if (flags & promote)
1324         strcat(s, " promote");
1325
1326     if (flags & dropmask)
1327         strcat(s, " drop:");
1328
1329     if ((piece = (flags & pmask)))
1330     {
1331         l = strlen(s);
1332
1333         if (is_promoted[piece])
1334             s[l++] = '+';
1335
1336         s[l++] = pxx[piece];
1337         s[l] = '\0';
1338     }
1339
1340     if (flags & capture)
1341         strcat(s, " capture");
1342
1343     if (flags & exact)
1344         strcat(s, " exact");
1345
1346     if (flags & tesuji)
1347         strcat(s, " tesuji");
1348
1349     if (flags & check)
1350         strcat(s, " check");
1351
1352     if (flags & draw)
1353         strcat(s, " draw");
1354
1355     if (flags & stupid)
1356         strcat(s, " stupid");
1357
1358     if (flags & questionable)
1359         strcat(s, " questionable");
1360
1361     if (flags & kingattack)
1362         strcat(s, " kingattack");
1363
1364     if (flags & book)
1365         strcat(s, " book");
1366 }
1367
1368
1369 static void
1370 TestSpeed(void(*f)(short side, short ply,
1371                    short in_check, short blockable),
1372           unsigned j)
1373 {
1374 #ifdef test
1375     unsigned jj;
1376 #endif
1377
1378     unsigned i;
1379     long cnt, t1, t2;
1380
1381 #ifdef HAVE_GETTIMEOFDAY
1382     struct timeval tv;
1383 #endif
1384
1385 #ifdef HAVE_GETTIMEOFDAY
1386     gettimeofday(&tv, NULL);
1387     t1 = (tv.tv_sec*100 + (tv.tv_usec/10000));
1388 #else
1389     t1 = time(0);
1390 #endif
1391
1392     for (i = 0; i < j; i++)
1393     {
1394         f(opponent, 2, -1, true);
1395
1396 #ifdef test
1397         for (jj = TrPnt[2]; i < TrPnt[3]; jj++)
1398         {
1399             if (!pick(jj, TrPnt[3] - 1))
1400                 break;
1401         }
1402 #endif
1403     }
1404
1405 #ifdef HAVE_GETTIMEOFDAY
1406     gettimeofday(&tv, NULL);
1407     t2 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1408 #else
1409     t2 = time(0);
1410 #endif
1411
1412     cnt = j * (TrPnt[3] - TrPnt[2]);
1413
1414     if (t2 - t1)
1415         et = (t2 - t1);
1416     else
1417         et = 1;
1418
1419     dsp->ShowNodeCnt(cnt);
1420 }
1421
1422
1423 static void
1424 TestPSpeed(short(*f) (short side), unsigned j)
1425 {
1426     unsigned i;
1427     long cnt, t1, t2;
1428 #ifdef HAVE_GETTIMEOFDAY
1429     struct timeval tv;
1430 #endif
1431
1432 #ifdef HAVE_GETTIMEOFDAY
1433     gettimeofday(&tv, NULL);
1434     t1 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1435 #else
1436     t1 = time(0);
1437 #endif
1438
1439     for (i = 0; i < j; i++)
1440         (void) f(opponent);
1441
1442 #ifdef HAVE_GETTIMEOFDAY
1443     gettimeofday(&tv, NULL);
1444     t2 = (tv.tv_sec * 100 + (tv.tv_usec / 10000));
1445 #else
1446     t2 = time(0);
1447 #endif
1448
1449     cnt = j;
1450
1451     if (t2 - t1)
1452         et = (t2 - t1);
1453     else
1454         et = 1;
1455
1456     dsp->ShowNodeCnt(cnt);
1457 }
1458
1459
1460 static void
1461 SetOppTime(char *time)
1462 {
1463     int m, t, sec;
1464
1465     sec = 0;
1466     t = (int)strtol(time, &time, 10);
1467
1468     if (*time == ':')
1469     {
1470         time++;
1471         /* FIXME: sec is parsed but ignored */
1472         sec = (int)strtol(time, &time, 10);
1473     }
1474
1475     m = (int)strtol(time, &time, 10);
1476
1477     if (t)
1478         TimeControl.clock[opponent] = t;
1479
1480     if (m)
1481         TimeControl.moves[opponent] = m;
1482
1483     ElapsedTime(COMPUTE_AND_INIT_MODE);
1484
1485     if (XSHOGI)
1486     {
1487         /* just to inform xshogi about availability of otime command */
1488         printf("otime %d %d\n", t, m);
1489     }
1490 }
1491
1492
1493 static void
1494 SetMachineTime(char *time)
1495 {
1496     int m, t, sec;
1497
1498     sec = 0;
1499     t = (int)strtol(time, &time, 10);
1500
1501     if (*time == ':')
1502     {
1503         time++;
1504         /* FIXME: sec is parsed but ignored */
1505         sec = (int)strtol(time, &time, 10);
1506     }
1507
1508     m = (int)strtol(time, &time, 10);
1509
1510     if (t)
1511         TimeControl.clock[computer] = t;
1512
1513     if (m)
1514         TimeControl.moves[computer] = m;
1515
1516     ElapsedTime(COMPUTE_AND_INIT_MODE);
1517
1518     if (XSHOGI)
1519     {
1520         /* just to inform xshogi about availability of time command */
1521         printf("time %d %d\n", t, m);
1522     }
1523 }
1524
1525
1526 /* FIXME!  This is truly the function from hell! */
1527
1528 /*
1529  * Process the user's command. If easy mode is OFF (the computer is thinking
1530  * on opponents time) and the program is out of book, then make the 'hint'
1531  * move on the board and call SelectMove() to find a response. The user
1532  * terminates the search by entering a command. If the opponent does not make
1533  * the hint move, then set Sdepth to zero.
1534  */
1535
1536 void
1537 InputCommand(char *command)
1538 {
1539     short have_shown_prompt = false;
1540     short ok, done, is_move = false;
1541     unsigned short mv;
1542     char s[80], sx[80];
1543
1544     ok = flag.quit = done = false;
1545     player = opponent;
1546
1547 #if ttblsz
1548     if (TTadd > ttbllimit)
1549         ZeroTTable();
1550 #endif
1551
1552     if ((hint > 0) && !flag.easy && !flag.force)
1553     {
1554         /*
1555          * A hint move for the player is available.  Compute a move for the
1556          * opponent in background mode assuming that the hint move will be
1557          * selected by the player.
1558          */
1559
1560         ft = time0; /* Save reference time for the player. */
1561         fflush(stdout);
1562         algbr((short) hint >> 8, (short) hint & 0xff, false);
1563         strcpy(s, mvstr[0]);
1564
1565         if (flag.post)
1566             dsp->GiveHint();
1567
1568         /* do the hint move */
1569         if (VerifyMove(s, VERIFY_AND_TRY_MODE, &mv))
1570         {
1571             Sdepth = 0;
1572
1573 #ifdef QUIETBACKGROUND
1574             dsp->ShowPrompt();
1575             have_shown_prompt = true;
1576 #endif /* QUIETBACKGROUND */
1577
1578             /* Start computing a move until the search is interrupted. */
1579
1580 #ifdef INTERRUPT_TEST
1581             itime0 = 0;
1582 #endif
1583
1584             /* would love to put null move in here */
1585             /* after we make the hint move make a 2 ply search
1586              * with both plys our moves */
1587             /* think on opponents time */
1588             SelectMove(computer, BACKGROUND_MODE);
1589
1590 #ifdef INTERRUPT_TEST
1591             ElapsedTime(COMPUTE_INTERRUPT_MODE);
1592
1593             if (itime0 == 0)
1594             {
1595                 printf("searching not terminated by interrupt!\n");
1596             }
1597             else
1598             {
1599                 printf("elapsed time from interrupt to "
1600                        "terminating search: %ld\n", it);
1601             }
1602 #endif
1603
1604             /* undo the hint and carry on */
1605             VerifyMove(s, UNMAKE_MODE, &mv);
1606             Sdepth = 0;
1607         }
1608
1609         time0 = ft; /* Restore reference time for the player. */
1610     }
1611
1612     while(!(ok || flag.quit || done))
1613     {
1614         player = opponent;
1615
1616 #ifdef QUIETBACKGROUND
1617         if (!have_shown_prompt)
1618         {
1619 #endif /* QUIETBACKGROUND */
1620
1621             dsp->ShowPrompt();
1622
1623 #ifdef QUIETBACKGROUND
1624         }
1625
1626         have_shown_prompt = false;
1627 #endif /* QUIETBACKGROUND */
1628
1629         if (command == NULL) {
1630             int eof = dsp->GetString(sx);
1631             if (eof)
1632                 dsp->ExitShogi();
1633         } else {
1634             strcpy(sx, command);
1635             done = true;
1636         }
1637
1638         /* extract first word */
1639         if (sscanf(sx, "%s", s) < 1)
1640             continue;
1641
1642         if (strcmp(s, "bd") == 0)   /* bd -- display board */
1643         {
1644             /* FIXME: Hack alert! */
1645             short old_xshogi = XSHOGI;
1646
1647             if (old_xshogi)
1648                 display_type = DISPLAY_RAW;
1649
1650             dsp->ClearScreen();
1651             dsp->UpdateDisplay(0, 0, 1, 0);
1652
1653             if (old_xshogi)
1654                 display_type = DISPLAY_X;
1655         }
1656         else if (strcmp(s, "post") == 0)
1657         {
1658             flag.post = !flag.post;
1659         }
1660         else if (strcmp(s, "alg") == 0)
1661         {
1662             /* noop */ ;
1663         }
1664         else if ((strcmp(s, "quit") == 0)
1665                  || (strcmp(s, "exit") == 0))
1666         {
1667             flag.quit = true;
1668         }
1669         else if ((strcmp(s, "set") == 0)
1670                  || (strcmp(s, "edit") == 0))
1671         {
1672             dsp->EditBoard();
1673         }
1674         else if (strcmp(s, "setup") == 0)
1675         {
1676             dsp->SetupBoard();
1677         }
1678         else if (strcmp(s, "first") == 0)
1679         {
1680             ok = true;
1681         }
1682         else if (strcmp(s, "go") == 0)
1683         {
1684             ok = true;
1685             flag.force = false;
1686
1687             if (computer == black)
1688             {
1689                 computer = white;
1690                 opponent = black;
1691             }
1692             else
1693             {
1694                 computer = black;
1695                 opponent = white;
1696             }
1697         }
1698         else if (strcmp(s, "help") == 0)
1699         {
1700             dsp->help();
1701         }
1702         else if (strcmp(s, "material") == 0)
1703         {
1704             flag.material = !flag.material;
1705         }
1706         else if (strcmp(s, "force") == 0)
1707         {
1708             if (XSHOGI)
1709             {
1710                 flag.force = true;
1711                 flag.bothsides = false;
1712             }
1713             else
1714             {
1715                 flag.force = !flag.force;
1716                 flag.bothsides = false;
1717             }
1718         }
1719         else if (strcmp(s, "book") == 0)
1720         {
1721             Book = Book ? 0 : BOOKFAIL;
1722         }
1723         else if (strcmp(s, "new") == 0)
1724         {
1725             NewGame();
1726             dsp->UpdateDisplay(0, 0, 1, 0);
1727         }
1728         else if (strcmp(s, "list") == 0)
1729         {
1730             ListGame();
1731         }
1732         else if (strcmp(s, "level") == 0)
1733         {
1734             dsp->SelectLevel(sx + strlen("level"));
1735         }
1736         else if (strcmp(s, "clock") == 0)
1737         {
1738             dsp->SelectLevel(sx + strlen("clock"));
1739         }
1740         else if (strcmp(s, "hash") == 0)
1741         {
1742             flag.hash = !flag.hash;
1743         }
1744         else if (strcmp(s, "gamein") == 0)
1745         {
1746             flag.gamein = !flag.gamein;
1747         }
1748         else if (strcmp(s, "beep") == 0)
1749         {
1750             flag.beep = !flag.beep;
1751         }
1752         else if (strcmp(s, "time") == 0)
1753         {
1754             SetMachineTime(sx + strlen("time"));
1755         }
1756         else if (strcmp(s, "otime") == 0)
1757         {
1758             SetOppTime(sx + strlen("otime"));
1759         }
1760         else if (strcmp(s, "Awindow") == 0)
1761         {
1762             dsp->ChangeAlphaWindow();
1763         }
1764         else if (strcmp(s, "Bwindow") == 0)
1765         {
1766             dsp->ChangeBetaWindow();
1767         }
1768         else if (strcmp(s, "rcptr") == 0)
1769         {
1770             flag.rcptr = !flag.rcptr;
1771         }
1772         else if (strcmp(s, "hint") == 0)
1773         {
1774             dsp->GiveHint();
1775         }
1776         else if (strcmp(s, "both") == 0)
1777         {
1778             flag.bothsides = !flag.bothsides;
1779             flag.force = false;
1780             Sdepth = 0;
1781             ElapsedTime(COMPUTE_AND_INIT_MODE);
1782             SelectMove(opponent, FOREGROUND_MODE);
1783             ok = true;
1784         }
1785         else if (strcmp(s, "reverse") == 0)
1786         {
1787             flag.reverse = !flag.reverse;
1788             dsp->ClearScreen();
1789             dsp->UpdateDisplay(0, 0, 1, 0);
1790         }
1791         else if (strcmp(s, "switch") == 0)
1792         {
1793             computer = computer ^ 1;
1794             opponent = opponent ^ 1;
1795             xwndw = (computer == black) ? WXWNDW : BXWNDW;
1796             flag.force = false;
1797             Sdepth = 0;
1798             ok = true;
1799         }
1800         else if (strcmp(s, "black") == 0)
1801         {
1802             computer = white;
1803             opponent = black;
1804             xwndw = WXWNDW;
1805             flag.force = false;
1806             Sdepth = 0;
1807
1808             /*
1809              * ok = true; don't automatically start with black command
1810              */
1811         }
1812         else if (strcmp(s, "white") == 0)
1813         {
1814             computer = black;
1815             opponent = white;
1816             xwndw = BXWNDW;
1817             flag.force = false;
1818             Sdepth = 0;
1819
1820             /*
1821              * ok = true; don't automatically start with white command
1822              */
1823         }
1824         else if (strcmp(s, "undo") == 0 && GameCnt > 0)
1825         {
1826             Undo();
1827         }
1828         else if (strcmp(s, "remove") == 0 && GameCnt > 1)
1829         {
1830             Undo();
1831             Undo();
1832         }
1833         /* CHECKME: are these next three correct? */
1834         else if (!XSHOGI && strcmp(s, "xget") == 0)
1835         {
1836             GetXGame();
1837         }
1838         else if (!XSHOGI && strcmp(s, "xsave") == 0)
1839         {
1840             SaveXGame();
1841         }
1842         else if (!XSHOGI && strcmp(s, "bsave") == 0)
1843         {
1844             BookSave();
1845         }
1846 #ifdef EASY_OPENINGS
1847         else if ((strcmp(s, "?") == 0)
1848                  || (strcmp(s, "!") == 0)
1849                  || (strcmp(s, "~") == 0))
1850 #else
1851         else if ((strcmp(s, "?") == 0)
1852                  || (strcmp(s, "!") == 0))
1853 #endif
1854         {
1855             FlagMove(*s);
1856         }
1857         else if (strcmp(s, "get") == 0)
1858         {
1859             GetGame();
1860         }
1861         else if (strcmp(s, "save") == 0)
1862         {
1863             SaveGame();
1864         }
1865         else if (strcmp(s, "depth") == 0)
1866         {
1867             dsp->ChangeSearchDepth(sx + strlen("depth"));
1868         }
1869         else if (strcmp(s, "sd") == 0)
1870         {
1871             dsp->ChangeSearchDepth(sx + strlen("sd"));
1872         }
1873         else if (strcmp(s, "hashdepth") == 0)
1874         {
1875             dsp->ChangeHashDepth();
1876         }
1877         else if (strcmp(s, "random") == 0)
1878         {
1879             dither = DITHER;
1880         }
1881         else if (strcmp(s, "hard") == 0)
1882         {
1883             flag.easy = false;
1884         }
1885         else if (strcmp(s, "easy") == 0)
1886         {
1887             flag.easy = !flag.easy;
1888         }
1889         else if (strcmp(s, "tsume") == 0)
1890         {
1891             flag.tsume = !flag.tsume;
1892         }
1893         else if (strcmp(s, "contempt") == 0)
1894         {
1895             dsp->SetContempt();
1896         }
1897         else if (strcmp(s, "xwndw") == 0)
1898         {
1899             dsp->ChangeXwindow();
1900         }
1901         else if (strcmp(s, "rv") == 0)
1902         {
1903             flag.rv = !flag.rv;
1904             dsp->UpdateDisplay(0, 0, 1, 0);
1905         }
1906         else if (strcmp(s, "coords") == 0)
1907         {
1908             flag.coords = !flag.coords;
1909             dsp->UpdateDisplay(0, 0, 1, 0);
1910         }
1911         else if (strcmp(s, "stars") == 0)
1912         {
1913             flag.stars = !flag.stars;
1914             dsp->UpdateDisplay(0, 0, 1, 0);
1915         }
1916         else if (!XSHOGI && strcmp(s, "moves") == 0)
1917         {
1918             short temp;
1919
1920 #if MAXDEPTH > 3
1921             if (GameCnt > 0)
1922             {
1923                 extern unsigned short PrVar[MAXDEPTH];
1924
1925                 SwagHt = (GameList[GameCnt].gmove == PrVar[1])
1926                     ? PrVar[2] : 0;
1927             }
1928             else
1929 #endif
1930                 SwagHt = 0;
1931
1932             dsp->ShowMessage("Testing MoveList Speed");
1933             temp = generate_move_flags;
1934             generate_move_flags = true;
1935             TestSpeed(MoveList, 1);
1936             generate_move_flags = temp;
1937             dsp->ShowMessage("Testing CaptureList Speed");
1938             TestSpeed(CaptureList, 1);
1939             dsp->ShowMessage("Testing Eval Speed");
1940             ExaminePosition(opponent);
1941             TestPSpeed(ScorePosition, 1);
1942         }
1943         else if (!XSHOGI && strcmp(s, "test") == 0)
1944         {
1945 #ifdef SLOW_CPU
1946             dsp->ShowMessage("Testing MoveList Speed");
1947             TestSpeed(MoveList, 2000);
1948             dsp->ShowMessage("Testing CaptureList Speed");
1949             TestSpeed(CaptureList, 3000);
1950             dsp->ShowMessage("Testing Eval Speed");
1951             ExaminePosition(opponent);
1952             TestPSpeed(ScorePosition, 1500);
1953 #else
1954             dsp->ShowMessage("Testing MoveList Speed");
1955             TestSpeed(MoveList, 20000);
1956             dsp->ShowMessage("Testing CaptureList Speed");
1957             TestSpeed(CaptureList, 30000);
1958             dsp->ShowMessage("Testing Eval Speed");
1959             ExaminePosition(opponent);
1960             TestPSpeed(ScorePosition, 15000);
1961 #endif
1962         }
1963         else if (!XSHOGI && strcmp(s, "p") == 0)
1964         {
1965             dsp->ShowPostnValues();
1966         }
1967         else if (!XSHOGI && strcmp(s, "debug") == 0)
1968         {
1969             dsp->DoDebug();
1970         }
1971         else
1972         {
1973             if (flag.mate)
1974             {
1975                 ok = true;
1976             }
1977             else if ((ok = VerifyMove(s, VERIFY_AND_MAKE_MODE, &mv)))
1978             {
1979                 /* check for repetition */
1980                 short rpt = repetition();
1981
1982                 if (rpt >= 3)
1983                 {
1984                     DRAW = DRAW_REPETITION;
1985                     dsp->ShowMessage(DRAW);
1986                     GameList[GameCnt].flags |= draw;
1987
1988                         flag.mate = true;
1989                 }
1990                 else
1991                 {
1992                     is_move = true;
1993                 }
1994             }
1995
1996             Sdepth = 0;
1997         }
1998     }
1999
2000     ElapsedTime(COMPUTE_AND_INIT_MODE);
2001
2002     if (flag.force)
2003     {
2004         computer = opponent;
2005         opponent = computer ^ 1;
2006     }
2007
2008     if (XSHOGI)
2009     {
2010         /* add remaining time in milliseconds for xshogi */
2011         if (is_move)
2012         {
2013             printf("%d. %s %ld\n",
2014                    ++mycnt2, s, TimeControl.clock[player] * 10);
2015         }
2016
2017 #ifdef notdef /* optional pass best line to frontend with move */
2018         if (flag.post && !flag.mate)
2019         {
2020             int i;
2021
2022             printf(" %6d ", MSCORE);
2023
2024             for (i = 1; MV[i] > 0; i++)
2025             {
2026                 algbr((short) (MV[i] >> 8), (short) (MV[i] & 0xFF), false);
2027                 printf("%5s ", mvstr[0]);
2028             }
2029         }
2030         printf("\n");
2031 #endif
2032     }
2033 }
2034
2035
2036 void
2037 SetTimeControl(void)
2038 {
2039     if (TCflag)
2040     {
2041         TimeControl.moves[black] = TimeControl.moves[white] = TCmoves;
2042         TimeControl.clock[black] += 6000L * TCminutes + TCseconds * 100;
2043         TimeControl.clock[white] += 6000L * TCminutes + TCseconds * 100;
2044     }
2045     else
2046     {
2047         TimeControl.moves[black] = TimeControl.moves[white] = 0;
2048         TimeControl.clock[black] = TimeControl.clock[white] = 0;
2049     }
2050
2051     flag.onemove = (TCmoves == 1);
2052     et = 0;
2053     ElapsedTime(COMPUTE_AND_INIT_MODE);
2054 }