xref: /original-bsd/games/chess/uxdsp.c (revision 331bfa8d)
1 /*
2   ALPHA interface for CHESS
3 
4   Revision: 4-25-88
5 
6   Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
7   Copyright (c) 1988  John Stanback
8 
9   This file is part of CHESS.
10 
11   CHESS is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY.  No author or distributor
13   accepts responsibility to anyone for the consequences of using it
14   or for whether it serves any particular purpose or works at all,
15   unless he says so in writing.  Refer to the CHESS General Public
16   License for full details.
17 
18   Everyone is granted permission to copy, modify and redistribute
19   CHESS, but only under the conditions described in the
20   CHESS General Public License.   A copy of this license is
21   supposed to have been given to you along with CHESS so you
22   can know your rights and responsibilities.  It should be in a
23   file named COPYING.  Among other things, the copyright notice
24   and this notice must be preserved on all copies.
25 */
26 
27 
28 #include <stdio.h>
29 #include <ctype.h>
30 #include <sys/param.h>
31 #include <sys/times.h>
32 #include <sys/file.h>
33 #include <curses.h>
34 #include <signal.h>
35 #include "gnuchess.h"
36 #ifdef NEWMOVE
37 #include "move.h"
38 #endif
39 #include "pathnames.h"
40 
41 struct tms tmbuf1,tmbuf2;
42 void TerminateSearch(),Die();
43 
44 #define scanz fflush(stdout),scanw
45 #define printz printw
46 
47 
48 Initialize()
49 {
50   signal(SIGINT,Die); signal(SIGQUIT,Die);
51   initscr();
52   crmode();
53 }
54 
55 
56 ExitChess()
57 {
58   nocrmode();
59   endwin();
60   exit(0);
61 }
62 
63 
64 void
65 Die()
66 {
67 char s[80];
68   signal(SIGINT,SIG_IGN);
69   signal(SIGQUIT,SIG_IGN);
70   ShowMessage("Abort? ");
71   scanz("%s",s);
72   if (strcmp(s,"yes") == 0) ExitChess();
73   signal(SIGINT,Die); signal(SIGQUIT,Die);
74 }
75 
76 
77 void
78 TerminateSearch()
79 {
80   signal(SIGINT,SIG_IGN);
81   signal(SIGQUIT,SIG_IGN);
82   timeout = true;
83   bothsides = false;
84   signal(SIGINT,Die); signal(SIGQUIT,Die);
85 }
86 
87 
88 InputCommand()
89 
90 /*
91    Process the users command. If easy mode is OFF (the computer is
92    thinking on opponents time) and the program is out of book, then make
93    the 'hint' move on the board and call SelectMove() to find a response.
94    The user terminates the search by entering ^C (quit siqnal) before
95    entering a command. If the opponent does not make the hint move, then
96    set Sdepth to zero.
97 */
98 
99 {
100 short ok,i,tmp;
101 long cnt,rate,t1,t2;
102 unsigned short mv;
103 char s[80];
104 
105   ok = quit = false;
106   player = opponent;
107   ShowSidetomove();
108   ft = 0;
109   if (hint > 0 && !easy && Book == NULL)
110     {
111       fflush(stdout);
112       time0 = time((long *)0);
113       algbr(hint>>8,hint & 0xFF,false);
114       strcpy(s,mvstr1);
115       tmp = epsquare;
116       if (VerifyMove(s,1,&mv))
117         {
118           PromptForMove();
119           SelectMove(computer,2);
120           VerifyMove(mvstr1,2,&mv);
121           if (Sdepth > 0) Sdepth--;
122         }
123       ft = time((time_t *)0) - time0;
124       epsquare = tmp;
125     }
126 
127   signal(SIGINT,Die); signal(SIGQUIT,Die);
128   while (!(ok || quit))
129     {
130       PromptForMove();
131       scanz("%s",s);
132       player = opponent;
133       ok = VerifyMove(s,0,&mv);
134       if (ok && mv != hint)
135         {
136           Sdepth = 0;
137           ft = 0;
138         }
139 
140       if (strcmp(s,"bd") == 0)
141         {
142           ClrScreen();
143           UpdateDisplay(0,0,1,0);
144         }
145       if (strcmp(s,"quit") == 0) quit = true;
146       if (strcmp(s,"post") == 0) post = !post;
147       if (strcmp(s,"edit") == 0) EditBoard();
148       if (strcmp(s,"go") == 0) ok = true;
149       if (strcmp(s,"help") == 0) help();
150       if (strcmp(s,"force") == 0) force = !force;
151       if (strcmp(s,"book") == 0) Book = NULL;
152       if (strcmp(s,"undo") == 0 && GameCnt >= 0) Undo();
153       if (strcmp(s,"new") == 0) NewGame();
154       if (strcmp(s,"list") == 0) ListGame();
155       if (strcmp(s,"level") == 0) SelectLevel();
156       if (strcmp(s,"hash") == 0) hashflag = !hashflag;
157       if (strcmp(s,"beep") == 0) beep = !beep;
158       if (strcmp(s,"Awindow") == 0) ChangeAlphaWindow();
159       if (strcmp(s,"Bwindow") == 0) ChangeBetaWindow();
160       if (strcmp(s,"hint") == 0) GiveHint();
161       if (strcmp(s,"both") == 0)
162         {
163           bothsides = !bothsides;
164           Sdepth = 0;
165           SelectMove(opponent,1);
166           ok = true;
167         }
168       if (strcmp(s,"reverse") == 0)
169         {
170           reverse = !reverse;
171           ClrScreen();
172           UpdateDisplay(0,0,1,0);
173         }
174       if (strcmp(s,"switch") == 0)
175         {
176           computer = otherside[computer];
177           opponent = otherside[opponent];
178           force = false;
179           Sdepth = 0;
180           ok = true;
181         }
182       if (strcmp(s,"white") == 0)
183         {
184           computer = white; opponent = black;
185           ok = true; force = false;
186           Sdepth = 0;
187         }
188       if (strcmp(s,"black") == 0)
189         {
190           computer = black; opponent = white;
191           ok = true; force = false;
192           Sdepth = 0;
193         }
194       if (strcmp(s,"remove") == 0 && GameCnt >= 1)
195         {
196           Undo(); Undo();
197         }
198       if (strcmp(s,"get") == 0) GetGame();
199       if (strcmp(s,"save") == 0) SaveGame();
200       if (strcmp(s,"depth") == 0) ChangeSearchDepth();
201       if (strcmp(s,"random") == 0) dither = 6;
202       if (strcmp(s,"easy") == 0) easy = !easy;
203       if (strcmp(s,"contempt") == 0) SetContempt();
204       if (strcmp(s,"xwndw") == 0) ChangeXwindow();
205       if (strcmp(s,"test") == 0)
206         {
207           t1 = time(0);
208           cnt = 0;
209           for (i = 0; i < 10000; i++)
210             {
211               MoveList(opponent,2);
212               cnt += TrPnt[3] - TrPnt[2];
213             }
214           t2 = time(0);
215           rate = cnt / (t2-t1);
216           gotoXY(50,24);
217           printz("cnt= %ld  rate= %ld",cnt,rate);
218           ClrEoln();
219         }
220       if (strcmp(s,"p") == 0) ShowPostnValues();
221       if (strcmp(s,"debug") == 0) DoDebug();
222     }
223 
224   ClearMessage();
225   ElapsedTime(1);
226   if (force)
227     {
228       computer = opponent; opponent = otherside[computer];
229     }
230   (void) times(&tmbuf1);
231   signal(SIGINT,TerminateSearch); signal(SIGQUIT,TerminateSearch);
232 }
233 
234 
235 EditBoard()
236 
237 /*
238    Set up a board position. Pieces are entered by typing the piece
239    followed by the location. For example, Nf3 will place a knight on
240    square f3.
241 */
242 
243 {
244 short a,r,c,sq;
245 char s[80];
246 
247   ClrScreen();
248   UpdateDisplay(0,0,1,0);
249   gotoXY(50,2); printz(".   Exit to main");
250   gotoXY(50,3); printz("#   Clear board");
251   gotoXY(49,5); printz("Enter piece & location: ");
252   a = white;
253   do
254   {
255     gotoXY(73,5); ClrEoln(); scanz("%s",s);
256     if (s[0] == '#')
257       {
258         for (sq = 0; sq < 64; sq++)
259           {
260             board[sq] = no_piece; color[sq] = neutral;
261           }
262         UpdateDisplay(0,0,1,0);
263       }
264     if (s[0] == 'c' || s[0] == 'C') a = otherside[a];
265     c = s[1]-'a'; r = s[2]-'1';
266     if ((c >= 0) && (c < 8) && (r >= 0) && (r < 8))
267       {
268         sq = locn[r][c];
269         color[sq] = a;
270         if (s[0] == 'p') board[sq] = pawn;
271         else if (s[0] == 'n') board[sq] = knight;
272         else if (s[0] == 'b') board[sq] = bishop;
273         else if (s[0] == 'r') board[sq] = rook;
274         else if (s[0] == 'q') board[sq] = queen;
275         else if (s[0] == 'k') board[sq] = king;
276         else { board[sq] = no_piece; color[sq] = neutral; }
277         DrawPiece(sq);
278       }
279   }
280   while (s[0] != '.');
281   if (board[4] != king) kingmoved[white] = 10;
282   if (board[60] != king) kingmoved[black] = 10;
283   GameCnt = -1; Game50 = 0; Sdepth = 0;
284   InitializeStats();
285   ClrScreen();
286   UpdateDisplay(0,0,1,0);
287 }
288 
289 
290 help()
291 {
292   ClrScreen();
293   gotoXY(28,1); printz("CHESS command summary");
294   gotoXY(1,3); printz("g1f3      move from g1 to f3");
295   gotoXY(1,4); printz("nf3       move knight to f3");
296   gotoXY(1,5); printz("o-o       castle king side");
297   gotoXY(1,6); printz("o-o-o     castle queen side");
298   gotoXY(1,7); printz("edit      edit board");
299   gotoXY(1,8); printz("switch    sides with computer");
300   gotoXY(1,9); printz("white     computer plays white");
301   gotoXY(1,10); printz("black     computer plays black");
302   gotoXY(1,11); printz("reverse   board display");
303   gotoXY(1,12); printz("both      computer match");
304   gotoXY(1,13); printz("random    randomize play");
305   gotoXY(1,14); printz("undo      undo last move");
306   gotoXY(42,3); printz("level     change level");
307   gotoXY(42,4); printz("depth     set search depth");
308   gotoXY(42,5); printz("post      principle variation");
309   gotoXY(42,6); printz("hint      suggest a move");
310   gotoXY(42,7); printz("bd        redraw board");
311   gotoXY(42,8); printz("force     enter game moves");
312   gotoXY(42,9); printz("list      game to chess.lst");
313   gotoXY(42,10); printz("save      game to file");
314   gotoXY(42,11); printz("get       game from file");
315   gotoXY(42,12); printz("new       start new game");
316   gotoXY(42,13); printz("quit      exit CHESS");
317   gotoXY(10,21); printz("Computer: ");
318   if (computer == white) printz("WHITE"); else printz("BLACK");
319   gotoXY(10,22); printz("Opponent: ");
320   if (opponent == white) printz("WHITE"); else printz("BLACK");
321   gotoXY(10,23); printz("Level: %ld",Level," sec.");
322   gotoXY(10,24); printz("Easy mode: ");
323   if (easy) printz("ON"); else printz("OFF");
324   gotoXY(40,21); printz("Depth: %d",MaxSearchDepth);
325   gotoXY(40,22); printz("Random: ");
326   if (dither) printz("ON"); else printz("OFF");
327   gotoXY(40,23); printz("Transposition table: ");
328   if (hashflag) printz("ON"); else printz("OFF");
329   refresh();
330   while (getchar() != 27);
331   ClrScreen();
332   UpdateDisplay(0,0,1,0);
333 }
334 
335 
336 ShowDepth(ch)
337 char ch;
338 {
339   gotoXY(50,4); printz("Depth= %d%c ",Sdepth,ch); ClrEoln();
340 }
341 
342 
343 ShowResults(score,bstline,ch)
344 short score;
345 unsigned short bstline[];
346 char ch;
347 {
348 short d,e,ply;
349   if (post && player == computer)
350     {
351       e = lpost;
352       gotoXY(50,5); printz("Score= %d",score); ClrEoln();
353       d = 8; gotoXY(50,d); ClrEoln();
354       for (ply = 1; bstline[ply] > 0; ply++)
355         {
356           algbr(bstline[ply] >> 8,bstline[ply] & 0xFF,false);
357           if (ply == 5 || ply == 9 || ply == 13 || ply == 17)
358             {
359               gotoXY(50,++d); ClrEoln();
360             }
361           printz("%5s ",mvstr1);
362         }
363       ClrEoln();
364       lpost = d;
365       while (++d <= e)
366         {
367           gotoXY(50,d); ClrEoln();
368         }
369     }
370 }
371 
372 
373 SearchStartStuff(side)
374 short side;
375 {
376 short i;
377   signal(SIGINT,TerminateSearch); signal(SIGQUIT,TerminateSearch);
378   if (player == computer)
379     for (i = 5; i < 14; i++)
380       {
381         gotoXY(50,i); ClrEoln();
382       }
383 }
384 
385 
386 OutputMove()
387 {
388   if (root->flags & epmask) UpdateDisplay(0,0,1,0);
389   else UpdateDisplay(root->f,root->t,0,root->flags & cstlmask);
390   gotoXY(50,17); printz("My move is: %s",mvstr1);
391   if (beep) putchar(7);
392   ClrEoln();
393 
394   gotoXY(50,24);
395   if (root->flags & draw) printz("Draw game!");
396   else if (root->score == -9999) printz("opponent mates!");
397   else if (root->score == 9998) printz("computer mates!");
398   else if (root->score < -9000) printz("opponent will soon mate!");
399   else if (root->score > 9000)  printz("computer will soon mate!");
400   ClrEoln();
401 
402   if (post)
403     {
404       gotoXY(50,22); printz("Nodes=   %6ld",NodeCnt); ClrEoln();
405       gotoXY(50,23); printz("Nodes/Sec= %4ld",evrate); ClrEoln();
406     }
407 }
408 
409 
410 ElapsedTime(iop)
411 
412 /*
413    Determine the time that has passed since the search was started. If
414    the elapsed time exceeds the target (ResponseTime+ExtraTime) then set
415    timeout to true which will terminate the search.
416 */
417 
418 short iop;
419 {
420   et = time((time_t *)0) - time0;
421   if (et < 0) et = 0;
422   ETnodes += 50;
423   if (et > et0 || iop == 1)
424     {
425       if (et > ResponseTime+ExtraTime && Sdepth > 1) timeout = true;
426       et0 = et;
427       if (iop == 1)
428         {
429           time0 = time((time_t *)0); et0 = 0;
430         }
431       (void) times(&tmbuf2);
432       cputimer = 100*(tmbuf2.tms_utime - tmbuf1.tms_utime) / HZ;
433       if (cputimer > 0) evrate = (100*NodeCnt)/(cputimer+100*ft);
434       else evrate = 0;
435       ETnodes = NodeCnt + 50;
436       UpdateClocks();
437     }
438 }
439 
440 
441 UpdateClocks()
442 {
443 short m,s;
444   m = et/60; s = (et - 60*m);
445   if (TCflag)
446     {
447       m = (TimeControl.clock[player] - et) / 60;
448       s = TimeControl.clock[player] - et - 60*m;
449     }
450   if (m < 0) m = 0;
451   if (s < 0) s = 0;
452   if (player == white)
453     if (reverse) gotoXY(20,2); else gotoXY(20,23);
454   else
455     if (reverse) gotoXY(20,23); else gotoXY(20,2);
456   printz("%d:%2d   ",m,s);
457   if (post)
458     {
459       gotoXY(50,22); printz("Nodes=   %6ld",NodeCnt);
460       gotoXY(50,23); printz("Nodes/Sec= %4ld",evrate);
461     }
462   refresh();
463 }
464 
465 
466 
467 SetTimeControl()
468 {
469   if (TCflag)
470     {
471       TimeControl.moves[white] = TimeControl.moves[black] = TCmoves;
472       TimeControl.clock[white] = TimeControl.clock[black] = 60*(long)TCminutes;
473     }
474   else
475     {
476       TimeControl.moves[white] = TimeControl.moves[black] = 0;
477       TimeControl.clock[white] = TimeControl.clock[black] = 0;
478       Level = 60*(long)TCminutes;
479     }
480   et = 0;
481   ElapsedTime(1);
482 }
483 
484 
485 gotoXY(x,y)
486 short x,y;
487 {
488   move(y-1,x-1);
489 }
490 
491 
492 ClrScreen()
493 {
494   clear(); refresh();
495 }
496 
497 
498 ClrEoln()
499 {
500   clrtoeol(); refresh();
501 }
502 
503 
504 DrawPiece(sq)
505 short sq;
506 {
507 short r,c; char x;
508   if (reverse) r = 7-row[sq]; else r = row[sq];
509   if (reverse) c = 7-column[sq]; else c = column[sq];
510   if (color[sq] == black) x = '*'; else x = ' ';
511   gotoXY(5+5*c,5+2*(7-r)); printz("%c%c ",x,pxx[board[sq]]);
512 }
513 
514 
515 UpdateDisplay(f,t,flag,iscastle)
516 short f,t,flag,iscastle;
517 {
518 short i,l,z;
519   if (flag)
520     {
521       gotoXY(56,2); printz("CHESS");
522       i = 3;
523       gotoXY(3,++i);
524       printz("|----|----|----|----|----|----|----|----|");
525       while (i<19)
526         {
527           gotoXY(1,++i);
528           if (reverse) z = (i/2)-1; else z = 10-(i/2);
529           printz("%d |    |    |    |    |    |    |    |    |",z);
530           gotoXY(3,++i);
531           if (i < 19)
532             printz("+----+----+----+----+----+----+----+----+");
533         }
534       printz("|----|----|----|----|----|----|----|----|");
535       gotoXY(3,21);
536       if (reverse) printz("  h    g    f    e    d    c    b    a");
537               else printz("  a    b    c    d    e    f    g    h");
538       if (reverse) gotoXY(5,23); else gotoXY(5,2);
539       if (computer == black) printz("Computer"); else printz("Human   ");
540       if (reverse) gotoXY(5,2); else gotoXY(5,23);
541       if (computer == white) printz("Computer"); else printz("Human   ");
542       for (l = 0; l < 64; l++) DrawPiece(l);
543     }
544   else
545     {
546       DrawPiece(f); DrawPiece(t);
547       if (iscastle)
548         if (t > f)
549           { DrawPiece(f+3); DrawPiece(t-1); }
550         else
551           { DrawPiece(f-4); DrawPiece(t+1); }
552     }
553   refresh();
554 }
555 
556 
557 GetOpenings()
558 
559 /*
560    Read in the Opening Book file and parse the algebraic notation for a
561    move into an unsigned integer format indicating the from and to
562    square. Create a linked list of opening lines of play, with
563    entry->next pointing to the next line and entry->move pointing to a
564    chunk of memory containing the moves. More Opening lines of up to 256
565    half moves may be added to gnuchess.book.
566 */
567 
568 {
569 FILE *fd;
570 int c,i,j,side;
571 struct BookEntry *entry;
572 unsigned short mv,*mp,tmp[100];
573 
574   if ((fd = fopen(_PATH_CHESSBOOK,"r")) != NULL)
575     {
576       Book = NULL;
577       i = 0; side = white;
578       while ((c = parse(fd,&mv,side)) >= 0)
579         if (c == 1)
580           {
581             tmp[++i] = mv;
582             side = otherside[side];
583           }
584         else if (c == 0 && i > 0)
585           {
586             entry = (struct BookEntry *)malloc(sizeof(struct BookEntry));
587             mp = (unsigned short *)malloc((i+1)*sizeof(unsigned short));
588             entry->mv = mp;
589             entry->next = Book;
590             Book = entry;
591             for (j = 1; j <= i; j++) *(mp++) = tmp[j];
592             *mp = 0;
593             i = 0; side = white;
594           }
595       fclose(fd);
596     }
597     else
598       {
599 	fprintf(stderr, "\nchess: can't read %s.\n", _PATH_CHESSBOOK);
600 	exit(1);
601       }
602 }
603 
604 
605 int parse(fd,mv,side)
606 FILE *fd;
607 unsigned short *mv;
608 short side;
609 {
610 int c,i,r1,r2,c1,c2;
611 char s[100];
612   while ((c = getc(fd)) == ' ');
613   i = 0; s[0] = c;
614   while (c != ' ' && c != '\n' && c != EOF) s[++i] = c = getc(fd);
615   s[++i] = '\0';
616   if (c == EOF) return(-1);
617   if (s[0] == '!' || i < 3)
618     {
619       while (c != '\n' && c != EOF) c = getc(fd);
620       return(0);
621     }
622   if (s[4] == 'o')
623     if (side == black) *mv = 0x3C3A; else *mv = 0x0402;
624   else if (s[0] == 'o')
625     if (side == black) *mv = 0x3C3E; else *mv = 0x0406;
626   else
627     {
628       c1 = s[0] - 'a'; r1 = s[1] - '1';
629       c2 = s[2] - 'a'; r2 = s[3] - '1';
630       *mv = (locn[r1][c1]<<8) + locn[r2][c2];
631     }
632   return(1);
633 }
634 
635 
636 GetGame()
637 {
638 FILE *fd;
639 char fname[40];
640 int c;
641 short sq;
642 unsigned short m;
643 
644   ShowMessage("File name: ");
645   scanz("%s",fname);
646   if (fname[0] == '\0') strcpy(fname,"chess.000");
647   if ((fd = fopen(fname,"r")) != NULL)
648     {
649       fscanf(fd,"%hd%hd%hd",&computer,&opponent,&Game50);
650       fscanf(fd,"%hd%hd%hd%hd",
651              &castld[white],&castld[black],
652              &kingmoved[white],&kingmoved[black]);
653       fscanf(fd,"%hd%hd",&TCflag,&OperatorTime);
654       fscanf(fd,"%ld%ld%hd%hd",
655              &TimeControl.clock[white],&TimeControl.clock[black],
656              &TimeControl.moves[white],&TimeControl.moves[black]);
657       for (sq = 0; sq < 64; sq++)
658         {
659           fscanf(fd,"%hd",&m);
660           board[sq] = (m >> 8); color[sq] = (m & 0xFF);
661           if (color[sq] == 0) color[sq] = neutral; else --color[sq];
662         }
663       GameCnt = -1; c = '?';
664       while (c != EOF)
665         {
666           ++GameCnt;
667           c = fscanf(fd,"%hd%hd%hd%ld%hd%hd%hd",&GameList[GameCnt].gmove,
668                      &GameList[GameCnt].score,&GameList[GameCnt].depth,
669                      &GameList[GameCnt].nodes,&GameList[GameCnt].time,
670                      &GameList[GameCnt].piece,&GameList[GameCnt].color);
671           if (GameList[GameCnt].color == 0) GameList[GameCnt].color = neutral;
672           else --GameList[GameCnt].color;
673         }
674       GameCnt--;
675       if (TimeControl.clock[white] > 0) TCflag = true;
676       computer--; opponent--;
677     }
678   fclose(fd);
679   InitializeStats();
680   UpdateDisplay(0,0,1,0);
681   Sdepth = 0;
682 }
683 
684 
685 SaveGame()
686 {
687 FILE *fd;
688 char fname[40];
689 short sq,i,c;
690 
691   ShowMessage("File name: ");
692   scanz("%s",fname);
693 
694   if (fname[0] == '\0' || access(fname,W_OK) == -1) strcpy(fname,"chess.000");
695   fd = fopen(fname,"w");
696   fprintf(fd,"%d %d %d\n",computer+1,opponent+1,Game50);
697   fprintf(fd,"%d %d %d %d\n",
698           castld[white],castld[black],kingmoved[white],kingmoved[black]);
699   fprintf(fd,"%d %d\n",TCflag,OperatorTime);
700   fprintf(fd,"%ld %ld %d %d\n",
701           TimeControl.clock[white],TimeControl.clock[black],
702           TimeControl.moves[white],TimeControl.moves[black]);
703   for (sq = 0; sq < 64; sq++)
704     {
705       if (color[sq] == neutral) c = 0; else c = color[sq]+1;
706       fprintf(fd,"%d\n",256*board[sq] + c);
707     }
708   for (i = 0; i <= GameCnt; i++)
709     {
710       if (GameList[i].color == neutral) c = 0;
711       else c = GameList[i].color + 1;
712       fprintf(fd,"%d %d %d %ld %d %d %d\n",
713               GameList[i].gmove,GameList[i].score,GameList[i].depth,
714               GameList[i].nodes,GameList[i].time,
715               GameList[i].piece,c);
716     }
717   fclose(fd);
718 }
719 
720 
721 ListGame()
722 {
723 FILE *fd;
724 short i,f,t;
725   fd = fopen("chess.lst","w");
726   fprintf(fd,"\n");
727   fprintf(fd,"       score  depth  nodes  time         ");
728   fprintf(fd,"       score  depth  nodes  time\n");
729   for (i = 0; i <= GameCnt; i++)
730     {
731       f = GameList[i].gmove>>8; t = (GameList[i].gmove & 0xFF);
732       algbr(f,t,false);
733       if ((i % 2) == 0) fprintf(fd,"\n"); else fprintf(fd,"         ");
734       fprintf(fd,"%5s  %5d     %2d %6ld %5d",mvstr1,
735               GameList[i].score,GameList[i].depth,
736               GameList[i].nodes,GameList[i].time);
737     }
738   fprintf(fd,"\n\n");
739   fclose(fd);
740 }
741 
742 
743 Undo()
744 
745 /*
746    Undo the most recent half-move.
747 */
748 
749 {
750 short f,t;
751   f = GameList[GameCnt].gmove>>8;
752   t = GameList[GameCnt].gmove & 0xFF;
753   if (board[t] == king && distance(t,f) > 1)
754     castle(GameList[GameCnt].color,f,t,2);
755   else
756     {
757       board[f] = board[t]; color[f] = color[t];
758       board[t] = GameList[GameCnt].piece;
759       color[t] = GameList[GameCnt].color;
760       if (board[f] == king) --kingmoved[color[f]];
761     }
762   if (TCflag) ++TimeControl.moves[color[f]];
763   GameCnt--; mate = false; Sdepth = 0;
764   UpdateDisplay(0,0,1,0);
765   InitializeStats();
766 }
767 
768 
769 ShowMessage(s)
770 char *s;
771 {
772   gotoXY(50,24); printz("%s",s); ClrEoln();
773 }
774 
775 ClearMessage()
776 {
777   gotoXY(50,24); ClrEoln();
778 }
779 
780 ShowSidetomove()
781 {
782   gotoXY(50,14);
783   if (player == white) printz("%2d:   WHITE",1+(GameCnt+1)/2);
784   else printz("%2d:   BLACK",1+(GameCnt+1)/2);
785   ClrEoln();
786 }
787 
788 PromptForMove()
789 {
790   gotoXY(50,19); printz("Your move is? "); ClrEoln();
791 }
792 
793 ShowCurrentMove(pnt,f,t)
794 short pnt,f,t;
795 {
796   algbr(f,t,false);
797   gotoXY(50,7); printz("(%2d) %4s",pnt,mvstr1);
798 }
799 
800 ChangeAlphaWindow()
801 {
802   ShowMessage("window: ");
803   scanz("%hd",&Awindow);
804 }
805 
806 ChangeBetaWindow()
807 {
808   ShowMessage("window: ");
809   scanz("%hd",&Bwindow);
810 }
811 
812 GiveHint()
813 {
814 char s[40];
815   algbr((short)(hint>>8),(short)(hint & 0xFF),false);
816   strcpy(s,"try ");
817   strcat(s,mvstr1);
818   ShowMessage(s);
819 }
820 
821 ChangeSearchDepth()
822 {
823   ShowMessage("depth= ");
824   scanz("%hd",&MaxSearchDepth);
825 }
826 
827 SetContempt()
828 {
829   ShowMessage("contempt= ");
830   scanz("%hd",&contempt);
831 }
832 
833 ChangeXwindow()
834 {
835   ShowMessage("xwndw= ");
836   scanz("%hd",&xwndw);
837 }
838 
839 
840 SelectLevel()
841 {
842   ClrScreen();
843   gotoXY(32,2); printz("CHESS");
844   gotoXY(20,4); printz(" 1.   60 moves in   5 minutes");
845   gotoXY(20,5); printz(" 2.   60 moves in  15 minutes");
846   gotoXY(20,6); printz(" 3.   60 moves in  30 minutes");
847   gotoXY(20,7); printz(" 4.   40 moves in  30 minutes");
848   gotoXY(20,8); printz(" 5.   40 moves in  60 minutes");
849   gotoXY(20,9); printz(" 6.   40 moves in 120 minutes");
850   gotoXY(20,10); printz(" 7.   40 moves in 240 minutes");
851   gotoXY(20,11); printz(" 8.    1 move  in  15 minutes");
852   gotoXY(20,12); printz(" 9.    1 move  in  60 minutes");
853   gotoXY(20,13); printz("10.    1 move  in 600 minutes");
854 
855   OperatorTime = 0; TCmoves = 60; TCminutes = 5;
856 
857   gotoXY(20,17); printz("Enter Level: ");
858   refresh();
859   scanz("%ld",&Level);
860   switch (Level)
861     {
862       case 1 : TCmoves = 60; TCminutes = 5; break;
863       case 2 : TCmoves = 60; TCminutes = 15; break;
864       case 3 : TCmoves = 60; TCminutes = 30; break;
865       case 4 : TCmoves = 40; TCminutes = 30; break;
866       case 5 : TCmoves = 40; TCminutes = 60; break;
867       case 6 : TCmoves = 40; TCminutes = 120; break;
868       case 7 : TCmoves = 40; TCminutes = 240; break;
869       case 8 : TCmoves = 1; TCminutes = 15; break;
870       case 9 : TCmoves = 1; TCminutes = 60; break;
871       case 10 : TCmoves = 1; TCminutes = 600; break;
872     }
873 
874   TCflag = (TCmoves > 1);
875   SetTimeControl();
876   ClrScreen();
877   UpdateDisplay(0,0,1,0);
878 }
879 
880 
881 ShowPostnValues()
882 {
883 short i,r,c;
884   ExaminePosition();
885   for (i = 0; i < 64; i++)
886     {
887       if (reverse) r = 7-row[i]; else r = row[i];
888       if (reverse) c = 7-column[i]; else c = column[i];
889       gotoXY(4+5*c,5+2*(7-r));
890       c1 = color[i]; c2 = otherside[c1];
891       PC1 = PawnCnt[c1]; PC2 = PawnCnt[c2];
892       atk1 = atak[c1]; atk2 = atak[c2];
893       if (color[i] == neutral) printz("   ");
894       else printz("%3d ",SqValue(i,opponent));
895     }
896   ScorePosition(opponent,&i);
897   gotoXY(50,24);
898   printz("Score= %d",i); ClrEoln();
899 }
900 
901 
902 DoDebug()
903 {
904 short k,p,i,r,c,tp,tc;
905 char s[40];
906   ExaminePosition();
907   ShowMessage("Enter piece: ");
908   scanz("%s",s);
909   if (s[0] == 'w') k = white; else k = black;
910   if (s[1] == 'p') p = pawn;
911   else if (s[1] == 'n') p = knight;
912   else if (s[1] == 'b') p = bishop;
913   else if (s[1] == 'r') p = rook;
914   else if (s[1] == 'q') p = queen;
915   else if (s[1] == 'k') p = king;
916   else p = no_piece;
917   for (i = 0; i < 64; i++)
918     {
919       if (reverse) r = 7-row[i]; else r = row[i];
920       if (reverse) c = 7-column[i]; else c = column[i];
921       gotoXY(4+5*c,5+2*(7-r));
922       tp = board[i]; tc = color[i];
923       board[i] = p; color[i] = k;
924       c1 = k; c2 = otherside[c1];
925       PC1 = PawnCnt[c1]; PC2 = PawnCnt[c2];
926       atk1 = atak[c1]; atk2 = atak[c2];
927       printz("%3d ",SqValue(i,opponent));
928       board[i] = tp; color[i] = tc;
929     }
930   ScorePosition(opponent,&i);
931   gotoXY(50,24);
932   printz("Score= %d",i); ClrEoln();
933 }
934