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