Curses: fix inverted column numbers display for minishogi.
[gnushogi.git] / gnushogi / cursesdsp.c
1 /*
2  * FILE: cursesdsp.c
3  *
4  *     Curses interface for GNU Shogi
5  *
6  * ----------------------------------------------------------------------
7  * Copyright (c) 1993, 1994, 1995 Matthias Mutz
8  * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
9  * 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 MARGIN (4)
68 #define TAB (58)
69
70 #define VIR_C(s)  ((flag.reverse) ? (NO_COLS - 1 - column(s)) : column(s))
71 #define VIR_R(s)  ((flag.reverse) ? (NO_ROWS - 1 - row(s)) : row(s))
72
73 unsigned short MV[MAXDEPTH];
74 int MSCORE;
75 char *DRAW;
76
77 /* Forward declarations. */
78 /* FIXME: change this name, puh-leeze! */
79
80 static void UpdateCatched(void);
81 static void DrawPiece(short sq);
82 static void ShowScore(short score);
83
84 /****************************************
85  * Trivial output functions.
86  ****************************************/
87
88 static void
89 ClearEoln(void)
90 {
91     clrtoeol();
92     refresh();
93 }
94
95
96 void
97 Curses_ClearScreen(void)
98 {
99     clear();
100     refresh();
101 }
102
103
104 static void
105 gotoXY(short x, short y)
106 {
107     move(y - 1, x - 1);
108 }
109
110
111 static void
112 ClearMessage(void)
113 {
114     gotoXY(TAB, 6);
115     ClearEoln();
116 }
117
118
119 void
120 Curses_ShowCurrentMove(short pnt, short f, short t)
121 {
122     algbr(f, t, false);
123     gotoXY(TAB, 7);
124     printw("(%2d) %5s ", pnt, mvstr[0]);
125 }
126
127
128 void
129 Curses_ShowDepth(char ch)
130 {
131     gotoXY(TAB, 4);
132     printw("Depth= %d%c ", Sdepth, ch);
133     ClearEoln();
134 }
135
136
137 void
138 Curses_ShowGameType(void)
139 {
140     if (flag.post)
141     {
142         gotoXY(TAB, 20);
143         printw("%c vs. %c", GameType[black], GameType[white]);
144     }
145 }
146
147
148 void
149 ShowHeader(void)
150 {
151     gotoXY(TAB, 2);
152     printw("GNU Shogi %s", PACKAGE_VERSION);
153 }
154
155
156 void
157 Curses_ShowLine(unsigned short *bstline)
158 {
159 }
160
161
162 void
163 Curses_ShowMessage(char *s)
164 {
165     gotoXY(TAB, 6);
166     printw("%s", s);
167     ClearEoln();
168 }
169
170
171 void
172 Curses_AlwaysShowMessage(const char *format, va_list ap)
173 {
174     static char buffer[60];
175     vsnprintf(buffer, sizeof(buffer), format, ap);
176     Curses_ShowMessage(buffer);
177 }
178
179
180 void
181 Curses_Printf(const char *format, va_list ap)
182 {
183     static char buffer[60];
184     vsnprintf(buffer, sizeof(buffer), format, ap);
185     printw("%s", buffer);
186 }
187
188
189 void
190 Curses_doRequestInputString(const char* fmt, char* buffer)
191 {
192     FLUSH_SCANW(fmt, buffer);
193 }
194
195
196 int
197 Curses_GetString(char* sx)
198 {
199     fflush(stdout);
200     return (getstr(sx) == ERR);
201 }
202
203
204 void
205 Curses_ShowNodeCnt(long NodeCnt)
206 {
207     gotoXY(TAB, 22);
208     /* printw("Nodes = %8ld, Nodes/Sec = %5ld", NodeCnt, (et > 100) ? NodeCnt / (et / 100) : 0); */
209     printw("n = %ld n/s = %ld", 
210            NodeCnt, (et > 100) ? NodeCnt / (et / 100) : 0);
211     ClearEoln();
212 }
213
214
215 void
216 Curses_ShowPatternCount(short side, short n)
217 {
218     if (flag.post)
219     {
220         gotoXY(TAB + 10 + 3 * side, 20);          /* CHECKME */
221
222         if (n >= 0)
223             printw("%3d", n);
224         else
225             printw("   ");
226     }
227 }
228
229
230 static void
231 ShowPlayers(void)
232 {
233     gotoXY(5, ((flag.reverse) ? (5 + 2*NO_ROWS) : 2));
234     printw("%s", (computer == white) ? "Computer" : "Human   ");
235     gotoXY(5, ((flag.reverse) ? 2 : (5 + 2*NO_ROWS)));
236     printw("%s", (computer == black) ? "Computer" : "Human   ");
237 }
238
239
240 void
241 Curses_ShowPrompt(void)
242 {
243     Curses_ShowSidetoMove();
244     gotoXY(TAB, 17);
245     printw("Your move is? ");
246     ClearEoln();
247 }
248
249
250 void
251 Curses_ShowResponseTime(void)
252 {
253     if (flag.post)
254     {
255         short TCC = TCcount;
256         gotoXY(TAB, 21);
257         printw("%ld, %d, %ld, %ld, %ld, %d",
258                ResponseTime, TCC, TCleft, ExtraTime, et, flag.timeout);
259         ClearEoln();
260     }
261 }
262
263
264 void
265 Curses_ShowResults(short score, unsigned short *bstline, char ch)
266 {
267     unsigned char d, ply;
268
269     if (flag.post)
270     {
271         Curses_ShowDepth(ch);
272         ShowScore(score);
273         d = 7;
274
275         for (ply = 1; bstline[ply] > 0; ply++)
276         {
277             if (ply % 2 == 1)
278             {
279                 gotoXY(TAB, ++d);
280                 ClearEoln();
281             }
282
283             algbr((short) bstline[ply] >> 8, 
284                   (short) bstline[ply] & 0xFF, false);
285             printw("%5s ", mvstr[0]);
286         }
287
288         ClearEoln();
289
290         while (d < 13)
291         {
292             gotoXY(TAB, ++d);
293             ClearEoln();
294         }
295     }
296 }
297
298
299 static void
300 ShowScore(short score)
301 {
302     gotoXY(TAB, 5);
303     printw("Score= %d", score);
304     ClearEoln();
305 }
306
307
308 void
309 Curses_ShowSidetoMove(void)
310 {
311     gotoXY(TAB, 14);
312     printw("%2d:   %s", 1 + GameCnt / 2, ColorStr[player]);
313     ClearEoln();
314 }
315
316
317 void
318 Curses_ShowStage(void)
319 {
320     gotoXY(TAB, 19);
321     printw("Stage= %2d%c B= %2d W= %2d",
322            stage, flag.tsume?'T':' ', balance[black], balance[white]);
323     ClearEoln();
324 }
325
326 /****************************************
327  * End of trivial output routines.
328  ****************************************/
329
330 void
331 Curses_Initialize(void)
332 {
333     signal(SIGINT, Curses_Die);
334     signal(SIGQUIT, Curses_Die);
335     initscr();
336     crmode();
337 }
338
339
340 void
341 Curses_ExitShogi(void)
342
343     if (!nolist)
344         ListGame();
345
346     gotoXY(1, 24);
347
348     refresh();
349     nocrmode();
350     endwin();
351
352     exit(0);
353 }
354
355
356 void
357 Curses_Die(int sig)
358 {
359     char s[80];
360
361     signal(SIGINT, SIG_IGN);
362     signal(SIGQUIT, SIG_IGN);
363
364     Curses_ShowMessage("Abort? ");
365     FLUSH_SCANW("%s", s);
366
367     if (strcmp(s, "yes") == 0)
368         Curses_ExitShogi();
369
370     signal(SIGINT, Curses_Die);
371     signal(SIGQUIT, Curses_Die);
372 }
373
374
375 void
376 Curses_TerminateSearch(int sig)
377 {
378     signal(SIGINT, SIG_IGN);
379     signal(SIGQUIT, SIG_IGN);
380
381     if (!flag.timeout)
382         flag.musttimeout = true;
383
384     Curses_ShowMessage("Terminate Search");
385     flag.bothsides = false;
386     signal(SIGINT, Curses_Die);
387     signal(SIGQUIT, Curses_Die);
388 }
389
390
391 void
392 Curses_help(void)
393 {
394     Curses_ClearScreen();
395     printw("GNU Shogi %s command summary\n", PACKAGE_VERSION);
396     printw("-------------------------------"
397            "---------------------------------\n");
398     printw("7g7f      move from 7g to 7f      quit      Exit Shogi\n");
399     printw("S6h       move silver to 6h       beep      turn %s\n", (flag.beep) ? "OFF" : "ON");
400     printw("2d2c+     move to 2c and promote  material  turn %s\n", (flag.material) ? "OFF" : "ON");
401     printw("P*5e      drop pawn to 5e         easy      turn %s\n", (flag.easy) ? "OFF" : "ON");
402     printw("tsume     toggle tsume mode       hash      turn %s\n", (flag.hash) ? "OFF" : "ON");
403     printw("bd        redraw board            reverse   board display\n");
404     printw("list      game to shogi.lst       book      turn %s used %d of %d\n", (Book) ? "OFF" : "ON", bookcount, BOOKSIZE);
405     printw("undo      undo last ply           remove    take back a move\n");
406     printw("edit      edit board              force     toggle manual move mode\n");
407     printw("switch    sides with computer     both      computer match\n");
408     printw("black     computer plays black    white     computer plays white\n");
409     printw("depth     set search depth        clock     set time control\n");
410     printw("post      principle variation     hint      suggest a move\n", (flag.post) ? "OFF" : "ON");
411     printw("save      game to file            get       game from file\n");
412     printw("random    randomize play          new       start new game\n");
413     gotoXY(10, 20);
414     printw("Computer: %s", ColorStr[computer]);
415     gotoXY(10, 21);
416     printw("Opponent: %s", ColorStr[opponent]);
417     gotoXY(10, 22);
418     printw("Level: %ld", MaxResponseTime/100);
419     gotoXY(10, 23);
420     printw("Easy mode: %s", (flag.easy) ? "ON" : "OFF");
421     gotoXY(25, 23);
422     printw("Tsume: %s", (flag.tsume) ? "ON" : "OFF");
423     gotoXY(40, 20);
424     printw("Depth: %d", MaxSearchDepth);
425     gotoXY(40, 21);
426     printw("Random: %s", (dither) ? "ON" : "OFF");
427     gotoXY(40, 22);
428     printw("Transposition table: %s", (flag.hash) ? "ON" : "OFF");
429     gotoXY(40, 23);
430     printw("Hit <RET> to return: ");
431     gotoXY(10, 24);
432     printw("Time Control %s %d moves %d sec %d add %d depth\n", (TCflag) ? "ON" : "OFF",
433            TimeControl.moves[black], 
434            TimeControl.clock[black] / 100, 
435            OperatorTime, MaxSearchDepth);
436
437     refresh();
438
439 #ifdef BOGUS
440     fflush(stdin); /* what is this supposed to do?? */
441 #endif /* BOGUS */
442
443     getchar();
444     Curses_ClearScreen();
445     Curses_UpdateDisplay(0, 0, 1, 0);
446 }
447
448
449 static const short x0[2] = { 54, 2 };
450 static const short y0[2] = { 20, 4 };
451
452
453 /*
454  * Set up a board position. Pieces are entered by typing the piece followed
455  * by the location. For example, N3f will place a knight on square 3f.
456  * P* will put a pawn to the captured pieces.
457  */
458
459 void
460 Curses_EditBoard(void)
461 {
462     short a, c, sq, i, found;
463     short r = 0;
464     char s[80];
465
466     flag.regularstart = true;
467     Book = BOOKFAIL;
468     Curses_ClearScreen();
469     Curses_UpdateDisplay(0, 0, 1, 0);
470     gotoXY(TAB, 3);
471     printw(".   Exit to main\n");
472     gotoXY(TAB, 4);
473     printw("#   Clear board\n");
474     gotoXY(TAB, 5);
475     printw("c   Change sides\n");
476     gotoXY(TAB, 7);
477     printw("Enter piece & location: ");
478     a = black;
479
480     while(1)
481     {
482         gotoXY(TAB, 6);
483         printw("Editing: %s", ColorStr[a]);
484         gotoXY(TAB + 24, 7);
485         ClearEoln();
486         FLUSH_SCANW("%s", s);
487         found = 0;
488
489         if (s[0] == '.')
490             break;
491
492         if (s[0] == '#')
493         {
494             for (sq = 0; sq < NO_SQUARES; sq++)
495             {
496                 board[sq] = no_piece;
497                 color[sq] = neutral;
498                 DrawPiece(sq);
499             }
500
501             ClearCaptured();
502             UpdateCatched();
503             continue;
504         }
505
506         if (s[0] == 'c') {
507             a = otherside[a];
508             continue;
509         }
510
511         if (s[1] == '*')
512         {
513             for (i = NO_PIECES; i > no_piece; i--)
514             {
515                 if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
516                 {
517                     Captured[a][unpromoted[i]]++;
518                     UpdateCatched();
519                     found = 1;
520                     break;
521                 }
522             }
523
524             continue;
525         }
526
527         c = COL_NUM(s[1]);
528         r = ROW_NUM(s[2]);
529
530         if ((c < 0) || (c >= NO_COLS) || (r < 0) || (r >= NO_ROWS))
531             continue;
532
533         sq = locn(r, c);
534         color[sq] = a;
535         board[sq] = no_piece;
536
537         for (i = NO_PIECES; i > no_piece; i--)
538         {
539             if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
540             {
541                 if (s[3] == '+')
542                     board[sq] = promoted[i];
543                 else
544                     board[sq] = unpromoted[i];
545
546                 found = 1;
547                 break;
548             }
549         }
550
551
552         if (found == 0)
553             color[sq] = neutral;
554
555         DrawPiece(sq);
556     }
557
558     for (sq = 0; sq < NO_SQUARES; sq++)
559         Mvboard[sq] = ((board[sq] != Stboard[sq]) ? 10 : 0);
560
561     GameCnt = 0;
562     Game50 = 1;
563     ZeroRPT();
564     Sdepth = 0;
565     InitializeStats();
566     Curses_ClearScreen();
567     Curses_UpdateDisplay(0, 0, 1, 0);
568 }
569
570
571 static void 
572 UpdateCatched()
573 {
574     short side;
575
576     for (side = black; side <= white; side++)
577     { 
578         short x, y, piece, cside, k;
579
580         cside = flag.reverse ? (side ^ 1) : side;
581         x = x0[cside];
582         y = y0[cside];
583         k = 0;
584
585         for (piece = pawn; piece <= king; piece++)
586         {
587             short n;
588
589             if ((n = Captured[side][piece]))
590             {
591                 gotoXY(x, y); 
592                 printw("%i%c", n, pxx[piece]);
593
594                 if (cside == black) 
595                     y--; 
596                 else 
597                     y++;
598             }
599             else
600             {
601                 k++;
602             }
603         }
604
605         while (k)
606         {
607             k--;
608             gotoXY(x, y);
609             printw("  ");
610
611             if (cside == black) 
612                 y--; 
613             else 
614                 y++;
615         }
616     }
617
618     refresh();
619 }
620
621
622 void
623 Curses_SearchStartStuff(short side)
624 {
625     short i;
626
627     signal(SIGINT, Curses_TerminateSearch);
628     signal(SIGQUIT, Curses_TerminateSearch);
629
630     for (i = 4; i < 14; i++)                      /* CHECKME */
631     {
632         gotoXY(TAB, i);
633         ClearEoln();
634     }
635 }
636
637
638 void
639 Curses_OutputMove(void)
640 {
641
642     Curses_UpdateDisplay(root->f, root->t, 0, (short) root->flags);
643     gotoXY(TAB, 16);
644
645     if (flag.illegal) 
646     {
647         printw("Illegal position.");
648         return;
649     }
650
651     printw("My move is: %5s", mvstr[0]);
652
653     if (flag.beep)
654         putchar(7);
655
656     ClearEoln();
657
658     gotoXY(TAB, 18);
659
660     if (root->flags & draw)
661         printw("Drawn game!");
662     else if (root->score == -(SCORE_LIMIT + 999))
663         printw("Opponent mates!");
664     else if (root->score == SCORE_LIMIT + 998)
665         printw("Computer mates!");
666 #ifdef VERYBUGGY
667     else if (root->score < -SCORE_LIMIT)
668         printw("Opp: mate in %d!", SCORE_LIMIT + 999 + root->score - 1);
669     else if (root->score > SCORE_LIMIT)
670         printw("Comp: mate in %d!", SCORE_LIMIT + 998 - root->score - 1);
671 #endif /* VERYBUGGY */
672
673     ClearEoln();
674
675     if (flag.post)
676     {
677         short h, l, t;
678
679         h = TREE;
680         l = 0;
681         t = TREE >> 1;
682
683         while (l != t)
684         {
685             if (Tree[t].f || Tree[t].t)
686                 l = t;
687             else
688                 h = t;
689
690             t = (l + h) >> 1;
691         }
692
693         ShowNodeCnt(NodeCnt);
694         gotoXY(TAB, 23);
695         printw("Max Tree = %5d", t);
696         ClearEoln();
697     }
698
699     Curses_ShowSidetoMove();
700 }
701
702
703 void
704 Curses_UpdateClocks(void)
705 {
706     short m, s;
707     long dt;
708
709     if (TCflag)
710     {
711         m = (short) ((dt = (TimeControl.clock[player] - et)) / 6000);
712         s = (short) ((dt - 6000 * (long) m) / 100);
713     }
714     else
715     {
716         m = (short) ((dt = et) / 6000);
717         s = (short) (et - 6000 * (long) m) / 100;
718     }
719
720     if (m < 0)
721         m = 0;
722
723     if (s < 0)
724         s = 0;
725
726     if (player == black)
727         gotoXY(20, (flag.reverse) ? 2 : 23);
728     else
729         gotoXY(20, (flag.reverse) ? 23 : 2);
730
731     /* printw("%d:%02d %ld  ", m, s, dt); */
732     printw("%d:%02d  ", m, s); 
733
734     if (flag.post)
735         ShowNodeCnt(NodeCnt);
736
737     refresh();
738 }
739
740
741 static void
742 DrawPiece(short sq)
743 {
744     char y;
745     char piece, l, r, p; 
746
747     if (color[sq] == neutral)
748     {
749         l = r = ' ';
750     }
751     else if (flag.reverse ^ (color[sq] == black))
752     {
753         l = '/';
754         r = '\\';
755     } 
756     else
757     {
758         l = '\\', r = '/';
759     }
760
761     piece = board[sq];
762
763     if (is_promoted[(int)piece])
764     {
765         p = '+';
766         y = pxx[unpromoted[(int)piece]];
767     } 
768     else
769     {
770         p = ' ';
771         y = pxx[(int)piece];
772     }
773
774     gotoXY(MARGIN + 3 + 5 * VIR_C(sq), 4 + 2 * ((NO_ROWS - 1) - VIR_R(sq)));
775     printw("%c%c%c%c", l, p, y, r);
776 }
777
778
779 /*
780  * Curses_ShowPostnValue(): must have called ExaminePosition() first
781  */
782 void
783 Curses_ShowPostnValue(short sq)
784 {
785     short score;
786
787     gotoXY(4 + 5 * VIR_C(sq), 5 + 2 * (7 - VIR_R(sq))); /* CHECKME */
788     score = ScorePosition(color[sq]);
789
790     if (color[sq] != neutral)
791 #if defined SAVE_SVALUE
792     {
793         printw("??? ");
794     }
795 #else
796     {
797         printw("%3d ", svalue[sq]);
798     }
799 #endif
800     else
801     {
802         printw("   ");
803     }
804 }
805
806
807 void
808 Curses_ShowPostnValues(void)
809 {
810     short sq, score;
811
812     ExaminePosition(opponent);
813
814     for (sq = 0; sq < NO_SQUARES; sq++)
815         Curses_ShowPostnValue(sq);
816
817     score = ScorePosition(opponent);
818     gotoXY(TAB, 5);
819     printw("S%d m%d ps%d gt%c m%d ps%d gt%c", score,
820            mtl[computer], pscore[computer], GameType[computer],
821            mtl[opponent], pscore[opponent], GameType[opponent]);
822
823     ClearEoln();
824 }
825
826
827 void
828 Curses_UpdateDisplay(short f, short t, short redraw, short isspec)
829 {
830     short i, sq, z;
831     int j;
832
833     if (redraw)
834     {
835         ShowHeader();
836         ShowPlayers();
837
838         i = 2;
839         gotoXY(MARGIN, ++i);
840
841         printw("  +");
842         for (j=0; j<NO_COLS; j++)
843             printw("----+");
844
845         while (i <= 1 + 2*NO_ROWS)
846         {
847             gotoXY(MARGIN, ++i);
848
849             if (flag.reverse)
850                 z = (i / 2) - 1;
851             else
852                 z = NO_ROWS + 2 - ((i + 1) / 2);
853
854             printw("%c |", ROW_NAME(z+1));
855             for (j=0; j<NO_COLS; j++)
856                 printw("    |");
857
858             gotoXY(MARGIN, ++i);
859
860             if (i < 2 + 2*NO_ROWS)
861             {
862                 printw("  +");
863                 for (j=0; j<NO_COLS; j++)
864                     printw("----+");
865             }
866         }
867
868         printw("  +");
869         for (j=0; j<NO_COLS; j++)
870             printw("----+");
871
872         gotoXY(MARGIN, 4 + 2*NO_ROWS);
873         printw("  ");
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("  5    4    3    2    1");
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 }