4 * Curses interface for GNU Shogi
6 * ----------------------------------------------------------------------
7 * Copyright (c) 1993, 1994, 1995 Matthias Mutz
8 * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
10 * GNU SHOGI is based on GNU CHESS
12 * Copyright (c) 1988, 1989, 1990 John Stanback
13 * Copyright (c) 1992 Free Software Foundation
15 * This file is part of GNU SHOGI.
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.
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
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 * ----------------------------------------------------------------------
38 #include <sys/param.h>
39 #include <sys/types.h>
50 /* Definition of FIONREAD */
51 #include <sys/filio.h>
55 /* Definition of errno(). */
59 #define FLUSH_SCANW fflush(stdout), scanw
65 #define VIR_C(s) ((flag.reverse) ? (NO_COLS - 1 - column(s)) : column(s))
66 #define VIR_R(s) ((flag.reverse) ? (NO_ROWS - 1 - row(s)) : row(s))
68 unsigned short MV[MAXDEPTH];
72 /****************************************
73 * forward declarations
74 ****************************************/
76 /* FIXME: change this name, puh-leeze! */
77 static void UpdateCatched(void);
78 static void DrawPiece(short sq);
79 static void ShowScore(short score);
80 void Curses_UpdateDisplay(short f, short t, short redraw, short isspec);
81 void Curses_Die(int sig);
83 /****************************************
84 * Trivial output functions.
85 ****************************************/
96 Curses_ClearScreen(void)
104 gotoXY(short x, short y)
119 Curses_ShowCurrentMove(short pnt, short f, short t)
123 printw("(%2d) %5s ", pnt, mvstr[0]);
128 Curses_ShowDepth(char ch)
131 printw("Depth= %d%c ", Sdepth, ch);
137 Curses_ShowGameType(void)
142 printw("%c vs. %c", GameType[black], GameType[white]);
151 printw("GNU Shogi %s", PACKAGE_VERSION);
156 Curses_ShowLine(unsigned short *bstline)
162 Curses_ShowMessage(char *s)
171 Curses_AlwaysShowMessage(const char *format, ...)
173 static char buffer[60];
175 va_start(ap, format);
176 vsnprintf(buffer, sizeof(buffer), format, ap);
177 Curses_ShowMessage(buffer);
183 Curses_Printf(const char *format, ...)
185 static char buffer[60];
187 va_start(ap, format);
188 vsnprintf(buffer, sizeof(buffer), format, ap);
189 printw("%s", buffer);
195 Curses_doRequestInputString(const char* fmt, char* buffer)
197 FLUSH_SCANW(fmt, buffer);
202 Curses_GetString(char* sx)
205 return (getstr(sx) == ERR);
210 Curses_ShowNodeCnt(long NodeCnt)
213 /* printw("Nodes = %8ld, Nodes/Sec = %5ld", NodeCnt, (et > 100) ? NodeCnt / (et / 100) : 0); */
214 printw("n = %ld n/s = %ld",
215 NodeCnt, (et > 100) ? NodeCnt / (et / 100) : 0);
221 Curses_ShowPatternCount(short side, short n)
225 gotoXY(TAB + 10 + 3 * side, 20); /* CHECKME */
238 gotoXY(5, ((flag.reverse) ? (5 + 2*NO_ROWS) : 2));
239 printw("%s", (computer == white) ? "Computer" : "Human ");
240 gotoXY(5, ((flag.reverse) ? 2 : (5 + 2*NO_ROWS)));
241 printw("%s", (computer == black) ? "Computer" : "Human ");
246 Curses_ShowPrompt(void)
248 Curses_ShowSidetoMove();
250 printw("Your move is? ");
256 Curses_ShowResponseTime(void)
262 printw("%ld, %d, %ld, %ld, %ld, %d",
263 ResponseTime, TCC, TCleft, ExtraTime, et, flag.timeout);
270 Curses_ShowResults(short score, unsigned short *bstline, char ch)
272 unsigned char d, ply;
276 Curses_ShowDepth(ch);
280 for (ply = 1; bstline[ply] > 0; ply++)
288 algbr((short) bstline[ply] >> 8,
289 (short) bstline[ply] & 0xFF, false);
290 printw("%5s ", mvstr[0]);
305 ShowScore(short score)
308 printw("Score= %d", score);
314 Curses_ShowSidetoMove(void)
317 printw("%2d: %s", 1 + GameCnt / 2, ColorStr[player]);
323 Curses_ShowStage(void)
326 printw("Stage= %2d%c B= %2d W= %2d",
327 stage, flag.tsume?'T':' ', balance[black], balance[white]);
331 /****************************************
332 * End of trivial output routines.
333 ****************************************/
336 Curses_Initialize(void)
338 signal(SIGINT, Curses_Die);
339 signal(SIGQUIT, Curses_Die);
346 Curses_ExitShogi(void)
366 signal(SIGINT, SIG_IGN);
367 signal(SIGQUIT, SIG_IGN);
369 Curses_ShowMessage("Abort? ");
370 FLUSH_SCANW("%s", s);
372 if (strcmp(s, "yes") == 0)
375 signal(SIGINT, Curses_Die);
376 signal(SIGQUIT, Curses_Die);
381 Curses_TerminateSearch(int sig)
383 signal(SIGINT, SIG_IGN);
384 signal(SIGQUIT, SIG_IGN);
387 flag.musttimeout = true;
389 Curses_ShowMessage("Terminate Search");
390 flag.bothsides = false;
391 signal(SIGINT, Curses_Die);
392 signal(SIGQUIT, Curses_Die);
399 Curses_ClearScreen();
400 printw("GNU Shogi %s command summary\n", PACKAGE_VERSION);
401 printw("-------------------------------"
402 "---------------------------------\n");
403 printw("7g7f move from 7g to 7f quit Exit Shogi\n");
404 printw("S6h move silver to 6h beep turn %s\n", (flag.beep) ? "OFF" : "ON");
405 printw("2d2c+ move to 2c and promote material turn %s\n", (flag.material) ? "OFF" : "ON");
406 printw("P*5e drop pawn to 5e easy turn %s\n", (flag.easy) ? "OFF" : "ON");
407 printw("tsume toggle tsume mode hash turn %s\n", (flag.hash) ? "OFF" : "ON");
408 printw("bd redraw board reverse board display\n");
409 printw("list game to shogi.lst book turn %s used %d of %d\n", (Book) ? "OFF" : "ON", bookcount, BOOKSIZE);
410 printw("undo undo last ply remove take back a move\n");
411 printw("edit edit board force toggle manual move mode\n");
412 printw("switch sides with computer both computer match\n");
413 printw("black computer plays black white computer plays white\n");
414 printw("depth set search depth clock set time control\n");
415 printw("post principle variation hint suggest a move\n", (flag.post) ? "OFF" : "ON");
416 printw("save game to file get game from file\n");
417 printw("random randomize play new start new game\n");
419 printw("Computer: %s", ColorStr[computer]);
421 printw("Opponent: %s", ColorStr[opponent]);
423 printw("Level: %ld", MaxResponseTime/100);
425 printw("Easy mode: %s", (flag.easy) ? "ON" : "OFF");
427 printw("Tsume: %s", (flag.tsume) ? "ON" : "OFF");
429 printw("Depth: %d", MaxSearchDepth);
431 printw("Random: %s", (dither) ? "ON" : "OFF");
433 printw("Transposition table: %s", (flag.hash) ? "ON" : "OFF");
435 printw("Hit <RET> to return: ");
437 printw("Time Control %s %d moves %d sec %d add %d depth\n", (TCflag) ? "ON" : "OFF",
438 TimeControl.moves[black],
439 TimeControl.clock[black] / 100,
440 OperatorTime, MaxSearchDepth);
445 fflush(stdin); /* what is this supposed to do?? */
449 Curses_ClearScreen();
450 Curses_UpdateDisplay(0, 0, 1, 0);
454 static const short x0[2] = { 54, 2 };
455 static const short y0[2] = { 20, 4 };
459 * Set up a board position. Pieces are entered by typing the piece followed
460 * by the location. For example, N3f will place a knight on square 3f.
461 * P* will put a pawn to the captured pieces.
465 Curses_EditBoard(void)
471 flag.regularstart = true;
473 Curses_ClearScreen();
474 Curses_UpdateDisplay(0, 0, 1, 0);
476 printw(". Exit to main\n");
478 printw("# Clear board\n");
480 printw("c Change sides\n");
482 printw("Enter piece & location: ");
488 printw("Editing: %s", ColorStr[a]);
491 FLUSH_SCANW("%s", s);
495 for (sq = 0; sq < NO_SQUARES; sq++)
497 board[sq] = no_piece;
511 for (i = NO_PIECES; i > no_piece; i--)
513 if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
517 Captured[a][unpromoted[i]]++;
527 if ((c >= 0) && (c < NO_COLS) && (r >= 0) && (r < NO_ROWS))
531 for (i = NO_PIECES; i > no_piece; i--)
533 if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
543 color[sq] = ((board[sq] == no_piece) ? neutral : a);
549 for (sq = 0; sq < NO_SQUARES; sq++)
550 Mvboard[sq] = ((board[sq] != Stboard[sq]) ? 10 : 0);
557 Curses_ClearScreen();
558 Curses_UpdateDisplay(0, 0, 1, 0);
567 for (side = black; side <= white; side++)
569 short x, y, piece, cside, k;
571 cside = flag.reverse ? (side ^ 1) : side;
576 for (piece = pawn; piece <= king; piece++)
580 if ((n = Captured[side][piece]))
583 printw("%i%c", n, pxx[piece]);
614 Curses_SearchStartStuff(short side)
618 signal(SIGINT, Curses_TerminateSearch);
619 signal(SIGQUIT, Curses_TerminateSearch);
621 for (i = 4; i < 14; i++) /* CHECKME */
630 Curses_OutputMove(void)
633 Curses_UpdateDisplay(root->f, root->t, 0, (short) root->flags);
638 printw("Illegal position.");
642 printw("My move is: %5s", mvstr[0]);
651 if (root->flags & draw)
652 printw("Drawn game!");
653 else if (root->score == -(SCORE_LIMIT + 999))
654 printw("Opponent mates!");
655 else if (root->score == SCORE_LIMIT + 998)
656 printw("Computer mates!");
658 else if (root->score < -SCORE_LIMIT)
659 printw("Opp: mate in %d!", SCORE_LIMIT + 999 + root->score - 1);
660 else if (root->score > SCORE_LIMIT)
661 printw("Comp: mate in %d!", SCORE_LIMIT + 998 - root->score - 1);
662 #endif /* VERYBUGGY */
676 if (Tree[t].f || Tree[t].t)
684 Curses_ShowNodeCnt(NodeCnt);
686 printw("Max Tree = %5d", t);
690 Curses_ShowSidetoMove();
695 Curses_UpdateClocks(void)
702 m = (short) ((dt = (TimeControl.clock[player] - et)) / 6000);
703 s = (short) ((dt - 6000 * (long) m) / 100);
707 m = (short) ((dt = et) / 6000);
708 s = (short) (et - 6000 * (long) m) / 100;
718 gotoXY(20, (flag.reverse) ? 2 : 23);
720 gotoXY(20, (flag.reverse) ? 23 : 2);
722 /* printw("%d:%02d %ld ", m, s, dt); */
723 printw("%d:%02d ", m, s);
726 Curses_ShowNodeCnt(NodeCnt);
738 if (color[sq] == neutral)
742 else if (flag.reverse ^ (color[sq] == black))
754 if (is_promoted[(int)piece])
757 y = pxx[unpromoted[(int)piece]];
765 gotoXY(8 + 5 * VIR_C(sq), 4 + 2 * ((NO_ROWS - 1) - VIR_R(sq)));
766 printw("%c%c%c%c", l, p, y, r);
771 * Curses_ShowPostnValue(): must have called ExaminePosition() first
774 Curses_ShowPostnValue(short sq)
778 gotoXY(4 + 5 * VIR_C(sq), 5 + 2 * (7 - VIR_R(sq))); /* CHECKME */
779 score = ScorePosition(color[sq]);
781 if (color[sq] != neutral)
782 #if defined SAVE_SVALUE
788 printw("%3d ", svalue[sq]);
799 Curses_ShowPostnValues(void)
803 ExaminePosition(opponent);
805 for (sq = 0; sq < NO_SQUARES; sq++)
806 Curses_ShowPostnValue(sq);
808 score = ScorePosition(opponent);
810 printw("S%d m%d ps%d gt%c m%d ps%d gt%c", score,
811 mtl[computer], pscore[computer], GameType[computer],
812 mtl[opponent], pscore[opponent], GameType[opponent]);
819 Curses_UpdateDisplay(short f, short t, short redraw, short isspec)
833 for (j=0; j<NO_COLS; j++)
836 while (i <= 1 + 2*NO_ROWS)
843 z = NO_ROWS + 2 - ((i + 1) / 2);
845 printw(" %c |", ROW_NAME(z+1));
846 for (j=0; j<NO_COLS; j++)
851 if (i < 2 + 2*NO_ROWS)
854 for (j=0; j<NO_COLS; j++)
860 for (j=0; j<NO_COLS; j++)
863 gotoXY(3, 4 + 2*NO_ROWS);
868 printw(" 1 2 3 4 5 6 7 8 9");
870 printw(" 9 8 7 6 5 4 3 2 1");
873 printw(" 1 2 3 4 5");
875 printw(" 1 2 3 4 5");
878 for (sq = 0; sq < NO_SQUARES; sq++)
881 else /* not redraw */
889 if ((isspec & capture) || (isspec & dropmask) || redraw)
893 for (side = black; side <= white; side++)
895 short x, y, piece, cside, k;
896 cside = flag.reverse ? (side ^ 1) : side;
901 for (piece = pawn; piece <= king; piece++)
905 if ((n = Captured[side][piece]))
908 printw("%i%c", n, pxx[piece]);
910 if (cside == black) y--; else y++;
937 Curses_ChangeAlphaWindow(void)
939 Curses_ShowMessage("WAwindow = ");
940 FLUSH_SCANW("%hd", &WAwindow);
941 Curses_ShowMessage("BAwindow = ");
942 FLUSH_SCANW("%hd", &BAwindow);
947 Curses_ChangeBetaWindow(void)
949 Curses_ShowMessage("WBwindow = ");
950 FLUSH_SCANW("%hd", &WBwindow);
951 Curses_ShowMessage("BBwindow = ");
952 FLUSH_SCANW("%hd", &BBwindow);
957 Curses_GiveHint(void)
963 algbr((short) (hint >> 8), (short) (hint & 0xFF), false);
966 Curses_ShowMessage(s);
970 Curses_ShowMessage("I have no idea.\n");
976 Curses_ChangeSearchDepth(void)
978 Curses_ShowMessage("depth = ");
979 FLUSH_SCANW("%hd", &MaxSearchDepth);
980 TCflag = !(MaxSearchDepth > 0);
985 Curses_ChangeHashDepth(void)
987 Curses_ShowMessage("hashdepth = ");
988 FLUSH_SCANW("%hd", &HashDepth);
989 Curses_ShowMessage("MoveLimit = ");
990 FLUSH_SCANW("%hd", &HashMoveLimit);
995 Curses_SetContempt(void)
997 Curses_ShowMessage("contempt = ");
998 FLUSH_SCANW("%hd", &contempt);
1003 Curses_ChangeXwindow(void)
1005 Curses_ShowMessage("xwndw= ");
1006 FLUSH_SCANW("%hd", &xwndw);
1011 Curses_SelectLevel(char *sx)
1015 Curses_ClearScreen();
1017 printw("GNU Shogi %s", PACKAGE_VERSION);
1019 printw(" 1. 40 moves in 5 minutes");
1021 printw(" 2. 40 moves in 15 minutes");
1023 printw(" 3. 40 moves in 30 minutes");
1025 printw(" 4. all moves in 15 minutes");
1027 printw(" 5. all moves in 30 minutes");
1029 printw(" 6. all moves in 15 minutes, 30 seconds fischer clock");
1031 printw(" 7. all moves in 30 minutes, 30 seconds fischer clock");
1033 printw(" 8. 1 move in 1 minute");
1035 printw(" 9. 1 move in 15 minutes");
1037 printw("10. 1 move in 30 minutes");
1045 printw("Enter Level: ");
1047 FLUSH_SCANW("%d", &item);
1094 flag.onemove = true;
1100 flag.onemove = true;
1106 flag.onemove = true;
1110 TCflag = (TCmoves > 0);
1112 TimeControl.clock[black] = TimeControl.clock[white] = 0;
1115 Curses_ClearScreen();
1116 Curses_UpdateDisplay(0, 0, 1, 0);
1121 Curses_DoDebug(void)
1123 short c, p, sq, tp, tc, tsq, score;
1126 ExaminePosition(opponent);
1127 Curses_ShowMessage("Enter piece: ");
1128 FLUSH_SCANW("%s", s);
1131 if ((s[0] == 'b') || (s[0] == 'B'))
1134 if ((s[0] == 'w') || (s[0] == 'W'))
1137 for (p = king; p > no_piece; p--)
1139 if ((s[1] == pxx[p]) || (s[1] == qxx[p]))
1143 for (sq = 0; sq < NO_SQUARES; sq++)
1149 tsq = PieceList[c][1];
1150 PieceList[c][1] = sq;
1151 Curses_ShowPostnValue(sq);
1152 PieceList[c][1] = tsq;
1157 score = ScorePosition(opponent);
1159 printw("S%d m%d ps%d gt%c m%d ps%d gt%c", score,
1160 mtl[computer], pscore[computer], GameType[computer],
1161 mtl[opponent], pscore[opponent], GameType[opponent]);
1168 Curses_DoTable(short table[NO_SQUARES])
1171 ExaminePosition(opponent);
1173 for (sq = 0; sq < NO_SQUARES; sq++)
1175 gotoXY(4 + 5 * VIR_C(sq), 5 + 2 * (7 - VIR_R(sq)));
1176 printw("%3d ", table[sq]);
1182 Curses_PollForInput(void)
1187 if ((i = ioctl((int) 0, FIONREAD, &nchar)))
1191 "You probably have a non-ANSI <ioctl.h>; "
1192 "see README. %d %d %x\n",
1193 i, errno, FIONREAD);
1202 flag.bothsides = false;
1208 Curses_SetupBoard(void)
1210 Curses_ShowMessage("'setup' command is not supported in Cursesmode");
1214 struct display curses_display =
1216 .ChangeAlphaWindow = Curses_ChangeAlphaWindow,
1217 .ChangeBetaWindow = Curses_ChangeBetaWindow,
1218 .ChangeHashDepth = Curses_ChangeHashDepth,
1219 .ChangeSearchDepth = Curses_ChangeSearchDepth,
1220 .ChangeXwindow = Curses_ChangeXwindow,
1221 .ClearScreen = Curses_ClearScreen,
1222 .DoDebug = Curses_DoDebug,
1223 .DoTable = Curses_DoTable,
1224 .EditBoard = Curses_EditBoard,
1225 .ExitShogi = Curses_ExitShogi,
1226 .GiveHint = Curses_GiveHint,
1227 .Initialize = Curses_Initialize,
1228 .ShowNodeCnt = Curses_ShowNodeCnt,
1229 .OutputMove = Curses_OutputMove,
1230 .PollForInput = Curses_PollForInput,
1231 .SetContempt = Curses_SetContempt,
1232 .SearchStartStuff = Curses_SearchStartStuff,
1233 .SelectLevel = Curses_SelectLevel,
1234 .ShowCurrentMove = Curses_ShowCurrentMove,
1235 .ShowDepth = Curses_ShowDepth,
1236 .ShowGameType = Curses_ShowGameType,
1237 .ShowLine = Curses_ShowLine,
1238 .ShowMessage = Curses_ShowMessage,
1239 .AlwaysShowMessage = Curses_AlwaysShowMessage,
1240 .Printf = Curses_Printf,
1241 .doRequestInputString = Curses_doRequestInputString,
1242 .GetString = Curses_GetString,
1243 .SetupBoard = Curses_SetupBoard,
1244 .ShowPatternCount = Curses_ShowPatternCount,
1245 .ShowPostnValue = Curses_ShowPostnValue,
1246 .ShowPostnValues = Curses_ShowPostnValues,
1247 .ShowPrompt = Curses_ShowPrompt,
1248 .ShowResponseTime = Curses_ShowResponseTime,
1249 .ShowResults = Curses_ShowResults,
1250 .ShowSidetoMove = Curses_ShowSidetoMove,
1251 .ShowStage = Curses_ShowStage,
1252 .TerminateSearch = Curses_TerminateSearch,
1253 .UpdateClocks = Curses_UpdateClocks,
1254 .UpdateDisplay = Curses_UpdateDisplay,
1255 .help = Curses_help,