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