4 * Curses interface for GNU Shogi
6 * ----------------------------------------------------------------------
8 * Copyright (c) 2012 Free Software Foundation
10 * GNU SHOGI is based on GNU CHESS
12 * This file is part of GNU SHOGI.
14 * GNU Shogi is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 3 of the License,
17 * or (at your option) any later version.
19 * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
20 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * You should have received a copy of the GNU General Public License along
25 * with GNU Shogi; see the file COPYING. If not, see
26 * <http://www.gnu.org/licenses/>.
27 * ----------------------------------------------------------------------
34 #include <sys/param.h>
35 #include <sys/types.h>
40 #include "cursesdsp.h"
42 #define FLUSH_SCANW fflush(stdout), scanw
48 #define VIR_C(s) ((flag.reverse) ? (8 - column(s)) : column(s))
49 #define VIR_R(s) ((flag.reverse) ? (8 - row(s)) : row(s))
51 unsigned short MV[MAXDEPTH];
55 /* Forward declarations. */
56 /* FIXME: change this name, puh-leeze! */
58 static void UpdateCatched(void);
61 /****************************************
62 * Trivial output functions.
63 ****************************************/
74 Curses_ClearScreen(void)
91 gotoXY(short x, short y)
98 Curses_ShowCurrentMove(short pnt, short f, short t)
102 printw("(%2d) %5s ", pnt, mvstr[0]);
107 Curses_ShowDepth(char ch)
110 printw(CP[53], Sdepth, ch); /* Depth = %d%c */
116 Curses_ShowGameType(void)
121 printw("%c vs. %c", GameType[black], GameType[white]);
130 printw(CP[69], version, patchlevel);
135 Curses_ShowLine(unsigned short *bstline)
141 Curses_ShowMessage(char *s)
150 ShowNodeCnt(long NodeCnt)
153 /* printw(CP[90], NodeCnt, (et > 100) ? NodeCnt / (et / 100) : 0); */
154 printw("n = %ld n/s = %ld",
155 NodeCnt, (et > 100) ? NodeCnt / (et / 100) : 0);
161 Curses_ShowPatternCount(short side, short n)
165 gotoXY(TAB + 10 + 3 * side, 20);
178 gotoXY(5, ((flag.reverse) ? 23 : 2));
179 printw("%s", (computer == white) ? CP[218] : CP[74]);
180 gotoXY(5, ((flag.reverse) ? 2 : 23));
181 printw("%s", (computer == black) ? CP[218] : CP[74]);
189 printw(CP[121]); /* Your move is? */
195 Curses_ShowResponseTime(void)
201 /* printw("RT = %ld TCC = %d TCL = %ld EX = %ld ET = %ld TO = %d",
202 ResponseTime, TCC, TCleft, ExtraTime, et, flag.timeout); */
203 printw("%ld, %d, %ld, %ld, %ld, %d",
204 ResponseTime, TCC, TCleft, ExtraTime, et, flag.timeout);
211 Curses_ShowResults(short score, unsigned short *bstline, char ch)
213 unsigned char d, ply;
217 Curses_ShowDepth(ch);
221 for (ply = 1; bstline[ply] > 0; ply++)
229 algbr((short) bstline[ply] >> 8,
230 (short) bstline[ply] & 0xFF, false);
231 printw("%5s ", mvstr[0]);
246 ShowScore(short score)
249 printw(CP[104], score);
255 Curses_ShowSidetoMove(void)
258 printw("%2d: %s", 1 + GameCnt / 2, ColorStr[player]);
264 Curses_ShowStage(void)
267 printw("Stage= %2d%c B= %2d W= %2d",
268 stage, flag.tsume?'T':' ', balance[black], balance[white]);
273 /****************************************
274 * End of trivial output routines.
275 ****************************************/
279 Curses_Initialize(void)
281 signal(SIGINT, Curses_Die);
282 signal(SIGQUIT, Curses_Die);
289 Curses_ExitShogi(void)
310 signal(SIGINT, SIG_IGN);
311 signal(SIGQUIT, SIG_IGN);
313 Curses_ShowMessage(CP[31]); /* Abort? */
314 FLUSH_SCANW("%s", s);
316 if (strcmp(s, CP[210]) == 0) /* yes */
319 signal(SIGINT, Curses_Die);
320 signal(SIGQUIT, Curses_Die);
326 Curses_TerminateSearch(int sig)
328 signal(SIGINT, SIG_IGN);
329 signal(SIGQUIT, SIG_IGN);
332 flag.musttimeout = true;
334 Curses_ShowMessage("Terminate Search");
335 flag.bothsides = false;
336 signal(SIGINT, Curses_Die);
337 signal(SIGQUIT, Curses_Die);
345 Curses_ClearScreen();
346 /* printw("GNU Shogi ??p? command summary\n"); */
347 printw(CP[40], version, patchlevel);
348 printw("-------------------------------"
349 "---------------------------------\n");
350 /* printw("7g7f move from 7g to 7f quit
353 /* printw("S6h move silver to 6h beep
354 * turn %s\n", (flag.beep) ? "off" : "on"); */
355 printw(CP[86], (flag.beep) ? CP[92] : CP[93]);
356 /* printw("2d2c+ move to 2c and promote\n"); */
357 printw(CP[128], (flag.material) ? CP[92] : CP[93]);
358 /* printw("P*5e drop a pawn to 5e easy
359 * turn %s\n", (flag.easy) ? "off" : "on"); */
360 printw(CP[173], (flag.easy) ? CP[92] : CP[93]);
362 * turn %s\n", (flag.hash) ? "off" : "on"); */
363 printw(CP[174], (flag.hash) ? CP[92] : CP[93]);
364 /* printw("bd redraw board reverse
365 * board display\n"); */
367 /* printw("list game to shogi.lst book
368 * turn %s used %d of %d\n", (Book) ? "off" : "on", book
370 printw(CP[170], (Book) ? CP[92] : CP[93], bookcount, BOOKSIZE);
371 /* printw("undo undo last ply remove
372 * take back a move\n"); */
374 /* printw("edit edit board force
375 * enter game moves\n"); */
377 /* printw("switch sides with computer both
378 * computer match\n"); */
380 /* printw("black computer plays black white
381 * computer plays white\n"); */
383 /* printw("depth set search depth clock
384 * set time control\n"); */
386 /* printw("hint suggest a move post
387 * turn %s principle variation\n", (flag.post) ? "off" :
389 printw(CP[177], (flag.post) ? CP[92] : CP[93]);
390 /* printw("save game to file get
391 * game from file\n"); */
393 /* printw("random randomize play new
394 * start new game\n"); */
397 printw(CP[47], ColorStr[computer]);
399 printw(CP[97], ColorStr[opponent]);
401 printw(CP[79], MaxResponseTime/100);
403 printw(CP[59], (flag.easy) ? CP[93] : CP[92]);
405 printw(CP[231], (flag.tsume) ? CP[93] : CP[92]);
407 printw(CP[52], MaxSearchDepth);
409 printw(CP[100], (dither) ? CP[93] : CP[92]);
411 printw(CP[112], (flag.hash) ? CP[93] : CP[92]);
415 printw(CP[110], (TCflag) ? CP[93] : CP[92],
416 TimeControl.moves[black],
417 TimeControl.clock[black] / 100,
418 OperatorTime, MaxSearchDepth);
423 fflush(stdin); /* what is this supposed to do?? */
427 Curses_ClearScreen();
428 Curses_UpdateDisplay(0, 0, 1, 0);
432 static const short x0[2] = { 54, 2 };
433 static const short y0[2] = { 20, 4 };
437 * Set up a board position. Pieces are entered by typing the piece followed
438 * by the location. For example, N3f will place a knight on square 3f.
439 * P* will put a pawn to the captured pieces.
443 Curses_EditBoard(void)
449 flag.regularstart = true;
451 Curses_ClearScreen();
452 Curses_UpdateDisplay(0, 0, 1, 0);
466 printw(CP[60], ColorStr[a]); /* Editing %s */
469 FLUSH_SCANW("%s", s);
471 if (s[0] == CP[28][0]) /* # */
473 for (sq = 0; sq < NO_SQUARES; sq++)
475 board[sq] = no_piece;
484 if (s[0] == CP[136][0]) /* c */
489 for (i = NO_PIECES; i > no_piece; i--)
491 if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
495 Captured[a][unpromoted[i]]++;
505 if ((c >= 0) && (c < NO_COLS) && (r >= 0) && (r < NO_ROWS))
509 for (i = NO_PIECES; i > no_piece; i--)
511 if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
521 color[sq] = ((board[sq] == no_piece) ? neutral : a);
525 while (s[0] != CP[29][0]); /* . */
527 for (sq = 0; sq < NO_SQUARES; sq++)
528 Mvboard[sq] = ((board[sq] != Stboard[sq]) ? 10 : 0);
535 Curses_ClearScreen();
536 Curses_UpdateDisplay(0, 0, 1, 0);
546 for (side = black; side <= white; side++)
548 short x, y, piece, cside, k;
550 cside = flag.reverse ? (side ^ 1) : side;
555 for (piece = pawn; piece <= king; piece++)
559 if ((n = Captured[side][piece]))
562 printw("%i%c", n, pxx[piece]);
594 Curses_SearchStartStuff(short side)
598 signal(SIGINT, Curses_TerminateSearch);
599 signal(SIGQUIT, Curses_TerminateSearch);
601 for (i = 4; i < 14; i++)
611 Curses_OutputMove(void)
614 Curses_UpdateDisplay(root->f, root->t, 0, (short) root->flags);
623 printw(CP[84], mvstr[0]); /* My move is %s */
632 if (root->flags & draw)
634 else if (root->score == -(SCORE_LIMIT + 999))
636 else if (root->score == SCORE_LIMIT + 998)
639 else if (root->score < -SCORE_LIMIT)
640 printw(CP[96], SCORE_LIMIT + 999 + root->score - 1);
641 else if (root->score > SCORE_LIMIT)
642 printw(CP[45], SCORE_LIMIT + 998 - root->score - 1);
643 #endif /* VERYBUGGY */
657 if (Tree[t].f || Tree[t].t)
665 ShowNodeCnt(NodeCnt);
667 printw(CP[81], t); /* Max Tree= */
671 Curses_ShowSidetoMove();
684 m = (short) ((dt = (TimeControl.clock[player] - et)) / 6000);
685 s = (short) ((dt - 6000 * (long) m) / 100);
689 m = (short) ((dt = et) / 6000);
690 s = (short) (et - 6000 * (long) m) / 100;
700 gotoXY(20, (flag.reverse) ? 2 : 23);
702 gotoXY(20, (flag.reverse) ? 23 : 2);
704 /* printw("%d:%02d %ld ", m, s, dt); */
705 printw("%d:%02d ", m, s);
708 ShowNodeCnt(NodeCnt);
721 if (color[sq] == neutral)
725 else if (flag.reverse ^ (color[sq] == black))
737 if (is_promoted[(int)piece])
740 y = pxx[unpromoted[(int)piece]];
748 gotoXY(8 + 5 * VIR_C(sq), 4 + 2 * (8 - VIR_R(sq)));
749 printw("%c%c%c%c", l, p, y, r);
756 * Curses_ShowPostnValue(): must have called ExaminePosition() first
760 Curses_ShowPostnValue(short sq)
764 gotoXY(4 + 5 * VIR_C(sq), 5 + 2 * (7 - VIR_R(sq)));
765 score = ScorePosition(color[sq]);
767 if (color[sq] != neutral)
768 #if defined SAVE_SVALUE
774 printw("%3d ", svalue[sq]);
786 Curses_ShowPostnValues(void)
790 ExaminePosition(opponent);
792 for (sq = 0; sq < NO_SQUARES; sq++)
793 Curses_ShowPostnValue(sq);
795 score = ScorePosition(opponent);
797 printw(CP[103], score,
798 mtl[computer], pscore[computer], GameType[computer],
799 mtl[opponent], pscore[opponent], GameType[opponent]);
807 Curses_UpdateDisplay(short f, short t, short redraw, short isspec)
819 printw(" +----+----+----+----+----+----+----+----+----+");
828 z = 11 - ((i + 1) / 2);
830 printw(" %c | | | | | |"
831 " | | | |", 'a' + 9 - z);
837 printw(" +----+----+----+----+----+----+----+----+----+");
841 printw(" +----+----+----+----+----+----+----+----+----+");
851 for (sq = 0; sq < NO_SQUARES; sq++)
854 else /* not redraw */
862 if ((isspec & capture) || (isspec & dropmask) || redraw)
866 for (side = black; side <= white; side++)
868 short x, y, piece, cside, k;
869 cside = flag.reverse ? (side ^ 1) : side;
874 for (piece = pawn; piece <= king; piece++)
878 if ((n = Captured[side][piece]))
881 printw("%i%c", n, pxx[piece]);
883 if (cside == black) y--; else y++;
913 Curses_ChangeAlphaWindow(void)
915 Curses_ShowMessage(CP[114]);
916 FLUSH_SCANW("%hd", &WAwindow);
917 Curses_ShowMessage(CP[34]);
918 FLUSH_SCANW("%hd", &BAwindow);
924 Curses_ChangeBetaWindow(void)
926 Curses_ShowMessage(CP[115]);
927 FLUSH_SCANW("%hd", &WBwindow);
928 Curses_ShowMessage(CP[35]);
929 FLUSH_SCANW("%hd", &BBwindow);
935 Curses_GiveHint(void)
941 algbr((short) (hint >> 8), (short) (hint & 0xFF), false);
942 strcpy(s, CP[198]); /* try */
944 Curses_ShowMessage(s);
948 Curses_ShowMessage(CP[223]);
955 Curses_ChangeSearchDepth(void)
957 Curses_ShowMessage(CP[150]);
958 FLUSH_SCANW("%hd", &MaxSearchDepth);
959 TCflag = !(MaxSearchDepth > 0);
964 Curses_ChangeHashDepth(void)
966 Curses_ShowMessage(CP[163]);
967 FLUSH_SCANW("%hd", &HashDepth);
968 Curses_ShowMessage(CP[82]);
969 FLUSH_SCANW("%hd", &HashMoveLimit);
974 Curses_SetContempt(void)
976 Curses_ShowMessage(CP[142]);
977 FLUSH_SCANW("%hd", &contempt);
983 Curses_ChangeXwindow(void)
985 Curses_ShowMessage(CP[208]);
986 FLUSH_SCANW("%hd", &xwndw);
992 Curses_SelectLevel(char *sx)
996 Curses_ClearScreen();
998 printw(CP[41], version, patchlevel);
1028 FLUSH_SCANW("%d", &item);
1075 flag.onemove = true;
1081 flag.onemove = true;
1087 flag.onemove = true;
1091 TCflag = (TCmoves > 0);
1093 TimeControl.clock[black] = TimeControl.clock[white] = 0;
1096 Curses_ClearScreen();
1097 Curses_UpdateDisplay(0, 0, 1, 0);
1103 Curses_DoDebug(void)
1105 short c, p, sq, tp, tc, tsq, score;
1108 ExaminePosition(opponent);
1109 Curses_ShowMessage(CP[65]);
1110 FLUSH_SCANW("%s", s);
1113 if ((s[0] == CP[9][0]) || (s[0] == CP[9][1])) /* b B */
1116 if ((s[0] == CP[9][2]) || (s[0] == CP[9][3])) /* w W */
1119 for (p = king; p > no_piece; p--)
1121 if ((s[1] == pxx[p]) || (s[1] == qxx[p]))
1125 for (sq = 0; sq < NO_SQUARES; sq++)
1131 tsq = PieceList[c][1];
1132 PieceList[c][1] = sq;
1133 Curses_ShowPostnValue(sq);
1134 PieceList[c][1] = tsq;
1139 score = ScorePosition(opponent);
1141 printw(CP[103], score,
1142 mtl[computer], pscore[computer], GameType[computer],
1143 mtl[opponent], pscore[opponent], GameType[opponent]);
1151 Curses_DoTable(short table[NO_SQUARES])
1154 ExaminePosition(opponent);
1156 for (sq = 0; sq < NO_SQUARES; sq++)
1158 gotoXY(4 + 5 * VIR_C(sq), 5 + 2 * (7 - VIR_R(sq)));
1159 printw("%3d ", table[sq]);