xref: /original-bsd/games/chess/uxdsp.c (revision 07303858)
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,m = 0, j;
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 	  for (j = 0; j < 8; j++) {
531 		  printz("|");
532 		  if (j % 2 == m)
533 			  printz("#");
534 		  else
535 			  printz(" ");
536 		  printz("   ");
537 	  }
538 	  printz("|");
539 	  m = (m + 1) % 2;
540           gotoXY(3,++i);
541           if (i < 19)
542             printz("+----+----+----+----+----+----+----+----+");
543         }
544       printz("|----|----|----|----|----|----|----|----|");
545       gotoXY(3,21);
546       if (reverse) printz("  h    g    f    e    d    c    b    a");
547               else printz("  a    b    c    d    e    f    g    h");
548       if (reverse) gotoXY(5,23); else gotoXY(5,2);
549       if (computer == black) printz("Computer"); else printz("Human   ");
550       if (reverse) gotoXY(5,2); else gotoXY(5,23);
551       if (computer == white) printz("Computer"); else printz("Human   ");
552       for (l = 0; l < 64; l++) DrawPiece(l);
553     }
554   else
555     {
556       DrawPiece(f); DrawPiece(t);
557       if (iscastle)
558         if (t > f)
559           { DrawPiece(f+3); DrawPiece(t-1); }
560         else
561           { DrawPiece(f-4); DrawPiece(t+1); }
562     }
563   refresh();
564 }
565 
566 
567 GetOpenings()
568 
569 /*
570    Read in the Opening Book file and parse the algebraic notation for a
571    move into an unsigned integer format indicating the from and to
572    square. Create a linked list of opening lines of play, with
573    entry->next pointing to the next line and entry->move pointing to a
574    chunk of memory containing the moves. More Opening lines of up to 256
575    half moves may be added to gnuchess.book.
576 */
577 
578 {
579 FILE *fd;
580 int c,i,j,side;
581 struct BookEntry *entry;
582 unsigned short mv,*mp,tmp[100];
583 
584   if ((fd = fopen(_PATH_CHESSBOOK,"r")) != NULL)
585     {
586       Book = NULL;
587       i = 0; side = white;
588       while ((c = parse(fd,&mv,side)) >= 0)
589         if (c == 1)
590           {
591             tmp[++i] = mv;
592             side = otherside[side];
593           }
594         else if (c == 0 && i > 0)
595           {
596             entry = (struct BookEntry *)malloc(sizeof(struct BookEntry));
597             mp = (unsigned short *)malloc((i+1)*sizeof(unsigned short));
598             entry->mv = mp;
599             entry->next = Book;
600             Book = entry;
601             for (j = 1; j <= i; j++) *(mp++) = tmp[j];
602             *mp = 0;
603             i = 0; side = white;
604           }
605       fclose(fd);
606     }
607     else
608       {
609 	fprintf(stderr, "\nchess: can't read %s.\n", _PATH_CHESSBOOK);
610 	exit(1);
611       }
612 }
613 
614 
615 int parse(fd,mv,side)
616 FILE *fd;
617 unsigned short *mv;
618 short side;
619 {
620 int c,i,r1,r2,c1,c2;
621 char s[100];
622   while ((c = getc(fd)) == ' ');
623   i = 0; s[0] = c;
624   while (c != ' ' && c != '\n' && c != EOF) s[++i] = c = getc(fd);
625   s[++i] = '\0';
626   if (c == EOF) return(-1);
627   if (s[0] == '!' || i < 3)
628     {
629       while (c != '\n' && c != EOF) c = getc(fd);
630       return(0);
631     }
632   if (s[4] == 'o')
633     if (side == black) *mv = 0x3C3A; else *mv = 0x0402;
634   else if (s[0] == 'o')
635     if (side == black) *mv = 0x3C3E; else *mv = 0x0406;
636   else
637     {
638       c1 = s[0] - 'a'; r1 = s[1] - '1';
639       c2 = s[2] - 'a'; r2 = s[3] - '1';
640       *mv = (locn[r1][c1]<<8) + locn[r2][c2];
641     }
642   return(1);
643 }
644 
645 
646 GetGame()
647 {
648 FILE *fd;
649 char fname[40];
650 int c;
651 short sq;
652 unsigned short m;
653 
654   ShowMessage("File name: ");
655   scanz("%s",fname);
656   if (fname[0] == '\0') strcpy(fname,"chess.000");
657   if ((fd = fopen(fname,"r")) != NULL)
658     {
659       fscanf(fd,"%hd%hd%hd",&computer,&opponent,&Game50);
660       fscanf(fd,"%hd%hd%hd%hd",
661              &castld[white],&castld[black],
662              &kingmoved[white],&kingmoved[black]);
663       fscanf(fd,"%hd%hd",&TCflag,&OperatorTime);
664       fscanf(fd,"%ld%ld%hd%hd",
665              &TimeControl.clock[white],&TimeControl.clock[black],
666              &TimeControl.moves[white],&TimeControl.moves[black]);
667       for (sq = 0; sq < 64; sq++)
668         {
669           fscanf(fd,"%hd",&m);
670           board[sq] = (m >> 8); color[sq] = (m & 0xFF);
671           if (color[sq] == 0) color[sq] = neutral; else --color[sq];
672         }
673       GameCnt = -1; c = '?';
674       while (c != EOF)
675         {
676           ++GameCnt;
677           c = fscanf(fd,"%hd%hd%hd%ld%hd%hd%hd",&GameList[GameCnt].gmove,
678                      &GameList[GameCnt].score,&GameList[GameCnt].depth,
679                      &GameList[GameCnt].nodes,&GameList[GameCnt].time,
680                      &GameList[GameCnt].piece,&GameList[GameCnt].color);
681           if (GameList[GameCnt].color == 0) GameList[GameCnt].color = neutral;
682           else --GameList[GameCnt].color;
683         }
684       GameCnt--;
685       if (TimeControl.clock[white] > 0) TCflag = true;
686       computer--; opponent--;
687     }
688   fclose(fd);
689   InitializeStats();
690   UpdateDisplay(0,0,1,0);
691   Sdepth = 0;
692 }
693 
694 
695 SaveGame()
696 {
697 FILE *fd;
698 char fname[40];
699 short sq,i,c;
700 
701   ShowMessage("File name: ");
702   scanz("%s",fname);
703 
704   if (fname[0] == '\0' || access(fname,W_OK) == -1) strcpy(fname,"chess.000");
705   fd = fopen(fname,"w");
706   fprintf(fd,"%d %d %d\n",computer+1,opponent+1,Game50);
707   fprintf(fd,"%d %d %d %d\n",
708           castld[white],castld[black],kingmoved[white],kingmoved[black]);
709   fprintf(fd,"%d %d\n",TCflag,OperatorTime);
710   fprintf(fd,"%ld %ld %d %d\n",
711           TimeControl.clock[white],TimeControl.clock[black],
712           TimeControl.moves[white],TimeControl.moves[black]);
713   for (sq = 0; sq < 64; sq++)
714     {
715       if (color[sq] == neutral) c = 0; else c = color[sq]+1;
716       fprintf(fd,"%d\n",256*board[sq] + c);
717     }
718   for (i = 0; i <= GameCnt; i++)
719     {
720       if (GameList[i].color == neutral) c = 0;
721       else c = GameList[i].color + 1;
722       fprintf(fd,"%d %d %d %ld %d %d %d\n",
723               GameList[i].gmove,GameList[i].score,GameList[i].depth,
724               GameList[i].nodes,GameList[i].time,
725               GameList[i].piece,c);
726     }
727   fclose(fd);
728 }
729 
730 
731 ListGame()
732 {
733 FILE *fd;
734 short i,f,t;
735   fd = fopen("chess.lst","w");
736   fprintf(fd,"\n");
737   fprintf(fd,"       score  depth  nodes  time         ");
738   fprintf(fd,"       score  depth  nodes  time\n");
739   for (i = 0; i <= GameCnt; i++)
740     {
741       f = GameList[i].gmove>>8; t = (GameList[i].gmove & 0xFF);
742       algbr(f,t,false);
743       if ((i % 2) == 0) fprintf(fd,"\n"); else fprintf(fd,"         ");
744       fprintf(fd,"%5s  %5d     %2d %6ld %5d",mvstr1,
745               GameList[i].score,GameList[i].depth,
746               GameList[i].nodes,GameList[i].time);
747     }
748   fprintf(fd,"\n\n");
749   fclose(fd);
750 }
751 
752 
753 Undo()
754 
755 /*
756    Undo the most recent half-move.
757 */
758 
759 {
760 short f,t;
761   f = GameList[GameCnt].gmove>>8;
762   t = GameList[GameCnt].gmove & 0xFF;
763   if (board[t] == king && distance(t,f) > 1)
764     castle(GameList[GameCnt].color,f,t,2);
765   else
766     {
767       board[f] = board[t]; color[f] = color[t];
768       board[t] = GameList[GameCnt].piece;
769       color[t] = GameList[GameCnt].color;
770       if (board[f] == king) --kingmoved[color[f]];
771     }
772   if (TCflag) ++TimeControl.moves[color[f]];
773   GameCnt--; mate = false; Sdepth = 0;
774   UpdateDisplay(0,0,1,0);
775   InitializeStats();
776 }
777 
778 
779 ShowMessage(s)
780 char *s;
781 {
782   gotoXY(50,24); printz("%s",s); ClrEoln();
783 }
784 
785 ClearMessage()
786 {
787   gotoXY(50,24); ClrEoln();
788 }
789 
790 ShowSidetomove()
791 {
792   gotoXY(50,14);
793   if (player == white) printz("%2d:   WHITE",1+(GameCnt+1)/2);
794   else printz("%2d:   BLACK",1+(GameCnt+1)/2);
795   ClrEoln();
796 }
797 
798 PromptForMove()
799 {
800   gotoXY(50,19); printz("Your move is? "); ClrEoln();
801 }
802 
803 ShowCurrentMove(pnt,f,t)
804 short pnt,f,t;
805 {
806   algbr(f,t,false);
807   gotoXY(50,7); printz("(%2d) %4s",pnt,mvstr1);
808 }
809 
810 ChangeAlphaWindow()
811 {
812   ShowMessage("window: ");
813   scanz("%hd",&Awindow);
814 }
815 
816 ChangeBetaWindow()
817 {
818   ShowMessage("window: ");
819   scanz("%hd",&Bwindow);
820 }
821 
822 GiveHint()
823 {
824 char s[40];
825   algbr((short)(hint>>8),(short)(hint & 0xFF),false);
826   strcpy(s,"try ");
827   strcat(s,mvstr1);
828   ShowMessage(s);
829 }
830 
831 ChangeSearchDepth()
832 {
833   ShowMessage("depth= ");
834   scanz("%hd",&MaxSearchDepth);
835 }
836 
837 SetContempt()
838 {
839   ShowMessage("contempt= ");
840   scanz("%hd",&contempt);
841 }
842 
843 ChangeXwindow()
844 {
845   ShowMessage("xwndw= ");
846   scanz("%hd",&xwndw);
847 }
848 
849 
850 SelectLevel()
851 {
852   ClrScreen();
853   gotoXY(32,2); printz("CHESS");
854   gotoXY(20,4); printz(" 1.   60 moves in   5 minutes");
855   gotoXY(20,5); printz(" 2.   60 moves in  15 minutes");
856   gotoXY(20,6); printz(" 3.   60 moves in  30 minutes");
857   gotoXY(20,7); printz(" 4.   40 moves in  30 minutes");
858   gotoXY(20,8); printz(" 5.   40 moves in  60 minutes");
859   gotoXY(20,9); printz(" 6.   40 moves in 120 minutes");
860   gotoXY(20,10); printz(" 7.   40 moves in 240 minutes");
861   gotoXY(20,11); printz(" 8.    1 move  in  15 minutes");
862   gotoXY(20,12); printz(" 9.    1 move  in  60 minutes");
863   gotoXY(20,13); printz("10.    1 move  in 600 minutes");
864 
865   OperatorTime = 0; TCmoves = 60; TCminutes = 5;
866 
867   gotoXY(20,17); printz("Enter Level: ");
868   refresh();
869   scanz("%ld",&Level);
870   switch (Level)
871     {
872       case 1 : TCmoves = 60; TCminutes = 5; break;
873       case 2 : TCmoves = 60; TCminutes = 15; break;
874       case 3 : TCmoves = 60; TCminutes = 30; break;
875       case 4 : TCmoves = 40; TCminutes = 30; break;
876       case 5 : TCmoves = 40; TCminutes = 60; break;
877       case 6 : TCmoves = 40; TCminutes = 120; break;
878       case 7 : TCmoves = 40; TCminutes = 240; break;
879       case 8 : TCmoves = 1; TCminutes = 15; break;
880       case 9 : TCmoves = 1; TCminutes = 60; break;
881       case 10 : TCmoves = 1; TCminutes = 600; break;
882     }
883 
884   TCflag = (TCmoves > 1);
885   SetTimeControl();
886   ClrScreen();
887   UpdateDisplay(0,0,1,0);
888 }
889 
890 
891 ShowPostnValues()
892 {
893 short i,r,c;
894   ExaminePosition();
895   for (i = 0; i < 64; i++)
896     {
897       if (reverse) r = 7-row[i]; else r = row[i];
898       if (reverse) c = 7-column[i]; else c = column[i];
899       gotoXY(4+5*c,5+2*(7-r));
900       c1 = color[i]; c2 = otherside[c1];
901       PC1 = PawnCnt[c1]; PC2 = PawnCnt[c2];
902       atk1 = atak[c1]; atk2 = atak[c2];
903       if (color[i] == neutral) printz("   ");
904       else printz("%3d ",SqValue(i,opponent));
905     }
906   ScorePosition(opponent,&i);
907   gotoXY(50,24);
908   printz("Score= %d",i); ClrEoln();
909 }
910 
911 
912 DoDebug()
913 {
914 short k,p,i,r,c,tp,tc;
915 char s[40];
916   ExaminePosition();
917   ShowMessage("Enter piece: ");
918   scanz("%s",s);
919   if (s[0] == 'w') k = white; else k = black;
920   if (s[1] == 'p') p = pawn;
921   else if (s[1] == 'n') p = knight;
922   else if (s[1] == 'b') p = bishop;
923   else if (s[1] == 'r') p = rook;
924   else if (s[1] == 'q') p = queen;
925   else if (s[1] == 'k') p = king;
926   else p = no_piece;
927   for (i = 0; i < 64; i++)
928     {
929       if (reverse) r = 7-row[i]; else r = row[i];
930       if (reverse) c = 7-column[i]; else c = column[i];
931       gotoXY(4+5*c,5+2*(7-r));
932       tp = board[i]; tc = color[i];
933       board[i] = p; color[i] = k;
934       c1 = k; c2 = otherside[c1];
935       PC1 = PawnCnt[c1]; PC2 = PawnCnt[c2];
936       atk1 = atak[c1]; atk2 = atak[c2];
937       printz("%3d ",SqValue(i,opponent));
938       board[i] = tp; color[i] = tc;
939     }
940   ScorePosition(opponent,&i);
941   gotoXY(50,24);
942   printz("Score= %d",i); ClrEoln();
943 }
944