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>
44 #include "cursesdsp.h"
51 /* Definition of FIONREAD */
52 #include <sys/filio.h>
56 /* Definition of errno(). */
60 #define FLUSH_SCANW fflush(stdout), scanw
66 #define VIR_C(s) ((flag.reverse) ? (NO_COLS - 1 - column(s)) : column(s))
67 #define VIR_R(s) ((flag.reverse) ? (NO_ROWS - 1 - row(s)) : row(s))
69 unsigned short MV
[MAXDEPTH
];
73 /* Forward declarations. */
74 /* FIXME: change this name, puh-leeze! */
76 static void UpdateCatched(void);
77 static void DrawPiece(short sq
);
78 static void ShowScore(short score
);
80 /****************************************
81 * Trivial output functions.
82 ****************************************/
93 Curses_ClearScreen(void)
101 gotoXY(short x
, short y
)
116 Curses_ShowCurrentMove(short pnt
, short f
, short t
)
120 printw("(%2d) %5s ", pnt
, mvstr
[0]);
125 Curses_ShowDepth(char ch
)
128 printw(CP
[53], Sdepth
, ch
); /* Depth = %d%c */
134 Curses_ShowGameType(void)
139 printw("%c vs. %c", GameType
[black
], GameType
[white
]);
148 printw(CP
[69], version
, patchlevel
);
153 Curses_ShowLine(unsigned short *bstline
)
159 Curses_ShowMessage(char *s
)
168 Curses_AlwaysShowMessage(const char *format
, va_list ap
)
170 static char buffer
[60];
171 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
172 Curses_ShowMessage(buffer
);
177 Curses_Printf(const char *format
, va_list ap
)
179 static char buffer
[60];
180 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
181 printw("%s", buffer
);
186 Curses_doRequestInputString(const char* fmt
, char* buffer
)
188 FLUSH_SCANW(fmt
, buffer
);
193 Curses_GetString(char* sx
)
196 return (getstr(sx
) == ERR
);
201 Curses_ShowNodeCnt(long NodeCnt
)
204 /* printw(CP[90], NodeCnt, (et > 100) ? NodeCnt / (et / 100) : 0); */
205 printw("n = %ld n/s = %ld",
206 NodeCnt
, (et
> 100) ? NodeCnt
/ (et
/ 100) : 0);
212 Curses_ShowPatternCount(short side
, short n
)
216 gotoXY(TAB
+ 10 + 3 * side
, 20); /* CHECKME */
229 gotoXY(5, ((flag
.reverse
) ? (5 + 2*NO_ROWS
) : 2));
230 printw("%s", (computer
== white
) ? CP
[218] : CP
[74]);
231 gotoXY(5, ((flag
.reverse
) ? 2 : (5 + 2*NO_ROWS
)));
232 printw("%s", (computer
== black
) ? CP
[218] : CP
[74]);
237 Curses_ShowPrompt(void)
239 Curses_ShowSidetoMove();
241 printw(CP
[121]); /* Your move is? */
247 Curses_ShowResponseTime(void)
253 /* printw("RT = %ld TCC = %d TCL = %ld EX = %ld ET = %ld TO = %d",
254 ResponseTime, TCC, TCleft, ExtraTime, et, flag.timeout); */
255 printw("%ld, %d, %ld, %ld, %ld, %d",
256 ResponseTime
, TCC
, TCleft
, ExtraTime
, et
, flag
.timeout
);
263 Curses_ShowResults(short score
, unsigned short *bstline
, char ch
)
265 unsigned char d
, ply
;
269 Curses_ShowDepth(ch
);
273 for (ply
= 1; bstline
[ply
] > 0; ply
++)
281 algbr((short) bstline
[ply
] >> 8,
282 (short) bstline
[ply
] & 0xFF, false);
283 printw("%5s ", mvstr
[0]);
298 ShowScore(short score
)
301 printw(CP
[104], score
);
307 Curses_ShowSidetoMove(void)
310 printw("%2d: %s", 1 + GameCnt
/ 2, ColorStr
[player
]);
316 Curses_ShowStage(void)
319 printw("Stage= %2d%c B= %2d W= %2d",
320 stage
, flag
.tsume
?'T':' ', balance
[black
], balance
[white
]);
324 /****************************************
325 * End of trivial output routines.
326 ****************************************/
329 Curses_Initialize(void)
331 signal(SIGINT
, Curses_Die
);
332 signal(SIGQUIT
, Curses_Die
);
339 Curses_ExitShogi(void)
359 signal(SIGINT
, SIG_IGN
);
360 signal(SIGQUIT
, SIG_IGN
);
362 Curses_ShowMessage(CP
[31]); /* Abort? */
363 FLUSH_SCANW("%s", s
);
365 if (strcmp(s
, CP
[210]) == 0) /* yes */
368 signal(SIGINT
, Curses_Die
);
369 signal(SIGQUIT
, Curses_Die
);
374 Curses_TerminateSearch(int sig
)
376 signal(SIGINT
, SIG_IGN
);
377 signal(SIGQUIT
, SIG_IGN
);
380 flag
.musttimeout
= true;
382 Curses_ShowMessage("Terminate Search");
383 flag
.bothsides
= false;
384 signal(SIGINT
, Curses_Die
);
385 signal(SIGQUIT
, Curses_Die
);
392 Curses_ClearScreen();
393 /* printw("GNU Shogi ??p? command summary\n"); */
394 printw(CP
[40], version
, patchlevel
);
395 printw("-------------------------------"
396 "---------------------------------\n");
397 /* printw("7g7f move from 7g to 7f quit
400 /* printw("S6h move silver to 6h beep
401 * turn %s\n", (flag.beep) ? "off" : "on"); */
402 printw(CP
[86], (flag
.beep
) ? CP
[92] : CP
[93]);
403 /* printw("2d2c+ move to 2c and promote\n"); */
404 printw(CP
[128], (flag
.material
) ? CP
[92] : CP
[93]);
405 /* printw("P*5e drop a pawn to 5e easy
406 * turn %s\n", (flag.easy) ? "off" : "on"); */
407 printw(CP
[173], (flag
.easy
) ? CP
[92] : CP
[93]);
409 * turn %s\n", (flag.hash) ? "off" : "on"); */
410 printw(CP
[174], (flag
.hash
) ? CP
[92] : CP
[93]);
411 /* printw("bd redraw board reverse
412 * board display\n"); */
414 /* printw("list game to shogi.lst book
415 * turn %s used %d of %d\n", (Book) ? "off" : "on", book
417 printw(CP
[170], (Book
) ? CP
[92] : CP
[93], bookcount
, BOOKSIZE
);
418 /* printw("undo undo last ply remove
419 * take back a move\n"); */
421 /* printw("edit edit board force
422 * enter game moves\n"); */
424 /* printw("switch sides with computer both
425 * computer match\n"); */
427 /* printw("black computer plays black white
428 * computer plays white\n"); */
430 /* printw("depth set search depth clock
431 * set time control\n"); */
433 /* printw("hint suggest a move post
434 * turn %s principle variation\n", (flag.post) ? "off" :
436 printw(CP
[177], (flag
.post
) ? CP
[92] : CP
[93]);
437 /* printw("save game to file get
438 * game from file\n"); */
440 /* printw("random randomize play new
441 * start new game\n"); */
444 printw(CP
[47], ColorStr
[computer
]);
446 printw(CP
[97], ColorStr
[opponent
]);
448 printw(CP
[79], MaxResponseTime
/100);
450 printw(CP
[59], (flag
.easy
) ? CP
[93] : CP
[92]);
452 printw(CP
[231], (flag
.tsume
) ? CP
[93] : CP
[92]);
454 printw(CP
[52], MaxSearchDepth
);
456 printw(CP
[100], (dither
) ? CP
[93] : CP
[92]);
458 printw(CP
[112], (flag
.hash
) ? CP
[93] : CP
[92]);
462 printw(CP
[110], (TCflag
) ? CP
[93] : CP
[92],
463 TimeControl
.moves
[black
],
464 TimeControl
.clock
[black
] / 100,
465 OperatorTime
, MaxSearchDepth
);
470 fflush(stdin
); /* what is this supposed to do?? */
474 Curses_ClearScreen();
475 Curses_UpdateDisplay(0, 0, 1, 0);
479 static const short x0
[2] = { 54, 2 };
480 static const short y0
[2] = { 20, 4 };
484 * Set up a board position. Pieces are entered by typing the piece followed
485 * by the location. For example, N3f will place a knight on square 3f.
486 * P* will put a pawn to the captured pieces.
490 Curses_EditBoard(void)
496 flag
.regularstart
= true;
498 Curses_ClearScreen();
499 Curses_UpdateDisplay(0, 0, 1, 0);
513 printw(CP
[60], ColorStr
[a
]); /* Editing %s */
516 FLUSH_SCANW("%s", s
);
518 if (s
[0] == CP
[28][0]) /* # */
520 for (sq
= 0; sq
< NO_SQUARES
; sq
++)
522 board
[sq
] = no_piece
;
531 if (s
[0] == CP
[136][0]) /* c */
536 for (i
= NO_PIECES
; i
> no_piece
; i
--)
538 if ((s
[0] == pxx
[i
]) || (s
[0] == qxx
[i
]))
542 Captured
[a
][unpromoted
[i
]]++;
552 if ((c
>= 0) && (c
< NO_COLS
) && (r
>= 0) && (r
< NO_ROWS
))
556 for (i
= NO_PIECES
; i
> no_piece
; i
--)
558 if ((s
[0] == pxx
[i
]) || (s
[0] == qxx
[i
]))
568 color
[sq
] = ((board
[sq
] == no_piece
) ? neutral
: a
);
572 while (s
[0] != CP
[29][0]); /* . */
574 for (sq
= 0; sq
< NO_SQUARES
; sq
++)
575 Mvboard
[sq
] = ((board
[sq
] != Stboard
[sq
]) ? 10 : 0);
582 Curses_ClearScreen();
583 Curses_UpdateDisplay(0, 0, 1, 0);
592 for (side
= black
; side
<= white
; side
++)
594 short x
, y
, piece
, cside
, k
;
596 cside
= flag
.reverse
? (side
^ 1) : side
;
601 for (piece
= pawn
; piece
<= king
; piece
++)
605 if ((n
= Captured
[side
][piece
]))
608 printw("%i%c", n
, pxx
[piece
]);
639 Curses_SearchStartStuff(short side
)
643 signal(SIGINT
, Curses_TerminateSearch
);
644 signal(SIGQUIT
, Curses_TerminateSearch
);
646 for (i
= 4; i
< 14; i
++) /* CHECKME */
655 Curses_OutputMove(void)
658 Curses_UpdateDisplay(root
->f
, root
->t
, 0, (short) root
->flags
);
667 printw(CP
[84], mvstr
[0]); /* My move is %s */
676 if (root
->flags
& draw
)
678 else if (root
->score
== -(SCORE_LIMIT
+ 999))
680 else if (root
->score
== SCORE_LIMIT
+ 998)
683 else if (root
->score
< -SCORE_LIMIT
)
684 printw(CP
[96], SCORE_LIMIT
+ 999 + root
->score
- 1);
685 else if (root
->score
> SCORE_LIMIT
)
686 printw(CP
[45], SCORE_LIMIT
+ 998 - root
->score
- 1);
687 #endif /* VERYBUGGY */
701 if (Tree
[t
].f
|| Tree
[t
].t
)
709 ShowNodeCnt(NodeCnt
);
711 printw(CP
[81], t
); /* Max Tree= */
715 Curses_ShowSidetoMove();
720 Curses_UpdateClocks(void)
727 m
= (short) ((dt
= (TimeControl
.clock
[player
] - et
)) / 6000);
728 s
= (short) ((dt
- 6000 * (long) m
) / 100);
732 m
= (short) ((dt
= et
) / 6000);
733 s
= (short) (et
- 6000 * (long) m
) / 100;
743 gotoXY(20, (flag
.reverse
) ? 2 : 23);
745 gotoXY(20, (flag
.reverse
) ? 23 : 2);
747 /* printw("%d:%02d %ld ", m, s, dt); */
748 printw("%d:%02d ", m
, s
);
751 ShowNodeCnt(NodeCnt
);
763 if (color
[sq
] == neutral
)
767 else if (flag
.reverse
^ (color
[sq
] == black
))
779 if (is_promoted
[(int)piece
])
782 y
= pxx
[unpromoted
[(int)piece
]];
790 gotoXY(8 + 5 * VIR_C(sq
), 4 + 2 * ((NO_ROWS
- 1) - VIR_R(sq
)));
791 printw("%c%c%c%c", l
, p
, y
, r
);
796 * Curses_ShowPostnValue(): must have called ExaminePosition() first
799 Curses_ShowPostnValue(short sq
)
803 gotoXY(4 + 5 * VIR_C(sq
), 5 + 2 * (7 - VIR_R(sq
))); /* CHECKME */
804 score
= ScorePosition(color
[sq
]);
806 if (color
[sq
] != neutral
)
807 #if defined SAVE_SVALUE
813 printw("%3d ", svalue
[sq
]);
824 Curses_ShowPostnValues(void)
828 ExaminePosition(opponent
);
830 for (sq
= 0; sq
< NO_SQUARES
; sq
++)
831 Curses_ShowPostnValue(sq
);
833 score
= ScorePosition(opponent
);
835 printw(CP
[103], score
,
836 mtl
[computer
], pscore
[computer
], GameType
[computer
],
837 mtl
[opponent
], pscore
[opponent
], GameType
[opponent
]);
844 Curses_UpdateDisplay(short f
, short t
, short redraw
, short isspec
)
858 for (j
=0; j
<NO_COLS
; j
++)
861 while (i
<= 1 + 2*NO_ROWS
)
868 z
= NO_ROWS
+ 2 - ((i
+ 1) / 2);
870 printw(" %c |", ROW_NAME(z
+1));
871 for (j
=0; j
<NO_COLS
; j
++)
876 if (i
< 2 + 2*NO_ROWS
)
879 for (j
=0; j
<NO_COLS
; j
++)
885 for (j
=0; j
<NO_COLS
; j
++)
888 gotoXY(3, 4 + 2*NO_ROWS
);
896 for (sq
= 0; sq
< NO_SQUARES
; sq
++)
899 else /* not redraw */
907 if ((isspec
& capture
) || (isspec
& dropmask
) || redraw
)
911 for (side
= black
; side
<= white
; side
++)
913 short x
, y
, piece
, cside
, k
;
914 cside
= flag
.reverse
? (side
^ 1) : side
;
919 for (piece
= pawn
; piece
<= king
; piece
++)
923 if ((n
= Captured
[side
][piece
]))
926 printw("%i%c", n
, pxx
[piece
]);
928 if (cside
== black
) y
--; else y
++;
955 Curses_ChangeAlphaWindow(void)
957 Curses_ShowMessage(CP
[114]);
958 FLUSH_SCANW("%hd", &WAwindow
);
959 Curses_ShowMessage(CP
[34]);
960 FLUSH_SCANW("%hd", &BAwindow
);
965 Curses_ChangeBetaWindow(void)
967 Curses_ShowMessage(CP
[115]);
968 FLUSH_SCANW("%hd", &WBwindow
);
969 Curses_ShowMessage(CP
[35]);
970 FLUSH_SCANW("%hd", &BBwindow
);
975 Curses_GiveHint(void)
981 algbr((short) (hint
>> 8), (short) (hint
& 0xFF), false);
982 strcpy(s
, CP
[198]); /* try */
984 Curses_ShowMessage(s
);
988 Curses_ShowMessage(CP
[223]);
994 Curses_ChangeSearchDepth(void)
996 Curses_ShowMessage(CP
[150]);
997 FLUSH_SCANW("%hd", &MaxSearchDepth
);
998 TCflag
= !(MaxSearchDepth
> 0);
1003 Curses_ChangeHashDepth(void)
1005 Curses_ShowMessage(CP
[163]);
1006 FLUSH_SCANW("%hd", &HashDepth
);
1007 Curses_ShowMessage(CP
[82]);
1008 FLUSH_SCANW("%hd", &HashMoveLimit
);
1013 Curses_SetContempt(void)
1015 Curses_ShowMessage(CP
[142]);
1016 FLUSH_SCANW("%hd", &contempt
);
1021 Curses_ChangeXwindow(void)
1023 Curses_ShowMessage(CP
[208]);
1024 FLUSH_SCANW("%hd", &xwndw
);
1029 Curses_SelectLevel(char *sx
)
1033 Curses_ClearScreen();
1035 printw(CP
[41], version
, patchlevel
);
1065 FLUSH_SCANW("%d", &item
);
1112 flag
.onemove
= true;
1118 flag
.onemove
= true;
1124 flag
.onemove
= true;
1128 TCflag
= (TCmoves
> 0);
1130 TimeControl
.clock
[black
] = TimeControl
.clock
[white
] = 0;
1133 Curses_ClearScreen();
1134 Curses_UpdateDisplay(0, 0, 1, 0);
1139 Curses_DoDebug(void)
1141 short c
, p
, sq
, tp
, tc
, tsq
, score
;
1144 ExaminePosition(opponent
);
1145 Curses_ShowMessage(CP
[65]);
1146 FLUSH_SCANW("%s", s
);
1149 if ((s
[0] == CP
[9][0]) || (s
[0] == CP
[9][1])) /* b B */
1152 if ((s
[0] == CP
[9][2]) || (s
[0] == CP
[9][3])) /* w W */
1155 for (p
= king
; p
> no_piece
; p
--)
1157 if ((s
[1] == pxx
[p
]) || (s
[1] == qxx
[p
]))
1161 for (sq
= 0; sq
< NO_SQUARES
; sq
++)
1167 tsq
= PieceList
[c
][1];
1168 PieceList
[c
][1] = sq
;
1169 Curses_ShowPostnValue(sq
);
1170 PieceList
[c
][1] = tsq
;
1175 score
= ScorePosition(opponent
);
1177 printw(CP
[103], score
,
1178 mtl
[computer
], pscore
[computer
], GameType
[computer
],
1179 mtl
[opponent
], pscore
[opponent
], GameType
[opponent
]);
1186 Curses_DoTable(short table
[NO_SQUARES
])
1189 ExaminePosition(opponent
);
1191 for (sq
= 0; sq
< NO_SQUARES
; sq
++)
1193 gotoXY(4 + 5 * VIR_C(sq
), 5 + 2 * (7 - VIR_R(sq
)));
1194 printw("%3d ", table
[sq
]);
1200 Curses_PollForInput(void)
1205 if ((i
= ioctl((int) 0, FIONREAD
, &nchar
)))
1209 "You probably have a non-ANSI <ioctl.h>; "
1210 "see README. %d %d %x\n",
1211 i
, errno
, FIONREAD
);
1220 flag
.bothsides
= false;
1226 Curses_SetupBoard(void)
1228 Curses_ShowMessage("'setup' command is not supported in Cursesmode");