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