Allow "depth <n>" syntax.
[gnushogi.git] / gnushogi / cursesdsp.c
1 /*
2  * FILE: cursesdsp.c
3  *
4  *     Curses interface 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 #include <ctype.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdarg.h>
38
39 #include <sys/param.h>
40 #include <sys/types.h>
41 #include <sys/file.h>
42 #include <curses.h>
43
44 #include "gnushogi.h"
45
46 #if HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49
50 #if HAVE_SYS_FILIO_H
51 /* Definition of FIONREAD */
52 #include <sys/filio.h>
53 #endif
54
55 #if HAVE_ERRNO_H
56 /* Definition of errno(). */
57 #include <errno.h>
58 #endif
59
60 #define FLUSH_SCANW fflush(stdout), scanw
61
62 int mycnt1, mycnt2;
63
64 #define TAB (58)
65
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))
68
69 unsigned short MV[MAXDEPTH];
70 int MSCORE;
71 char *DRAW;
72
73 /****************************************
74  * forward declarations
75  ****************************************/
76
77 /* FIXME: change this name, puh-leeze! */
78 static void UpdateCatched(void);
79 static void DrawPiece(short sq);
80 static void ShowScore(short score);
81 void Curses_UpdateDisplay(short f, short t, short redraw, short isspec);
82 void Curses_Die(int sig);
83 void Curses_ShowSidetoMove(void);
84
85 /****************************************
86  * Trivial output functions.
87  ****************************************/
88
89 static void
90 ClearEoln(void)
91 {
92     clrtoeol();
93     refresh();
94 }
95
96
97 void
98 Curses_ClearScreen(void)
99 {
100     clear();
101     refresh();
102 }
103
104
105 static void
106 gotoXY(short x, short y)
107 {
108     move(y - 1, x - 1);
109 }
110
111
112 void
113 Curses_ShowCurrentMove(short pnt, short f, short t)
114 {
115     algbr(f, t, false);
116     gotoXY(TAB, 7);
117     printw("(%2d) %5s ", pnt, mvstr[0]);
118 }
119
120
121 void
122 Curses_ShowDepth(char ch)
123 {
124     gotoXY(TAB, 4);
125     printw("Depth= %d%c ", Sdepth, ch);
126     ClearEoln();
127 }
128
129
130 void
131 Curses_ShowGameType(void)
132 {
133     if (flag.post)
134     {
135         gotoXY(TAB, 20);
136         printw("%c vs. %c", GameType[black], GameType[white]);
137     }
138 }
139
140
141 void
142 ShowHeader(void)
143 {
144     gotoXY(TAB, 2);
145     printw("GNU Shogi %s", PACKAGE_VERSION);
146 }
147
148
149 void
150 Curses_ShowLine(unsigned short *bstline)
151 {
152 }
153
154
155 void
156 Curses_ShowMessage(char *s)
157 {
158     gotoXY(TAB, 6);
159     printw("%s", s);
160     ClearEoln();
161 }
162
163
164 void
165 Curses_AlwaysShowMessage(const char *format, ...)
166 {
167     static char buffer[60];
168     va_list ap;
169     va_start(ap, format);
170     vsnprintf(buffer, sizeof(buffer), format, ap);
171     Curses_ShowMessage(buffer);
172     va_end(ap);
173 }
174
175
176 void
177 Curses_Printf(const char *format, ...)
178 {
179     static char buffer[60];
180     va_list ap;
181     va_start(ap, format);
182     vsnprintf(buffer, sizeof(buffer), format, ap);
183     printw("%s", buffer);
184     va_end(ap);
185 }
186
187
188 void
189 Curses_doRequestInputString(const char* fmt, char* buffer)
190 {
191     FLUSH_SCANW(fmt, buffer);
192 }
193
194
195 int
196 Curses_GetString(char* sx)
197 {
198     fflush(stdout);
199     return (getstr(sx) == ERR);
200 }
201
202
203 void
204 Curses_ShowNodeCnt(long NodeCnt)
205 {
206     gotoXY(TAB, 22);
207     /* printw("Nodes = %8ld, Nodes/Sec = %5ld", NodeCnt, (et > 100) ? NodeCnt / (et / 100) : 0); */
208     printw("n = %ld n/s = %ld", 
209            NodeCnt, (et > 100) ? NodeCnt / (et / 100) : 0);
210     ClearEoln();
211 }
212
213
214 void
215 Curses_ShowPatternCount(short side, short n)
216 {
217     if (flag.post)
218     {
219         gotoXY(TAB + 10 + 3 * side, 20);          /* CHECKME */
220
221         if (n >= 0)
222             printw("%3d", n);
223         else
224             printw("   ");
225     }
226 }
227
228
229 static void
230 ShowPlayers(void)
231 {
232     gotoXY(5, ((flag.reverse) ? (5 + 2*NO_ROWS) : 2));
233     printw("%s", (computer == white) ? "Computer" : "Human   ");
234     gotoXY(5, ((flag.reverse) ? 2 : (5 + 2*NO_ROWS)));
235     printw("%s", (computer == black) ? "Computer" : "Human   ");
236 }
237
238
239 void
240 Curses_ShowPrompt(void)
241 {
242     Curses_ShowSidetoMove();
243     gotoXY(TAB, 17);
244     printw("Your move is? ");
245     ClearEoln();
246 }
247
248
249 void
250 Curses_ShowResponseTime(void)
251 {
252     if (flag.post)
253     {
254         short TCC = TCcount;
255         gotoXY(TAB, 21);
256         printw("%ld, %d, %ld, %ld, %ld, %d",
257                ResponseTime, TCC, TCleft, ExtraTime, et, flag.timeout);
258         ClearEoln();
259     }
260 }
261
262
263 void
264 Curses_ShowResults(short score, unsigned short *bstline, char ch)
265 {
266     unsigned char d, ply;
267
268     if (flag.post)
269     {
270         Curses_ShowDepth(ch);
271         ShowScore(score);
272         d = 7;
273
274         for (ply = 1; bstline[ply] > 0; ply++)
275         {
276             if (ply % 2 == 1)
277             {
278                 gotoXY(TAB, ++d);
279                 ClearEoln();
280             }
281
282             algbr((short) bstline[ply] >> 8, 
283                   (short) bstline[ply] & 0xFF, false);
284             printw("%5s ", mvstr[0]);
285         }
286
287         ClearEoln();
288
289         while (d < 13)
290         {
291             gotoXY(TAB, ++d);
292             ClearEoln();
293         }
294     }
295 }
296
297
298 static void
299 ShowScore(short score)
300 {
301     gotoXY(TAB, 5);
302     printw("Score= %d", score);
303     ClearEoln();
304 }
305
306
307 void
308 Curses_ShowSidetoMove(void)
309 {
310     gotoXY(TAB, 14);
311     printw("%2d:   %s", 1 + GameCnt / 2, ColorStr[player]);
312     ClearEoln();
313 }
314
315
316 void
317 Curses_ShowStage(void)
318 {
319     gotoXY(TAB, 19);
320     printw("Stage= %2d%c B= %2d W= %2d",
321            stage, flag.tsume?'T':' ', balance[black], balance[white]);
322     ClearEoln();
323 }
324
325 /****************************************
326  * End of trivial output routines.
327  ****************************************/
328
329 void
330 Curses_Initialize(void)
331 {
332     signal(SIGINT, Curses_Die);
333     signal(SIGQUIT, Curses_Die);
334     initscr();
335     crmode();
336 }
337
338
339 void
340 Curses_ExitShogi(void)
341
342     if (!nolist)
343         ListGame();
344
345     gotoXY(1, 24);
346
347     refresh();
348     nocrmode();
349     endwin();
350
351     exit(0);
352 }
353
354
355 void
356 Curses_Die(int sig)
357 {
358     char s[80];
359
360     signal(SIGINT, SIG_IGN);
361     signal(SIGQUIT, SIG_IGN);
362
363     Curses_ShowMessage("Abort? ");
364     FLUSH_SCANW("%s", s);
365
366     if (strcmp(s, "yes") == 0)
367         Curses_ExitShogi();
368
369     signal(SIGINT, Curses_Die);
370     signal(SIGQUIT, Curses_Die);
371 }
372
373
374 void
375 Curses_TerminateSearch(int sig)
376 {
377     signal(SIGINT, SIG_IGN);
378     signal(SIGQUIT, SIG_IGN);
379
380     if (!flag.timeout)
381         flag.musttimeout = true;
382
383     Curses_ShowMessage("Terminate Search");
384     flag.bothsides = false;
385     signal(SIGINT, Curses_Die);
386     signal(SIGQUIT, Curses_Die);
387 }
388
389
390 void
391 Curses_help(void)
392 {
393     Curses_ClearScreen();
394     printw("GNU Shogi %s command summary\n", PACKAGE_VERSION);
395     printw("-------------------------------"
396            "---------------------------------\n");
397     printw("7g7f      move from 7g to 7f      quit      Exit Shogi\n");
398     printw("S6h       move silver to 6h       beep      turn %s\n", (flag.beep) ? "OFF" : "ON");
399     printw("2d2c+     move to 2c and promote  material  turn %s\n", (flag.material) ? "OFF" : "ON");
400     printw("P*5e      drop pawn to 5e         easy      turn %s\n", (flag.easy) ? "OFF" : "ON");
401     printw("tsume     toggle tsume mode       hash      turn %s\n", (flag.hash) ? "OFF" : "ON");
402     printw("bd        redraw board            reverse   board display\n");
403     printw("list      game to shogi.lst       book      turn %s used %d of %d\n", (Book) ? "OFF" : "ON", bookcount, BOOKSIZE);
404     printw("undo      undo last ply           remove    take back a move\n");
405     printw("edit      edit board              force     toggle manual move mode\n");
406     printw("switch    sides with computer     both      computer match\n");
407     printw("black     computer plays black    white     computer plays white\n");
408     printw("depth     set search depth        clock     set time control\n");
409     printw("post      principle variation     hint      suggest a move\n", (flag.post) ? "OFF" : "ON");
410     printw("save      game to file            get       game from file\n");
411     printw("random    randomize play          new       start new game\n");
412     gotoXY(10, 20);
413     printw("Computer: %s", ColorStr[computer]);
414     gotoXY(10, 21);
415     printw("Opponent: %s", ColorStr[opponent]);
416     gotoXY(10, 22);
417     printw("Level: %ld", MaxResponseTime/100);
418     gotoXY(10, 23);
419     printw("Easy mode: %s", (flag.easy) ? "ON" : "OFF");
420     gotoXY(25, 23);
421     printw("Tsume: %s", (flag.tsume) ? "ON" : "OFF");
422     gotoXY(40, 20);
423     printw("Depth: %d", MaxSearchDepth);
424     gotoXY(40, 21);
425     printw("Random: %s", (dither) ? "ON" : "OFF");
426     gotoXY(40, 22);
427     printw("Transposition table: %s", (flag.hash) ? "ON" : "OFF");
428     gotoXY(40, 23);
429     printw("Hit <RET> to return: ");
430     gotoXY(10, 24);
431     printw("Time Control %s %d moves %d sec %d add %d depth\n", (TCflag) ? "ON" : "OFF",
432            TimeControl.moves[black], 
433            TimeControl.clock[black] / 100, 
434            OperatorTime, MaxSearchDepth);
435
436     refresh();
437
438 #ifdef BOGUS
439     fflush(stdin); /* what is this supposed to do?? */
440 #endif /* BOGUS */
441
442     getchar();
443     Curses_ClearScreen();
444     Curses_UpdateDisplay(0, 0, 1, 0);
445 }
446
447
448 static const short x0[2] = { 54, 2 };
449 static const short y0[2] = { 20, 4 };
450
451
452 /*
453  * Set up a board position. Pieces are entered by typing the piece followed
454  * by the location. For example, N3f will place a knight on square 3f.
455  * P* will put a pawn to the captured pieces.
456  */
457
458 void
459 Curses_EditBoard(void)
460 {
461     short a, c, sq, i;
462     short r = 0;
463     char s[80];
464
465     flag.regularstart = true;
466     Book = BOOKFAIL;
467     Curses_ClearScreen();
468     Curses_UpdateDisplay(0, 0, 1, 0);
469     gotoXY(TAB, 3);
470     printw(".   Exit to main\n");
471     gotoXY(TAB, 4);
472     printw("#   Clear board\n");
473     gotoXY(TAB, 5);
474     printw("c   Change sides\n");
475     gotoXY(TAB, 7);
476     printw("Enter piece & location: ");
477     a = black;
478
479     do
480     {
481         gotoXY(TAB, 6);
482         printw("Editing: %s", ColorStr[a]);
483         gotoXY(TAB + 24, 7);
484         ClearEoln();
485         FLUSH_SCANW("%s", s);
486
487         if (s[0] == '#')
488         {
489             for (sq = 0; sq < NO_SQUARES; sq++)
490             {
491                 board[sq] = no_piece;
492                 color[sq] = neutral;
493                 DrawPiece(sq);
494             }
495
496             ClearCaptured();
497             UpdateCatched();
498         }
499
500         if (s[0] == 'c')
501             a = otherside[a];
502
503         if (s[1] == '*')
504         {
505             for (i = NO_PIECES; i > no_piece; i--)
506             {
507                 if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
508                     break;
509             }
510
511             Captured[a][unpromoted[i]]++;
512             UpdateCatched();
513             c = -1;
514         }
515         else
516         {
517             c = COL_NAME(s[1]);
518             r = ROW_NAME(s[2]);
519         }
520
521         if ((c >= 0) && (c < NO_COLS) && (r >= 0) && (r < NO_ROWS))
522         {
523             sq = locn(r, c);
524
525             for (i = NO_PIECES; i > no_piece; i--)
526             {
527                 if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
528                     break;
529             }
530
531             if (s[3] == '+')
532                 i = promoted[i];
533             else
534                 i = unpromoted[i];
535
536             board[sq] = i;
537             color[sq] = ((board[sq] == no_piece) ? neutral : a);
538             DrawPiece(sq);
539         }
540     }
541     while (s[0] != '.');
542
543     for (sq = 0; sq < NO_SQUARES; sq++)
544         Mvboard[sq] = ((board[sq] != Stboard[sq]) ? 10 : 0);
545
546     GameCnt = 0;
547     Game50 = 1;
548     ZeroRPT();
549     Sdepth = 0;
550     InitializeStats();
551     Curses_ClearScreen();
552     Curses_UpdateDisplay(0, 0, 1, 0);
553 }
554
555
556 static void 
557 UpdateCatched()
558 {
559     short side;
560
561     for (side = black; side <= white; side++)
562     { 
563         short x, y, piece, cside, k;
564
565         cside = flag.reverse ? (side ^ 1) : side;
566         x = x0[cside];
567         y = y0[cside];
568         k = 0;
569
570         for (piece = pawn; piece <= king; piece++)
571         {
572             short n;
573
574             if ((n = Captured[side][piece]))
575             {
576                 gotoXY(x, y); 
577                 printw("%i%c", n, pxx[piece]);
578
579                 if (cside == black) 
580                     y--; 
581                 else 
582                     y++;
583             }
584             else
585             {
586                 k++;
587             }
588         }
589
590         while (k)
591         {
592             k--;
593             gotoXY(x, y);
594             printw("  ");
595
596             if (cside == black) 
597                 y--; 
598             else 
599                 y++;
600         }
601     }
602
603     refresh();
604 }
605
606
607 void
608 Curses_SearchStartStuff(short side)
609 {
610     short i;
611
612     signal(SIGINT, Curses_TerminateSearch);
613     signal(SIGQUIT, Curses_TerminateSearch);
614
615     for (i = 4; i < 14; i++)                      /* CHECKME */
616     {
617         gotoXY(TAB, i);
618         ClearEoln();
619     }
620 }
621
622
623 void
624 Curses_OutputMove(void)
625 {
626
627     Curses_UpdateDisplay(root->f, root->t, 0, (short) root->flags);
628     gotoXY(TAB, 16);
629
630     if (flag.illegal) 
631     {
632         printw("Illegal position.");
633         return;
634     }
635
636     printw("My move is: %5s", mvstr[0]);
637
638     if (flag.beep)
639         putchar(7);
640
641     ClearEoln();
642
643     gotoXY(TAB, 18);
644
645     if (root->flags & draw)
646         printw("Drawn game!");
647     else if (root->score == -(SCORE_LIMIT + 999))
648         printw("Opponent mates!");
649     else if (root->score == SCORE_LIMIT + 998)
650         printw("Computer mates!");
651 #ifdef VERYBUGGY
652     else if (root->score < -SCORE_LIMIT)
653         printw("Opp: mate in %d!", SCORE_LIMIT + 999 + root->score - 1);
654     else if (root->score > SCORE_LIMIT)
655         printw("Comp: mate in %d!", SCORE_LIMIT + 998 - root->score - 1);
656 #endif /* VERYBUGGY */
657
658     ClearEoln();
659
660     if (flag.post)
661     {
662         short h, l, t;
663
664         h = TREE;
665         l = 0;
666         t = TREE >> 1;
667
668         while (l != t)
669         {
670             if (Tree[t].f || Tree[t].t)
671                 l = t;
672             else
673                 h = t;
674
675             t = (l + h) >> 1;
676         }
677
678         Curses_ShowNodeCnt(NodeCnt);
679         gotoXY(TAB, 23);
680         printw("Max Tree = %5d", t);
681         ClearEoln();
682     }
683
684     Curses_ShowSidetoMove();
685 }
686
687
688 void
689 Curses_UpdateClocks(void)
690 {
691     short m, s;
692     long dt;
693
694     if (TCflag)
695     {
696         m = (short) ((dt = (TimeControl.clock[player] - et)) / 6000);
697         s = (short) ((dt - 6000 * (long) m) / 100);
698     }
699     else
700     {
701         m = (short) ((dt = et) / 6000);
702         s = (short) (et - 6000 * (long) m) / 100;
703     }
704
705     if (m < 0)
706         m = 0;
707
708     if (s < 0)
709         s = 0;
710
711     if (player == black)
712         gotoXY(20, (flag.reverse) ? 2 : 23);
713     else
714         gotoXY(20, (flag.reverse) ? 23 : 2);
715
716     /* printw("%d:%02d %ld  ", m, s, dt); */
717     printw("%d:%02d  ", m, s); 
718
719     if (flag.post)
720         Curses_ShowNodeCnt(NodeCnt);
721
722     refresh();
723 }
724
725
726 static void
727 DrawPiece(short sq)
728 {
729     char y;
730     char piece, l, r, p; 
731
732     if (color[sq] == neutral)
733     {
734         l = r = ' ';
735     }
736     else if (flag.reverse ^ (color[sq] == black))
737     {
738         l = '/';
739         r = '\\';
740     } 
741     else
742     {
743         l = '\\', r = '/';
744     }
745
746     piece = board[sq];
747
748     if (is_promoted[(int)piece])
749     {
750         p = '+';
751         y = pxx[unpromoted[(int)piece]];
752     } 
753     else
754     {
755         p = ' ';
756         y = pxx[(int)piece];
757     }
758
759     gotoXY(8 + 5 * VIR_C(sq), 4 + 2 * ((NO_ROWS - 1) - VIR_R(sq)));
760     printw("%c%c%c%c", l, p, y, r);
761 }
762
763
764 /*
765  * Curses_ShowPostnValue(): must have called ExaminePosition() first
766  */
767 void
768 Curses_ShowPostnValue(short sq)
769 {
770     gotoXY(4 + 5 * VIR_C(sq), 5 + 2 * (7 - VIR_R(sq))); /* CHECKME */
771     (void) ScorePosition(color[sq]);
772
773     if (color[sq] != neutral)
774 #if defined SAVE_SVALUE
775     {
776         printw("??? ");
777     }
778 #else
779     {
780         printw("%3d ", svalue[sq]);
781     }
782 #endif
783     else
784     {
785         printw("   ");
786     }
787 }
788
789
790 void
791 Curses_ShowPostnValues(void)
792 {
793     short sq, score;
794
795     ExaminePosition(opponent);
796
797     for (sq = 0; sq < NO_SQUARES; sq++)
798         Curses_ShowPostnValue(sq);
799
800     score = ScorePosition(opponent);
801     gotoXY(TAB, 5);
802     printw("S%d m%d ps%d gt%c m%d ps%d gt%c", score,
803            mtl[computer], pscore[computer], GameType[computer],
804            mtl[opponent], pscore[opponent], GameType[opponent]);
805
806     ClearEoln();
807 }
808
809
810 void
811 Curses_UpdateDisplay(short f, short t, short redraw, short isspec)
812 {
813     short i, sq, z;
814     int j;
815
816     if (redraw)
817     {
818         ShowHeader();
819         ShowPlayers();
820
821         i = 2;
822         gotoXY(3, ++i);
823
824         printw("    +");
825         for (j=0; j<NO_COLS; j++)
826             printw("----+");
827
828         while (i <= 1 + 2*NO_ROWS)
829         {
830             gotoXY(1, ++i);
831
832             if (flag.reverse)
833                 z = (i / 2) - 1;
834             else
835                 z = NO_ROWS + 2 - ((i + 1) / 2);
836
837             printw("    %c |", ROW_NAME(z+1));
838             for (j=0; j<NO_COLS; j++)
839                 printw("    |");
840
841             gotoXY(3, ++i);
842
843             if (i < 2 + 2*NO_ROWS)
844             {
845                 printw("    +");
846                 for (j=0; j<NO_COLS; j++)
847                     printw("----+");
848             }
849         }
850
851         printw("    +");
852         for (j=0; j<NO_COLS; j++)
853             printw("----+");
854
855         gotoXY(3, 4 + 2*NO_ROWS);
856         printw("    ");
857
858 #ifndef MINISHOGI
859         if (flag.reverse)
860             printw("  1    2    3    4    5    6    7    8    9");
861         else
862             printw("  9    8    7    6    5    4    3    2    1");
863 #else
864         if (flag.reverse)
865             printw("  1    2    3    4    5");
866         else
867             printw("  1    2    3    4    5");
868 #endif
869
870         for (sq = 0; sq < NO_SQUARES; sq++)
871             DrawPiece(sq);
872     }
873     else /* not redraw */
874     {
875         if (f < NO_SQUARES)
876             DrawPiece(f);
877
878         DrawPiece(t & 0x7f);
879     }
880
881     if ((isspec & capture) || (isspec & dropmask) || redraw)
882     {
883         short side;
884
885         for (side = black; side <= white; side++)
886         {
887             short x, y, piece, cside, k;
888             cside = flag.reverse ? (side ^ 1) : side;
889             x = x0[cside];
890             y = y0[cside];
891             k = 0;
892
893             for (piece = pawn; piece <= king; piece++)
894             {
895                 short n;
896
897                 if ((n = Captured[side][piece]))
898                 {
899                     gotoXY(x, y); 
900                     printw("%i%c", n, pxx[piece]);
901
902                     if (cside == black) y--; else y++;
903                 }
904                 else
905                 {
906                     k++;
907                 }
908             }
909
910             while (k)
911             {
912                 k--;
913                 gotoXY(x, y);
914                 printw("  ");
915
916                 if (cside == black) 
917                     y--;
918                 else 
919                     y++;
920             }
921         }
922     }
923
924     refresh();
925 }
926
927
928 void
929 Curses_ChangeAlphaWindow(void)
930 {
931     Curses_ShowMessage("WAwindow = ");
932     FLUSH_SCANW("%hd", &WAwindow);
933     Curses_ShowMessage("BAwindow = ");
934     FLUSH_SCANW("%hd", &BAwindow);
935 }
936
937
938 void
939 Curses_ChangeBetaWindow(void)
940 {
941     Curses_ShowMessage("WBwindow = ");
942     FLUSH_SCANW("%hd", &WBwindow);
943     Curses_ShowMessage("BBwindow = ");
944     FLUSH_SCANW("%hd", &BBwindow);
945 }
946
947
948 void
949 Curses_GiveHint(void)
950 {
951     char s[40];
952
953     if (hint)
954     {
955         algbr((short) (hint >> 8), (short) (hint & 0xFF), false);
956         strcpy(s, "try ");
957         strcat(s, mvstr[0]);
958         Curses_ShowMessage(s);
959     }
960     else
961     {
962         Curses_ShowMessage("I have no idea.\n");
963     }
964 }
965
966
967 void
968 Curses_ChangeSearchDepth(char* sx)
969 {
970     Curses_ShowMessage("depth = ");
971     FLUSH_SCANW("%hd", &MaxSearchDepth);
972     TCflag = !(MaxSearchDepth > 0);
973 }
974
975
976 void
977 Curses_ChangeHashDepth(void)
978 {
979     Curses_ShowMessage("hashdepth = ");
980     FLUSH_SCANW("%hd", &HashDepth);
981     Curses_ShowMessage("MoveLimit = ");
982     FLUSH_SCANW("%hd", &HashMoveLimit);
983 }
984
985
986 void
987 Curses_SetContempt(void)
988 {
989     Curses_ShowMessage("contempt = ");
990     FLUSH_SCANW("%hd", &contempt);
991 }
992
993
994 void
995 Curses_ChangeXwindow(void)
996 {
997     Curses_ShowMessage("xwndw= ");
998     FLUSH_SCANW("%hd", &xwndw);
999 }
1000
1001
1002 void
1003 Curses_SelectLevel(char *sx)
1004 {
1005     int item;
1006
1007     Curses_ClearScreen();
1008     gotoXY(32, 2);
1009     printw("GNU Shogi %s", PACKAGE_VERSION);
1010     gotoXY(20, 4);
1011     printw(" 1.   40 moves in   5 minutes");
1012     gotoXY(20, 5);
1013     printw(" 2.   40 moves in  15 minutes");
1014     gotoXY(20, 6);
1015     printw(" 3.   40 moves in  30 minutes");
1016     gotoXY(20, 7);
1017     printw(" 4.  all moves in  15 minutes");
1018     gotoXY(20, 8);
1019     printw(" 5.  all moves in  30 minutes");
1020     gotoXY(20, 9);
1021     printw(" 6.  all moves in  15 minutes, 30 seconds fischer clock");
1022     gotoXY(20, 10);
1023     printw(" 7.  all moves in  30 minutes, 30 seconds fischer clock");
1024     gotoXY(20, 11);
1025     printw(" 8.    1 move  in   1 minute");
1026     gotoXY(20, 12);
1027     printw(" 9.    1 move  in  15 minutes");
1028     gotoXY(20, 13);
1029     printw("10.    1 move  in  30 minutes");
1030
1031     OperatorTime = 0;
1032     TCmoves = 40;
1033     TCminutes = 5;
1034     TCseconds = 0;
1035
1036     gotoXY(20, 17);
1037     printw("Enter Level: ");
1038     refresh();
1039     FLUSH_SCANW("%d", &item);
1040
1041     switch(item)
1042     {
1043     case 1:
1044         TCmoves = 40;
1045         TCminutes = 5;
1046         break;
1047
1048     case 2:
1049         TCmoves = 40;
1050         TCminutes = 15;
1051         break;
1052
1053     case 3:
1054         TCmoves = 40;
1055         TCminutes = 30;
1056         break;
1057
1058     case 4:
1059         TCmoves = 80;
1060         TCminutes = 15;
1061         flag.gamein = true;
1062         break;
1063
1064     case 5:
1065         TCmoves = 80;
1066         TCminutes = 30;
1067         flag.gamein = true;
1068         break;
1069
1070     case 6:
1071         TCmoves = 80;
1072         TCminutes = 15;
1073         TCadd = 3000;
1074         flag.gamein = true;
1075         break;
1076
1077     case 7:
1078         TCmoves = 80;
1079         TCminutes = 30;
1080         TCadd = 3000;
1081         break;
1082
1083     case 8:
1084         TCmoves = 1;
1085         TCminutes = 1;
1086         flag.onemove = true;
1087         break;
1088
1089     case 9:
1090         TCmoves = 1;
1091         TCminutes = 15;
1092         flag.onemove = true;
1093         break;
1094
1095     case 10:
1096         TCmoves = 1;
1097         TCminutes = 30;
1098         flag.onemove = true;
1099         break;
1100     }
1101
1102     TCflag = (TCmoves > 0);
1103
1104     TimeControl.clock[black] = TimeControl.clock[white] = 0; 
1105
1106     SetTimeControl();
1107     Curses_ClearScreen();
1108     Curses_UpdateDisplay(0, 0, 1, 0);
1109 }
1110
1111
1112 void
1113 Curses_DoDebug(void)
1114 {
1115     short c, p, sq, tp, tc, tsq, score;
1116     char s[40];
1117
1118     ExaminePosition(opponent);
1119     Curses_ShowMessage("Enter piece: ");
1120     FLUSH_SCANW("%s", s);
1121     c = neutral;
1122
1123     if ((s[0] == 'b') || (s[0] == 'B'))
1124         c = black;
1125
1126     if ((s[0] == 'w') || (s[0] == 'W'))
1127         c = white;
1128
1129     for (p = king; p > no_piece; p--)
1130     {
1131         if ((s[1] == pxx[p]) || (s[1] == qxx[p]))
1132             break;
1133     }
1134
1135     for (sq = 0; sq < NO_SQUARES; sq++)
1136     {
1137         tp = board[sq];
1138         tc = color[sq];
1139         board[sq] = p;
1140         color[sq] = c;
1141         tsq = PieceList[c][1];
1142         PieceList[c][1] = sq;
1143         Curses_ShowPostnValue(sq);
1144         PieceList[c][1] = tsq;
1145         board[sq] = tp;
1146         color[sq] = tc;
1147     }
1148
1149     score = ScorePosition(opponent);
1150     gotoXY(TAB, 5);
1151     printw("S%d m%d ps%d gt%c m%d ps%d gt%c", score,
1152            mtl[computer], pscore[computer], GameType[computer],
1153            mtl[opponent], pscore[opponent], GameType[opponent]);
1154
1155     ClearEoln();
1156 }
1157
1158
1159 void
1160 Curses_DoTable(short table[NO_SQUARES])
1161 {
1162     short  sq;
1163     ExaminePosition(opponent);
1164
1165     for (sq = 0; sq < NO_SQUARES; sq++)
1166     {
1167         gotoXY(4 + 5 * VIR_C(sq), 5 + 2 * (7 - VIR_R(sq)));
1168         printw("%3d ", table[sq]);
1169     }
1170
1171
1172
1173 void
1174 Curses_PollForInput(void)
1175 {
1176     int  i;
1177     int  nchar;
1178
1179     if ((i = ioctl((int) 0, FIONREAD, &nchar)))
1180     {
1181         perror("FIONREAD");
1182         fprintf(stderr,
1183                 "You probably have a non-ANSI <ioctl.h>; "
1184                 "see README. %d %d %x\n",
1185                 i, errno, FIONREAD);
1186         exit(1);
1187     }
1188
1189     if (nchar)
1190     {
1191         if (!flag.timeout)
1192             flag.back = true;
1193
1194         flag.bothsides = false;
1195     }
1196 }
1197
1198
1199 void
1200 Curses_SetupBoard(void)
1201 {
1202     Curses_ShowMessage("'setup' command is not supported in Cursesmode");
1203 }
1204
1205
1206 struct display curses_display =
1207 {
1208     .ChangeAlphaWindow    = Curses_ChangeAlphaWindow,
1209     .ChangeBetaWindow     = Curses_ChangeBetaWindow,
1210     .ChangeHashDepth      = Curses_ChangeHashDepth,
1211     .ChangeSearchDepth    = Curses_ChangeSearchDepth,
1212     .ChangeXwindow        = Curses_ChangeXwindow,
1213     .ClearScreen          = Curses_ClearScreen,
1214     .DoDebug              = Curses_DoDebug,
1215     .DoTable              = Curses_DoTable,
1216     .EditBoard            = Curses_EditBoard,
1217     .ExitShogi            = Curses_ExitShogi,
1218     .GiveHint             = Curses_GiveHint,
1219     .Initialize           = Curses_Initialize,
1220     .ShowNodeCnt          = Curses_ShowNodeCnt,
1221     .OutputMove           = Curses_OutputMove,
1222     .PollForInput         = Curses_PollForInput,
1223     .SetContempt          = Curses_SetContempt,
1224     .SearchStartStuff     = Curses_SearchStartStuff,
1225     .SelectLevel          = Curses_SelectLevel,
1226     .ShowCurrentMove      = Curses_ShowCurrentMove,
1227     .ShowDepth            = Curses_ShowDepth,
1228     .ShowGameType         = Curses_ShowGameType,
1229     .ShowLine             = Curses_ShowLine,
1230     .ShowMessage          = Curses_ShowMessage,
1231     .AlwaysShowMessage    = Curses_AlwaysShowMessage,
1232     .Printf               = Curses_Printf,
1233     .doRequestInputString = Curses_doRequestInputString,
1234     .GetString            = Curses_GetString,
1235     .SetupBoard           = Curses_SetupBoard,
1236     .ShowPatternCount     = Curses_ShowPatternCount,
1237     .ShowPostnValue       = Curses_ShowPostnValue,
1238     .ShowPostnValues      = Curses_ShowPostnValues,
1239     .ShowPrompt           = Curses_ShowPrompt,
1240     .ShowResponseTime     = Curses_ShowResponseTime,
1241     .ShowResults          = Curses_ShowResults,
1242     .ShowSidetoMove       = Curses_ShowSidetoMove,
1243     .ShowStage            = Curses_ShowStage,
1244     .TerminateSearch      = Curses_TerminateSearch,
1245     .UpdateClocks         = Curses_UpdateClocks,
1246     .UpdateDisplay        = Curses_UpdateDisplay,
1247     .help                 = Curses_help,
1248 };