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