Curses: shift board one char to the right to leave enough space for captures.
[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 (5)
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, 11);
471     printw(".   Exit to main\n");
472     gotoXY(TAB, 12);
473     printw("#   Clear board\n");
474     gotoXY(TAB, 13);
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, 4);
483         printw("Editing: %s", ColorStr[a]);
484         gotoXY(TAB + 2, 8);
485         ClearEoln();
486         FLUSH_SCANW("%s", s);
487         found = 0;
488         ClearMessage();
489
490         if (s[0] == '.')
491             break;
492
493         if (s[0] == '#')
494         {
495             for (sq = 0; sq < NO_SQUARES; sq++)
496             {
497                 board[sq] = no_piece;
498                 color[sq] = neutral;
499                 DrawPiece(sq);
500             }
501
502             ClearCaptured();
503             UpdateCatched();
504             continue;
505         }
506
507         if (s[0] == 'c') {
508             a = otherside[a];
509             continue;
510         }
511
512         if (s[1] == '*')
513         {
514             for (i = NO_PIECES; i > no_piece; i--)
515             {
516                 if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
517                 {
518                     Captured[a][unpromoted[i]]++;
519                     UpdateCatched();
520                     found = 1;
521                     break;
522                 }
523             }
524             if (!found)
525                 AlwaysShowMessage("Invalid piece type '%c'", s[0]);
526             continue;
527         }
528
529         c = COL_NUM(s[1]);
530         r = ROW_NUM(s[2]);
531
532         if ((c < 0) || (c >= NO_COLS) || (r < 0) || (r >= NO_ROWS)) {
533             AlwaysShowMessage("Out-of-board '%c%c'", s[1], s[2]);
534             continue;
535         }
536
537         sq = locn(r, c);
538
539         for (i = NO_PIECES; i > no_piece; i--)
540         {
541             if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
542             {
543                 color[sq] = a;
544                 if (s[3] == '+')
545                     board[sq] = promoted[i];
546                 else
547                     board[sq] = unpromoted[i];
548
549                 found = 1;
550                 break;
551             }
552         }
553
554         if (!found)
555             AlwaysShowMessage("Invalid piece type '%c'", s[0]);
556
557         DrawPiece(sq);
558     }
559
560     for (sq = 0; sq < NO_SQUARES; sq++)
561         Mvboard[sq] = ((board[sq] != Stboard[sq]) ? 10 : 0);
562
563     GameCnt = 0;
564     Game50 = 1;
565     ZeroRPT();
566     Sdepth = 0;
567     InitializeStats();
568     Curses_ClearScreen();
569     Curses_UpdateDisplay(0, 0, 1, 0);
570 }
571
572
573 static void 
574 UpdateCatched()
575 {
576     short side;
577
578     for (side = black; side <= white; side++)
579     { 
580         short x, y, piece, cside, k;
581
582         cside = flag.reverse ? (side ^ 1) : side;
583         x = x0[cside];
584         y = y0[cside];
585         k = 0;
586
587         for (piece = pawn; piece <= king; piece++)
588         {
589             short n;
590
591             if ((n = Captured[side][piece]))
592             {
593                 gotoXY(x, y); 
594                 printw("%i%c", n, pxx[piece]);
595
596                 if (cside == black) 
597                     y--; 
598                 else 
599                     y++;
600             }
601             else
602             {
603                 k++;
604             }
605         }
606
607         while (k)
608         {
609             k--;
610             gotoXY(x, y);
611             printw("  ");
612
613             if (cside == black) 
614                 y--; 
615             else 
616                 y++;
617         }
618     }
619
620     refresh();
621 }
622
623
624 void
625 Curses_SearchStartStuff(short side)
626 {
627     short i;
628
629     signal(SIGINT, Curses_TerminateSearch);
630     signal(SIGQUIT, Curses_TerminateSearch);
631
632     for (i = 4; i < 14; i++)                      /* CHECKME */
633     {
634         gotoXY(TAB, i);
635         ClearEoln();
636     }
637 }
638
639
640 void
641 Curses_OutputMove(void)
642 {
643
644     Curses_UpdateDisplay(root->f, root->t, 0, (short) root->flags);
645     gotoXY(TAB, 16);
646
647     if (flag.illegal) 
648     {
649         printw("Illegal position.");
650         return;
651     }
652
653     printw("My move is: %5s", mvstr[0]);
654
655     if (flag.beep)
656         putchar(7);
657
658     ClearEoln();
659
660     gotoXY(TAB, 18);
661
662     if (root->flags & draw)
663         printw("Drawn game!");
664     else if (root->score == -(SCORE_LIMIT + 999))
665         printw("Opponent mates!");
666     else if (root->score == SCORE_LIMIT + 998)
667         printw("Computer mates!");
668 #ifdef VERYBUGGY
669     else if (root->score < -SCORE_LIMIT)
670         printw("Opp: mate in %d!", SCORE_LIMIT + 999 + root->score - 1);
671     else if (root->score > SCORE_LIMIT)
672         printw("Comp: mate in %d!", SCORE_LIMIT + 998 - root->score - 1);
673 #endif /* VERYBUGGY */
674
675     ClearEoln();
676
677     if (flag.post)
678     {
679         short h, l, t;
680
681         h = TREE;
682         l = 0;
683         t = TREE >> 1;
684
685         while (l != t)
686         {
687             if (Tree[t].f || Tree[t].t)
688                 l = t;
689             else
690                 h = t;
691
692             t = (l + h) >> 1;
693         }
694
695         ShowNodeCnt(NodeCnt);
696         gotoXY(TAB, 23);
697         printw("Max Tree = %5d", t);
698         ClearEoln();
699     }
700
701     Curses_ShowSidetoMove();
702 }
703
704
705 void
706 Curses_UpdateClocks(void)
707 {
708     short m, s;
709     long dt;
710
711     if (TCflag)
712     {
713         m = (short) ((dt = (TimeControl.clock[player] - et)) / 6000);
714         s = (short) ((dt - 6000 * (long) m) / 100);
715     }
716     else
717     {
718         m = (short) ((dt = et) / 6000);
719         s = (short) (et - 6000 * (long) m) / 100;
720     }
721
722     if (m < 0)
723         m = 0;
724
725     if (s < 0)
726         s = 0;
727
728     if (player == black)
729         gotoXY(20, (flag.reverse) ? 2 : (5 + 2*NO_ROWS));
730     else
731         gotoXY(20, (flag.reverse) ? (5 + 2*NO_ROWS) : 2);
732
733     /* printw("%d:%02d %ld  ", m, s, dt); */
734     printw("%d:%02d  ", m, s); 
735
736     if (flag.post)
737         ShowNodeCnt(NodeCnt);
738
739     refresh();
740 }
741
742
743 static void
744 DrawPiece(short sq)
745 {
746     char y;
747     char piece, l, r, p; 
748
749     if (color[sq] == neutral)
750     {
751         l = r = ' ';
752     }
753     else if (flag.reverse ^ (color[sq] == black))
754     {
755         l = '/';
756         r = '\\';
757     } 
758     else
759     {
760         l = '\\', r = '/';
761     }
762
763     piece = board[sq];
764
765     if (is_promoted[(int)piece])
766     {
767         p = '+';
768         y = pxx[unpromoted[(int)piece]];
769     } 
770     else
771     {
772         p = ' ';
773         y = pxx[(int)piece];
774     }
775
776     gotoXY(MARGIN + 3 + 5 * VIR_C(sq), 4 + 2 * ((NO_ROWS - 1) - VIR_R(sq)));
777     printw("%c%c%c%c", l, p, y, r);
778 }
779
780
781 /*
782  * Curses_ShowPostnValue(): must have called ExaminePosition() first
783  */
784 void
785 Curses_ShowPostnValue(short sq)
786 {
787     short score;
788
789     gotoXY(4 + 5 * VIR_C(sq), 5 + 2 * (7 - VIR_R(sq))); /* CHECKME */
790     score = ScorePosition(color[sq]);
791
792     if (color[sq] != neutral)
793 #if defined SAVE_SVALUE
794     {
795         printw("??? ");
796     }
797 #else
798     {
799         printw("%3d ", svalue[sq]);
800     }
801 #endif
802     else
803     {
804         printw("   ");
805     }
806 }
807
808
809 void
810 Curses_ShowPostnValues(void)
811 {
812     short sq, score;
813
814     ExaminePosition(opponent);
815
816     for (sq = 0; sq < NO_SQUARES; sq++)
817         Curses_ShowPostnValue(sq);
818
819     score = ScorePosition(opponent);
820     gotoXY(TAB, 5);
821     printw("S%d m%d ps%d gt%c m%d ps%d gt%c", score,
822            mtl[computer], pscore[computer], GameType[computer],
823            mtl[opponent], pscore[opponent], GameType[opponent]);
824
825     ClearEoln();
826 }
827
828
829 void
830 Curses_UpdateDisplay(short f, short t, short redraw, short isspec)
831 {
832     short i, sq, z;
833     int j;
834
835     if (redraw)
836     {
837         ShowHeader();
838         ShowPlayers();
839
840         i = 2;
841         gotoXY(MARGIN, ++i);
842
843         printw("  +");
844         for (j=0; j<NO_COLS; j++)
845             printw("----+");
846
847         while (i <= 1 + 2*NO_ROWS)
848         {
849             gotoXY(MARGIN, ++i);
850
851             if (flag.reverse)
852                 z = (i / 2) - 1;
853             else
854                 z = NO_ROWS + 2 - ((i + 1) / 2);
855
856             printw("%c |", ROW_NAME(z+1));
857             for (j=0; j<NO_COLS; j++)
858                 printw("    |");
859
860             gotoXY(MARGIN, ++i);
861
862             if (i < 2 + 2*NO_ROWS)
863             {
864                 printw("  +");
865                 for (j=0; j<NO_COLS; j++)
866                     printw("----+");
867             }
868         }
869
870         printw("  +");
871         for (j=0; j<NO_COLS; j++)
872             printw("----+");
873
874         gotoXY(MARGIN, 4 + 2*NO_ROWS);
875         printw("  ");
876 #ifndef MINISHOGI
877         if (flag.reverse)
878             printw("  1    2    3    4    5    6    7    8    9");
879         else
880             printw("  9    8    7    6    5    4    3    2    1");
881 #else
882         if (flag.reverse)
883             printw("  1    2    3    4    5");
884         else
885             printw("  5    4    3    2    1");
886 #endif
887
888         for (sq = 0; sq < NO_SQUARES; sq++)
889             DrawPiece(sq);
890     }
891     else /* not redraw */
892     {
893         if (f < NO_SQUARES)
894             DrawPiece(f);
895
896         DrawPiece(t & 0x7f);
897     }
898
899     if ((isspec & capture) || (isspec & dropmask) || redraw)
900     {
901         short side;
902
903         for (side = black; side <= white; side++)
904         {
905             short x, y, piece, cside, k;
906             cside = flag.reverse ? (side ^ 1) : side;
907             x = x0[cside];
908             y = y0[cside];
909             k = 0;
910
911             for (piece = pawn; piece <= king; piece++)
912             {
913                 short n;
914
915                 if ((n = Captured[side][piece]))
916                 {
917                     gotoXY(x, y); 
918                     printw("%i%c", n, pxx[piece]);
919
920                     if (cside == black) y--; else y++;
921                 }
922                 else
923                 {
924                     k++;
925                 }
926             }
927
928             while (k)
929             {
930                 k--;
931                 gotoXY(x, y);
932                 printw("  ");
933
934                 if (cside == black) 
935                     y--;
936                 else 
937                     y++;
938             }
939         }
940     }
941
942     refresh();
943 }
944
945
946 void
947 Curses_ChangeAlphaWindow(void)
948 {
949     Curses_ShowMessage("WAwindow = ");
950     FLUSH_SCANW("%hd", &WAwindow);
951     Curses_ShowMessage("BAwindow = ");
952     FLUSH_SCANW("%hd", &BAwindow);
953 }
954
955
956 void
957 Curses_ChangeBetaWindow(void)
958 {
959     Curses_ShowMessage("WBwindow = ");
960     FLUSH_SCANW("%hd", &WBwindow);
961     Curses_ShowMessage("BBwindow = ");
962     FLUSH_SCANW("%hd", &BBwindow);
963 }
964
965
966 void
967 Curses_GiveHint(void)
968 {
969     char s[40];
970
971     if (hint)
972     {
973         algbr((short) (hint >> 8), (short) (hint & 0xFF), false);
974         strcpy(s, "try ");
975         strcat(s, mvstr[0]);
976         Curses_ShowMessage(s);
977     }
978     else
979     {
980         Curses_ShowMessage("I have no idea.\n");
981     }
982 }
983
984
985 void
986 Curses_ChangeSearchDepth(void)
987 {
988     Curses_ShowMessage("depth = ");
989     FLUSH_SCANW("%hd", &MaxSearchDepth);
990     TCflag = !(MaxSearchDepth > 0);
991 }
992
993
994 void
995 Curses_ChangeHashDepth(void)
996 {
997     Curses_ShowMessage("hashdepth = ");
998     FLUSH_SCANW("%hd", &HashDepth);
999     Curses_ShowMessage("MoveLimit = ");
1000     FLUSH_SCANW("%hd", &HashMoveLimit);
1001 }
1002
1003
1004 void
1005 Curses_SetContempt(void)
1006 {
1007     Curses_ShowMessage("contempt = ");
1008     FLUSH_SCANW("%hd", &contempt);
1009 }
1010
1011
1012 void
1013 Curses_ChangeXwindow(void)
1014 {
1015     Curses_ShowMessage("xwndw= ");
1016     FLUSH_SCANW("%hd", &xwndw);
1017 }
1018
1019
1020 void
1021 Curses_SelectLevel(char *sx)
1022 {
1023     int item;
1024
1025     Curses_ClearScreen();
1026     gotoXY(32, 2);
1027     printw("GNU Shogi %s", PACKAGE_VERSION);
1028     gotoXY(20, 4);
1029     printw(" 1.   40 moves in   5 minutes");
1030     gotoXY(20, 5);
1031     printw(" 2.   40 moves in  15 minutes");
1032     gotoXY(20, 6);
1033     printw(" 3.   40 moves in  30 minutes");
1034     gotoXY(20, 7);
1035     printw(" 4.  all moves in  15 minutes");
1036     gotoXY(20, 8);
1037     printw(" 5.  all moves in  30 minutes");
1038     gotoXY(20, 9);
1039     printw(" 6.  all moves in  15 minutes, 30 seconds fischer clock");
1040     gotoXY(20, 10);
1041     printw(" 7.  all moves in  30 minutes, 30 seconds fischer clock");
1042     gotoXY(20, 11);
1043     printw(" 8.    1 move  in   1 minute");
1044     gotoXY(20, 12);
1045     printw(" 9.    1 move  in  15 minutes");
1046     gotoXY(20, 13);
1047     printw("10.    1 move  in  30 minutes");
1048
1049     OperatorTime = 0;
1050     TCmoves = 40;
1051     TCminutes = 5;
1052     TCseconds = 0;
1053
1054     gotoXY(20, 17);
1055     printw("Enter Level: ");
1056     refresh();
1057     FLUSH_SCANW("%d", &item);
1058
1059     switch(item)
1060     {
1061     case 1:
1062         TCmoves = 40;
1063         TCminutes = 5;
1064         break;
1065
1066     case 2:
1067         TCmoves = 40;
1068         TCminutes = 15;
1069         break;
1070
1071     case 3:
1072         TCmoves = 40;
1073         TCminutes = 30;
1074         break;
1075
1076     case 4:
1077         TCmoves = 80;
1078         TCminutes = 15;
1079         flag.gamein = true;
1080         break;
1081
1082     case 5:
1083         TCmoves = 80;
1084         TCminutes = 30;
1085         flag.gamein = true;
1086         break;
1087
1088     case 6:
1089         TCmoves = 80;
1090         TCminutes = 15;
1091         TCadd = 3000;
1092         flag.gamein = true;
1093         break;
1094
1095     case 7:
1096         TCmoves = 80;
1097         TCminutes = 30;
1098         TCadd = 3000;
1099         break;
1100
1101     case 8:
1102         TCmoves = 1;
1103         TCminutes = 1;
1104         flag.onemove = true;
1105         break;
1106
1107     case 9:
1108         TCmoves = 1;
1109         TCminutes = 15;
1110         flag.onemove = true;
1111         break;
1112
1113     case 10:
1114         TCmoves = 1;
1115         TCminutes = 30;
1116         flag.onemove = true;
1117         break;
1118     }
1119
1120     TCflag = (TCmoves > 0);
1121
1122     TimeControl.clock[black] = TimeControl.clock[white] = 0; 
1123
1124     SetTimeControl();
1125     Curses_ClearScreen();
1126     Curses_UpdateDisplay(0, 0, 1, 0);
1127 }
1128
1129
1130 void
1131 Curses_DoDebug(void)
1132 {
1133     short c, p, sq, tp, tc, tsq, score;
1134     char s[40];
1135
1136     ExaminePosition(opponent);
1137     Curses_ShowMessage("Enter piece: ");
1138     FLUSH_SCANW("%s", s);
1139     c = neutral;
1140
1141     if ((s[0] == 'b') || (s[0] == 'B'))
1142         c = black;
1143
1144     if ((s[0] == 'w') || (s[0] == 'W'))
1145         c = white;
1146
1147     for (p = king; p > no_piece; p--)
1148     {
1149         if ((s[1] == pxx[p]) || (s[1] == qxx[p]))
1150             break;
1151     }
1152
1153     for (sq = 0; sq < NO_SQUARES; sq++)
1154     {
1155         tp = board[sq];
1156         tc = color[sq];
1157         board[sq] = p;
1158         color[sq] = c;
1159         tsq = PieceList[c][1];
1160         PieceList[c][1] = sq;
1161         Curses_ShowPostnValue(sq);
1162         PieceList[c][1] = tsq;
1163         board[sq] = tp;
1164         color[sq] = tc;
1165     }
1166
1167     score = ScorePosition(opponent);
1168     gotoXY(TAB, 5);
1169     printw("S%d m%d ps%d gt%c m%d ps%d gt%c", score,
1170            mtl[computer], pscore[computer], GameType[computer],
1171            mtl[opponent], pscore[opponent], GameType[opponent]);
1172
1173     ClearEoln();
1174 }
1175
1176
1177 void
1178 Curses_DoTable(short table[NO_SQUARES])
1179 {
1180     short  sq;
1181     ExaminePosition(opponent);
1182
1183     for (sq = 0; sq < NO_SQUARES; sq++)
1184     {
1185         gotoXY(4 + 5 * VIR_C(sq), 5 + 2 * (7 - VIR_R(sq)));
1186         printw("%3d ", table[sq]);
1187     }
1188
1189
1190
1191 void
1192 Curses_PollForInput(void)
1193 {
1194     int  i;
1195     int  nchar;
1196
1197     if ((i = ioctl((int) 0, FIONREAD, &nchar)))
1198     {
1199         perror("FIONREAD");
1200         fprintf(stderr,
1201                 "You probably have a non-ANSI <ioctl.h>; "
1202                 "see README. %d %d %x\n",
1203                 i, errno, FIONREAD);
1204         exit(1);
1205     }
1206
1207     if (nchar)
1208     {
1209         if (!flag.timeout)
1210             flag.back = true;
1211
1212         flag.bothsides = false;
1213     }
1214 }
1215
1216
1217 void
1218 Curses_SetupBoard(void)
1219 {
1220     Curses_ShowMessage("'setup' command is not supported in Cursesmode");
1221 }