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