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