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