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