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