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