4 * Common display routines for GNU Shogi.
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
11 * GNU SHOGI is based on GNU CHESS
13 * Copyright (c) 1988, 1989, 1990 John Stanback
14 * Copyright (c) 1992 Free Software Foundation
16 * This file is part of GNU SHOGI.
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.
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
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 * ----------------------------------------------------------------------
35 /* request *snprintf prototypes */
36 #define _POSIX_C_SOURCE 200112L
42 #if defined HAVE_GETTIMEOFDAY
49 #include <sys/param.h>
50 #include <sys/types.h>
56 struct display
*dsp
= &raw_display
;
63 movealgbr(short m
, char *s
)
66 short piece
= 0, flag
= 0;
79 piece
= f
- NO_SQUARES
;
81 if (piece
> NO_PIECES
)
84 flag
= (dropmask
| piece
);
99 *s
= COL_NAME(column(t
));
101 *s
= ROW_NAME(row(t
));
106 *s
= COL_NAME(column(f
));
108 *s
= ROW_NAME(row(f
));
110 *s
= COL_NAME(column(t
));
112 *s
= ROW_NAME(row(t
));
131 #endif /* BOOKTEST */
135 * Generate move strings in different formats.
138 * - f piece to be moved
139 * - 0 < f < NO_SQUARES source square
140 * - NO_SQUARES <= f NO_SQUARES + 2*NO_PIECES dropped piece modulo NO_PIECES
141 * - t & 0x7f target square
142 * - t & 0x80 promotion flag
144 * - if flag & dropmask, piece type encoded in flag & pmask
146 * FIXME: that makes 2 ways to specify drops and promotions, why ?
153 algbr(short f
, short t
, short flags
)
159 piece
= f
- NO_SQUARES
;
161 if (f
> (NO_SQUARES
+ NO_PIECES
))
164 flags
= (dropmask
| piece
);
173 if ((f
== t
) && ((f
!= 0) || (t
!= 0)))
176 dsp
->Printf("error in algbr: FROM=TO=%d, flags=0x%4x\n", t
, flags
);
179 mvstr
[0][0] = mvstr
[1][0] = mvstr
[2][0] = mvstr
[3][0] = '\0';
181 else if ((flags
& dropmask
) != 0)
183 short piece
= flags
& pmask
;
185 mvstr
[0][0] = pxx
[piece
];
186 mvstr
[0][1] = xboard
? '@' : '*';
187 mvstr
[0][2] = COL_NAME(column(t
));
188 mvstr
[0][3] = ROW_NAME(row(t
));
190 strcpy(mvstr
[1], mvstr
[0]);
191 strcpy(mvstr
[2], mvstr
[0]);
192 strcpy(mvstr
[3], mvstr
[0]);
194 else if ((f
!= 0) || (t
!= 0))
196 /* pure coordinates notation */
197 mvstr
[0][0] = COL_NAME(column(f
));
198 mvstr
[0][1] = ROW_NAME(row(f
));
199 mvstr
[0][2] = COL_NAME(column(t
));
200 mvstr
[0][3] = ROW_NAME(row(t
));
203 /* algebraic notation without disambiguation */
204 mvstr
[1][0] = pxx
[board
[f
]];
205 mvstr
[1][1] = mvstr
[0][2]; /* to column */
206 mvstr
[1][2] = mvstr
[0][3]; /* to row */
209 /* algebraic notation with row disambiguation */
210 mvstr
[2][0] = mvstr
[1][0];
211 mvstr
[2][1] = mvstr
[0][1];
212 mvstr
[2][2] = mvstr
[0][2]; /* to column */
213 mvstr
[2][3] = mvstr
[0][3]; /* to row */
216 /* algebraic notation with column disambiguation */
217 strcpy(mvstr
[3], mvstr
[2]);
218 mvstr
[3][1] = mvstr
[0][0];
222 strcat(mvstr
[0], "+");
223 strcat(mvstr
[1], "+");
224 strcat(mvstr
[2], "+");
225 strcat(mvstr
[3], "+");
230 mvstr
[0][0] = mvstr
[1][0] = mvstr
[2][0] = mvstr
[3][0] = '\0';
236 * Compare the string 's' to the list of legal moves available for the
237 * opponent. If a match is found, make the move on the board.
241 VerifyMove(char *s
, VerifyMove_mode iop
, unsigned short *mv
)
243 static short pnt
, tempb
, tempc
, tempsf
, tempst
, cnt
;
244 static struct leaf xnode
;
246 short i
, l
, local_flags
;
249 /* check and remove quality flags */
250 for (i
= local_flags
= 0, l
= strlen(s
); i
< l
; i
++)
255 local_flags
|= badmove
;
260 local_flags
|= goodmove
;
266 local_flags
|= difficult
;
275 if (iop
== UNMAKE_MODE
)
277 UnmakeMove(opponent
, &xnode
, &tempb
, &tempc
, &tempsf
, &tempst
);
283 if (iop
== VERIFY_AND_MAKE_MODE
)
284 generate_move_flags
= true;
286 MoveList(opponent
, 2, -1, true);
287 generate_move_flags
= false;
289 if(s
[4] == '=') s
[4] = '\0'; /* deferral is implied */
291 while (pnt
< TrPnt
[3])
294 algbr(node
->f
, node
->t
, (short) node
->flags
);
296 if ((strcmp(s
, mvstr
[0]) == 0)
297 || (strcmp(s
, mvstr
[1]) == 0)
298 || (strcmp(s
, mvstr
[2]) == 0)
299 || (strcmp(s
, mvstr
[3]) == 0))
306 if ((cnt
== 1) && (xnode
.score
> DONTUSE
))
310 MakeMove(opponent
, &xnode
, &tempb
, &tempc
,
311 &tempsf
, &tempst
, &INCscore
);
313 if (SqAttacked(PieceList
[opponent
][0], computer
, &blocked
))
315 UnmakeMove(opponent
, &xnode
, &tempb
, &tempc
, &tempsf
, &tempst
);
316 dsp
->AlwaysShowMessage("Illegal move (in check): %s", s
);
321 if (iop
== VERIFY_AND_TRY_MODE
)
324 dsp
->UpdateDisplay(xnode
.f
, xnode
.t
, 0, (short) xnode
.flags
);
325 GameList
[GameCnt
].depth
= GameList
[GameCnt
].score
= 0;
326 GameList
[GameCnt
].nodes
= 0;
327 ElapsedTime(COMPUTE_AND_INIT_MODE
);
328 GameList
[GameCnt
].time
= (short) (et
+ 50)/100;
329 GameList
[GameCnt
].flags
|= local_flags
;
333 TimeControl
.clock
[opponent
] -= et
;
334 timeopp
[oppptr
] = et
;
335 --TimeControl
.moves
[opponent
];
338 *mv
= (xnode
.f
<< 8) | xnode
.t
;
339 algbr(xnode
.f
, xnode
.t
, 0);
341 /* in force mode, check for mate conditions */
344 if (IsCheckmate(opponent
^ 1, -1, -1))
348 sprintf(buf
, "%s mates!\n", ColorStr
[opponent
]);
349 dsp
->ShowMessage(buf
);
358 dsp
->AlwaysShowMessage("Illegal move (no match): %s", s
);
360 if (!XSHOGI
&& (cnt
> 1))
362 sprintf(buffer
, "Ambiguous Move %s!", s
);
363 dsp
->ShowMessage(buffer
);
371 parser(char *f
, short *fpiece
)
379 for (i
= 1, *fpiece
= no_piece
; i
< NO_PIECES
; i
++)
381 if (f
[0] == pxx
[i
] || f
[0] == qxx
[i
])
383 *fpiece
= (p
? promoted
[i
] : unpromoted
[i
]);
388 if (f
[1] == '*' || f
[1] == '\'')
393 return ((NO_SQUARES
+ *fpiece
) << 8) | locn(r2
, c2
);
401 p
= (f
[5] == '+') ? 0x80 : 0;
403 return (locn(r1
, c1
) << 8) | locn(r2
, c2
) | p
;
411 while (*InPtr
!= ' ')
414 while (*InPtr
== ' ')
422 while (*InPtr
== ' ')
427 void RequestInputString(char* buffer
, unsigned bufsize
)
430 int ret
= snprintf(fmt
, sizeof(fmt
), "%%%us", bufsize
);
432 perror("RequestInputString snprintf");
435 if (ret
>= sizeof(fmt
)) {
437 "Insufficient format-buffer size in %s for bufsize=%u\n",
438 __FUNCTION__
, bufsize
);
441 dsp
->doRequestInputString(fmt
, buffer
);
455 strcpy(fname
, savefile
);
457 dsp
->ShowMessage("Enter file name: ");
458 RequestInputString(fname
, sizeof(fname
)-1);
461 if (fname
[0] == '\0')
462 strcpy(fname
, "shogi.000");
464 if ((fd
= fopen(fname
, "r")) != NULL
)
467 fgets(fname
, 256, fd
);
468 computer
= opponent
= black
;
477 /* FIXME: write a skipn() function so that we can get
478 * 3 skips by doing skipn(3) */
482 Game50
= atoi(InPtr
);
484 flag
.force
= (*InPtr
== 'f');
485 fgets(fname
, 256, fd
); /* empty */
486 fgets(fname
, 256, fd
);
489 TCflag
= atoi(InPtr
);
493 OperatorTime
= atoi(InPtr
);
494 fgets(fname
, 256, fd
);
497 TimeControl
.clock
[black
] = atol(InPtr
);
500 TimeControl
.moves
[black
] = atoi(InPtr
);
501 fgets(fname
, 256, fd
);
504 TimeControl
.clock
[white
] = atol(InPtr
);
507 TimeControl
.moves
[white
] = atoi(InPtr
);
508 fgets(fname
, 256, fd
); /* empty */
510 for (i
= NO_ROWS
- 1; i
> -1; i
--)
512 fgets(fname
, 256, fd
);
516 for (j
= 0; j
< NO_COLS
; j
++)
518 sq
= i
* NO_COLS
+ j
;
524 board
[sq
] = no_piece
;
529 for (c
= 0; c
< NO_PIECES
; c
++)
534 board
[sq
] = promoted
[c
];
536 board
[sq
] = unpromoted
[c
];
542 for (c
= 0; c
< NO_PIECES
; c
++)
547 board
[sq
] = promoted
[c
];
549 board
[sq
] = unpromoted
[c
];
557 Mvboard
[sq
] = atoi(InPtr
);
562 fgets(fname
, 256, fd
); /* empty */
563 fgets(fname
, 256, fd
); /* 9 8 7 ... */
564 fgets(fname
, 256, fd
); /* empty */
565 fgets(fname
, 256, fd
); /* p l n ... */
568 for (side
= 0; side
<= 1; side
++)
570 fgets(fname
, 256, fd
);
574 Captured
[side
][pawn
] = atoi(InPtr
);
577 Captured
[side
][lance
] = atoi(InPtr
);
579 Captured
[side
][knight
] = atoi(InPtr
);
582 Captured
[side
][silver
] = atoi(InPtr
);
584 Captured
[side
][gold
] = atoi(InPtr
);
586 Captured
[side
][bishop
] = atoi(InPtr
);
588 Captured
[side
][rook
] = atoi(InPtr
);
590 Captured
[side
][king
] = atoi(InPtr
);
594 flag
.regularstart
= true;
596 fgets(fname
, 256, fd
); /* empty */
597 fgets(fname
, 256, fd
); /* move score ... */
599 while (fgets(fname
, 256, fd
))
608 g
= &GameList
[GameCnt
];
609 g
->gmove
= parser(InPtr
, &g
->fpiece
);
611 g
->score
= atoi(InPtr
);
613 g
->depth
= atoi(InPtr
);
615 g
->nodes
= atol(InPtr
);
617 g
->time
= atol(InPtr
);
619 g
->flags
= c
= atoi(InPtr
);
621 g
->hashkey
= strtol(InPtr
, (char **) NULL
, 16);
623 g
->hashbd
= strtol(InPtr
, (char **) NULL
, 16);
631 for (piece
= no_piece
, i
= 0; i
< NO_PIECES
; i
++)
633 if (pxx
[i
] == *InPtr
)
641 g
->color
= ((*InPtr
== 'W') ? white
: black
);
643 g
->piece
= (*InPtr
== '+'
645 : unpromoted
[piece
]);
654 if (TimeControl
.clock
[black
] > 0)
662 dsp
->UpdateDisplay(0, 0, 1, 0);
673 short sq
, i
, c
, f
, t
;
676 char empty
[2] = "\n";
679 strcpy(fname
, savefile
);
681 dsp
->ShowMessage("Enter file name: ");
682 RequestInputString(fname
, sizeof(fname
)-1);
685 if (fname
[0] == '\0')
686 strcpy(fname
, "shogi.000");
688 if ((fd
= fopen(fname
, "w")) != NULL
)
693 if (computer
== white
)
696 if (computer
== black
)
699 fprintf(fd
, "White %s Black %s %d %s\n", w
, b
, Game50
,
700 flag
.force
? "force" : "");
702 fprintf(fd
, "TimeControl %d Operator Time %d\n", TCflag
, OperatorTime
);
703 fprintf(fd
, "Black Clock %ld Moves %d\nWhite Clock %ld Moves %d\n",
704 TimeControl
.clock
[black
], TimeControl
.moves
[black
],
705 TimeControl
.clock
[white
], TimeControl
.moves
[white
]);
708 for (i
= NO_ROWS
- 1; i
> -1; i
--)
710 fprintf(fd
, "%c ", ROW_NAME(i
));
712 for (c
= 0; c
< NO_COLS
; c
++)
714 sq
= i
* NO_COLS
+ c
;
716 p
= is_promoted
[piece
] ? '+' : ' ';
717 fprintf(fd
, "%c", p
);
733 fprintf(fd
, "%c", p
);
738 for (f
= i
* NO_COLS
; f
< i
* NO_COLS
+ NO_ROWS
; f
++)
739 fprintf(fd
, " %d", Mvboard
[f
]);
746 fprintf(fd
, " 9 8 7 6 5 4 3 2 1\n");
748 fprintf(fd
, " p l n s g b r k\n");
750 fprintf(fd
, " 5 4 3 2 1\n");
752 fprintf(fd
, " p s g b r k\n");
755 for (side
= 0; side
<= 1; side
++)
757 fprintf(fd
, "%c", (side
== black
) ? 'B' : 'W');
758 fprintf(fd
, " %2d", Captured
[side
][pawn
]);
760 fprintf(fd
, " %2d", Captured
[side
][lance
]);
761 fprintf(fd
, " %2d", Captured
[side
][knight
]);
763 fprintf(fd
, " %2d", Captured
[side
][silver
]);
764 fprintf(fd
, " %2d", Captured
[side
][gold
]);
765 fprintf(fd
, " %2d", Captured
[side
][bishop
]);
766 fprintf(fd
, " %2d", Captured
[side
][rook
]);
767 fprintf(fd
, " %2d", Captured
[side
][king
]);
772 fputs(" move score depth nodes time flags capture\n", fd
);
774 for (i
= 1; i
<= GameCnt
; i
++)
776 struct GameRec
*g
= &GameList
[i
];
779 t
= (g
->gmove
& 0xFF);
780 algbr(f
, t
, g
->flags
);
782 fprintf(fd
, "%c%c%-5s %6d %5d %7ld %6ld %5d 0x%08lx 0x%08lx",
785 : (is_promoted
[g
->fpiece
] ? '+' : ' ')),
787 ((f
> NO_SQUARES
) ? &mvstr
[0][1] : mvstr
[0]),
789 g
->nodes
, g
->time
, g
->flags
,
790 g
->hashkey
, g
->hashbd
);
792 if (g
->piece
!= no_piece
)
794 fprintf(fd
, " %c %s %c\n",
795 pxx
[g
->piece
], ColorStr
[g
->color
],
796 (is_promoted
[g
->piece
] ? '+' : ' '));
806 dsp
->ShowMessage("Game saved");
810 dsp
->ShowMessage("Could not open file");
816 * GetXGame, SaveXGame and BookGame used to only be defined if
817 * xshogi wasn't defined -- wonder why?
829 dsp
->ShowMessage("Enter file name: ");
830 RequestInputString(fname
, sizeof(fname
)-1);
832 if (fname
[0] == '\0')
833 strcpy(fname
, "xshogi.position.read");
835 if ((fd
= fopen(fname
, "r")) != NULL
)
838 flag
.regularstart
= false;
841 /* xshogi position file ... */
842 fgets(fname
, 256, fd
);
847 if (strcmp(fname
, "xshogi"))
851 /* -- empty line -- */
852 fgets(fname
, 256, fd
);
853 /* -- empty line -- */
854 fgets(fname
, 256, fd
);
856 for (i
= NO_ROWS
- 1; i
> -1; i
--)
858 fgets(fname
, 256, fd
);
861 for (j
= 0; j
< NO_COLS
; j
++)
863 sq
= i
* NO_COLS
+ j
;
869 board
[sq
] = no_piece
;
874 for (c
= 0; c
< NO_PIECES
; c
++)
879 board
[sq
] = promoted
[c
];
881 board
[sq
] = unpromoted
[c
];
887 for (c
= 0; c
< NO_PIECES
; c
++)
892 board
[sq
] = promoted
[c
];
894 board
[sq
] = unpromoted
[c
];
907 for (side
= 0; side
<= 1; side
++)
909 fgets(fname
, 256, fd
);
911 Captured
[side
][pawn
] = atoi(InPtr
);
914 Captured
[side
][lance
] = atoi(InPtr
);
916 Captured
[side
][knight
] = atoi(InPtr
);
919 Captured
[side
][silver
] = atoi(InPtr
);
921 Captured
[side
][gold
] = atoi(InPtr
);
923 Captured
[side
][bishop
] = atoi(InPtr
);
925 Captured
[side
][rook
] = atoi(InPtr
);
927 Captured
[side
][king
] = atoi(InPtr
);
930 if (fgets(fname
, 256, fd
) != NULL
&& strncmp(fname
, "white", 5) == 0)
943 dsp
->UpdateDisplay(0, 0, 1, 0);
958 dsp
->ShowMessage("Enter file name: ");
959 RequestInputString(fname
, sizeof(fname
)-1);
961 if (fname
[0] == '\0')
962 strcpy(fname
, "xshogi.position.read");
964 if ((fd
= fopen(fname
, "w")) != NULL
)
966 fputs("# xshogi position file -- \n", fd
);
970 for (i
= NO_ROWS
- 1; i
> -1; i
--)
974 for (j
= 0; j
< NO_COLS
; j
++)
976 sq
= i
* NO_COLS
+ j
;
978 isp
= is_promoted
[piece
];
979 *p
= (isp
? '+' : ' ');
982 if (piece
== no_piece
)
984 else if (color
[sq
] == white
)
997 for (side
= 0; side
<= 1; side
++)
1001 "%d %d %d %d %d %d %d %d\n",
1003 "%d %d %d %d %d %d\n",
1005 Captured
[side
][pawn
],
1007 Captured
[side
][lance
],
1008 Captured
[side
][knight
],
1010 Captured
[side
][silver
],
1011 Captured
[side
][gold
],
1012 Captured
[side
][bishop
],
1013 Captured
[side
][rook
],
1014 Captured
[side
][king
]);
1019 if (computer
== black
)
1020 fputs("white to play\n", fd
);
1022 fputs("black to play\n", fd
);
1033 char fname
[256], sflags
[4];
1037 strcpy(fname
, savefile
);
1039 /* Enter file name */
1040 dsp
->ShowMessage("Enter file name: ");
1041 RequestInputString(fname
, sizeof(fname
)-1);
1044 if (fname
[0] == '\0') {
1045 dsp
->AlwaysShowMessage("aborting book save");
1049 if ((fd
= fopen(fname
, "a")) != NULL
)
1053 for (i
= 1; i
<= GameCnt
; i
++)
1055 struct GameRec
*g
= &GameList
[i
];
1056 char mvnr
[20], mvs
[20];
1059 sprintf(mvnr
, "%d.", (i
+ 1)/2);
1064 t
= (g
->gmove
& 0xFF);
1065 algbr(f
, t
, g
->flags
);
1068 /* determine move quality string */
1069 if (g
->flags
& goodmove
)
1072 if (g
->flags
& badmove
)
1075 #ifdef EASY_OPENINGS
1076 if (g
->flags
& difficult
)
1082 /* determine move string */
1085 sprintf(mvs
, "%s%s ", &mvstr
[0][1], sflags
);
1089 sprintf(mvs
, "%c%c%c%c%c%s%s ",
1090 mvstr
[0][0], mvstr
[0][1],
1091 (g
->flags
& capture
) ? 'x' : '-',
1092 mvstr
[0][2], mvstr
[0][3],
1093 (mvstr
[0][4] == '+') ? "+" : "",
1097 fprintf(fd
, "%s%s%c%s",
1101 : (is_promoted
[g
->fpiece
] ? "+" : "")),
1114 dsp
->ShowMessage("Game saved");
1118 dsp
->ShowMessage("Could not open file");
1129 char fname
[256], dbuf
[256];
1133 strcpy(fname
, listfile
);
1138 strncpy(dbuf
, ctime(&when
), 20);
1145 /* use format "CL.Jan01-020304B" when
1148 program played white */
1150 sprintf(fname
, "CL.%s%s-%s%s%s%c",
1151 dbuf
+ 4, dbuf
+ 8, dbuf
+ 11, dbuf
+ 14,
1152 dbuf
+ 17, ColorStr
[computer
][0]);
1154 /* replace space padding with 0 */
1155 for (i
= 0; fname
[i
] != '\0'; i
++)
1157 if (fname
[i
] == ' ')
1162 fd
= fopen(fname
, "w");
1166 printf("Open failure for file: %s", fname
);
1170 fprintf(fd
, "gnushogi %s game\n", PACKAGE_VERSION
);
1171 fputs(" score depth nodes time ", fd
);
1172 fputs(" score depth nodes time\n", fd
);
1174 for (i
= 1; i
<= GameCnt
; i
++)
1176 f
= GameList
[i
].gmove
>> 8;
1177 t
= (GameList
[i
].gmove
& 0xFF);
1178 algbr(f
, t
, GameList
[i
].flags
);
1180 if (GameList
[i
].flags
& book
)
1182 fprintf(fd
, "%c%c%-5s %5d Book%7ld %5ld",
1185 : (is_promoted
[GameList
[i
].fpiece
] ? '+' : ' ')),
1186 pxx
[GameList
[i
].fpiece
],
1188 ? &mvstr
[0][1] : mvstr
[0]),
1195 fprintf(fd
, "%c%c%-5s %5d %2d %7ld %5ld",
1198 : (is_promoted
[GameList
[i
].fpiece
] ? '+' : ' ')),
1199 pxx
[GameList
[i
].fpiece
],
1200 (f
> NO_SQUARES
? &mvstr
[0][1] : mvstr
[0]),
1201 GameList
[i
].score
, GameList
[i
].depth
,
1202 GameList
[i
].nodes
, GameList
[i
].time
);
1215 fprintf(fd
, "\n\n");
1217 if (GameList
[GameCnt
].flags
& draw
)
1219 fprintf(fd
, "Draw %s\n", DRAW
);
1221 if (DRAW
== DRAW_REPETITION
)
1225 fprintf(fd
, "repetition by positions ");
1227 for (j
= GameCnt
- 1; j
>= Game50
; j
-= 2)
1229 if (GameList
[j
].hashkey
== hashkey
&&
1230 GameList
[j
].hashbd
== hashbd
)
1231 fprintf(fd
, "%d ", j
);
1237 else if (GameList
[GameCnt
].score
== -(SCORE_LIMIT
+ 999))
1239 fprintf(fd
, "%s\n", ColorStr
[player
]);
1241 else if (GameList
[GameCnt
].score
== (SCORE_LIMIT
+ 998))
1243 fprintf(fd
, "%s\n", ColorStr
[player
^ 1]);
1256 GameList
[GameCnt
].flags
|= badmove
;
1260 GameList
[GameCnt
].flags
|= goodmove
;
1263 #ifdef EASY_OPENINGS
1265 GameList
[GameCnt
].flags
|= difficult
;
1273 * Undo the most recent half-move.
1281 f
= GameList
[GameCnt
].gmove
>> 8;
1282 t
= GameList
[GameCnt
].gmove
& 0x7F;
1286 /* the move was a drop */
1287 Captured
[color
[t
]][board
[t
]]++;
1288 board
[t
] = no_piece
;
1294 if (GameList
[GameCnt
].flags
& promote
)
1295 board
[f
] = unpromoted
[board
[t
]];
1297 board
[f
] = board
[t
];
1299 color
[f
] = color
[t
];
1300 board
[t
] = GameList
[GameCnt
].piece
;
1301 color
[t
] = GameList
[GameCnt
].color
;
1303 if (board
[t
] != no_piece
)
1304 Captured
[color
[f
]][unpromoted
[board
[t
]]]--;
1306 if (color
[t
] != neutral
)
1314 if (TCflag
&& (TCmoves
> 1))
1315 ++TimeControl
.moves
[color
[f
]];
1317 hashkey
= GameList
[GameCnt
].hashkey
;
1318 hashbd
= GameList
[GameCnt
].hashbd
;
1320 computer
= computer
^ 1;
1321 opponent
= opponent
^ 1;
1324 player
= player
^ 1;
1325 dsp
->ShowSidetoMove();
1326 dsp
->UpdateDisplay(0, 0, 1, 0);
1328 if (flag
.regularstart
)
1334 TestSpeed(void(*f
)(short side
, short ply
,
1335 short in_check
, short blockable
),
1345 #ifdef HAVE_GETTIMEOFDAY
1349 #ifdef HAVE_GETTIMEOFDAY
1350 gettimeofday(&tv
, NULL
);
1351 t1
= (tv
.tv_sec
*100 + (tv
.tv_usec
/10000));
1356 for (i
= 0; i
< j
; i
++)
1358 f(opponent
, 2, -1, true);
1361 for (jj
= TrPnt
[2]; i
< TrPnt
[3]; jj
++)
1363 if (!pick(jj
, TrPnt
[3] - 1))
1369 #ifdef HAVE_GETTIMEOFDAY
1370 gettimeofday(&tv
, NULL
);
1371 t2
= (tv
.tv_sec
* 100 + (tv
.tv_usec
/ 10000));
1376 cnt
= j
* (TrPnt
[3] - TrPnt
[2]);
1383 dsp
->ShowNodeCnt(cnt
);
1388 TestPSpeed(short(*f
) (short side
), unsigned j
)
1392 #ifdef HAVE_GETTIMEOFDAY
1396 #ifdef HAVE_GETTIMEOFDAY
1397 gettimeofday(&tv
, NULL
);
1398 t1
= (tv
.tv_sec
* 100 + (tv
.tv_usec
/ 10000));
1403 for (i
= 0; i
< j
; i
++)
1406 #ifdef HAVE_GETTIMEOFDAY
1407 gettimeofday(&tv
, NULL
);
1408 t2
= (tv
.tv_sec
* 100 + (tv
.tv_usec
/ 10000));
1420 dsp
->ShowNodeCnt(cnt
);
1425 SetOppTime(char *time
)
1429 t
= (int)strtol(time
, &time
, 10);
1434 /* FIXME: sec is parsed but ignored */
1435 (void)strtol(time
, &time
, 10);
1438 m
= (int)strtol(time
, &time
, 10);
1441 TimeControl
.clock
[opponent
] = t
;
1444 TimeControl
.moves
[opponent
] = m
;
1446 ElapsedTime(COMPUTE_AND_INIT_MODE
);
1450 /* just to inform xshogi about availability of otime command */
1451 printf("otime %d %d\n", t
, m
);
1457 SetMachineTime(char *time
)
1461 t
= (int)strtol(time
, &time
, 10);
1466 /* FIXME: sec is parsed but ignored */
1467 (void)strtol(time
, &time
, 10);
1470 m
= (int)strtol(time
, &time
, 10);
1473 TimeControl
.clock
[computer
] = t
;
1476 TimeControl
.moves
[computer
] = m
;
1478 ElapsedTime(COMPUTE_AND_INIT_MODE
);
1482 /* just to inform xshogi about availability of time command */
1483 printf("time %d %d\n", t
, m
);
1488 /* FIXME! This is truly the function from hell! */
1491 * Process the user's command. If easy mode is OFF (the computer is thinking
1492 * on opponents time) and the program is out of book, then make the 'hint'
1493 * move on the board and call SelectMove() to find a response. The user
1494 * terminates the search by entering a command. If the opponent does not make
1495 * the hint move, then set Sdepth to zero.
1499 InputCommand(char *command
)
1501 #ifdef QUIETBACKGROUND
1502 short have_shown_prompt
= false;
1504 short ok
, done
, is_move
= false;
1508 ok
= flag
.quit
= done
= false;
1512 if (TTadd
> ttbllimit
)
1516 if ((hint
> 0) && !flag
.easy
&& !flag
.force
)
1519 * A hint move for the player is available. Compute a move for the
1520 * opponent in background mode assuming that the hint move will be
1521 * selected by the player.
1524 ft
= time0
; /* Save reference time for the player. */
1526 algbr((short) hint
>> 8, (short) hint
& 0xff, 0);
1527 strcpy(s
, mvstr
[0]);
1532 /* do the hint move */
1533 if (VerifyMove(s
, VERIFY_AND_TRY_MODE
, &mv
))
1537 #ifdef QUIETBACKGROUND
1539 have_shown_prompt
= true;
1540 #endif /* QUIETBACKGROUND */
1542 /* Start computing a move until the search is interrupted. */
1544 #ifdef INTERRUPT_TEST
1548 /* would love to put null move in here */
1549 /* after we make the hint move make a 2 ply search
1550 * with both plys our moves */
1551 /* think on opponents time */
1552 SelectMove(computer
, BACKGROUND_MODE
);
1554 #ifdef INTERRUPT_TEST
1555 ElapsedTime(COMPUTE_INTERRUPT_MODE
);
1559 printf("searching not terminated by interrupt!\n");
1563 printf("elapsed time from interrupt to "
1564 "terminating search: %ld\n", it
);
1568 /* undo the hint and carry on */
1569 VerifyMove(s
, UNMAKE_MODE
, &mv
);
1573 time0
= ft
; /* Restore reference time for the player. */
1576 while(!(ok
|| flag
.quit
|| done
))
1580 #ifdef QUIETBACKGROUND
1581 if (!have_shown_prompt
)
1583 #endif /* QUIETBACKGROUND */
1587 #ifdef QUIETBACKGROUND
1590 have_shown_prompt
= false;
1591 #endif /* QUIETBACKGROUND */
1593 if (command
== NULL
) {
1594 int eof
= dsp
->GetString(sx
);
1598 strcpy(sx
, command
);
1602 /* extract first word */
1603 if (sscanf(sx
, "%s", s
) < 1)
1606 if (strcmp(s
, "bd") == 0) /* bd -- display board */
1608 /* FIXME: Hack alert! */
1609 short old_xshogi
= XSHOGI
;
1612 display_type
= DISPLAY_RAW
;
1615 dsp
->UpdateDisplay(0, 0, 1, 0);
1618 display_type
= DISPLAY_X
;
1620 else if (strcmp(s
, "post") == 0)
1622 flag
.post
= (xboard
? 1 : !flag
.post
);
1624 else if (strcmp(s
, "nopost") == 0)
1629 else if (strcmp(s
, "variant") == 0)
1630 { /* only variant we play is minishogi */
1631 printf("setup (P.BR.S...G.+.++.+Kp.br.s...g.+.++.+k) 5x5+5_shogi rbsgk/4p/5/P4/KGSBR [-] w 0 1\n");
1634 else if (strcmp(s
, "alg") == 0 ||
1635 strcmp(s
, "accepted") == 0 || strcmp(s
, "rejected") == 0 ||
1636 strcmp(s
, "variant") == 0 || strcmp(s
, "computer") == 0)
1640 else if ((strcmp(s
, "quit") == 0) ||
1641 (strcmp(s
, "exit") == 0))
1645 else if (strcmp(s
, "xboard") == 0)
1648 strcpy(ColorStr
[0], "White");
1649 strcpy(ColorStr
[1], "Black");
1651 else if (strcmp(s
, "protover") == 0)
1653 printf("feature option=\"tsume -check 0\"\n");
1654 printf("feature option=\"contempt -spin %d -1000 1000\"\n", contempt
);
1655 printf("feature option=\"Hash-file search depth -spin %d 0 100\"\n", HashDepth
);
1656 printf("feature option=\"Hash-file move number -spin %d 0 100\"\n", HashMoveLimit
);
1657 printf("feature myname=\"GNU %s %s\" ",
1665 printf("variants=\"%s\" ",
1667 "5x5+5_shogi,minishogi"
1672 printf("debug=1 setboard=0 sigint=0 done=1\n");
1674 else if ((strcmp(s
, "set") == 0) ||
1675 (strcmp(s
, "edit") == 0))
1679 else if (strcmp(s
, "setup") == 0)
1683 else if (strcmp(s
, "first") == 0)
1687 else if (strcmp(s
, "go") == 0)
1692 if (computer
== black
)
1703 else if (strcmp(s
, "help") == 0)
1707 else if (strcmp(s
, "material") == 0)
1709 flag
.material
= !flag
.material
;
1711 else if (strcmp(s
, "force") == 0)
1716 flag
.bothsides
= false;
1720 flag
.force
= !flag
.force
;
1721 flag
.bothsides
= false;
1724 else if (strcmp(s
, "book") == 0)
1726 Book
= Book
? 0 : BOOKFAIL
;
1728 else if (strcmp(s
, "new") == 0)
1731 dsp
->UpdateDisplay(0, 0, 1, 0);
1733 else if (strcmp(s
, "list") == 0)
1737 else if (strcmp(s
, "level") == 0)
1739 dsp
->SelectLevel(sx
+ strlen("level"));
1741 else if (strcmp(s
, "clock") == 0)
1743 dsp
->SelectLevel(sx
+ strlen("clock"));
1745 else if (strcmp(s
, "hash") == 0)
1747 flag
.hash
= !flag
.hash
;
1749 else if (strcmp(s
, "gamein") == 0)
1751 flag
.gamein
= !flag
.gamein
;
1753 else if (strcmp(s
, "beep") == 0)
1755 flag
.beep
= !flag
.beep
;
1757 else if (strcmp(s
, "time") == 0)
1759 SetMachineTime(sx
+ strlen("time"));
1761 else if ((strcmp(s
, "otime") == 0) ||
1762 (xboard
&& (strcmp(s
, "otim")) == 0))
1764 SetOppTime(sx
+ strlen("otime"));
1766 else if (strcmp(s
, "Awindow") == 0)
1768 dsp
->ChangeAlphaWindow();
1770 else if (strcmp(s
, "Bwindow") == 0)
1772 dsp
->ChangeBetaWindow();
1774 else if (strcmp(s
, "rcptr") == 0)
1776 flag
.rcptr
= !flag
.rcptr
;
1778 else if (strcmp(s
, "hint") == 0)
1782 else if (strcmp(s
, "both") == 0)
1784 flag
.bothsides
= !flag
.bothsides
;
1787 ElapsedTime(COMPUTE_AND_INIT_MODE
);
1788 SelectMove(opponent
, FOREGROUND_MODE
);
1791 else if (strcmp(s
, "reverse") == 0)
1793 flag
.reverse
= !flag
.reverse
;
1795 dsp
->UpdateDisplay(0, 0, 1, 0);
1797 else if (strcmp(s
, "switch") == 0)
1799 computer
= computer
^ 1;
1800 opponent
= opponent
^ 1;
1801 xwndw
= (computer
== black
) ? WXWNDW
: BXWNDW
;
1805 dsp
->UpdateDisplay(0, 0, 1, 0);
1807 else if (xboard
? strcmp(s
, "white") == 0 : strcmp(s
, "black") == 0)
1816 * ok = true; don't automatically start with black command
1819 else if (xboard
? strcmp(s
, "black") == 0 : strcmp(s
, "white") == 0)
1828 * ok = true; don't automatically start with white command
1831 else if (strcmp(s
, "undo") == 0 && GameCnt
> 0)
1835 else if (strcmp(s
, "remove") == 0 && GameCnt
> 1)
1840 /* CHECKME: are these next three correct? */
1841 else if (!XSHOGI
&& strcmp(s
, "xget") == 0)
1845 else if (!XSHOGI
&& strcmp(s
, "xsave") == 0)
1849 else if (!XSHOGI
&& strcmp(s
, "bsave") == 0)
1853 #ifdef EASY_OPENINGS
1854 else if ((strcmp(s
, "?") == 0) ||
1855 (strcmp(s
, "!") == 0) ||
1856 (strcmp(s
, "~") == 0))
1858 else if ((strcmp(s
, "?") == 0) ||
1859 (strcmp(s
, "!") == 0))
1864 else if (strcmp(s
, "get") == 0)
1868 else if (strcmp(s
, "save") == 0)
1872 else if (strcmp(s
, "depth") == 0)
1874 dsp
->ChangeSearchDepth(sx
+ strlen("depth"));
1876 else if (strcmp(s
, "sd") == 0)
1878 dsp
->ChangeSearchDepth(sx
+ strlen("sd"));
1880 else if (strcmp(s
, "hashdepth") == 0)
1882 dsp
->ChangeHashDepth();
1884 else if (strcmp(s
, "random") == 0)
1888 else if (strcmp(s
, "hard") == 0)
1892 else if (strcmp(s
, "easy") == 0)
1894 flag
.easy
= !flag
.easy
;
1896 else if (strcmp(s
, "option") == 0)
1899 if (sscanf(sx
, "option tsume=%hd", &flag
.tsume
) == 1)
1901 if (sscanf(sx
, "option hash=%hd", &flag
.hash
) == 1)
1903 if (sscanf(sx
, "option Hash-file search depth=%hd", &HashDepth
) == 1)
1905 if (sscanf(sx
, "option Hash-file move number=%hd", &HashMoveLimit
) == 1)
1907 if (sscanf(sx
, "option contempt=%hd", &contempt
) == 1)
1909 dsp
->AlwaysShowMessage("Unknown '%s'", sx
);
1912 else if (strcmp(s
, "tsume") == 0)
1914 flag
.tsume
= !flag
.tsume
;
1916 else if (strcmp(s
, "contempt") == 0)
1920 else if (strcmp(s
, "xwndw") == 0)
1922 dsp
->ChangeXwindow();
1924 else if (strcmp(s
, "rv") == 0)
1927 dsp
->UpdateDisplay(0, 0, 1, 0);
1929 else if (strcmp(s
, "coords") == 0)
1931 flag
.coords
= !flag
.coords
;
1932 dsp
->UpdateDisplay(0, 0, 1, 0);
1934 else if (strcmp(s
, "stars") == 0)
1936 flag
.stars
= !flag
.stars
;
1937 dsp
->UpdateDisplay(0, 0, 1, 0);
1939 else if (!XSHOGI
&& strcmp(s
, "moves") == 0)
1946 extern unsigned short PrVar
[MAXDEPTH
];
1948 SwagHt
= (GameList
[GameCnt
].gmove
== PrVar
[1])
1955 dsp
->ShowMessage("Testing MoveList Speed");
1956 temp
= generate_move_flags
;
1957 generate_move_flags
= true;
1958 TestSpeed(MoveList
, 1);
1959 generate_move_flags
= temp
;
1960 dsp
->ShowMessage("Testing CaptureList Speed");
1961 TestSpeed(CaptureList
, 1);
1962 dsp
->ShowMessage("Testing Eval Speed");
1963 ExaminePosition(opponent
);
1964 TestPSpeed(ScorePosition
, 1);
1966 else if (!XSHOGI
&& strcmp(s
, "test") == 0)
1969 dsp
->ShowMessage("Testing MoveList Speed");
1970 TestSpeed(MoveList
, 2000);
1971 dsp
->ShowMessage("Testing CaptureList Speed");
1972 TestSpeed(CaptureList
, 3000);
1973 dsp
->ShowMessage("Testing Eval Speed");
1974 ExaminePosition(opponent
);
1975 TestPSpeed(ScorePosition
, 1500);
1977 dsp
->ShowMessage("Testing MoveList Speed");
1978 TestSpeed(MoveList
, 20000);
1979 dsp
->ShowMessage("Testing CaptureList Speed");
1980 TestSpeed(CaptureList
, 30000);
1981 dsp
->ShowMessage("Testing Eval Speed");
1982 ExaminePosition(opponent
);
1983 TestPSpeed(ScorePosition
, 15000);
1986 else if (!XSHOGI
&& strcmp(s
, "p") == 0)
1988 dsp
->ShowPostnValues();
1990 else if (!XSHOGI
&& strcmp(s
, "debug") == 0)
2000 else if ((ok
= VerifyMove(s
, VERIFY_AND_MAKE_MODE
, &mv
)))
2002 /* check for repetition */
2003 short rpt
= repetition();
2007 DRAW
= DRAW_REPETITION
;
2008 dsp
->ShowMessage(DRAW
);
2009 GameList
[GameCnt
].flags
|= draw
;
2023 ElapsedTime(COMPUTE_AND_INIT_MODE
);
2027 computer
= opponent
;
2028 opponent
= computer
^ 1;
2033 /* add remaining time in milliseconds for xshogi */
2036 printf("%d. %s %ld\n",
2037 ++mycnt2
, s
, TimeControl
.clock
[player
] * 10);