1 /*>>> epdglue.c: glue to connect Crafty to the EPD Kit routines */
2 #if defined(EPD)
3 /* Revised: 1996.04.21 */
4 /*
5  Copyright (C) 1996 by Steven J. Edwards (sje@mv.mv.com)
6  All rights reserved.  This code may be freely redistibuted and used by
7  both research and commerical applications.  No warranty exists.
8  */
9 /*
10  The contents of this source file form the programmatic glue between
11  the host program Crafty and the EPD Kit.  Therefore, this file will
12  have to be changed if used with a different host program.  Also, the
13  contents of the prototype include file (epdglue.h) may also require
14  modification for a different host.
15  The contents of the other source files in the EPD Kit (epddefs.h,
16  epd.h, and epd.c) should not have to be changed for different hosts.
17  */
18 /*
19  This file was originally prepared on an Apple Macintosh using the
20  Metrowerks CodeWarrior 6 ANSI C compiler.  Tabs are set at every
21  four columns.  Further testing and development was performed on a
22  generic PC running Linux 1.2.9 and using the gcc 2.6.3 compiler.
23  */
24 /* system includes */
25 #  if defined(UNIX)
26 #    include <unistd.h>
27 #  endif
28 #  include <ctype.h>
29 #  include <time.h>
30 #  if !defined(UNIX)
31 #    include <process.h>
32 #  endif
33 /* Crafty includes */
34 #  include "chess.h"
35 #  include "data.h"
36 /* EPD Kit definitions (host program independent) */
37 #  include "epddefs.h"
38 /* EPD Kit routine prototypes (host program independent) */
39 #  include "epd.h"
40 /* prototypes for this file (host program dependent) */
41 #  include "epdglue.h"
42 /* EPD glue command type */
43 typedef siT egcommT, *egcommptrT;
44 
45 #  define egcommL 26
46 #  define egcomm_nil (-1)
47 #  define egcomm_epdapgn  0 /* append a PGN game to a file */
48 #  define egcomm_epdbfix  1 /* fix file for Bookup import */
49 #  define egcomm_epdcert  2 /* display certain evaluation (if possible) */
50 #  define egcomm_epdcics  3 /* slave to an Internet Chess Server */
51 #  define egcomm_epdcomm  4 /* slave to the Duplex referee program */
52 #  define egcomm_epddpgn  5 /* display the current game in PGN */
53 #  define egcomm_epddsml  6 /* display SAN move list */
54 #  define egcomm_epddstr  7 /* display PGN Seven Tag Roster */
55 #  define egcomm_epddtpv  8 /* display PGN tag pair value */
56 #  define egcomm_epdenum  9 /* enumerate EPD file */
57 #  define egcomm_epdhelp 10 /* display EPD help */
58 #  define egcomm_epdlink 11 /* slave to the Argus referee program */
59 #  define egcomm_epdlpgn 12 /* load a PGN game from a file */
60 #  define egcomm_epdlrec 13 /* load an EPD record form a file */
61 #  define egcomm_epdmore 14 /* more help */
62 #  define egcomm_epdnoop 15 /* no operation */
63 #  define egcomm_epdpfdn 16 /* process file: data normalization */
64 #  define egcomm_epdpfdr 17 /* process file: data repair */
65 #  define egcomm_epdpfga 18 /* process file: general analysis */
66 #  define egcomm_epdpflc 19 /* process file: locate cooks */
67 #  define egcomm_epdpfop 20 /* process file: operation purge */
68 #  define egcomm_epdscor 21 /* score EPD benchmark result file */
69 #  define egcomm_epdshow 22 /* show EPD four fields for current position */
70 #  define egcomm_epdspgn 23 /* save a PGN game to a file */
71 #  define egcomm_epdstpv 24 /* set PGN tag pair value */
72 #  define egcomm_epdtest 25 /* developer testing */
73 /* output text buffer */
74 #  define tbufL 256
75 static char tbufv[tbufL];
76 
77 /* EPD glue command strings */
78 static charptrT egcommstrv[egcommL];
79 
80 /* EPD glue command string descriptions */
81 static charptrT eghelpstrv[egcommL];
82 
83 /* EPD glue command parameter counts (includes command token) */
84 /* the current (default) EPD game structure */
85 static gamptrT default_gamptr;
86 
87 /*--> EGPrint: print a string to the output */
88 static
EGPrint(charptrT s)89 void EGPrint(charptrT s) {
90 /* this is an internal EPD glue routine */
91 /*
92  This routine is provided as an alternative to direct writing to the
93  standard output.  All EPD glue printing output goes through here.  The
94  idea is that the host program may have some special requirements for
95  printing output (like a window display), so a convenient single point
96  is provided to handle this.
97  Note that there is no corresponding routine for reading from the
98  standard input because the EPD glue does no interactive reading, except
99  for a single getchar() call in the epdhelp display pager.
100  */
101 /* for Crafty, the standard output is used */
102   printf("%s", s);
103   return;
104 }
105 
106 /*--> EGPrintTB: print the contents of the text buffer */
107 static
EGPrintTB(void)108 void EGPrintTB(void) {
109 /* this is an internal EPD glue routine */
110   EGPrint(tbufv);
111   return;
112 }
113 
114 /*--> EGPL: print a string followed by a newline */
115 static
EGPL(charptrT s)116 void EGPL(charptrT s) {
117 /* this is an internal EPD glue routine */
118   EGPrint(s);
119   EGPrint("\n");
120   return;
121 }
122 
123 /*--> EGLocateCommand: locate an EPD glue command from a token */
EGLocateCommand(charptrT s)124 static egcommT EGLocateCommand(charptrT s) {
125   egcommT egcomm, index;
126 
127 /* this is an internal EPD glue routine */
128 /* set the default return value: no match */
129   egcomm = egcomm_nil;
130 /* scan the EPD glue command string vector */
131   index = 0;
132   while ((index < egcommL) && (egcomm == egcomm_nil))
133     if (strcmp(s, egcommstrv[index]) == 0)
134       egcomm = index;
135     else
136       index++;
137   return egcomm;
138 }
139 
140 /*--> EGMapFromHostColor: map a color from the host to the EPD style */
EGMapFromHostColor(siT color)141 static cT EGMapFromHostColor(siT color) {
142   cT c;
143 
144 /* this is an internal glue routine */
145 /* map from Crafty's color representation */
146   if (color == 1)
147     c = c_w;
148   else
149     c = c_b;
150   return c;
151 }
152 
153 /*--> EGMapToHostColor: map a color to the host from the EPD style */
EGMapToHostColor(cT c)154 static siT EGMapToHostColor(cT c) {
155   siT color;
156 
157 /* this is an internal glue routine */
158 /* map to Crafty's color representation */
159   if (c == c_w)
160     color = 1;
161   else
162     color = 0;
163   return color;
164 }
165 
166 /*--> EGMapFromHostCP: map a color piece from the host to the EPD style */
EGMapFromHostCP(siT hostcp)167 static cpT EGMapFromHostCP(siT hostcp) {
168   cpT cp = 0;
169 
170 /* this is an internal glue routine */
171 /* map from Crafty's color-piece representation */
172   switch (hostcp) {
173     case -queen:
174       cp = cp_bq;
175       break;
176     case -rook:
177       cp = cp_br;
178       break;
179     case -bishop:
180       cp = cp_bb;
181       break;
182     case -king:
183       cp = cp_bk;
184       break;
185     case -knight:
186       cp = cp_bn;
187       break;
188     case -pawn:
189       cp = cp_bp;
190       break;
191     case 0:
192       cp = cp_v0;
193       break;
194     case pawn:
195       cp = cp_wp;
196       break;
197     case knight:
198       cp = cp_wn;
199       break;
200     case king:
201       cp = cp_wk;
202       break;
203     case bishop:
204       cp = cp_wb;
205       break;
206     case rook:
207       cp = cp_wr;
208       break;
209     case queen:
210       cp = cp_wq;
211       break;
212   };
213   return cp;
214 }
215 
216 /*--> EGMapToHostCP: map a color piece to the host from the EPD style */
EGMapToHostCP(cpT cp)217 static siT EGMapToHostCP(cpT cp) {
218   siT hostcp = 0;
219 
220 /* this is an internal glue routine */
221 /* map to Crafty's color-piece representation */
222   switch (cp) {
223     case cp_wp:
224       hostcp = pawn;
225       break;
226     case cp_wn:
227       hostcp = knight;
228       break;
229     case cp_wb:
230       hostcp = bishop;
231       break;
232     case cp_wr:
233       hostcp = rook;
234       break;
235     case cp_wq:
236       hostcp = queen;
237       break;
238     case cp_wk:
239       hostcp = king;
240       break;
241     case cp_bp:
242       hostcp = -pawn;
243       break;
244     case cp_bn:
245       hostcp = -knight;
246       break;
247     case cp_bb:
248       hostcp = -bishop;
249       break;
250     case cp_br:
251       hostcp = -rook;
252       break;
253     case cp_bq:
254       hostcp = -queen;
255       break;
256     case cp_bk:
257       hostcp = -king;
258       break;
259     case cp_v0:
260       hostcp = 0;
261       break;
262   };
263   return hostcp;
264 }
265 
266 /*--> EGMapFromHostSq: map square index from host style */
EGMapFromHostSq(siT index)267 static sqT EGMapFromHostSq(siT index) {
268   sqT sq;
269 
270 /* this is an internal glue routine */
271 /* Crafty's square index is the same as the EPD Kit square index */
272   sq = index;
273   return sq;
274 }
275 
276 /*--> EGMapToHostSq: map square index to host style */
EGMapToHostSq(sqT sq)277 static siT EGMapToHostSq(sqT sq) {
278   siT index;
279 
280 /* this is an internal glue routine */
281 /* Crafty's square index is the same as the EPD Kit square index */
282   index = sq;
283   return index;
284 }
285 
286 /*--> EGMapFromHostScore: map score from host style */
EGMapFromHostScore(liT score)287 static cpevT EGMapFromHostScore(liT score) {
288   cpevT cpev;
289   liT distance;
290 
291 /* this is an internal EPD glue routine */
292 /* check for a forced mate */
293   if (score >= (MATE - MAXPLY)) {
294 /* convert forced mate score */
295     distance = (MATE - score) / 2;
296     cpev = synth_mate(distance);
297   } else if (score <= (MAXPLY - MATE)) {
298 /* convert forced loss score */
299     distance = (MATE + score) / 2;
300     cpev = synth_loss(distance);
301   } else {
302 /* convert regular score */
303     cpev = score;
304   };
305   return cpev;
306 }
307 
308 /*--> EGMapFromHostMove: map move from host style to EPD style */
EGMapFromHostMove(liT move)309 static mT EGMapFromHostMove(liT move) {
310   mT m;
311   siT flag;
312 
313 /* this is an internal EPD glue routine */
314 /* the EPD current position must be properly set */
315   m.m_flag = 0;
316   m.m_frsq = EGMapFromHostSq((siT) From(move));
317   m.m_tosq = EGMapFromHostSq((siT) To(move));
318   m.m_frcp = EPDFetchCP(m.m_frsq);
319   m.m_tocp = EPDFetchCP(m.m_tosq);
320 /* determine special case move indication */
321   flag = 0;
322   if (!flag)
323     if ((m.m_frcp == cp_wk) && (m.m_frsq == sq_e1) && (m.m_tosq == sq_g1)) {
324       m.m_scmv = scmv_cks;
325       flag = 1;
326     };
327   if (!flag)
328     if ((m.m_frcp == cp_bk) && (m.m_frsq == sq_e8) && (m.m_tosq == sq_g8)) {
329       m.m_scmv = scmv_cks;
330       flag = 1;
331     };
332   if (!flag)
333     if ((m.m_frcp == cp_wk) && (m.m_frsq == sq_e1) && (m.m_tosq == sq_c1)) {
334       m.m_scmv = scmv_cqs;
335       flag = 1;
336     };
337   if (!flag)
338     if ((m.m_frcp == cp_bk) && (m.m_frsq == sq_e8) && (m.m_tosq == sq_c8)) {
339       m.m_scmv = scmv_cqs;
340       flag = 1;
341     };
342   if (!flag)
343     if ((m.m_frcp == cp_wp) && (m.m_tosq == EPDFetchEPSQ())) {
344       m.m_scmv = scmv_epc;
345       flag = 1;
346     };
347   if (!flag)
348     if ((m.m_frcp == cp_bp) && (m.m_tosq == EPDFetchEPSQ())) {
349       m.m_scmv = scmv_epc;
350       flag = 1;
351     };
352   if (!flag)
353     if (Promote(move) != 0) {
354       switch (Promote(move)) {
355         case knight:
356           m.m_scmv = scmv_ppn;
357           break;
358         case bishop:
359           m.m_scmv = scmv_ppb;
360           break;
361         case rook:
362           m.m_scmv = scmv_ppr;
363           break;
364         case queen:
365           m.m_scmv = scmv_ppq;
366           break;
367       };
368       flag = 1;
369     };
370   if (!flag)
371     m.m_scmv = scmv_reg;
372   return m;
373 }
374 
375 /*--> EGGetIndexedHostPosition: copy from indexed host position */
376 static
EGGetIndexedHostPosition(TREE * RESTRICT tree,siT posdex,int active)377 void EGGetIndexedHostPosition(TREE * RESTRICT tree, siT posdex, int active) {
378   sqT sq;
379   rbT rb;
380   cT actc;
381   castT cast;
382   sqT epsq;
383   siT hmvc;
384   siT fmvn;
385 
386 /* this is an internal EPD glue routine */
387 /*
388  This routine is called from within the EPD glue to copy the host program's
389  current position at the given dpeth into the EPD Kit.  Information about
390  the previous EPD Kit current position is lost.
391  */
392 /* read from the host piece placement */
393   for (sq = sq_a1; sq <= sq_h8; sq++)
394     rb.rbv[sq] = EGMapFromHostCP(tree->position.board[EGMapToHostSq(sq)]);
395 /* read from the host piece active color */
396   actc = EGMapFromHostColor((siT) active);
397 /* read from the host piece castling availability */
398   cast = 0;
399   switch (tree->status[posdex].castle[1]) {
400     case 0:
401       break;
402     case 1:
403       cast |= cf_wk;
404       break;
405     case 2:
406       cast |= cf_wq;
407       break;
408     case 3:
409       cast |= cf_wk | cf_wq;
410       break;
411   };
412   switch (tree->status[posdex].castle[0]) {
413     case 0:
414       break;
415     case 1:
416       cast |= cf_bk;
417       break;
418     case 2:
419       cast |= cf_bq;
420       break;
421     case 3:
422       cast |= cf_bk | cf_bq;
423       break;
424   };
425 /* read from the host piece en passant target square */
426   epsq = sq_nil;
427   if (tree->status[posdex].enpassant_target != 0) {
428     sq = sq_a1;
429     while ((epsq == sq_nil) && (sq <= sq_h8))
430       if (tree->status[posdex].enpassant_target == EGMapToHostSq(sq))
431         epsq = sq;
432       else
433         sq++;
434   };
435 /* read from the host halfmove clock */
436   hmvc = tree->status[posdex].reversible;
437 /* read from the host fullmove number */
438   fmvn = move_number;
439 /* set the EPD current position */
440   EPDSetCurrentPosition(&rb, actc, cast, epsq, hmvc, fmvn);
441   return;
442 }
443 
444 /*--> EGGetHostPosition: copy from host position to EPD Kit position */
445 static
EGGetHostPosition(void)446 void EGGetHostPosition(void) {
447 /* this is an internal EPD glue routine */
448 /*
449  This routine is called from within the EPD glue to copy the host program's
450  current position into the EPD Kit.  Information about the previous EPD Kit
451  current position is lost.
452  */
453 /* transfer from ply zero host position */
454   EGGetIndexedHostPosition(block[0], 0, game_wtm);
455   return;
456 }
457 
458 /*--> EGPutHostPosition: copy from EPD Kit position to host position */
459 static
EGPutHostPosition(void)460 void EGPutHostPosition(void) {
461   sqT sq;
462   rbT rb;
463   cT actc;
464   castT cast;
465   sqT epsq;
466   siT hmvc;
467   siT fmvn;
468   siT index;
469   TREE *tree = block[0];
470 
471 /* this is an internal EPD glue routine */
472 /*
473  This routine is called from within the EPD glue to copy the EPD Kit's current
474  position into the host program.  If the previous host program current position
475  is different from the new position, then information about the previous host
476  program current position is lost.  This means that the host program preserves
477  history information if and only if such preservation is appropriate.
478  Actually, the host position data is completely overwritten, so the above
479  comment is temporarily false, but will be true as developement proceeds.
480  */
481 /* fetch the EPD current position data items */
482   rb = *EPDFetchBoard();
483   actc = EPDFetchACTC();
484   cast = EPDFetchCAST();
485   epsq = EPDFetchEPSQ();
486   hmvc = EPDFetchHMVC();
487   fmvn = EPDFetchFMVN();
488 /* copy the board into the host board */
489   for (sq = sq_a1; sq <= sq_h8; sq++)
490     tree->position.board[EGMapToHostSq(sq)] = EGMapToHostCP(rb.rbv[sq]);
491 /* copy the active color */
492   game_wtm = EGMapToHostColor(actc);
493 /* copy the castling availibility */
494   tree->status[0].castle[1] = 0;
495   if (cast & cf_wk)
496     tree->status[0].castle[1] += 1;
497   if (cast & cf_wq)
498     tree->status[0].castle[1] += 2;
499   tree->status[0].castle[0] = 0;
500   if (cast & cf_bk)
501     tree->status[0].castle[0] += 1;
502   if (cast & cf_bq)
503     tree->status[0].castle[0] += 2;
504 /* copy the en passant target square */
505   if (epsq == sq_nil)
506     tree->status[0].enpassant_target = 0;
507   else
508     tree->status[0].enpassant_target = EGMapToHostSq(epsq);
509 /* copy the halfmove clock */
510   tree->status[0].reversible = hmvc;
511 /* copy the fullmove number */
512   move_number = fmvn;
513 /* set secondary host data items */
514   SetChessBitBoards(tree);
515   rep_index = 0;
516   tree->rep_list[0] = HashKey;
517   moves_out_of_book = 0;
518   last_mate_score = 0;
519 /* clear the host killer information */
520   for (index = 0; index < MAXPLY; index++) {
521     tree->killers[index].move1 = 0;
522     tree->killers[index].move2 = 0;
523   }
524 /* clear miscellaneous host items */
525   ponder_move = 0;
526   last_pv.pathd = 0;
527   last_pv.pathl = 0;
528   over = 0;
529   return;
530 }
531 
532 /*--> EGEncodeHostHistory: generate a string from host move history */
EGEncodeHostHistory(void)533 static charptrT EGEncodeHostHistory(void) {
534   charptrT sptr;
535   gamptrT gamptr;
536   pgnstrT pgnstr;
537   mptrT mptr;
538   siT flag;
539   siT ch = 0;
540   charptrT s;
541   mT m;
542 
543 /* this works only for games starting form the initial position */
544 /* set default return value: failure */
545   sptr = NULL;
546 /* set okay  */
547   flag = 1;
548 /* reset the EPD current position */
549   EPDReset();
550 /* make sure the host history file exists */
551   if (history_file == NULL)
552     flag = 0;
553   else {
554     rewind(history_file);
555     ch = fgetc(history_file);
556   };
557 /* open a game structure */
558   gamptr = EPDGameOpen();
559 /* copy tag data from default game structure */
560   if (default_gamptr != NULL)
561     for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++)
562       EPDPGNPutSTR(gamptr, pgnstr, EPDPGNGetSTR(default_gamptr, pgnstr));
563 /* copy GTIM from default game structure */
564   if (default_gamptr != NULL)
565     EPDPutGTIM(gamptr, EPDGetGTIM(default_gamptr));
566 /* read the host history file */
567   while (flag && (ch != EOF)) {
568 /* skip whitespace */
569     while ((ch != EOF) && isspace(ch))
570       ch = fgetc(history_file);
571 /* if not EOF, then construct a move */
572     if (ch != EOF) {
573 /* attach the first character */
574       s = EPDStringGrab("");
575       s = EPDStringAppendChar(s, (char) ch);
576       ch = fgetc(history_file);
577 /* attach the remaining characters */
578       while ((ch != EOF) && !isspace(ch)) {
579         s = EPDStringAppendChar(s, (char) ch);
580         ch = fgetc(history_file);
581       };
582 /* match the move */
583       EPDGenMoves();
584       mptr = EPDSANDecodeAux(s, 0);
585       if (mptr == NULL)
586         flag = 0;
587       else {
588 /* execute the move */
589         m = *mptr;
590         EPDGameAppendMove(gamptr, &m);
591         EPDExecuteUpdate(&m);
592         EPDCollapse();
593       };
594 /* release move buffer storage */
595       EPDMemoryFree(s);
596     };
597   };
598 /* construct the string representation of the game */
599   if (flag)
600     sptr = EPDPGNHistory(gamptr);
601 /* clean up if there was a problem */
602   if (!flag)
603     if (sptr != NULL) {
604       EPDMemoryFree(sptr);
605       sptr = NULL;
606     };
607 /* close the game structure */
608   EPDGameClose(gamptr);
609   return sptr;
610 }
611 
612 /*--> EGIterate: wrapper function for host Iterate() call */
613 static
EGIterate(siT wtm_flag,siT think_flag)614 int EGIterate(siT wtm_flag, siT think_flag) {
615   int value;
616   epdptrT epdptr;
617   TREE *tree = block[0];
618 
619   EPDGenMoves();
620 /* save current kit position */
621   epdptr = EPDGetCurrentPosition();
622 /* more than one move, execute regular search */
623   value = Iterate(wtm_flag, think_flag, 0);
624 /* restore kit position */
625   EPDRealize(epdptr);
626   EPDReleaseEPD(epdptr);
627   EPDGenMoves();
628   last_pv = tree->pv[0];
629   last_value = value;
630   return value;
631 }
632 
633 /*--> EGCommHandler: callback routine for handling Duplex events */
EGCommHandler(epdptrT epdptr0,siptrT flagptr)634 static epdptrT EGCommHandler(epdptrT epdptr0, siptrT flagptr) {
635   epdptrT epdptr1;
636   eopptrT eopptr;
637   charptrT s;
638   fptrT fptr;
639   mptrT mptr;
640   mT m;
641   sanT san;
642   int move;
643   char tv[tL];
644   TREE *tree = block[0];
645 
646 /* set flag: no errors (so far) */
647   *flagptr = 1;
648 /* clear result */
649   epdptr1 = NULL;
650 /* process according to input referee command */
651   switch (EPDExtractRefcomIndex(epdptr0)) {
652     case refcom_conclude:
653 /* end of game */
654       s = EPDPGNHistory(default_gamptr);
655       if (s == NULL)
656         *flagptr = 0;
657       else {
658 /* append game to PGN output file */
659         sprintf(tv, "c%05hd.pgn", ((siT) getpid()));
660         fptr = fopen(tv, "a");
661         if (fptr == NULL)
662           *flagptr = 0;
663         else {
664           fprintf(fptr, "%s", s);
665           fclose(fptr);
666         };
667         EPDMemoryFree(s);
668       };
669 /* clean up and remove the temporary history file */
670       if (history_file != NULL) {
671         fclose(history_file);
672         history_file = NULL;
673       };
674       sprintf(tv, "h%05hd.pml", ((siT) getpid()));
675       remove(tv);
676 /* close the game structure */
677       if (default_gamptr != NULL) {
678         EPDGameClose(default_gamptr);
679         default_gamptr = NULL;
680       };
681       break;
682     case refcom_disconnect:
683 /* channel shutdown */
684 /* clean up and remove the temporary history file */
685       if (history_file != NULL) {
686         fclose(history_file);
687         history_file = NULL;
688       };
689       sprintf(tv, "h%05hd.pml", ((siT) getpid()));
690       remove(tv);
691 /* ensure game structure is closed */
692       if (default_gamptr != NULL) {
693         EPDGameClose(default_gamptr);
694         default_gamptr = NULL;
695       };
696       break;
697     case refcom_execute:
698 /* execute the supplied move */
699       eopptr = EPDLocateEOPCode(epdptr0, epdso_sm);
700       move = InputMove(tree, 0, game_wtm, 0, 0, eopptr->eop_headeov->eov_str);
701       if (history_file) {
702         fseek(history_file, ((((move_number - 1) * 2) + 1 - game_wtm) * 10),
703             SEEK_SET);
704         fprintf(history_file, "%9s\n", eopptr->eop_headeov->eov_str);
705       }
706       MakeMoveRoot(tree, game_wtm, move);
707       game_wtm = Flip(game_wtm);
708       if (game_wtm)
709         move_number++;
710 /* execute the move in the EPD Kit */
711       EPDGenMoves();
712       mptr = EPDSANDecodeAux(eopptr->eop_headeov->eov_str, 0);
713       m = *mptr;
714       EPDGameAppendMove(default_gamptr, &m);
715       EPDExecuteUpdate(&m);
716       EPDCollapse();
717       break;
718     case refcom_fault:
719 /* a problem occurred */
720       EGPL("EPDCommHandler: refcom fault");
721       *flagptr = 0;
722       break;
723     case refcom_inform:
724 /* process incidental information */
725       EPDCopyOutPTP(default_gamptr, epdptr0);
726 /* update the current game termination marker */
727       s = EPDPGNGetSTR(default_gamptr, pgnstr_result);
728       if ((s == NULL) || (strcmp(s, "*") == 0))
729         EPDPutGTIM(default_gamptr, gtim_u);
730       else if (strcmp(s, "1-0") == 0)
731         EPDPutGTIM(default_gamptr, gtim_w);
732       else if (strcmp(s, "0-1") == 0)
733         EPDPutGTIM(default_gamptr, gtim_b);
734       else if (strcmp(s, "1/2-1/2") == 0)
735         EPDPutGTIM(default_gamptr, gtim_d);
736       break;
737     case refcom_respond:
738 /* execute the supplied move (if any) */
739       eopptr = EPDLocateEOPCode(epdptr0, epdso_sm);
740       if (eopptr != NULL) {
741         move =
742             InputMove(tree, 0, game_wtm, 0, 0, eopptr->eop_headeov->eov_str);
743         if (history_file) {
744           fseek(history_file, ((((move_number - 1) * 2) + 1 - game_wtm) * 10),
745               SEEK_SET);
746           fprintf(history_file, "%9s\n", eopptr->eop_headeov->eov_str);
747         }
748         MakeMoveRoot(tree, game_wtm, move);
749         game_wtm = Flip(game_wtm);
750         if (game_wtm)
751           move_number++;
752 /* execute the move in the EPD Kit */
753         EPDGenMoves();
754         mptr = EPDSANDecodeAux(eopptr->eop_headeov->eov_str, 0);
755         m = *mptr;
756         EPDGameAppendMove(default_gamptr, &m);
757         EPDExecuteUpdate(&m);
758         EPDCollapse();
759       };
760 /* calculate move + respond */
761       EPDGenMoves();
762       if (EPDFetchMoveCount() > 0) {
763 /* at least one move exists, set up for search */
764         ponder_move = 0;
765         thinking = 1;
766         last_pv.pathd = 0;
767         last_pv.pathl = 0;
768         tree->status[1] = tree->status[0];
769 /* search */
770         EGIterate((siT) game_wtm, (siT) think);
771 /* process search result */
772         strcpy(tv, OutputMove(tree, 0, game_wtm, last_pv.path[1]));
773         move = last_pv.path[1];
774 /* locate SAN move */
775         mptr = EPDSANDecodeAux(tv, 0);
776         m = *mptr;
777         EPDSANEncode(&m, san);
778 /* output to temporary history file */
779         if (history_file) {
780           fseek(history_file, ((((move_number - 1) * 2) + 1 - game_wtm) * 10),
781               SEEK_SET);
782           fprintf(history_file, "%9s\n", san);
783         }
784 /* update host position */
785         MakeMoveRoot(tree, game_wtm, move);
786         game_wtm = Flip(game_wtm);
787         if (game_wtm)
788           move_number++;
789 /* create reply EPD structure */
790         epdptr1 = EPDGetCurrentPosition();
791 /* add in referee request */
792         EPDAddOpSym(epdptr1, epdso_refreq, EPDFetchRefreqStr(refreq_reply));
793 /* add in supplied move */
794         EPDAddOpSym(epdptr1, epdso_sm, san);
795 /* execute the move in the EPD Kit */
796         mptr = EPDSANDecodeAux(san, 0);
797         m = *mptr;
798         EPDGameAppendMove(default_gamptr, &m);
799         EPDExecuteUpdate(&m);
800         EPDCollapse();
801       } else {
802 /* no moves exist, so no move response possible */
803         epdptr1 = EPDGetCurrentPosition();
804         eopptr = EPDCreateEOPCode(epdso_refreq);
805         EPDAppendEOV(eopptr,
806             EPDCreateEOVSym(EPDFetchRefreqStr(refreq_reply)));
807         EPDAppendEOP(epdptr1, eopptr);
808       };
809       break;
810     case refcom_reset:
811 /* reset EPD Kit */
812       EPDReset();
813 /* reset host for a new game */
814       ponder = 0;
815       ponder_move = 0;
816       last_pv.pathd = 0;
817       last_pv.pathl = 0;
818       InitializeChessBoard(tree);
819       InitializeHashTables(0);
820       game_wtm = 1;
821       move_number = 1;
822 /* open the temporary history file */
823       if (history_file != NULL) {
824         fclose(history_file);
825         history_file = NULL;
826       };
827       sprintf(tv, "h%05hd.pml", ((siT) getpid()));
828       remove(tv);
829       history_file = fopen(tv, "w+");
830 /* open the current game structure */
831       if (default_gamptr != NULL)
832         EPDGameClose(default_gamptr);
833       default_gamptr = EPDGameOpen();
834       break;
835     case refcom_nil:
836       *flagptr = 0;
837       break;
838   };
839 /* clean up if there was a problem */
840   if (!(*flagptr))
841     if (epdptr1 != NULL) {
842       EPDReleaseEPD(epdptr1);
843       epdptr1 = NULL;
844     };
845   return epdptr1;
846 }
847 
848 /*--> EGProcessAPGN: process the EG command epdapgn */
EGProcessAPGN(void)849 static siT EGProcessAPGN(void) {
850   siT flag;
851   charptrT s;
852   fptrT fptr;
853 
854 /* this is an internal EPD glue routine */
855 /* set the default return value: success */
856   flag = 1;
857 /* parameter count check */
858   if (EPDTokenCount() != 2) {
859     EGPL("This command takes one parameter.");
860     flag = 0;
861   };
862 /* process the epdapgn command */
863   if (flag) {
864     s = EGEncodeHostHistory();
865     if (s == NULL)
866       flag = 0;
867     else {
868       fptr = fopen(EPDTokenFetch(1), "a");
869       if (fptr == NULL)
870         flag = 0;
871       else {
872         fprintf(fptr, "%s", s);
873         fclose(fptr);
874       };
875       EPDMemoryFree(s);
876     };
877   };
878   return flag;
879 }
880 
881 /*--> EGProcessBFIX: process the EG command epdbfix */
EGProcessBFIX(void)882 static siT EGProcessBFIX(void) {
883   siT flag;
884   fptrT fptr0, fptr1;
885   eopptrT eopptr;
886   epdptrT epdptr, nptr;
887   charptrT s;
888   char ev[epdL];
889 
890 /* this is an internal EPD glue routine */
891 /* set the default return value: success */
892   flag = 1;
893 /* clear the file pointers */
894   fptr0 = fptr1 = NULL;
895 /* parameter count check */
896   if (EPDTokenCount() != 3) {
897     EGPL("This command takes two parameters");
898     flag = 0;
899   };
900 /* set up the input file */
901   if (flag) {
902     fptr0 = fopen(EPDTokenFetch(1), "r");
903     if (fptr0 == NULL) {
904       sprintf(tbufv, "Can't open %s for reading\n", EPDTokenFetch(1));
905       EGPrintTB();
906       flag = 0;
907     };
908   };
909 /* set up the output file */
910   if (flag) {
911     fptr1 = fopen(EPDTokenFetch(2), "w");
912     if (fptr1 == NULL) {
913       sprintf(tbufv, "Can't open %s for writing\n", EPDTokenFetch(2));
914       EGPrintTB();
915       flag = 0;
916     };
917   };
918 /* scan the file */
919   if (flag)
920     while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL)) {
921 /* decode the record into an EPD structure */
922       epdptr = EPDDecode(ev);
923 /* check record decode validity */
924       if (epdptr == NULL)
925         flag = 0;
926       else {
927 /* clone the input EPD structure base */
928         nptr = EPDCloneEPDBase(epdptr);
929 /* copy the ce operation */
930         eopptr = EPDLocateEOPCode(epdptr, epdso_ce);
931         if (eopptr != NULL)
932           EPDAppendEOP(nptr, EPDCloneEOP(eopptr));
933 /* copy the pv operation */
934         eopptr = EPDLocateEOPCode(epdptr, epdso_pv);
935         if (eopptr != NULL)
936           EPDAppendEOP(nptr, EPDCloneEOP(eopptr));
937 /* output the new EPD strucutre */
938         s = EPDEncode(nptr);
939         fprintf(fptr1, "%s\n", s);
940         EPDMemoryFree(s);
941 /* deallocate both EPD structures */
942         EPDReleaseEPD(epdptr);
943         EPDReleaseEPD(nptr);
944       };
945     };
946 /* ensure file close */
947   if (fptr0 != NULL)
948     fclose(fptr0);
949   if (fptr1 != NULL)
950     fclose(fptr1);
951   return flag;
952 }
953 
954 /*--> EGProcessCICS: process the EG command epdcics */
EGProcessCICS(void)955 static siT EGProcessCICS(void) {
956   siT flag;
957 
958 /* this is an internal EPD glue routine */
959 /* set the default return value: success */
960   flag = 1;
961 /* parameter count check */
962   if (EPDTokenCount() != 3) {
963     EGPL("This command takes two parameters");
964     flag = 0;
965   };
966 /* process the epdcics command */
967   if (flag) {
968     EGPL("This command is not yet implemented.");
969     flag = 0;
970   };
971   return flag;
972 }
973 
974 /*--> EGProcessCOMM: process the EG command epdcomm */
EGProcessCOMM(void)975 static siT EGProcessCOMM(void) {
976   siT flag;
977   fptrT save_history_file;
978   gamptrT save_default_gamptr;
979 
980 /* this is an internal EPD glue routine */
981 /* set the default return value: success */
982   flag = 1;
983 /* parameter count check */
984   if (EPDTokenCount() != 2) {
985     EGPL("This command takes one parameter.");
986     flag = 0;
987   };
988 /* process the epdcomm command */
989   if (flag) {
990 /* save the history file pointer */
991     save_history_file = history_file;
992     history_file = NULL;
993 /* save the game structure */
994     save_default_gamptr = default_gamptr;
995     default_gamptr = NULL;
996 /* process via callback */
997     EGPL("Duplex slave mode begin");
998     flag = EPDComm(EGCommHandler, EPDTokenFetch(1));
999     EGPL("Duplex slave mode end");
1000 /* restore the game structure */
1001     if (default_gamptr != NULL) {
1002       EPDGameClose(default_gamptr);
1003       default_gamptr = NULL;
1004     };
1005     default_gamptr = save_default_gamptr;
1006 /* restore the history file pointer */
1007     history_file = save_history_file;
1008   };
1009   return flag;
1010 }
1011 
1012 /*--> EGProcessDPGN: process the EG command epddpgn */
EGProcessDPGN(void)1013 static siT EGProcessDPGN(void) {
1014   siT flag;
1015   charptrT s;
1016 
1017 /* this is an internal EPD glue routine */
1018 /* set the default return value: success */
1019   flag = 1;
1020 /* parameter count check */
1021   if (EPDTokenCount() != 1) {
1022     EGPL("This command takes no parameters.");
1023     flag = 0;
1024   };
1025 /* process the epddpgn command */
1026   if (flag) {
1027     s = EGEncodeHostHistory();
1028     if (s == NULL)
1029       flag = 0;
1030     else {
1031       EGPrint(s);
1032       EPDMemoryFree(s);
1033     };
1034   };
1035   return flag;
1036 }
1037 
1038 /*--> EGProcessDSML: process the EG command epddsml */
EGProcessDSML(void)1039 static siT EGProcessDSML(void) {
1040   siT flag;
1041   siT count, index;
1042   siT length, column;
1043   mT m;
1044   sanT san;
1045 
1046 /* this is an internal EPD glue routine */
1047 /* set the default return value: success */
1048   flag = 1;
1049 /* parameter count check */
1050   if (EPDTokenCount() != 1) {
1051     EGPL("This command takes no parameters.");
1052     flag = 0;
1053   };
1054 /* process the epddsml command */
1055   if (flag) {
1056 /* copy the current host position into the EPD Kit */
1057     EGGetHostPosition();
1058 /* generate  and count */
1059     EPDGenMoves();
1060     count = EPDFetchMoveCount();
1061     switch (count) {
1062       case 0:
1063         EGPL("No moves are available.");
1064         break;
1065       case 1:
1066         EGPL("There is 1 move available.");
1067         break;
1068       default:
1069         sprintf(tbufv, "There are %hd moves available.\n", count);
1070         EGPrintTB();
1071         break;
1072     };
1073 /* list moves */
1074     if (count > 0) {
1075       column = 0;
1076       EPDSortSAN();
1077       for (index = 0; index < count; index++) {
1078         m = *EPDFetchMove(index);
1079         EPDSANEncode(&m, san);
1080         length = strlen(san);
1081         if ((column + 1 + length) < columnL) {
1082           sprintf(tbufv, " %s", san);
1083           EGPrintTB();
1084           column += 1 + length;
1085         } else {
1086           EGPrint("\n");
1087           EGPrint(san);
1088           column = length;
1089         };
1090       };
1091       if (column > 0)
1092         EGPrint("\n");
1093     };
1094   };
1095   return flag;
1096 }
1097 
1098 /*--> EGProcessDSTR: process the EG command epddstr */
EGProcessDSTR(void)1099 static siT EGProcessDSTR(void) {
1100   siT flag;
1101   charptrT s;
1102 
1103 /* this is an internal EPD glue routine */
1104 /* set the default return value: success */
1105   flag = 1;
1106 /* parameter count check */
1107   if (EPDTokenCount() != 1) {
1108     EGPL("This command takes no parameters.");
1109     flag = 0;
1110   };
1111 /* process the epddstr command */
1112   if (flag) {
1113     s = EPDPGNGenSTR(default_gamptr);
1114     EGPrint(s);
1115     EPDMemoryFree(s);
1116   };
1117   return flag;
1118 }
1119 
1120 /*--> EGProcessDTPV: process the EG command epddtpv */
EGProcessDTPV(void)1121 static siT EGProcessDTPV(void) {
1122   siT flag;
1123   pgnstrT pgnstr;
1124 
1125 /* this is an internal EPD glue routine */
1126 /* set the default return value: success */
1127   flag = 1;
1128 /* parameter count check */
1129   if (EPDTokenCount() != 2) {
1130     EGPL("This command takes one parameter.");
1131     flag = 0;
1132   };
1133 /* process the epddtpv command */
1134   if (flag) {
1135     pgnstr = EPDPGNFetchTagIndex(EPDTokenFetch(1));
1136     if (pgnstr == pgnstr_nil) {
1137       EGPL("Unknown tag name; available tag names are:");
1138       for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++) {
1139         EGPrint("   ");
1140         EGPrint(EPDPGNFetchTagName(pgnstr));
1141       };
1142       EGPrint("\n");
1143       flag = 0;
1144     } else {
1145       sprintf(tbufv, "[%s \"%s\"]\n", EPDPGNFetchTagName(pgnstr),
1146           EPDPGNGetSTR(default_gamptr, pgnstr));
1147       EGPrintTB();
1148     };
1149   };
1150   return flag;
1151 }
1152 
1153 /*--> EGProcessENUM: process the EG command epdenum */
EGProcessENUM(void)1154 static siT EGProcessENUM(void) {
1155   siT flag;
1156   liT total;
1157 
1158 /* this is an internal EPD glue routine */
1159 /* set the default return value: success */
1160   flag = 1;
1161 /* parameter count check */
1162   if (EPDTokenCount() != 4) {
1163     EGPL("This command takes three parameters");
1164     flag = 0;
1165   };
1166 /* process the epdenum command */
1167   if (flag) {
1168     flag =
1169         EPDEnumerateFile((siT) atol(EPDTokenFetch(1)), EPDTokenFetch(2),
1170         EPDTokenFetch(3), &total);
1171     if (flag) {
1172       sprintf(tbufv, "Enumeration to depth %ld totals %ld\n",
1173           atol(EPDTokenFetch(1)), total);
1174       EGPrintTB();
1175     };
1176   };
1177   return flag;
1178 }
1179 
1180 /*--> EGProcessHELP: process the EG command epdhelp */
EGProcessHELP(void)1181 static siT EGProcessHELP(void) {
1182   siT flag;
1183   siT i;
1184   egcommT egcomm;
1185 
1186 /* this is an internal EPD glue routine */
1187 /* set the default return value: success */
1188   flag = 1;
1189 /* parameter count check */
1190   if (EPDTokenCount() != 1) {
1191     EGPL("This command takes no parameters.");
1192     flag = 0;
1193   };
1194 /* process the epdhelp command */
1195   if (flag) {
1196 /* it is not clear exactly why the next statment is needed */
1197     getchar();
1198 /* list all the commands */
1199     egcomm = 0;
1200     while (egcomm < egcommL) {
1201       EGPL("Available EPD glue command list");
1202       EGPL("-------------------------------");
1203       i = 0;
1204       while ((egcomm < egcommL) && (i < 10)) {
1205         sprintf(tbufv, "%s: %s\n", egcommstrv[egcomm], eghelpstrv[egcomm]);
1206         EGPrintTB();
1207         i++;
1208         egcomm++;
1209       };
1210       if (egcomm < egcommL) {
1211         EGPL("");
1212         EGPL("Press <return> for more command help");
1213         getchar();
1214         EGPL("");
1215       };
1216     };
1217   };
1218   return flag;
1219 }
1220 
1221 /*--> EGProcessLINK: process the EG command epdlink */
EGProcessLINK(void)1222 static siT EGProcessLINK(void) {
1223   siT flag;
1224 
1225 /* this is an internal EPD glue routine */
1226 /* set the default return value: success */
1227   flag = 1;
1228 /* parameter count check */
1229   if (EPDTokenCount() != 3) {
1230     EGPL("This command takes two parameters");
1231     flag = 0;
1232   };
1233 /* process the epdlink command */
1234   if (flag) {
1235     EGPL("This command is not yet implemented.");
1236     flag = 0;
1237   };
1238   return flag;
1239 }
1240 
1241 /*--> EGProcessLPGN: process the EG command epdlpgn */
EGProcessLPGN(void)1242 static siT EGProcessLPGN(void) {
1243   siT flag;
1244 
1245 /* this is an internal EPD glue routine */
1246 /* set the default return value: success */
1247   flag = 1;
1248 /* parameter count check */
1249   if (EPDTokenCount() != 2) {
1250     EGPL("This command takes one parameter.");
1251     flag = 0;
1252   };
1253 /* process the epdlpgn command */
1254   if (flag) {
1255     EGPL("This command is not yet implemented.");
1256     flag = 0;
1257   };
1258   return flag;
1259 }
1260 
1261 /*--> EGProcessLREC: process the EG command epdlrec */
EGProcessLREC(void)1262 static siT EGProcessLREC(void) {
1263   siT flag;
1264   fptrT fptr;
1265   liT i, n;
1266   epdptrT epdptr;
1267   char ev[epdL];
1268 
1269 /* this is an internal EPD glue routine */
1270 /* set the default return value: success */
1271   flag = 1;
1272 /* parameter count check */
1273   if (EPDTokenCount() != 3) {
1274     EGPL("This command takes two parameters");
1275     flag = 0;
1276   };
1277 /* process the epdlrec command */
1278   if (flag) {
1279     fptr = fopen(EPDTokenFetch(1), "r");
1280     if (fptr == NULL)
1281       flag = 0;
1282     else {
1283 /* read the indicated record */
1284       i = 0;
1285       n = atol(EPDTokenFetch(2));
1286       while (flag && (i < n))
1287         if (fgets(ev, (epdL - 1), fptr) == NULL)
1288           flag = 0;
1289         else
1290           i++;
1291       fclose(fptr);
1292 /* set the current position */
1293       if (flag) {
1294         epdptr = EPDDecode(ev);
1295         if (epdptr == NULL)
1296           flag = 0;
1297         else {
1298           EPDRealize(epdptr);
1299           EPDReleaseEPD(epdptr);
1300           EGPutHostPosition();
1301         };
1302       };
1303     };
1304   };
1305   return flag;
1306 }
1307 
1308 /*--> EGProcessMORE: process the EG command epdmore */
EGProcessMORE(void)1309 static siT EGProcessMORE(void) {
1310   siT flag;
1311 
1312 /* this is an internal EPD glue routine */
1313 /* set the default return value: success */
1314   flag = 1;
1315 /* parameter count check */
1316   if (EPDTokenCount() != 2) {
1317     EGPL("This command takes one parameter.");
1318     flag = 0;
1319   };
1320 /* process the epdmore command */
1321   if (flag)
1322     switch (EGLocateCommand(EPDTokenFetch(1))) {
1323       case egcomm_epdapgn:
1324         EGPL("epdapgn: Append the game to a PGN file");
1325         EGPL("");
1326         EGPL("This command is used to append the current game to a file");
1327         EGPL("using Portable Game Notation (PGN) format.  It takes one");
1328         EGPL("parameter which is the file name of interest.");
1329         break;
1330       case egcomm_epdbfix:
1331         EGPL("epdbfix: Fix an EPD file for import into Bookup");
1332         EGPL("");
1333         EGPL("This command takes two parameters.  Both parameters are");
1334         EGPL("names of EPD files.  The first is an existing EPD file with");
1335         EGPL("analysis data.  The second is the EPD file to be created");
1336         EGPL("from the first by removing all operations except the ce and");
1337         EGPL("pv operations.  This second file can then be imported into");
1338         EGPL("the Bookup program.");
1339         break;
1340       case egcomm_epdcert:
1341         EGPL("epdcert: Try to display a certain evaluation");
1342         EGPL("");
1343         EGPL("This command takes no parameters.  The current position is");
1344         EGPL("examined for legality, and if legal, an attempt is made to");
1345         EGPL("return an absolute certain evaluation.  An absolute certain");
1346         EGPL("evaluation is available for checkmates, stalemates, draws by");
1347         EGPL("insufficient material, and mate in one positions.  Also,");
1348         EGPL("if there are only a few chessmen on the board, then the");
1349         EGPL("current position is used as an index into an external file");
1350         EGPL("corresponding to the active color and the distribution of");
1351         EGPL("pieces.  If the appropriate external file is available, the");
1352         EGPL("position is evaluated by a single file look-up operation.");
1353         EGPL("These files are called tablebases and they should appear in");
1354         EGPL("the TB subdirectory of the current working directory.  These");
1355         EGPL("files may be obtained via ftp from the chess.onenet.net site");
1356         EGPL("in the pub/chess/TB directory.");
1357         break;
1358       case egcomm_epdcics:
1359         EGPL("epdcics: Slave to an Internet Chess Server");
1360         EGPL("");
1361         EGPL("This command causes the host program Crafty to becomed slaved");
1362         EGPL("to an Internet Chess Server (ICS).  This means that the host");
1363         EGPL("program will follow directions from the indicated Internet");
1364         EGPL("Chess Server until either the ICS tells the program to exit");
1365         EGPL("slave mode or the program is interrupted by the user.  This");
1366         EGPL("command takes two parameters.  The first is the name of the");
1367         EGPL("machine running the ICS and the second is the port number in");
1368         EGPL("use by the ICS.");
1369         break;
1370       case egcomm_epdcomm:
1371         EGPL("epdcomm: Slave to the Duplex referee program");
1372         EGPL("");
1373         EGPL("This command causes the host program Crafty to becomed slaved");
1374         EGPL("to the simple referee program Duplex.  Duplex must be started");
1375         EGPL("prior to entering this command.  Once the host program is");
1376         EGPL("slaved to Duplex, it will remain so until it is instructed");
1377         EGPL("by Duplex to terminate or is interrupted by the user.  This");
1378         EGPL("command is used to support the Duplex function of controlling");
1379         EGPL("automatic play between two host programs on the same Unix");
1380         EGPL("system.  The communication used is based on named pipes which");
1381         EGPL("are special files that support FIFO data operation.  This");
1382         EGPL("command takes one parameter which is a base name for a pair");
1383         EGPL("of named pipes.  The host output pipe name is generated by");
1384         EGPL("adding a \".pc0\" suffix to the base name and the host input");
1385         EGPL("pipe name is generated by addint a \".pc1\" suffix to the");
1386         EGPL("base name.  (Both pipe files are created and later removed");
1387         EGPL("automatically by the Duplex program.)  The Duplex program is");
1388         EGPL("given three parameters to run a series of games between two");
1389         EGPL("host programs: the first is the base name given to the first");
1390         EGPL("host program, the second is the base name given to the second");
1391         EGPL("host program, and the third is the count of the number of");
1392         EGPL("games to be played.");
1393         break;
1394       case egcomm_epddpgn:
1395         EGPL("epddpgn: Display the game using PGN");
1396         EGPL("");
1397         EGPL("This command displays the current game using Portable Game");
1398         EGPL("Notation (PGN).  It takes no parameters.");
1399         break;
1400       case egcomm_epddsml:
1401         EGPL("epddsml: Display SAN move list");
1402         EGPL("");
1403         EGPL("This command displays the ASCII sorted list of available");
1404         EGPL("moves using SAN (Standard Algebraic Notation).  The count");
1405         EGPL("of moves is also displayed.  This command takes no");
1406         EGPL("parameters.");
1407         break;
1408       case egcomm_epddstr:
1409         EGPL("epddstr: Display the PGN Seven Tag Roster");
1410         EGPL("");
1411         EGPL("This command displays the current values of each of the tag");
1412         EGPL("pairs of the PGN Seven Tag Roster.  These tags are: Event, ");
1413         EGPL("Site, Date, Round, White, Black, and Result.  This command");
1414         EGPL("takes no parameters.");
1415         break;
1416       case egcomm_epddtpv:
1417         EGPL("epddtpv: Display a PGN tag pair value");
1418         EGPL("");
1419         EGPL("This command displays the current value for the indicated");
1420         EGPL("PGN tag pair.  These available tag pair names are: Event, ");
1421         EGPL("Site, Date, Round, White, Black, and Result.  This command");
1422         EGPL("takes a single parameter which is the name of the tag pair");
1423         EGPL("to be displayed.");
1424         break;
1425       case egcomm_epdenum:
1426         EGPL("epdenum: Enumerate positions in an EPD file");
1427         EGPL("");
1428         EGPL("This command takes three parameters.  The first is a non-");
1429         EGPL("negative integer that gives a ply depth limit.  The second");
1430         EGPL("is an input EPD file with positions to be enumerated to the");
1431         EGPL("given depth.  The third parameter is the result EPD file");
1432         EGPL("with enumeration data given with the acd, acn, and acs");
1433         EGPL("operations.  The grand total of all enumerations is printed");
1434         EGPL("to the standard output.");
1435         break;
1436       case egcomm_epdhelp:
1437         EGPL("epdhelp: Display available epdglue commands");
1438         EGPL("");
1439         EGPL("This command takes no parameters.  It displays a list");
1440         EGPL("of all the epdglue commands with a single line description");
1441         EGPL("of each command.  The epdmore command gives a detailed");
1442         EGPL("description of a specified command.");
1443         break;
1444       case egcomm_epdlink:
1445         EGPL("epdlink: Slave to the Argus moderator program");
1446         EGPL("");
1447         EGPL("This command used to slave the host program to the Argus");
1448         EGPL("tournament referee program.  It takes two parameters.  The");
1449         EGPL("first is the name of the machine running the Argus referee");
1450         EGPL("and the second is the port number in use by Argus on the");
1451         EGPL("indicated machine.  The Argus program must be started prior");
1452         EGPL("to using this command.  Argus acts as a general tournament");
1453         EGPL("supervisor and mediator for any number of chessplaying");
1454         EGPL("programs competing in a compuer chess event.  It supplies");
1455         EGPL("the participating program entrants with everything needed");
1456         EGPL("for an entire tournament.");
1457         break;
1458       case egcomm_epdlpgn:
1459         EGPL("epdlpgn: Load the game from a PGN file");
1460         EGPL("");
1461         EGPL("This command loads a single game from a Portable Game");
1462         EGPL("Notation (PGN) file.  If there is more than one game in the");
1463         EGPL("file, then only the first one is loaded.  This command tales");
1464         EGPL("a single parameter which is the name of the file containing");
1465         EGPL("the PGN data of interest.");
1466         break;
1467       case egcomm_epdlrec:
1468         EGPL("epdlpgn: Load a selected EPD record from a file");
1469         EGPL("");
1470         EGPL("This command loads an EPD record from a file and causes it");
1471         EGPL("to become the current position in the host program.  This");
1472         EGPL("command takes two parameters.  The first is the name of the");
1473         EGPL("file with EPD records and the second is the record number");
1474         EGPL("of interest.  The epdlrec command is intended to assist with");
1475         EGPL("benchmark analysis by making it easy to select and load the");
1476         EGPL("Nth record of a benchmark file.");
1477         break;
1478       case egcomm_epdmore:
1479         EGPL("epdmore: Display detailed help for a given command");
1480         EGPL("");
1481         EGPL("This command takes a single parameter which is the name");
1482         EGPL("of one of the available epdglue commands.  A brief paragraph");
1483         EGPL("of helpful assistance is displayed.");
1484         break;
1485       case egcomm_epdnoop:
1486         EGPL("epdnoop: No operation");
1487         EGPL("");
1488         EGPL("This command performs no operation.  It is provided for");
1489         EGPL("development purposes.");
1490         break;
1491       case egcomm_epdpfdn:
1492         EGPL("epdpfdn: Process file: data normalization");
1493         EGPL("");
1494         EGPL("This command takes two parameters.  The first is the name of");
1495         EGPL("an input EPD data file.  The second is the name of the EPD");
1496         EGPL("output file to be produced from normalizing the input.  The");
1497         EGPL("normalization process produces a canonical external");
1498         EGPL("representation for each EPD input record.");
1499         break;
1500       case egcomm_epdpfdr:
1501         EGPL("epdpfdr: Process file: data repair");
1502         EGPL("");
1503         EGPL("This command takes two parameters.  The first is the name of");
1504         EGPL("an input EPD data file.  The second is the name of the EPD");
1505         EGPL("output file to be produced from repairing the input.  The");
1506         EGPL("repair process attempts to map all chess move data present");
1507         EGPL("in the input into Standard Algebraic Notation.  This repair");
1508         EGPL("effort affects the am, bm, pm, pv, sm, and sv operations.");
1509         break;
1510       case egcomm_epdpfga:
1511         EGPL("epdpfga: Process file: general analysis");
1512         EGPL("");
1513         EGPL("This command takes two parameters.  The first is the name of");
1514         EGPL("an input EPD data file.  The second is the name of the EPD");
1515         EGPL("output file to be produced from applying general analysis");
1516         EGPL("to each position in the input file.  The output analysis is");
1517         EGPL("contained in the acd, acn, acs, ce, and pv operations.");
1518         break;
1519       case egcomm_epdpflc:
1520         EGPL("epdpflc: Process file: locate cooks");
1521         EGPL("");
1522         EGPL("This command is used to scan an EPD file and report on any");
1523         EGPL("checkmating cooks.  The signle parameter is the name of the");
1524         EGPL("EPD file to be scanned.  Each record is scanned and if the");
1525         EGPL("centipawn evaluation indicates a forced mate, then the move");
1526         EGPL("appearing as the result of a search is checked against the");
1527         EGPL("moves appearing in the bm (best moves) operation on the same");
1528         EGPL("record.  If the result move does not appear in the bm list,");
1529         EGPL("then the record is reported as a cook.");
1530         break;
1531       case egcomm_epdpfop:
1532         EGPL("epdpfop: Process file: operation purge");
1533         EGPL("");
1534         EGPL("This command takes threee parameters.  The first is the name");
1535         EGPL("of an EPD operation mnemonic to be purged.  The second is the");
1536         EGPL("name fo the input EPD file, and the third is the name of the");
1537         EGPL("EPD output to be produced by purging the specified operation");
1538         EGPL("from the input file.");
1539         break;
1540       case egcomm_epdscor:
1541         EGPL("epdscor: Score EPD analysis file");
1542         EGPL("");
1543         EGPL("This command takes one parameter.  It is the name of an input");
1544         EGPL("EPD data file containing analysis result data.  The input");
1545         EGPL("data analysis is scanned and a brief statistical report is");
1546         EGPL("displayed.");
1547         break;
1548       case egcomm_epdshow:
1549         EGPL("epdshow: Show EPD four fields for the current position");
1550         EGPL("");
1551         EGPL("This command takes no parameters.  It causes the EPD four");
1552         EGPL("data fields for the current position to be displayed.");
1553         break;
1554       case egcomm_epdspgn:
1555         EGPL("epdspgn: Save the game to a PGN file");
1556         EGPL("");
1557         EGPL("This command is used to save the current game to a file");
1558         EGPL("using Portable Game Notation (PGN) format.  It takes one");
1559         EGPL("parameter which is the file name of interest.  The previous");
1560         EGPL("copy of the file, if any, is overwritten.");
1561         break;
1562       case egcomm_epdstpv:
1563         EGPL("epdstpv: Set a PGN tag pair value");
1564         EGPL("");
1565         EGPL("This command sets the current value for the indicated");
1566         EGPL("PGN tag pair.  These available tag pair names are: Event, ");
1567         EGPL("Site, Date, Round, White, Black, and Result.  This command");
1568         EGPL("takes two parameters.  The first which is the name of the");
1569         EGPL("tag pair of interest and the second is the value to be");
1570         EGPL("assigned.  Underscore characters in the value are mapped");
1571         EGPL("to blanks; this allows embedded spaces to appear in the");
1572         EGPL("received value.");
1573         break;
1574       case egcomm_epdtest:
1575         EGPL("epdtest: Developer testing");
1576         EGPL("");
1577         EGPL("This command takes no parameters.  It is used for developer");
1578         EGPL("testing purposes.");
1579         break;
1580       case egcomm_nil:
1581         sprintf(tbufv, "Unknown command: %s\n", EPDTokenFetch(1));
1582         EGPrintTB();
1583         flag = 0;
1584         break;
1585     };
1586   return flag;
1587 }
1588 
1589 /*--> EGProcessNOOP: process the EG command epdnoop */
EGProcessNOOP(void)1590 static siT EGProcessNOOP(void) {
1591   siT flag;
1592 
1593 /* this is an internal EPD glue routine */
1594 /* set the default return value: success */
1595   flag = 1;
1596 /* process the epdnoop command */
1597   return flag;
1598 }
1599 
1600 /*--> EGProcessPFDN: process the EG command epdpfdn */
EGProcessPFDN(void)1601 static siT EGProcessPFDN(void) {
1602   siT flag;
1603 
1604 /* this is an internal EPD glue routine */
1605 /* set the default return value: success */
1606   flag = 1;
1607 /* parameter count check */
1608   if (EPDTokenCount() != 3) {
1609     EGPL("This command takes two parameters");
1610     flag = 0;
1611   };
1612 /* process the epdpfdn command */
1613   if (flag)
1614     flag = EPDNormalizeFile(EPDTokenFetch(1), EPDTokenFetch(2));
1615   return flag;
1616 }
1617 
1618 /*--> EGProcessPFDR: process the EG command epdpfdr */
EGProcessPFDR(void)1619 static siT EGProcessPFDR(void) {
1620   siT flag;
1621 
1622 /* this is an internal EPD glue routine */
1623 /* set the default return value: success */
1624   flag = 1;
1625 /* parameter count check */
1626   if (EPDTokenCount() != 3) {
1627     EGPL("This command takes two parameters");
1628     flag = 0;
1629   };
1630 /* process the epdpfdr command */
1631   if (flag)
1632     flag = EPDRepairFile(EPDTokenFetch(1), EPDTokenFetch(2));
1633   return flag;
1634 }
1635 
1636 /*--> EGProcessPFGA: process the EG command epdpfga */
EGProcessPFGA(void)1637 static siT EGProcessPFGA(void) {
1638   siT flag;
1639   fptrT fptr0, fptr1;
1640   liT record;
1641   time_t start_time;
1642   liT result;
1643   siT index;
1644   liT host_acd, host_acn, host_acs;
1645   cpevT host_ce;
1646   charptrT s;
1647   liT move;
1648   mT m;
1649   sanT san;
1650   eovptrT eovptr;
1651   eopptrT eopptr;
1652   epdptrT epdptr;
1653   char ev[epdL];
1654   TREE *tree = block[0];
1655 
1656 /* this is an internal EPD glue routine */
1657 /* set the default return value: success */
1658   flag = 1;
1659 /* clear the file pointers */
1660   fptr0 = fptr1 = NULL;
1661 /* parameter count check */
1662   if (EPDTokenCount() != 3) {
1663     EGPL("This command takes two parameters");
1664     flag = 0;
1665   };
1666 /* set up the input file */
1667   if (flag) {
1668     fptr0 = fopen(EPDTokenFetch(1), "r");
1669     if (fptr0 == NULL) {
1670       sprintf(tbufv, "Can't open %s for reading\n", EPDTokenFetch(1));
1671       EGPrintTB();
1672       flag = 0;
1673     };
1674   };
1675 /* set up the output file */
1676   if (flag) {
1677     fptr1 = fopen(EPDTokenFetch(2), "w");
1678     if (fptr1 == NULL) {
1679       sprintf(tbufv, "Can't open %s for writing\n", EPDTokenFetch(2));
1680       EGPrintTB();
1681       flag = 0;
1682     };
1683   };
1684 /* scan the file */
1685   if (flag) {
1686 /* initialize the record count */
1687     record = 0;
1688 /* read one record per loop */
1689     while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL)) {
1690 /* decode the record into an EPD structure */
1691       epdptr = EPDDecode(ev);
1692 /* check record decode validity */
1693       if (epdptr == NULL)
1694         flag = 0;
1695       else {
1696 /* set up the position in the EPD Kit */
1697         EPDRealize(epdptr);
1698 /* legality test */
1699         if (!EPDIsLegal())
1700           flag = 0;
1701         else {
1702 /* output record information to the display */
1703           sprintf(tbufv, "PFGA: EPD record: %ld", (record + 1));
1704           EGPrintTB();
1705           if (((eopptr = EPDLocateEOPCode(epdptr, epdso_id)) != NULL)
1706               && ((eovptr = eopptr->eop_headeov) != NULL)
1707               && ((s = eovptr->eov_str) != NULL)) {
1708             EGPrint(" ID: ");
1709             EGPrint(s);
1710           };
1711           EGPrint("\n");
1712 /* output record information to the log file */
1713           if (log_file != NULL) {
1714             fprintf(log_file, "PFGA: EPD record: %ld", (record + 1));
1715             if (((eopptr = EPDLocateEOPCode(epdptr, epdso_id)) != NULL)
1716                 && ((eovptr = eopptr->eop_headeov) != NULL)
1717                 && ((s = eovptr->eov_str) != NULL))
1718               fprintf(log_file, "   ID: %s", s);
1719             fprintf(log_file, "\n");
1720           };
1721 /* set up the host current position */
1722           EGPutHostPosition();
1723 /* set host search parameters */
1724           tree->status[1] = tree->status[0];
1725           iteration = 0;
1726           ponder = 0;
1727 /* get the starting time */
1728           start_time = time(NULL);
1729 /* run host search; EPD Kit position may be changed */
1730           result = EGIterate(EGMapToHostColor(EPDFetchACTC()), think);
1731 /* refresh the EPD Kit current position */
1732           EGGetHostPosition();
1733 /* extract analysis count: depth */
1734           host_acd = iteration;
1735           if (host_acd == 0)
1736             host_acd = 1;
1737 /* insert analysis count: depth */
1738           EPDAddOpInt(epdptr, epdso_acd, host_acd);
1739 /* extract analysis count: nodes */
1740           host_acn = tree->nodes_searched;
1741           if (host_acn == 0)
1742             host_acn = 1;
1743 /* insert analysis count: nodes */
1744           EPDAddOpInt(epdptr, epdso_acn, host_acn);
1745 /* extract analysis count: seconds */
1746           host_acs = time(NULL) - start_time;
1747           if (host_acs == 0)
1748             host_acs = 1;
1749 /* insert analysis count: seconds */
1750           EPDAddOpInt(epdptr, epdso_acs, host_acs);
1751 /* extract centipawn evaluation */
1752           host_ce = EGMapFromHostScore(result);
1753 /*
1754           host_ce = (EGMapToHostColor(EPDFetchACTC())) ? result : -result;
1755 */
1756 /* insert centipawn evaluation */
1757           EPDAddOpInt(epdptr, epdso_ce, host_ce);
1758 /* delete predicted move */
1759           EPDDropIfLocEOPCode(epdptr, epdso_pm);
1760 /* extract/insert predicted variation */
1761           EPDDropIfLocEOPCode(epdptr, epdso_pv);
1762           eopptr = EPDCreateEOPCode(epdso_pv);
1763           for (index = 1; index < (int) tree->pv[0].pathl; index++) {
1764 /* generate moves for the current position */
1765             EPDGenMoves();
1766 /* fetch the predicted move at this ply */
1767             move = tree->pv[0].path[index];
1768 /* map the host move to EPD style */
1769             m = EGMapFromHostMove(move);
1770 /* set the flag bits in the EPD move */
1771             EPDSetMoveFlags(&m);
1772 /* construct the SAN for the move */
1773             EPDSANEncode(&m, san);
1774 /* create and append the SAN move */
1775             eovptr = EPDCreateEOVSym(san);
1776             EPDAppendEOV(eopptr, eovptr);
1777 /* execute the move to update the EPD position */
1778             EPDExecuteUpdate(&m);
1779           };
1780 /* retract predicted variation moves */
1781           EPDRetractAll();
1782 /* append the pv operation to the EPD structure */
1783           EPDAppendEOP(epdptr, eopptr);
1784 /* encode the EPD into a string, write, and release */
1785           s = EPDEncode(epdptr);
1786           fprintf(fptr1, "%s\n", s);
1787           fflush(fptr1);
1788           EPDMemoryFree(s);
1789         };
1790 /* deallocate the EPD structure */
1791         EPDReleaseEPD(epdptr);
1792       };
1793 /* increment EPD record count */
1794       record++;
1795     };
1796   };
1797 /* ensure file close */
1798   if (fptr0 != NULL)
1799     fclose(fptr0);
1800   if (fptr1 != NULL)
1801     fclose(fptr1);
1802   return flag;
1803 }
1804 
1805 /*--> EGProcessPFLC: process the EG command epdpflc */
EGProcessPFLC(void)1806 static siT EGProcessPFLC(void) {
1807   siT flag;
1808   fptrT fptr;
1809   epdptrT epdptr;
1810   eopptrT eopptr;
1811   eovptrT eovptr;
1812   liT record;
1813   charptrT s;
1814   char ev[epdL];
1815 
1816 /* this is an internal EPD glue routine */
1817 /* set the default return value: success */
1818   flag = 1;
1819 /* parameter count check */
1820   if (EPDTokenCount() != 2) {
1821     EGPL("This command takes one parameter.");
1822     flag = 0;
1823   };
1824 /* clear the file pointer */
1825   fptr = NULL;
1826 /* set up the input file */
1827   if (flag) {
1828     fptr = fopen(EPDTokenFetch(1), "r");
1829     if (fptr == NULL) {
1830       sprintf(tbufv, "Can't open %s for reading\n", EPDTokenFetch(1));
1831       EGPrintTB();
1832       flag = 0;
1833     };
1834   };
1835 /* scan the file */
1836   if (flag) {
1837 /* clear record count */
1838     record = 0;
1839 /* scan each record */
1840     while (flag && (fgets(ev, (epdL - 1), fptr) != NULL)) {
1841 /* decode the record into an EPD structure */
1842       epdptr = EPDDecode(ev);
1843 /* check record decode validity */
1844       if (epdptr == NULL)
1845         flag = 0;
1846       else {
1847 /* did the expectation indicate a forced mate? */
1848         if (((eopptr = EPDLocateEOPCode(epdptr, epdso_ce)) != NULL)
1849             && ((eovptr = eopptr->eop_headeov) != NULL)
1850             && forced_mate(atol(eovptr->eov_str))) {
1851 /* get the analysis result move from the pv */
1852           eopptr = EPDLocateEOPCode(epdptr, epdso_pv);
1853           if ((eopptr != NULL) && ((eovptr = eopptr->eop_headeov) != NULL)) {
1854 /* get a pointer to the result move */
1855             s = eovptr->eov_str;
1856 /* get the best move operation */
1857             eopptr = EPDLocateEOPCode(epdptr, epdso_bm);
1858             if (eopptr != NULL) {
1859 /* check for a matching best move */
1860               eovptr = EPDLocateEOV(eopptr, s);
1861 /* if not found, then it's a cook */
1862               if (eovptr == NULL) {
1863 /* issue report */
1864                 sprintf(tbufv, "PFLC: record %ld:   cook: %s", (record + 1),
1865                     s);
1866                 EGPrintTB();
1867                 eopptr = EPDLocateEOPCode(epdptr, epdso_id);
1868                 if ((eopptr != NULL)
1869                     && ((eovptr = eopptr->eop_headeov) != NULL)) {
1870                   EGPrint("   ID: ");
1871                   EGPrint(eovptr->eov_str);
1872                 };
1873                 EGPrint("\n");
1874               };
1875             };
1876           };
1877         };
1878 /* deallocate the EPD structure */
1879         EPDReleaseEPD(epdptr);
1880       };
1881 /* next record */
1882       record++;
1883     };
1884   };
1885 /* ensure input file closed */
1886   if (fptr != NULL)
1887     fclose(fptr);
1888   return flag;
1889 }
1890 
1891 /*--> EGProcessPFOP: process the EG command epdpfop */
EGProcessPFOP(void)1892 static siT EGProcessPFOP(void) {
1893   siT flag;
1894 
1895 /* this is an internal EPD glue routine */
1896 /* set the default return value: success */
1897   flag = 1;
1898 /* parameter count check */
1899   if (EPDTokenCount() != 4) {
1900     EGPL("This command takes three parameters");
1901     flag = 0;
1902   };
1903 /* process the epdpfop command */
1904   if (flag)
1905     flag =
1906         EPDPurgeOpFile(EPDTokenFetch(1), EPDTokenFetch(2), EPDTokenFetch(3));
1907   return flag;
1908 }
1909 
1910 /*--> EGProcessSCOR: process the EG command epdscor */
EGProcessSCOR(void)1911 static siT EGProcessSCOR(void) {
1912   siT flag;
1913   bmsT bms;
1914 
1915 /* this is an internal EPD glue routine */
1916 /* set the default return value: success */
1917   flag = 1;
1918 /* parameter count check */
1919   if (EPDTokenCount() != 2) {
1920     EGPL("This command takes one parameter.");
1921     flag = 0;
1922   };
1923 /* process the epdscor command */
1924   if (flag) {
1925     flag = EPDScoreFile(EPDTokenFetch(1), &bms);
1926     if (flag) {
1927       sprintf(tbufv, "total: %ld\n", bms.bms_total);
1928       EGPrintTB();
1929       if (bms.bms_total != 0) {
1930         if (bms.bms_acdflag) {
1931           sprintf(tbufv, "total acd: %ld   mean total acd: %.2f\n",
1932               bms.bms_total_acd, ((lrT) bms.bms_total_acd / bms.bms_total));
1933           EGPrintTB();
1934         };
1935         if (bms.bms_acnflag) {
1936           sprintf(tbufv, "total acn: %ld   mean total acn: %.2f\n",
1937               bms.bms_total_acn, ((lrT) bms.bms_total_acn / bms.bms_total));
1938           EGPrintTB();
1939         };
1940         if (bms.bms_acsflag) {
1941           sprintf(tbufv, "total acs: %ld   mean total acs: %.2f\n",
1942               bms.bms_total_acs, ((lrT) bms.bms_total_acs / bms.bms_total));
1943           EGPrintTB();
1944         };
1945         if (bms.bms_acnflag && bms.bms_acsflag)
1946           if (bms.bms_total_acs != 0) {
1947             sprintf(tbufv, "total mean node frequency: %.2f Hz\n",
1948                 ((lrT) bms.bms_total_acn / bms.bms_total_acs));
1949             EGPrintTB();
1950           };
1951         sprintf(tbufv, "solve: %ld   solve percent: %.2f\n", bms.bms_solve,
1952             (((lrT) bms.bms_solve * 100.0) / bms.bms_total));
1953         EGPrintTB();
1954         if (bms.bms_solve != 0) {
1955           if (bms.bms_acdflag) {
1956             sprintf(tbufv, "solve acd: %ld   mean solve acd: %.2f\n",
1957                 bms.bms_solve_acd, ((lrT) bms.bms_solve_acd / bms.bms_solve));
1958             EGPrintTB();
1959           };
1960           if (bms.bms_acnflag) {
1961             sprintf(tbufv, "solve acn: %ld   mean solve acn: %.2f\n",
1962                 bms.bms_solve_acn, ((lrT) bms.bms_solve_acn / bms.bms_solve));
1963             EGPrintTB();
1964           };
1965           if (bms.bms_acsflag) {
1966             sprintf(tbufv, "solve acs: %ld   mean solve acs: %.2f\n",
1967                 bms.bms_solve_acs, ((lrT) bms.bms_solve_acs / bms.bms_solve));
1968             EGPrintTB();
1969           };
1970           if (bms.bms_acnflag && bms.bms_acsflag)
1971             if (bms.bms_solve_acs != 0) {
1972               sprintf(tbufv, "solve mean node frequency: %.2f Hz\n",
1973                   ((lrT) bms.bms_solve_acn / bms.bms_solve_acs));
1974               EGPrintTB();
1975             };
1976         };
1977         sprintf(tbufv, "unsol: %ld   unsol percent: %.2f\n", bms.bms_unsol,
1978             (((lrT) bms.bms_unsol * 100.0) / bms.bms_total));
1979         EGPrintTB();
1980         if (bms.bms_unsol != 0) {
1981           if (bms.bms_acdflag) {
1982             sprintf(tbufv, "unsol acd: %ld   mean unsol acd: %.2f\n",
1983                 bms.bms_unsol_acd, ((lrT) bms.bms_unsol_acd / bms.bms_unsol));
1984             EGPrintTB();
1985           };
1986           if (bms.bms_acnflag) {
1987             sprintf(tbufv, "unsol acn: %ld   mean unsol acn: %.2f\n",
1988                 bms.bms_unsol_acn, ((lrT) bms.bms_unsol_acn / bms.bms_unsol));
1989             EGPrintTB();
1990           };
1991           if (bms.bms_acsflag) {
1992             sprintf(tbufv, "unsol acs: %ld   mean unsol acs: %.2f\n",
1993                 bms.bms_unsol_acs, ((lrT) bms.bms_unsol_acs / bms.bms_unsol));
1994             EGPrintTB();
1995           };
1996           if (bms.bms_acnflag && bms.bms_acsflag)
1997             if (bms.bms_unsol_acs != 0) {
1998               sprintf(tbufv, "unsol mean node frequency: %.2f Hz\n",
1999                   ((lrT) bms.bms_unsol_acn / bms.bms_unsol_acs));
2000               EGPrintTB();
2001             };
2002         };
2003       };
2004     };
2005   };
2006   return flag;
2007 }
2008 
2009 /*--> EGProcessSHOW: process the EG command epdshow */
EGProcessSHOW(void)2010 static siT EGProcessSHOW(void) {
2011   siT flag;
2012   charptrT s;
2013 
2014 /* this is an internal EPD glue routine */
2015 /* set the default return value: success */
2016   flag = 1;
2017 /* parameter count check */
2018   if (EPDTokenCount() != 1) {
2019     EGPL("This command takes no parameters.");
2020     flag = 0;
2021   };
2022 /* process the epdshow command */
2023   if (flag) {
2024 /* load the host pointion into the EPD Kit */
2025     EGGetHostPosition();
2026 /* get the EPD string for the current position */
2027     s = EPDGenBasicCurrent();
2028 /* print and release */
2029     sprintf(tbufv, "%s\n", s);
2030     EGPrintTB();
2031     EPDMemoryFree(s);
2032   };
2033   return flag;
2034 }
2035 
2036 /*--> EGProcessSPGN: process the EG command epdspgn */
EGProcessSPGN(void)2037 static siT EGProcessSPGN(void) {
2038   siT flag;
2039   charptrT s;
2040   fptrT fptr;
2041 
2042 /* this is an internal EPD glue routine */
2043 /* set the default return value: success */
2044   flag = 1;
2045 /* parameter count check */
2046   if (EPDTokenCount() != 2) {
2047     EGPL("This command takes one parameter.");
2048     flag = 0;
2049   };
2050 /* process the epdspgn command */
2051   if (flag) {
2052     s = EGEncodeHostHistory();
2053     if (s == NULL)
2054       flag = 0;
2055     else {
2056       fptr = fopen(EPDTokenFetch(1), "w");
2057       if (fptr == NULL)
2058         flag = 0;
2059       else {
2060         fprintf(fptr, "%s", s);
2061         fclose(fptr);
2062       };
2063       EPDMemoryFree(s);
2064     };
2065   };
2066   return flag;
2067 }
2068 
2069 /*--> EGProcessSTPV: process the EG command epdstpv */
EGProcessSTPV(void)2070 static siT EGProcessSTPV(void) {
2071   siT flag;
2072   pgnstrT pgnstr;
2073   charptrT s;
2074   liT i, length;
2075 
2076 /* this is an internal EPD glue routine */
2077 /* set the default return value: success */
2078   flag = 1;
2079 /* parameter count check */
2080   if (EPDTokenCount() != 3) {
2081     EGPL("This command takes two parameters");
2082     flag = 0;
2083   };
2084 /* process the epdstpv command */
2085   if (flag) {
2086     pgnstr = EPDPGNFetchTagIndex(EPDTokenFetch(1));
2087     if (pgnstr == pgnstr_nil) {
2088       EGPL("Unknown tag name; available tag names are:");
2089       for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++) {
2090         EGPrint("   ");
2091         EGPrint(EPDPGNFetchTagName(pgnstr));
2092       };
2093       EGPrint("\n");
2094       flag = 0;
2095     } else {
2096 /* change underscore characters to blanks */
2097       s = EPDStringGrab(EPDTokenFetch(2));
2098       length = strlen(s);
2099       for (i = 0; i < length; i++)
2100         if (*(s + i) == '_')
2101           *(s + i) = ' ';
2102       EPDPGNPutSTR(default_gamptr, pgnstr, s);
2103       EPDMemoryFree(s);
2104     };
2105   };
2106   return flag;
2107 }
2108 
2109 /*--> EGProcessTEST: process the EG command epdtest */
EGProcessTEST(void)2110 static siT EGProcessTEST(void) {
2111   siT flag;
2112 
2113 /* this is an internal EPD glue routine */
2114 /* set the default return value: success */
2115   flag = 1;
2116 /* parameter count check */
2117   if (EPDTokenCount() != 1) {
2118     EGPL("This command takes no parameters.");
2119     flag = 0;
2120   };
2121 /* process the epdtest command */
2122   if (flag) {
2123     EGPL("This command is not yet implemented.");
2124     flag = 0;
2125   };
2126   return flag;
2127 }
2128 
2129 /*--> EGCommandCheck: check if a string starts with an EPD command token */
EGCommandCheck(char * s)2130 nonstatic int EGCommandCheck(char *s) {
2131   siT flag;
2132   charptrT tokenptr;
2133   egcommT egcomm;
2134 
2135 /* this routine is called from Option() in option.c */
2136 /*
2137  This routine is used to quickly check if an input command line starts with
2138  one of the available EPD glue command tokens.  The idea is that EPD action
2139  can be quickly selected (or deselected) for any command input text string.
2140  Because Crafty distributes command input one token at a time, the calls to
2141  this routine in this implementation will only have a single token for input.
2142  Other implementations that use an entire input command line will use the
2143  full power of this routine which includes token scanning and recording
2144  which is handled by the EPD Kit routines in the epd.c file.
2145  */
2146 /* set default return value: no match */
2147   flag = 0;
2148 /* tokenize the input string */
2149   EPDTokenize(s);
2150 /* was there at least one token? */
2151   if (EPDTokenCount() > 0) {
2152 /* get a pointer to the first token (origin zero) */
2153     tokenptr = EPDTokenFetch(0);
2154 /* get the glue command indicator */
2155     egcomm = EGLocateCommand(tokenptr);
2156 /* was there a command match? */
2157     if (egcomm != egcomm_nil)
2158       flag = 1;
2159   };
2160   return flag;
2161 }
2162 
2163 /*--> EGCommand: process an EPD command string */
EGCommand(char * s)2164 nonstatic int EGCommand(char *s) {
2165   siT flag;
2166   egcommT egcomm;
2167 
2168 /* this routine is called from Option() in option.c */
2169 /*
2170  This routine actviates EPD glue command processing.  it is called with a
2171  string that represents an entire EPD glue command input, including any
2172  parameters following the command.
2173  Because Crafty distributes command input one token at a time, it is
2174  necessary for the host calling code to assemble a command line from the
2175  input token stream.  See the code in Option() for details.
2176  */
2177 /* set the default return value: success */
2178   flag = 1;
2179 /* check the command string (this also tokenizes it) */
2180   if (EGCommandCheck(s))
2181     egcomm = EGLocateCommand(EPDTokenFetch(0));
2182   else
2183     egcomm = egcomm_nil;
2184 /* was a valid EPD glue command located? */
2185   if (egcomm == egcomm_nil) {
2186     EGPL("EG fault: can't locate valid EG command");
2187     flag = 0;
2188   } else {
2189 /* a valid command token was found; perform command dispatch */
2190     switch (egcomm) {
2191       case egcomm_epdapgn:
2192         flag = EGProcessAPGN();
2193         break;
2194       case egcomm_epdbfix:
2195         flag = EGProcessBFIX();
2196         break;
2197       case egcomm_epdcics:
2198         flag = EGProcessCICS();
2199         break;
2200       case egcomm_epdcomm:
2201         flag = EGProcessCOMM();
2202         break;
2203       case egcomm_epddpgn:
2204         flag = EGProcessDPGN();
2205         break;
2206       case egcomm_epddsml:
2207         flag = EGProcessDSML();
2208         break;
2209       case egcomm_epddstr:
2210         flag = EGProcessDSTR();
2211         break;
2212       case egcomm_epddtpv:
2213         flag = EGProcessDTPV();
2214         break;
2215       case egcomm_epdenum:
2216         flag = EGProcessENUM();
2217         break;
2218       case egcomm_epdhelp:
2219         flag = EGProcessHELP();
2220         break;
2221       case egcomm_epdlink:
2222         flag = EGProcessLINK();
2223         break;
2224       case egcomm_epdlpgn:
2225         flag = EGProcessLPGN();
2226         break;
2227       case egcomm_epdlrec:
2228         flag = EGProcessLREC();
2229         break;
2230       case egcomm_epdmore:
2231         flag = EGProcessMORE();
2232         break;
2233       case egcomm_epdnoop:
2234         flag = EGProcessNOOP();
2235         break;
2236       case egcomm_epdpfdn:
2237         flag = EGProcessPFDN();
2238         break;
2239       case egcomm_epdpfdr:
2240         flag = EGProcessPFDR();
2241         break;
2242       case egcomm_epdpfga:
2243         flag = EGProcessPFGA();
2244         break;
2245       case egcomm_epdpflc:
2246         flag = EGProcessPFLC();
2247         break;
2248       case egcomm_epdpfop:
2249         flag = EGProcessPFOP();
2250         break;
2251       case egcomm_epdscor:
2252         flag = EGProcessSCOR();
2253         break;
2254       case egcomm_epdshow:
2255         flag = EGProcessSHOW();
2256         break;
2257       case egcomm_epdspgn:
2258         flag = EGProcessSPGN();
2259         break;
2260       case egcomm_epdstpv:
2261         flag = EGProcessSTPV();
2262         break;
2263       case egcomm_epdtest:
2264         flag = EGProcessTEST();
2265         break;
2266     };
2267 /* check result */
2268     if (!flag) {
2269       sprintf(tbufv, "EG fault: a problem occurred during %s processing\n",
2270           EPDTokenFetch(0));
2271       EGPrintTB();
2272     };
2273   };
2274   return flag;
2275 }
2276 
2277 /*--> EGInit: one time EPD glue initialization */
EGInit(void)2278 nonstatic void EGInit(void) {
2279 /* this is called by Initialize() in init.c */
2280   EGPL("EPD Kit revision date: 1996.04.21");
2281 /* call the EPD one time set up code */
2282   EPDInit();
2283 /* initialize the EPD glue command strings vector */
2284   egcommstrv[egcomm_epdapgn] = "epdapgn";
2285   egcommstrv[egcomm_epdbfix] = "epdbfix";
2286   egcommstrv[egcomm_epdcert] = "epdcert";
2287   egcommstrv[egcomm_epdcics] = "epdcics";
2288   egcommstrv[egcomm_epdcomm] = "epdcomm";
2289   egcommstrv[egcomm_epddpgn] = "epddpgn";
2290   egcommstrv[egcomm_epddsml] = "epddsml";
2291   egcommstrv[egcomm_epddstr] = "epddstr";
2292   egcommstrv[egcomm_epddtpv] = "epddtpv";
2293   egcommstrv[egcomm_epdenum] = "epdenum";
2294   egcommstrv[egcomm_epdhelp] = "epdhelp";
2295   egcommstrv[egcomm_epdlink] = "epdlink";
2296   egcommstrv[egcomm_epdlpgn] = "epdlpgn";
2297   egcommstrv[egcomm_epdlrec] = "epdlrec";
2298   egcommstrv[egcomm_epdmore] = "epdmore";
2299   egcommstrv[egcomm_epdnoop] = "epdnoop";
2300   egcommstrv[egcomm_epdpfdn] = "epdpfdn";
2301   egcommstrv[egcomm_epdpfdr] = "epdpfdr";
2302   egcommstrv[egcomm_epdpfga] = "epdpfga";
2303   egcommstrv[egcomm_epdpflc] = "epdpflc";
2304   egcommstrv[egcomm_epdpfop] = "epdpfop";
2305   egcommstrv[egcomm_epdscor] = "epdscor";
2306   egcommstrv[egcomm_epdshow] = "epdshow";
2307   egcommstrv[egcomm_epdspgn] = "epdspgn";
2308   egcommstrv[egcomm_epdstpv] = "epdstpv";
2309   egcommstrv[egcomm_epdtest] = "epdtest";
2310 /* initialize the EPD glue command string descriptions vector */
2311   eghelpstrv[egcomm_epdapgn] = "Append PGN game to <file>";
2312   eghelpstrv[egcomm_epdbfix] = "Fix <file1> data for Bookup input <file2>";
2313   eghelpstrv[egcomm_epdcert] =
2314       "Display certain score for the current position";
2315   eghelpstrv[egcomm_epdcics] = "Slave to ICS at <hostname> and <portnumber>";
2316   eghelpstrv[egcomm_epdcomm] = "Slave to Duplex using <pipefile-basename>";
2317   eghelpstrv[egcomm_epddpgn] = "Display game using PGN";
2318   eghelpstrv[egcomm_epddsml] = "Display SAN move list";
2319   eghelpstrv[egcomm_epddstr] = "Display PGN Seven Tag Roster";
2320   eghelpstrv[egcomm_epddtpv] = "Display PGN tag pair <tag-name> value";
2321   eghelpstrv[egcomm_epdenum] = "Enumerate to <depth> from <file1> to <file2>";
2322   eghelpstrv[egcomm_epdhelp] = "Display EPD glue command descriptions";
2323   eghelpstrv[egcomm_epdlink] =
2324       "Slave to Argus at <hostname> and <portnumber>";
2325   eghelpstrv[egcomm_epdlpgn] = "Load PGN game from <file>";
2326   eghelpstrv[egcomm_epdlrec] = "Load EPD record from <file> <line-number>";
2327   eghelpstrv[egcomm_epdmore] = "Display more help for <command>";
2328   eghelpstrv[egcomm_epdnoop] = "No operation";
2329   eghelpstrv[egcomm_epdpfdn] = "Normalize EPD data from <file1> to <file2>";
2330   eghelpstrv[egcomm_epdpfdr] = "Repair EPD data from <file1> to <file2>";
2331   eghelpstrv[egcomm_epdpfga] = "Analyze EPD data from <file1> to <file2>";
2332   eghelpstrv[egcomm_epdpflc] = "Locate mating cooks in result <file>";
2333   eghelpstrv[egcomm_epdpfop] = "Purge EPD <opcode> from <file1> to <file2>";
2334   eghelpstrv[egcomm_epdscor] = "Score benchmark EPD results from <file>";
2335   eghelpstrv[egcomm_epdshow] =
2336       "Show EPD four fields for the current position";
2337   eghelpstrv[egcomm_epdspgn] = "Save PGN game to <file>";
2338   eghelpstrv[egcomm_epdstpv] = "Set PGN tag pair <tag-name> to <value>";
2339   eghelpstrv[egcomm_epdtest] = "EPD glue developer testing";
2340 /* initialize the EPD glue command parameter counts vector */
2341 /* set up the default game structure */
2342   default_gamptr = EPDGameOpen();
2343   return;
2344 }
2345 
2346 /*--> EGTerm: one time EPD glue termination */
EGTerm(void)2347 nonstatic void EGTerm(void) {
2348 /* this is called by Option() in option.c */
2349 /* release the default game structure */
2350   if (default_gamptr != NULL)
2351     EPDGameClose(default_gamptr);
2352 /* call the EPD one time close down code */
2353   EPDTerm();
2354   return;
2355 }
2356 #endif
2357 /*<<< epdglue.c: EOF */
2358