1 /*>>> epd.c: Extended Position Description routines */
2 #if defined(EPD)
3 /* Revised: 1996.06.23 */
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  Everything in this source file is independent of the host program, as
11  are the prototypes in the epd.h include file.  Requests for changes
12  and additions should be communicated to the author via the e-mail
13  address given above.
14  */
15 /*
16  This file was originally prepared on an Apple Macintosh using the
17  Metrowerks CodeWarrior 6 ANSI C compiler.  Tabs are set at every
18  four columns.  Further testing and development was performed on a
19  generic PC running Linux 1.3.20 and using the gcc 2.7.0 compiler.
20  */
21 /* system includes */
22 #  include <ctype.h>
23 #  include <time.h>
24 #  include "chess.h"
25 #  include "data.h"
26 /* EPD definitions (host independent) */
27 #  include "epddefs.h"
28 /* EPD routine prototypes (host independent) */
29 #  include "epd.h"
30 /* ASCII character constants */
31 #  define ascii_nul ((char) 0x00)
32 #  define ascii_sp  ((char) 0x20)
33 /* tree limit; adjust according to memory availability */
34 #  define treeL 16384
35 /* tree overrun safety margin */
36 #  define treemarginL 256
37 /* played moves history limit; adjust according to memory availability */
38 #  define pmhL 512
39 /* data flows (input and output) */
40 #  define flowL 2
41 /* character case mapping */
42 #  define map_lower(ch) (isupper((ch)) ? tolower((ch)) : (ch))
43 #  define map_upper(ch) (islower((ch)) ? toupper((ch)) : (ch))
44 /* identifier character check */
45 #  define IdentChar(ch) (isalpha((ch)) || isdigit((ch)) || ((ch) == '_'))
46 /* vacancy check */
47 #  define Vacant(sq) (EPDboard.rbv[(sq)] == cp_v0)
48 /* token record type (for token chain) */
49 typedef struct tknS {
50   charptrT tkn_str;             /* allocated token string value */
51   struct tknS *tkn_prev;        /* previous record */
52   struct tknS *tkn_next;        /* next record */
53 } tknT, *tknptrT;
54 
55 /* tree stack entry record type */
56 typedef struct tseS {
57   siT tse_count;                /* entry count for this level */
58   mptrT tse_base;               /* first move in moveset */
59   mptrT tse_curr;               /* current move of interest in moveset */
60 } tseT, *tseptrT;
61 
62 /* color to move strings */
63 /* global game chain anchors */
64 static gamptrT head_gamptr;
65 static gamptrT tail_gamptr;
66 
67 /* EPD standard opcode mnemonics */
68 static charptrT epdsostrv[epdsoL];
69 
70 /* EPD refcom operand strings */
71 static charptrT refcomstrv[refcomL];
72 
73 /* EPD refreq operand strings */
74 static charptrT refreqstrv[refreqL];
75 
76 /* PGN Seven Tag Roster names */
77 static charptrT pgnstrstrv[pgnstrL];
78 
79 /* game termination indication marker strings */
80 static charptrT gtimstrv[gtimL];
81 
82 /* player name strings */
83 /* character conversion vectors (colors and pieces) */
84 static char asccv[rcL];
85 static char ascpv[rpL];
86 
87 /* character conversion vectors (ranks and files) */
88 static char ascrv[rankL];
89 static char ascfv[fileL];
90 
91 /* promotion piece from special case move code coversion vector */
92 static pT cv_p_scmvv[scmvL];
93 
94 /* various color and piece conversion vectors */
95 static cpT cv_cp_c_pv[rcL][rpL];
96 static cT cv_c_cpv[cpL];
97 static pT cv_p_cpv[cpL];
98 static cT inv_cv[rcL];
99 
100 /* direction vectors */
101 static dvT dvv[dxL];
102 static xdvT xdvv[dxL];
103 
104 /* extension board (border detection) */
105 static xbT xb;
106 
107 /* token chain anchors */
108 static tknptrT head_tknptr;
109 static tknptrT tail_tknptr;
110 
111 /* local SAN vector and its index */
112 static sanT lsan;
113 static siT lsani;
114 
115 /* census vectors */
116 static siT count_cv[rcL];
117 static siT count_cpv[rcL][rpL];
118 
119 /* the current board */
120 static rbT EPDboard;
121 
122 /* the current environment stack entry */
123 static eseT ese;
124 
125 /* the current tree stack entry */
126 static tseT tse;
127 
128 /* the master ply index */
129 static siT ply;
130 
131 /* the base of the move tree and its current pointer */
132 static mptrT treebaseptr;
133 static mptrT treeptr;
134 
135 /* the base of the tree stack entry stack and its current pointer */
136 static tseptrT tsebaseptr;
137 static tseptrT tseptr;
138 
139 /* base of the environment stack and its current pointer */
140 static eseptrT esebaseptr;
141 static eseptrT eseptr;
142 
143 /* return area for board data */
144 static rbT ret_rb;
145 
146 /* return area for move data */
147 static mT ret_m;
148 
149 /*--> EPDFatal: emit fatal diagnostic and quit */
EPDFatal(charptrT s)150 nonstatic void EPDFatal(charptrT s) {
151   fprintf(stderr, "EPD Fatal error: %s.\n", s);
152   exit(1);
153 }
154 
155 /*--> EPDSwitchFault: emit switch fault diagnostic and quit */
EPDSwitchFault(charptrT s)156 nonstatic void EPDSwitchFault(charptrT s) {
157   fprintf(stderr, "Switch fault detected.\n");
158   EPDFatal(s);
159   return;
160 }
161 
162 /*--> EPDMemoryGrab: allocate memory */
EPDMemoryGrab(liT n)163 nonstatic voidptrT EPDMemoryGrab(liT n) {
164   voidptrT ptr;
165 
166   ptr = (voidptrT) malloc((n == 0) ? 1 : n);
167   if (ptr == NULL)
168     EPDFatal("EPDMemoryGrab");
169   return ptr;
170 }
171 
172 /*--> EPDMemoryFree: deallocate memory */
EPDMemoryFree(voidptrT ptr)173 nonstatic void EPDMemoryFree(voidptrT ptr) {
174   if (ptr != NULL)
175     free(ptr);
176   return;
177 }
178 
179 /*--> EPDStringGrab: allocate and copy a string */
EPDStringGrab(charptrT s)180 nonstatic charptrT EPDStringGrab(charptrT s) {
181   charptrT ptr;
182 
183   ptr = (charptrT) EPDMemoryGrab(strlen(s) + 1);
184   strcpy(ptr, s);
185   return ptr;
186 }
187 
188 /*--> EPDStringAppendChar: append a character to a string */
EPDStringAppendChar(charptrT s,char c)189 nonstatic charptrT EPDStringAppendChar(charptrT s, char c) {
190   charptrT ptr;
191   liT length;
192 
193 /* the first argument is deallocated */
194   length = strlen(s);
195   ptr = (charptrT) EPDMemoryGrab(length + 2);
196   strcpy(ptr, s);
197   EPDMemoryFree(s);
198   *(ptr + length) = c;
199   *(ptr + length + 1) = ascii_nul;
200   return ptr;
201 }
202 
203 /*--> EPDStringAppendStr: append a string to a string */
EPDStringAppendStr(charptrT s0,charptrT s1)204 nonstatic charptrT EPDStringAppendStr(charptrT s0, charptrT s1) {
205   charptrT ptr;
206   liT length;
207 
208 /* the first argument is deallocated */
209   length = strlen(s0) + strlen(s1);
210   ptr = (charptrT) EPDMemoryGrab(length + 1);
211   strcpy(ptr, s0);
212   strcat(ptr, s1);
213   EPDMemoryFree(s0);
214   return ptr;
215 }
216 
217 /*--> EPDNewGPM: allocate and initialize a new GPM record */
EPDNewGPM(mptrT mptr)218 static gpmptrT EPDNewGPM(mptrT mptr) {
219   gpmptrT gpmptr;
220   cT c;
221   sqT sq;
222   cpT cp0, cp1;
223 
224   gpmptr = (gpmptrT) EPDMemoryGrab(sizeof(gpmT));
225   gpmptr->gpm_m = *mptr;
226   gpmptr->gpm_ese.ese_actc = ese.ese_actc;
227   gpmptr->gpm_ese.ese_cast = ese.ese_cast;
228   gpmptr->gpm_ese.ese_epsq = ese.ese_epsq;
229   gpmptr->gpm_ese.ese_hmvc = ese.ese_hmvc;
230   gpmptr->gpm_ese.ese_fmvn = ese.ese_fmvn;
231   for (c = c_w; c <= c_b; c++)
232     gpmptr->gpm_ese.ese_ksqv[c] = ese.ese_ksqv[c];
233   for (sq = sq_a1; sq <= sq_h8; sq += 2) {
234     cp0 = EPDboard.rbv[sq + 0];
235     cp1 = EPDboard.rbv[sq + 1];
236     gpmptr->gpm_nbv[sq >> 1] = ((cp1 << nybbW) | cp0);
237   };
238   gpmptr->gpm_prev = gpmptr->gpm_next = NULL;
239   return gpmptr;
240 }
241 
242 /*--> EPDReleaseGPM: release a GPM record */
243 static
EPDReleaseGPM(gpmptrT gpmptr)244 void EPDReleaseGPM(gpmptrT gpmptr) {
245   if (gpmptr != NULL)
246     EPDMemoryFree(gpmptr);
247   return;
248 }
249 
250 /*--> EPDAppendGPM: append a GPM record to a game  */
251 static
EPDAppendGPM(gamptrT gamptr,gpmptrT gpmptr)252 void EPDAppendGPM(gamptrT gamptr, gpmptrT gpmptr) {
253   if (gamptr->gam_tailgpm == NULL)
254     gamptr->gam_headgpm = gpmptr;
255   else
256     gamptr->gam_tailgpm->gpm_next = gpmptr;
257   gpmptr->gpm_prev = gamptr->gam_tailgpm;
258   gpmptr->gpm_next = NULL;
259   gamptr->gam_tailgpm = gpmptr;
260   return;
261 }
262 
263 /*--> EPDUnthreadGPM: unthread a GPM record from a game */
264 static
EPDUnthreadGPM(gamptrT gamptr,gpmptrT gpmptr)265 void EPDUnthreadGPM(gamptrT gamptr, gpmptrT gpmptr) {
266   if (gpmptr->gpm_prev == NULL)
267     gamptr->gam_headgpm = gpmptr->gpm_next;
268   else
269     gpmptr->gpm_prev->gpm_next = gpmptr->gpm_next;
270   if (gpmptr->gpm_next == NULL)
271     gamptr->gam_tailgpm = gpmptr->gpm_prev;
272   else
273     gpmptr->gpm_next->gpm_prev = gpmptr->gpm_prev;
274   return;
275 }
276 
277 /*--> EPDReleaseGPMoveChain: release the game played moves chain */
278 static
EPDReleaseGPMoveChain(gamptrT gamptr)279 void EPDReleaseGPMoveChain(gamptrT gamptr) {
280   gpmptrT gpmptr;
281 
282   while (gamptr->gam_headgpm != NULL) {
283     gpmptr = gamptr->gam_tailgpm;
284     EPDUnthreadGPM(gamptr, gpmptr);
285     EPDReleaseGPM(gpmptr);
286   };
287   return;
288 }
289 
290 /*--> EPDNewGAM: allocate and initialize a new GAM record */
EPDNewGAM(void)291 static gamptrT EPDNewGAM(void) {
292   gamptrT gamptr;
293   pgnstrT pgnstr;
294 
295   gamptr = (gamptrT) EPDMemoryGrab(sizeof(gamT));
296   for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++)
297     gamptr->gam_strv[pgnstr] = EPDStringGrab("");
298   gamptr->gam_gtim = gtim_u;
299   gamptr->gam_headgpm = gamptr->gam_tailgpm = NULL;
300   gamptr->gam_prev = gamptr->gam_next = NULL;
301   return gamptr;
302 }
303 
304 /*--> EPDReleaseGAM: release a GAM record */
305 static
EPDReleaseGAM(gamptrT gamptr)306 void EPDReleaseGAM(gamptrT gamptr) {
307   pgnstrT pgnstr;
308 
309   if (gamptr != NULL) {
310     for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++)
311       if (gamptr->gam_strv[pgnstr] != NULL)
312         EPDMemoryFree(gamptr->gam_strv[pgnstr]);
313     EPDReleaseGPMoveChain(gamptr);
314     EPDMemoryFree(gamptr);
315   };
316   return;
317 }
318 
319 /*--> EPDAppendGAM: append a GAM record to the game chain */
320 static
EPDAppendGAM(gamptrT gamptr)321 void EPDAppendGAM(gamptrT gamptr) {
322   if (tail_gamptr == NULL)
323     head_gamptr = gamptr;
324   else
325     tail_gamptr->gam_next = gamptr;
326   gamptr->gam_prev = tail_gamptr;
327   gamptr->gam_next = NULL;
328   tail_gamptr = gamptr;
329   return;
330 }
331 
332 /*--> EPDUnthreadGAM: unthread a GAM record from the game chain */
333 static
EPDUnthreadGAM(gamptrT gamptr)334 void EPDUnthreadGAM(gamptrT gamptr) {
335   if (gamptr->gam_prev == NULL)
336     head_gamptr = gamptr->gam_next;
337   else
338     gamptr->gam_prev->gam_next = gamptr->gam_next;
339   if (gamptr->gam_next == NULL)
340     tail_gamptr = gamptr->gam_prev;
341   else
342     gamptr->gam_next->gam_prev = gamptr->gam_prev;
343   return;
344 }
345 
346 /*--> EPDReleaseGameChain: release the game chain */
347 static
EPDReleaseGameChain(void)348 void EPDReleaseGameChain(void) {
349   gamptrT gamptr;
350 
351   while (head_gamptr != NULL) {
352     gamptr = tail_gamptr;
353     EPDUnthreadGAM(gamptr);
354     EPDReleaseGAM(gamptr);
355   };
356   return;
357 }
358 
359 /*--> EPDGamePlyCount: return ply count of a game */
EPDGamePlyCount(gamptrT gamptr)360 static siT EPDGamePlyCount(gamptrT gamptr) {
361   siT count;
362   gpmptrT gpmptr;
363 
364   count = 0;
365   gpmptr = gamptr->gam_headgpm;
366   while (gpmptr != NULL) {
367     count++;
368     gpmptr = gpmptr->gpm_next;
369   };
370   return count;
371 }
372 
373 /*--> EPDGameOpen: create/open a new game structure */
EPDGameOpen(void)374 nonstatic gamptrT EPDGameOpen(void) {
375   gamptrT gamptr;
376 
377   gamptr = EPDNewGAM();
378   EPDAppendGAM(gamptr);
379   return gamptr;
380 }
381 
382 /*--> EPDGameClose: close/destroy a game structure */
EPDGameClose(gamptrT gamptr)383 nonstatic void EPDGameClose(gamptrT gamptr) {
384   if (gamptr != NULL) {
385     EPDUnthreadGAM(gamptr);
386     EPDReleaseGAM(gamptr);
387   };
388   return;
389 }
390 
391 /*--> EPDGameAppendMove: append a move to a game structure */
EPDGameAppendMove(gamptrT gamptr,mptrT mptr)392 nonstatic void EPDGameAppendMove(gamptrT gamptr, mptrT mptr) {
393   gpmptrT gpmptr;
394 
395   gpmptr = EPDNewGPM(mptr);
396   EPDAppendGPM(gamptr, gpmptr);
397   return;
398 }
399 
400 /*--> EPDNewTKN: allocate and initialize a new TKN record */
EPDNewTKN(charptrT s)401 static tknptrT EPDNewTKN(charptrT s) {
402   tknptrT tknptr;
403 
404   tknptr = (tknptrT) EPDMemoryGrab(sizeof(tknT));
405   tknptr->tkn_str = EPDStringGrab(s);
406   tknptr->tkn_prev = tknptr->tkn_next = NULL;
407   return tknptr;
408 }
409 
410 /*--> EPDReleaseTKN: release a TKN record */
411 static
EPDReleaseTKN(tknptrT tknptr)412 void EPDReleaseTKN(tknptrT tknptr) {
413   if (tknptr != NULL) {
414     if (tknptr->tkn_str != NULL)
415       EPDMemoryFree(tknptr->tkn_str);
416     EPDMemoryFree(tknptr);
417   };
418   return;
419 }
420 
421 /*--> EPDAppendTKN: append a TKN record to the token chain */
422 static
EPDAppendTKN(tknptrT tknptr)423 void EPDAppendTKN(tknptrT tknptr) {
424   if (tail_tknptr == NULL)
425     head_tknptr = tknptr;
426   else
427     tail_tknptr->tkn_next = tknptr;
428   tknptr->tkn_prev = tail_tknptr;
429   tknptr->tkn_next = NULL;
430   tail_tknptr = tknptr;
431   return;
432 }
433 
434 /*--> EPDUnthreadTKN: unthread a TKN record from the token chain */
435 static
EPDUnthreadTKN(tknptrT tknptr)436 void EPDUnthreadTKN(tknptrT tknptr) {
437   if (tknptr->tkn_prev == NULL)
438     head_tknptr = tknptr->tkn_next;
439   else
440     tknptr->tkn_prev->tkn_next = tknptr->tkn_next;
441   if (tknptr->tkn_next == NULL)
442     tail_tknptr = tknptr->tkn_prev;
443   else
444     tknptr->tkn_next->tkn_prev = tknptr->tkn_prev;
445   return;
446 }
447 
448 /*--> EPDReleaseTokenChain: release the token chain */
449 static
EPDReleaseTokenChain(void)450 void EPDReleaseTokenChain(void) {
451   tknptrT tknptr;
452 
453   while (head_tknptr != NULL) {
454     tknptr = tail_tknptr;
455     EPDUnthreadTKN(tknptr);
456     EPDReleaseTKN(tknptr);
457   };
458   return;
459 }
460 
461 /*--> EPDTokenize: create the token chain */
EPDTokenize(charptrT s)462 nonstatic void EPDTokenize(charptrT s) {
463   siT i;
464   char c;
465   tknptrT tknptr;
466   charptrT str;
467 
468 /* first, release any existing chain */
469   EPDReleaseTokenChain();
470 /* scan the input until end of string */
471   i = 0;
472   c = *(s + i++);
473   while (c != ascii_nul) {
474 /* skip leading whitespace */
475     while ((c != ascii_nul) && isspace(c))
476       c = *(s + i++);
477 /* if not at end of string, then a token has started */
478     if (c != ascii_nul) {
479       str = EPDStringGrab("");
480       while ((c != ascii_nul) && !isspace(c)) {
481         str = EPDStringAppendChar(str, c);
482         c = *(s + i++);
483       };
484       tknptr = EPDNewTKN(str);
485       EPDAppendTKN(tknptr);
486       EPDMemoryFree(str);
487     };
488   };
489   return;
490 }
491 
492 /*--> EPDTokenCount: count the tokens in the token chain */
EPDTokenCount(void)493 nonstatic siT EPDTokenCount(void) {
494   siT n;
495   tknptrT tknptr;
496 
497   n = 0;
498   tknptr = head_tknptr;
499   while (tknptr != NULL) {
500     n++;
501     tknptr = tknptr->tkn_next;
502   };
503   return n;
504 }
505 
506 /*--> EPDTokenFetch: fetch n-th (zero origin) token from the token chain */
EPDTokenFetch(siT n)507 nonstatic charptrT EPDTokenFetch(siT n) {
508   charptrT s;
509   siT i;
510   tknptrT tknptr;
511 
512   i = 0;
513   tknptr = head_tknptr;
514   while ((tknptr != NULL) && (i < n)) {
515     i++;
516     tknptr = tknptr->tkn_next;
517   };
518   if (tknptr == NULL)
519     s = NULL;
520   else
521     s = tknptr->tkn_str;
522   return s;
523 }
524 
525 /*--> EPDCICharEqual: test for case independent character equality */
EPDCICharEqual(char ch0,char ch1)526 nonstatic siT EPDCICharEqual(char ch0, char ch1) {
527   siT flag;
528 
529   if (map_lower(ch0) == map_lower(ch1))
530     flag = 1;
531   else
532     flag = 0;
533   return flag;
534 }
535 
536 /*--> EPDPieceFromCP: fetch piece from color-piece */
EPDPieceFromCP(cpT cp)537 nonstatic pT EPDPieceFromCP(cpT cp) {
538   pT p;
539 
540   p = cv_p_cpv[cp];
541   return p;
542 }
543 
544 /*--> EPDCheckPiece: test if a character is a piece letter */
EPDCheckPiece(char ch)545 nonstatic siT EPDCheckPiece(char ch) {
546   siT flag;
547   pT p;
548 
549   flag = 0;
550   p = p_p;
551   while (!flag && (p <= p_k))
552     if (EPDCICharEqual(ch, ascpv[p]))
553       flag = 1;
554     else
555       p++;
556   return flag;
557 }
558 
559 /*--> EPDEvaluatePiece: evaluate a piece letter character */
EPDEvaluatePiece(char ch)560 nonstatic pT EPDEvaluatePiece(char ch) {
561   pT p;
562   siT flag;
563 
564   flag = 0;
565   p = p_p;
566   while (!flag && (p <= p_k))
567     if (EPDCICharEqual(ch, ascpv[p]))
568       flag = 1;
569     else
570       p++;
571   if (!flag)
572     p = p_nil;
573   return p;
574 }
575 
576 /*--> EPDCheckColor: test if a character is a color letter */
EPDCheckColor(char ch)577 nonstatic siT EPDCheckColor(char ch) {
578   siT flag;
579   cT c;
580 
581   flag = 0;
582   c = c_w;
583   while (!flag && (c <= c_b))
584     if (EPDCICharEqual(ch, asccv[c]))
585       flag = 1;
586     else
587       c++;
588   return flag;
589 }
590 
591 /*--> EPDEvaluateColor: evaluate a color letter character */
EPDEvaluateColor(char ch)592 nonstatic cT EPDEvaluateColor(char ch) {
593   cT c;
594   siT flag;
595 
596   flag = 0;
597   c = c_w;
598   while (!flag && (c <= c_b))
599     if (EPDCICharEqual(ch, asccv[c]))
600       flag = 1;
601     else
602       c++;
603   if (!flag)
604     c = c_nil;
605   return c;
606 }
607 
608 /*--> EPDCheckRank: test if a character is a rank character */
EPDCheckRank(char ch)609 nonstatic siT EPDCheckRank(char ch) {
610   siT flag;
611   rankT rank;
612 
613   flag = 0;
614   rank = rank_1;
615   while (!flag && (rank <= rank_8))
616     if (EPDCICharEqual(ch, ascrv[rank]))
617       flag = 1;
618     else
619       rank++;
620   return flag;
621 }
622 
623 /*--> EPDEvaluateRank: evaluate a color rank character */
EPDEvaluateRank(char ch)624 nonstatic rankT EPDEvaluateRank(char ch) {
625   rankT rank;
626   siT flag;
627 
628   flag = 0;
629   rank = rank_1;
630   while (!flag && (rank <= rank_8))
631     if (EPDCICharEqual(ch, ascrv[rank]))
632       flag = 1;
633     else
634       rank++;
635   if (!flag)
636     rank = rank_nil;
637   return rank;
638 }
639 
640 /*--> EPDCheckFile: test if a character is a file character */
EPDCheckFile(char ch)641 nonstatic siT EPDCheckFile(char ch) {
642   siT flag;
643   fileT file;
644 
645   flag = 0;
646   file = file_a;
647   while (!flag && (file <= file_h))
648     if (EPDCICharEqual(ch, ascfv[file]))
649       flag = 1;
650     else
651       file++;
652   return flag;
653 }
654 
655 /*--> EPDEvaluateFile: evaluate a color file character */
EPDEvaluateFile(char ch)656 nonstatic rankT EPDEvaluateFile(char ch) {
657   fileT file;
658   siT flag;
659 
660   flag = 0;
661   file = file_a;
662   while (!flag && (file <= file_h))
663     if (EPDCICharEqual(ch, ascfv[file]))
664       flag = 1;
665     else
666       file++;
667   if (!flag)
668     file = file_nil;
669   return file;
670 }
671 
672 /*--> EPDNewEOV: allocate a new EOV record */
EPDNewEOV(void)673 nonstatic eovptrT EPDNewEOV(void) {
674   eovptrT eovptr;
675 
676   eovptr = (eovptrT) EPDMemoryGrab(sizeof(eovT));
677   eovptr->eov_eob = eob_nil;
678   eovptr->eov_str = NULL;
679   eovptr->eov_prev = eovptr->eov_next = NULL;
680   return eovptr;
681 }
682 
683 /*--> EPDReleaseEOV: release an EOV record */
EPDReleaseEOV(eovptrT eovptr)684 nonstatic void EPDReleaseEOV(eovptrT eovptr) {
685   if (eovptr != NULL) {
686     if (eovptr->eov_str != NULL)
687       EPDMemoryFree(eovptr->eov_str);
688     EPDMemoryFree(eovptr);
689   };
690   return;
691 }
692 
693 /*--> EPDAppendEOV: append an EOV record */
EPDAppendEOV(eopptrT eopptr,eovptrT eovptr)694 nonstatic void EPDAppendEOV(eopptrT eopptr, eovptrT eovptr) {
695   if (eopptr->eop_taileov == NULL)
696     eopptr->eop_headeov = eovptr;
697   else
698     eopptr->eop_taileov->eov_next = eovptr;
699   eovptr->eov_prev = eopptr->eop_taileov;
700   eovptr->eov_next = NULL;
701   eopptr->eop_taileov = eovptr;
702   return;
703 }
704 
705 /*--> EPDUnthreadEOV: unthread an EOV record */
706 static
EPDUnthreadEOV(eopptrT eopptr,eovptrT eovptr)707 void EPDUnthreadEOV(eopptrT eopptr, eovptrT eovptr) {
708   if (eovptr->eov_prev == NULL)
709     eopptr->eop_headeov = eovptr->eov_next;
710   else
711     eovptr->eov_prev->eov_next = eovptr->eov_next;
712   if (eovptr->eov_next == NULL)
713     eopptr->eop_taileov = eovptr->eov_prev;
714   else
715     eovptr->eov_next->eov_prev = eovptr->eov_prev;
716   return;
717 }
718 
719 /*--> EPDCreateEOVSym: create a new EOV record with a symbol value */
EPDCreateEOVSym(charptrT sym)720 nonstatic eovptrT EPDCreateEOVSym(charptrT sym) {
721   eovptrT eovptr;
722 
723   eovptr = EPDNewEOV();
724   eovptr->eov_eob = eob_symbol;
725   eovptr->eov_str = EPDStringGrab(sym);
726   return eovptr;
727 }
728 
729 /*--> EPDCreateEOVInt: create a new EOV record with an integer value */
EPDCreateEOVInt(liT lval)730 nonstatic eovptrT EPDCreateEOVInt(liT lval) {
731   eovptrT eovptr;
732   char tv[tL];
733 
734   sprintf(tv, "%ld", lval);
735   eovptr = EPDNewEOV();
736   eovptr->eov_eob = eob_symbol;
737   eovptr->eov_str = EPDStringGrab(tv);
738   return eovptr;
739 }
740 
741 /*--> EPDLocateEOV: try to locate 1st EOV record with given string value */
EPDLocateEOV(eopptrT eopptr,charptrT strval)742 nonstatic eovptrT EPDLocateEOV(eopptrT eopptr, charptrT strval) {
743   eovptrT eovptr;
744   siT flag;
745 
746   flag = 0;
747   eovptr = eopptr->eop_headeov;
748   while (!flag && (eovptr != NULL))
749     if (strcmp(strval, eovptr->eov_str) == 0)
750       flag = 1;
751     else
752       eovptr = eovptr->eov_next;
753   if (!flag)
754     eovptr = NULL;
755   return eovptr;
756 }
757 
758 /*--> EPDReplaceEOVStr: replace EOV string value with given string value */
EPDReplaceEOVStr(eovptrT eovptr,charptrT str)759 nonstatic void EPDReplaceEOVStr(eovptrT eovptr, charptrT str) {
760   if (eovptr->eov_str != NULL) {
761     EPDMemoryFree(eovptr->eov_str);
762     eovptr->eov_str = NULL;
763   };
764   if (str != NULL)
765     eovptr->eov_str = EPDStringGrab(str);
766   return;
767 }
768 
769 /*--> EPDNewEOP: allocate a new EOP record */
EPDNewEOP(void)770 nonstatic eopptrT EPDNewEOP(void) {
771   eopptrT eopptr;
772 
773   eopptr = (eopptrT) EPDMemoryGrab(sizeof(eopT));
774   eopptr->eop_opsym = NULL;
775   eopptr->eop_headeov = eopptr->eop_taileov = NULL;
776   eopptr->eop_prev = eopptr->eop_next = NULL;
777   return eopptr;
778 }
779 
780 /*--> EPDReleaseEOP: release an EOP record */
EPDReleaseEOP(eopptrT eopptr)781 nonstatic void EPDReleaseEOP(eopptrT eopptr) {
782   eovptrT eovptr0, eovptr1;
783 
784   if (eopptr != NULL) {
785     if (eopptr->eop_opsym != NULL)
786       EPDMemoryFree(eopptr->eop_opsym);
787     eovptr0 = eopptr->eop_headeov;
788     while (eovptr0 != NULL) {
789       eovptr1 = eovptr0->eov_next;
790       EPDUnthreadEOV(eopptr, eovptr0);
791       EPDReleaseEOV(eovptr0);
792       eovptr0 = eovptr1;
793     };
794     EPDMemoryFree(eopptr);
795   };
796   return;
797 }
798 
799 /*--> EPDAppendEOP: append an EOP record */
EPDAppendEOP(epdptrT epdptr,eopptrT eopptr)800 nonstatic void EPDAppendEOP(epdptrT epdptr, eopptrT eopptr) {
801   if (epdptr->epd_taileop == NULL)
802     epdptr->epd_headeop = eopptr;
803   else
804     epdptr->epd_taileop->eop_next = eopptr;
805   eopptr->eop_prev = epdptr->epd_taileop;
806   eopptr->eop_next = NULL;
807   epdptr->epd_taileop = eopptr;
808   return;
809 }
810 
811 /*--> EPDUnthreadEOP: unthread an EOP record */
812 static
EPDUnthreadEOP(epdptrT epdptr,eopptrT eopptr)813 void EPDUnthreadEOP(epdptrT epdptr, eopptrT eopptr) {
814   if (eopptr->eop_prev == NULL)
815     epdptr->epd_headeop = eopptr->eop_next;
816   else
817     eopptr->eop_prev->eop_next = eopptr->eop_next;
818   if (eopptr->eop_next == NULL)
819     epdptr->epd_taileop = eopptr->eop_prev;
820   else
821     eopptr->eop_next->eop_prev = eopptr->eop_prev;
822   return;
823 }
824 
825 /*--> EPDCreateEOP: create a new EOP record with opsym */
EPDCreateEOP(charptrT opsym)826 nonstatic eopptrT EPDCreateEOP(charptrT opsym) {
827   eopptrT eopptr;
828 
829   eopptr = EPDNewEOP();
830   eopptr->eop_opsym = EPDStringGrab(opsym);
831   return eopptr;
832 }
833 
834 /*--> EPDCreateEOPCode: create a new EOP record using opsym index */
EPDCreateEOPCode(epdsoT epdso)835 nonstatic eopptrT EPDCreateEOPCode(epdsoT epdso) {
836   eopptrT eopptr;
837 
838   eopptr = EPDCreateEOP(EPDFetchOpsym(epdso));
839   return eopptr;
840 }
841 
842 /*--> EPDLocateEOP: attempt to locate EOP record with given opsym */
EPDLocateEOP(epdptrT epdptr,charptrT opsym)843 nonstatic eopptrT EPDLocateEOP(epdptrT epdptr, charptrT opsym) {
844   eopptrT eopptr;
845   siT flag;
846 
847   flag = 0;
848   eopptr = epdptr->epd_headeop;
849   while (!flag && (eopptr != NULL))
850     if (strcmp(opsym, eopptr->eop_opsym) == 0)
851       flag = 1;
852     else
853       eopptr = eopptr->eop_next;
854   if (!flag)
855     eopptr = NULL;
856   return eopptr;
857 }
858 
859 /*--> EPDLocateEOPCode: attempt to locate EOP record with given code */
EPDLocateEOPCode(epdptrT epdptr,epdsoT epdso)860 nonstatic eopptrT EPDLocateEOPCode(epdptrT epdptr, epdsoT epdso) {
861   return EPDLocateEOP(epdptr, epdsostrv[epdso]);
862 }
863 
864 /*--> EPDDropIfLocEOPCode: try to locate/drop EOP record with given code */
EPDDropIfLocEOPCode(epdptrT epdptr,epdsoT epdso)865 nonstatic void EPDDropIfLocEOPCode(epdptrT epdptr, epdsoT epdso) {
866   eopptrT eopptr;
867 
868   eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso]);
869   if (eopptr != NULL) {
870     EPDUnthreadEOP(epdptr, eopptr);
871     EPDReleaseEOP(eopptr);
872   };
873   return;
874 }
875 
876 /*--> EPDAddOpInt: add a single integer operand operation */
EPDAddOpInt(epdptrT epdptr,epdsoT epdso,liT val)877 nonstatic void EPDAddOpInt(epdptrT epdptr, epdsoT epdso, liT val) {
878   eopptrT eopptr;
879   eovptrT eovptr;
880 
881   eovptr = EPDCreateEOVInt(val);
882   eopptr = EPDCreateEOPCode(epdso);
883   EPDAppendEOV(eopptr, eovptr);
884   EPDDropIfLocEOPCode(epdptr, epdso);
885   EPDAppendEOP(epdptr, eopptr);
886   return;
887 }
888 
889 /*--> EPDAddOpSym: add a single symbol operand operation */
EPDAddOpSym(epdptrT epdptr,epdsoT epdso,charptrT s)890 nonstatic void EPDAddOpSym(epdptrT epdptr, epdsoT epdso, charptrT s) {
891   eopptrT eopptr;
892   eovptrT eovptr;
893 
894   eovptr = EPDCreateEOVSym(s);
895   eopptr = EPDCreateEOPCode(epdso);
896   EPDAppendEOV(eopptr, eovptr);
897   EPDDropIfLocEOPCode(epdptr, epdso);
898   EPDAppendEOP(epdptr, eopptr);
899   return;
900 }
901 
902 /*--> EPDNewEPD: allocate a new EPD record */
EPDNewEPD(void)903 nonstatic epdptrT EPDNewEPD(void) {
904   epdptrT epdptr;
905   siT i;
906 
907   epdptr = (epdptrT) EPDMemoryGrab(sizeof(epdT));
908   for (i = 0; i < nbL; i++)
909     epdptr->epd_nbv[i] = ((cp_v0 << nybbW) | cp_v0);
910   epdptr->epd_actc = c_v;
911   epdptr->epd_cast = 0;
912   epdptr->epd_epsq = sq_nil;
913   epdptr->epd_headeop = epdptr->epd_taileop = NULL;
914   return epdptr;
915 }
916 
917 /*--> EPDReleaseOperations: release EPD operation list */
EPDReleaseOperations(epdptrT epdptr)918 nonstatic void EPDReleaseOperations(epdptrT epdptr) {
919   eopptrT eopptr0, eopptr1;
920 
921   if (epdptr != NULL) {
922     eopptr0 = epdptr->epd_headeop;
923     while (eopptr0 != NULL) {
924       eopptr1 = eopptr0->eop_next;
925       EPDUnthreadEOP(epdptr, eopptr0);
926       EPDReleaseEOP(eopptr0);
927       eopptr0 = eopptr1;
928     };
929     epdptr->epd_headeop = NULL;
930     epdptr->epd_taileop = NULL;
931   };
932   return;
933 }
934 
935 /*--> EPDReleaseEPD: release an EPD record */
EPDReleaseEPD(epdptrT epdptr)936 nonstatic void EPDReleaseEPD(epdptrT epdptr) {
937   if (epdptr != NULL) {
938     EPDReleaseOperations(epdptr);
939     EPDMemoryFree(epdptr);
940   };
941   return;
942 }
943 
944 /*--> EPDFetchOpsym: return a pointer to the indicated mnemonic */
EPDFetchOpsym(epdsoT epdso)945 nonstatic charptrT EPDFetchOpsym(epdsoT epdso) {
946   return epdsostrv[epdso];
947 }
948 
949 /*--> EPDCountOperands: count operands */
EPDCountOperands(eopptrT eopptr)950 static siT EPDCountOperands(eopptrT eopptr) {
951   siT count;
952   eovptrT eovptr;
953 
954   count = 0;
955   eovptr = eopptr->eop_headeov;
956   while (eovptr != NULL) {
957     count++;
958     eovptr = eovptr->eov_next;
959   };
960   return count;
961 }
962 
963 /*--> EPDCountOperations: count operations */
EPDCountOperations(epdptrT epdptr)964 static siT EPDCountOperations(epdptrT epdptr) {
965   siT count;
966   eopptrT eopptr;
967 
968   count = 0;
969   eopptr = epdptr->epd_headeop;
970   while (eopptr != NULL) {
971     count++;
972     eopptr = eopptr->eop_next;
973   };
974   return count;
975 }
976 
977 /*--> EPDSortOperands: sort operands according to string value */
978 static
EPDSortOperands(eopptrT eopptr)979 void EPDSortOperands(eopptrT eopptr) {
980   siT count;
981   siT pass, flag;
982   eovptrT ptr0, ptr1, ptr2, ptr3;
983 
984   count = EPDCountOperands(eopptr);
985   if (count > 1) {
986     flag = 1;
987     pass = 0;
988     while (flag && (pass < (count - 1))) {
989       flag = 0;
990       ptr0 = eopptr->eop_headeov;
991       ptr1 = ptr0->eov_next;
992       while (ptr1 != NULL) {
993         if (strcmp(ptr0->eov_str, ptr1->eov_str) > 0) {
994           flag = 1;
995           ptr2 = ptr0->eov_prev;
996           ptr3 = ptr1->eov_next;
997           ptr0->eov_prev = ptr1;
998           ptr0->eov_next = ptr3;
999           ptr1->eov_prev = ptr2;
1000           ptr1->eov_next = ptr0;
1001           if (ptr2 == NULL)
1002             eopptr->eop_headeov = ptr1;
1003           else
1004             ptr2->eov_next = ptr1;
1005           if (ptr3 == NULL)
1006             eopptr->eop_taileov = ptr0;
1007           else
1008             ptr3->eov_prev = ptr0;
1009         } else
1010           ptr0 = ptr1;
1011         ptr1 = ptr0->eov_next;
1012       };
1013       pass++;
1014     };
1015   };
1016   return;
1017 }
1018 
1019 /*--> EPDSortOperations: sort operations according to opcode */
1020 static
EPDSortOperations(epdptrT epdptr)1021 void EPDSortOperations(epdptrT epdptr) {
1022   siT count;
1023   siT pass, flag;
1024   eopptrT ptr0, ptr1, ptr2, ptr3;
1025 
1026   count = EPDCountOperations(epdptr);
1027   if (count > 1) {
1028     flag = 1;
1029     pass = 0;
1030     while (flag && (pass < (count - 1))) {
1031       flag = 0;
1032       ptr0 = epdptr->epd_headeop;
1033       ptr1 = ptr0->eop_next;
1034       while (ptr1 != NULL) {
1035         if (strcmp(ptr0->eop_opsym, ptr1->eop_opsym) > 0) {
1036           flag = 1;
1037           ptr2 = ptr0->eop_prev;
1038           ptr3 = ptr1->eop_next;
1039           ptr0->eop_prev = ptr1;
1040           ptr0->eop_next = ptr3;
1041           ptr1->eop_prev = ptr2;
1042           ptr1->eop_next = ptr0;
1043           if (ptr2 == NULL)
1044             epdptr->epd_headeop = ptr1;
1045           else
1046             ptr2->eop_next = ptr1;
1047           if (ptr3 == NULL)
1048             epdptr->epd_taileop = ptr0;
1049           else
1050             ptr3->eop_prev = ptr0;
1051         } else
1052           ptr0 = ptr1;
1053         ptr1 = ptr0->eop_next;
1054       };
1055       pass++;
1056     };
1057   };
1058   return;
1059 }
1060 
1061 /*--> EPDNormalize: apply normalizing sorts */
1062 static
EPDNormalize(epdptrT epdptr)1063 void EPDNormalize(epdptrT epdptr) {
1064   eopptrT eopptr;
1065   charptrT opsym;
1066   siT flag;
1067 
1068 /* sort all operations */
1069   EPDSortOperations(epdptr);
1070 /* sort operands for selected standard operations */
1071   eopptr = epdptr->epd_headeop;
1072   while (eopptr != NULL) {
1073     flag = 0;
1074     opsym = eopptr->eop_opsym;
1075     if (!flag && (strcmp(opsym, epdsostrv[epdso_am]) == 0)) {
1076       EPDSortOperands(eopptr);
1077       flag = 1;
1078     };
1079     if (!flag && (strcmp(opsym, epdsostrv[epdso_bm]) == 0)) {
1080       EPDSortOperands(eopptr);
1081       flag = 1;
1082     };
1083     eopptr = eopptr->eop_next;
1084   };
1085   return;
1086 }
1087 
1088 /*--> EPDCloneEPDBase: clone an EPD structure, base items only */
EPDCloneEPDBase(epdptrT epdptr)1089 nonstatic epdptrT EPDCloneEPDBase(epdptrT epdptr) {
1090   epdptrT nptr;
1091   siT index;
1092 
1093   nptr = EPDNewEPD();
1094   for (index = 0; index < nbL; index++)
1095     nptr->epd_nbv[index] = epdptr->epd_nbv[index];
1096   nptr->epd_actc = epdptr->epd_actc;
1097   nptr->epd_cast = epdptr->epd_cast;
1098   nptr->epd_epsq = epdptr->epd_epsq;
1099   return nptr;
1100 }
1101 
1102 /*--> EPDCloneEOV: clone an EOV structure */
EPDCloneEOV(eovptrT eovptr)1103 nonstatic eovptrT EPDCloneEOV(eovptrT eovptr) {
1104   eovptrT nptr;
1105 
1106   nptr = EPDNewEOV();
1107   nptr->eov_eob = eovptr->eov_eob;
1108   if (eovptr->eov_str != NULL)
1109     nptr->eov_str = EPDStringGrab(eovptr->eov_str);
1110   return nptr;
1111 }
1112 
1113 /*--> EPDCloneEOP: clone an EOP structure */
EPDCloneEOP(eopptrT eopptr)1114 nonstatic eopptrT EPDCloneEOP(eopptrT eopptr) {
1115   eopptrT nptr;
1116   eovptrT eovptr, rptr;
1117 
1118   nptr = EPDNewEOP();
1119   if (eopptr->eop_opsym != NULL)
1120     nptr->eop_opsym = EPDStringGrab(eopptr->eop_opsym);
1121   rptr = eopptr->eop_headeov;
1122   while (rptr != NULL) {
1123     eovptr = EPDCloneEOV(rptr);
1124     EPDAppendEOV(nptr, eovptr);
1125     rptr = rptr->eov_next;
1126   };
1127   return nptr;
1128 }
1129 
1130 /*--> EPDSetKings: set the king location vector */
1131 static
EPDSetKings(void)1132 void EPDSetKings(void) {
1133   sqT sq;
1134 
1135 /* this operates only on the local environment */
1136   ese.ese_ksqv[c_w] = ese.ese_ksqv[c_b] = sq_nil;
1137   for (sq = sq_a1; sq <= sq_h8; sq++)
1138     switch (EPDboard.rbv[sq]) {
1139       case cp_wk:
1140         ese.ese_ksqv[c_w] = sq;
1141         break;
1142       case cp_bk:
1143         ese.ese_ksqv[c_b] = sq;
1144         break;
1145       default:
1146         break;
1147     };
1148   return;
1149 }
1150 
1151 /*--> EPDSet: set up an EPD structure for the given position */
EPDSet(rbptrT rbptr,cT actc,castT cast,sqT epsq)1152 nonstatic epdptrT EPDSet(rbptrT rbptr, cT actc, castT cast, sqT epsq) {
1153   epdptrT epdptr;
1154   sqT sq;
1155   cpT cp0, cp1;
1156 
1157 /* this does not reference the current position */
1158   epdptr = EPDNewEPD();
1159   for (sq = sq_a1; sq <= sq_h8; sq += 2) {
1160     cp0 = rbptr->rbv[sq + 0];
1161     cp1 = rbptr->rbv[sq + 1];
1162     epdptr->epd_nbv[sq >> 1] = ((cp1 << nybbW) | cp0);
1163   };
1164   epdptr->epd_actc = actc;
1165   epdptr->epd_cast = cast;
1166   epdptr->epd_epsq = epsq;
1167   return epdptr;
1168 }
1169 
1170 /*--> EPDSetCurrentPosition: set current position */
EPDSetCurrentPosition(rbptrT rbptr,cT actc,castT cast,sqT epsq,siT hmvc,siT fmvn)1171 nonstatic void EPDSetCurrentPosition(rbptrT rbptr, cT actc, castT cast,
1172     sqT epsq, siT hmvc, siT fmvn) {
1173   sqT sq;
1174 
1175 /* this changes the current position */
1176   for (sq = sq_a1; sq <= sq_h8; sq++)
1177     EPDboard.rbv[sq] = rbptr->rbv[sq];
1178   ese.ese_actc = actc;
1179   ese.ese_cast = cast;
1180   ese.ese_epsq = epsq;
1181   ese.ese_hmvc = hmvc;
1182   ese.ese_fmvn = fmvn;
1183   EPDSetKings();
1184   return;
1185 }
1186 
1187 /*--> EPDGetCurrentPosition: return EPD structure for current position */
EPDGetCurrentPosition(void)1188 nonstatic epdptrT EPDGetCurrentPosition(void) {
1189   epdptrT epdptr;
1190   sqT sq;
1191   cpT cp0, cp1;
1192 
1193   epdptr = EPDNewEPD();
1194   for (sq = sq_a1; sq <= sq_h8; sq += 2) {
1195     cp0 = EPDboard.rbv[sq + 0];
1196     cp1 = EPDboard.rbv[sq + 1];
1197     epdptr->epd_nbv[sq >> 1] = ((cp1 << nybbW) | cp0);
1198   };
1199   epdptr->epd_actc = ese.ese_actc;
1200   epdptr->epd_cast = ese.ese_cast;
1201   epdptr->epd_epsq = ese.ese_epsq;
1202   return epdptr;
1203 }
1204 
1205 /*--> EPDFetchACTC: fetch current active color */
EPDFetchACTC(void)1206 nonstatic cT EPDFetchACTC(void) {
1207 /* return the value of the current active color */
1208   return ese.ese_actc;
1209 }
1210 
1211 /*--> EPDFetchCAST: fetch current castling availability */
EPDFetchCAST(void)1212 nonstatic castT EPDFetchCAST(void) {
1213 /* return the value of the current castling availability */
1214   return ese.ese_cast;
1215 }
1216 
1217 /*--> EPDFetchEPSQ: fetch current en passant target square */
EPDFetchEPSQ(void)1218 nonstatic sqT EPDFetchEPSQ(void) {
1219 /* return the value of the current en passant target square */
1220   return ese.ese_epsq;
1221 }
1222 
1223 /*--> EPDFetchHMVC: fetch current halfmove clock */
EPDFetchHMVC(void)1224 nonstatic siT EPDFetchHMVC(void) {
1225 /* return the value of the current halfmove clock */
1226   return ese.ese_hmvc;
1227 }
1228 
1229 /*--> EPDFetchFMVN: fetch current fullmove number */
EPDFetchFMVN(void)1230 nonstatic siT EPDFetchFMVN(void) {
1231 /* return the value of the current fullmove number */
1232   return ese.ese_fmvn;
1233 }
1234 
1235 /*--> EPDFetchBoard: fetch current board */
EPDFetchBoard(void)1236 nonstatic rbptrT EPDFetchBoard(void) {
1237 /* copy from the local board into the designated static return area */
1238   ret_rb = EPDboard;
1239   return &ret_rb;
1240 }
1241 
1242 /*--> EPDFetchCP: fetch color-piece */
EPDFetchCP(sqT sq)1243 nonstatic cpT EPDFetchCP(sqT sq) {
1244   cpT cp;
1245 
1246 /* fetch from the local board */
1247   cp = EPDboard.rbv[sq];
1248   return cp;
1249 }
1250 
1251 /*--> EPDGetGTIM: get game termination marker indicator */
EPDGetGTIM(gamptrT gamptr)1252 nonstatic gtimT EPDGetGTIM(gamptrT gamptr) {
1253   return gamptr->gam_gtim;
1254 }
1255 
1256 /*--> EPDPutGTIM: put game termination marker indicator */
EPDPutGTIM(gamptrT gamptr,gtimT gtim)1257 nonstatic void EPDPutGTIM(gamptrT gamptr, gtimT gtim) {
1258   gamptr->gam_gtim = gtim;
1259   return;
1260 }
1261 
1262 /*--> EPDGenBasic: generate basic EPD notation for a given position */
EPDGenBasic(rbptrT rbptr,cT actc,castT cast,sqT epsq)1263 nonstatic charptrT EPDGenBasic(rbptrT rbptr, cT actc, castT cast, sqT epsq) {
1264   charptrT ptr;
1265   epdptrT epdptr;
1266 
1267 /* this does not reference the current position */
1268   epdptr = EPDSet(rbptr, actc, cast, epsq);
1269   ptr = EPDEncode(epdptr);
1270   EPDReleaseEPD(epdptr);
1271   return ptr;
1272 }
1273 
1274 /*--> EPDGenBasicCurrent: generate basic EPD for current position */
EPDGenBasicCurrent(void)1275 nonstatic charptrT EPDGenBasicCurrent(void) {
1276   charptrT ptr;
1277 
1278 /* this references but does not change the current position */
1279   ptr = EPDGenBasic(&EPDboard, ese.ese_actc, ese.ese_cast, ese.ese_epsq);
1280   return ptr;
1281 }
1282 
1283 /*--> EPDDecode: read an EPD structure from a string */
EPDDecode(charptrT s)1284 nonstatic epdptrT EPDDecode(charptrT s) {
1285   epdptrT epdptr;
1286   eopptrT eopptr;
1287   eovptrT eovptr;
1288   siT flag, quoteflag;
1289   siT ch;
1290   liT i;
1291   siT j, d;
1292   byteptrT bptr;
1293   fileT file;
1294   rankT rank;
1295   sqT sq;
1296   cT c;
1297   pT p;
1298   cpT cp;
1299 
1300 /* this does not reference the current position */
1301 /* set up */
1302   flag = 1;
1303   i = 0;
1304   ch = *(s + i++);
1305 /* initialize the return structure */
1306   epdptr = EPDNewEPD();
1307 /* skip whitespace */
1308   if (flag) {
1309     while (flag && (ch != ascii_nul) && isspace(ch))
1310       ch = *(s + i++);
1311     if (ch == ascii_nul)
1312       flag = 0;
1313   };
1314 /* process piece placement data */
1315   if (flag) {
1316     rank = rank_8;
1317     file = file_a;
1318     while (flag && (ch != ascii_nul) && !isspace(ch)) {
1319       switch (ch) {
1320         case '/':
1321           if ((file != fileL) || (rank == rank_1))
1322             flag = 0;
1323           else {
1324             rank--;
1325             file = file_a;
1326           };
1327           break;
1328         case '1':
1329         case '2':
1330         case '3':
1331         case '4':
1332         case '5':
1333         case '6':
1334         case '7':
1335         case '8':
1336           d = ch - '0';
1337           if ((file + d) > fileL)
1338             flag = 0;
1339           else
1340             for (j = 0; j < d; j++) {
1341               sq = map_sq(rank, file);
1342               bptr = &epdptr->epd_nbv[sq >> 1];
1343               if ((sq % 2) == 0) {
1344                 *bptr &= ~nybbM;
1345                 *bptr |= cp_v0;
1346               } else {
1347                 *bptr &= ~(nybbM << nybbW);
1348                 *bptr |= (cp_v0 << nybbW);
1349               };
1350               file++;
1351             };
1352           break;
1353         default:
1354           if (!EPDCheckPiece((char) ch) || (file >= fileL))
1355             flag = 0;
1356           else {
1357             p = EPDEvaluatePiece((char) ch);
1358             if (isupper(ch))
1359               c = c_w;
1360             else
1361               c = c_b;
1362             sq = map_sq(rank, file);
1363             bptr = &epdptr->epd_nbv[sq >> 1];
1364             cp = cv_cp_c_pv[c][p];
1365             if ((sq % 2) == 0) {
1366               *bptr &= ~nybbM;
1367               *bptr |= cp;
1368             } else {
1369               *bptr &= ~(nybbM << nybbW);
1370               *bptr |= (cp << nybbW);
1371             };
1372             file++;
1373           };
1374           break;
1375       };
1376       ch = *(s + i++);
1377     };
1378     if (flag)
1379       if ((file != fileL) || (rank != rank_1))
1380         flag = 0;
1381   };
1382 /* need at least one whitespace character */
1383   if (flag)
1384     if ((ch == ascii_nul) || !isspace(ch))
1385       flag = 0;
1386 /* skip whitespace */
1387   if (flag) {
1388     while (flag && (ch != ascii_nul) && isspace(ch))
1389       ch = *(s + i++);
1390     if (ch == ascii_nul)
1391       flag = 0;
1392   };
1393 /* process active color */
1394   if (flag) {
1395     if (!EPDCheckColor((char) ch))
1396       flag = 0;
1397     else {
1398       epdptr->epd_actc = EPDEvaluateColor((char) ch);
1399       ch = *(s + i++);
1400     };
1401   };
1402 /* need at least one whitespace character */
1403   if (flag)
1404     if ((ch == ascii_nul) || !isspace(ch))
1405       flag = 0;
1406 /* skip whitespace */
1407   if (flag) {
1408     while (flag && (ch != ascii_nul) && isspace(ch))
1409       ch = *(s + i++);
1410     if (ch == ascii_nul)
1411       flag = 0;
1412   };
1413 /* process castling availability */
1414   if (flag) {
1415     epdptr->epd_cast = 0;
1416     if (ch == '-')
1417       ch = *(s + i++);
1418     else {
1419 /* white kingside castling availability */
1420       if (flag && (ch == map_upper(ascpv[p_k]))) {
1421         epdptr->epd_cast |= cf_wk;
1422         ch = *(s + i++);
1423         if (ch == ascii_nul)
1424           flag = 0;
1425       };
1426 /* white queenside castling availability */
1427       if (flag && (ch == map_upper(ascpv[p_q]))) {
1428         epdptr->epd_cast |= cf_wq;
1429         ch = *(s + i++);
1430         if (ch == ascii_nul)
1431           flag = 0;
1432       };
1433 /* black kingside castling availability */
1434       if (flag && (ch == map_lower(ascpv[p_k]))) {
1435         epdptr->epd_cast |= cf_bk;
1436         ch = *(s + i++);
1437         if (ch == ascii_nul)
1438           flag = 0;
1439       };
1440 /* black queenside castling availability */
1441       if (flag && (ch == map_lower(ascpv[p_q]))) {
1442         epdptr->epd_cast |= cf_bq;
1443         ch = *(s + i++);
1444         if (ch == ascii_nul)
1445           flag = 0;
1446       };
1447     };
1448   };
1449 /* need at least one whitespace character */
1450   if (flag)
1451     if ((ch == ascii_nul) || !isspace(ch))
1452       flag = 0;
1453 /* skip whitespace */
1454   if (flag) {
1455     while (flag && (ch != ascii_nul) && isspace(ch))
1456       ch = *(s + i++);
1457     if (ch == ascii_nul)
1458       flag = 0;
1459   };
1460 /* process en passant target */
1461   if (flag) {
1462     if (ch == '-') {
1463       epdptr->epd_epsq = sq_nil;
1464       ch = *(s + i++);
1465       if ((ch != ascii_nul) && !isspace(ch))
1466         flag = 0;
1467     } else {
1468       if (!EPDCheckFile((char) ch))
1469         flag = 0;
1470       else {
1471         file = EPDEvaluateFile((char) ch);
1472         ch = *(s + i++);
1473         if ((ch == ascii_nul) || !EPDCheckRank((char) ch))
1474           flag = 0;
1475         else {
1476           epdptr->epd_epsq = map_sq(EPDEvaluateRank((char) ch), file);
1477           ch = *(s + i++);
1478           if ((ch != ascii_nul) && !isspace(ch))
1479             flag = 0;
1480         };
1481       };
1482     }
1483   }
1484 /* skip whitespace (end-of-line is not an error) */
1485   if (flag)
1486     while ((ch != ascii_nul) && isspace(ch))
1487       ch = *(s + i++);
1488 /* process operation sequence (if any) */
1489   if (flag) {
1490     while (flag && (ch != ascii_nul)) {
1491 /* allocate a new operation */
1492       eopptr = EPDNewEOP();
1493 /* form opsym (first character) */
1494       if (IdentChar(ch)) {
1495         eopptr->eop_opsym = EPDStringGrab("");
1496         eopptr->eop_opsym = EPDStringAppendChar(eopptr->eop_opsym, (char) ch);
1497         ch = *(s + i++);
1498       } else
1499         flag = 0;
1500 /* form remainder of opsym */
1501       while (IdentChar(ch)) {
1502         eopptr->eop_opsym = EPDStringAppendChar(eopptr->eop_opsym, (char) ch);
1503         ch = *(s + i++);
1504       };
1505 /* skip whitespace */
1506       if (flag) {
1507         while (flag && (ch != ascii_nul) && isspace(ch))
1508           ch = *(s + i++);
1509         if (ch == ascii_nul)
1510           flag = 0;
1511       };
1512 /* process operand list */
1513       while (flag && (ch != ';')) {
1514 /* allocate operand value */
1515         eovptr = EPDNewEOV();
1516 /* set quoted string as appropriate */
1517         if (ch == '"') {
1518           quoteflag = 1;
1519           eovptr->eov_eob = eob_string;
1520           ch = *(s + i++);
1521         } else {
1522           quoteflag = 0;
1523           eovptr->eov_eob = eob_symbol;
1524         };
1525         eovptr->eov_str = EPDStringGrab("");
1526         if (quoteflag) {
1527           while (flag && (ch != '"')) {
1528             if (ch == ascii_nul)
1529               flag = 0;
1530             else {
1531               eovptr->eov_str =
1532                   EPDStringAppendChar(eovptr->eov_str, (char) ch);
1533               ch = *(s + i++);
1534             };
1535           };
1536           if (ch == '"')
1537             ch = *(s + i++);
1538         } else {
1539           while (flag && !isspace(ch) && (ch != ';')) {
1540             if (ch == ascii_nul)
1541               flag = 0;
1542             else {
1543               eovptr->eov_str =
1544                   EPDStringAppendChar(eovptr->eov_str, (char) ch);
1545               ch = *(s + i++);
1546             };
1547           };
1548         };
1549 /* append operand onto operation */
1550         if (flag)
1551           EPDAppendEOV(eopptr, eovptr);
1552         else
1553           EPDReleaseEOV(eovptr);
1554 /* skip whitespace */
1555         while (flag && (ch != ascii_nul) && isspace(ch))
1556           ch = *(s + i++);
1557       };
1558 /* process semicolon */
1559       if (flag) {
1560         if (ch == ';')
1561           ch = *(s + i++);
1562         else
1563           flag = 0;
1564       }
1565 /* append operation */
1566       if (flag)
1567         EPDAppendEOP(epdptr, eopptr);
1568       else
1569         EPDReleaseEOP(eopptr);
1570 /* skip whitespace (end-of-line is not an error) */
1571       if (flag)
1572         while (flag && (ch != ascii_nul) && isspace(ch))
1573           ch = *(s + i++);
1574     };
1575   };
1576 /* check for fault */
1577   if (!flag) {
1578     EPDReleaseEPD(epdptr);
1579     epdptr = NULL;
1580   };
1581 /* normalize */
1582   if (epdptr != NULL)
1583     EPDNormalize(epdptr);
1584   return epdptr;
1585 }
1586 
1587 /*--> EPDEncode: write an EPD structure to a string */
EPDEncode(epdptrT epdptr)1588 nonstatic charptrT EPDEncode(epdptrT epdptr) {
1589   charptrT ptr;
1590   sqT sq;
1591   cpT cp;
1592   rankT rank;
1593   fileT file;
1594   siT bi, ps, ch;
1595   char bv[tL];
1596   eopptrT eopptr;
1597   eovptrT eovptr;
1598   charptrT s0, s1;
1599 
1600 /* this does not reference the current position */
1601   bi = 0;
1602 /* normalize */
1603   EPDNormalize(epdptr);
1604 /* output board */
1605   for (rank = rank_8; rank >= rank_1; rank--) {
1606     ps = 0;
1607     for (file = file_a; file <= file_h; file++) {
1608       sq = map_sq(rank, file);
1609       if ((sq % 2) == 0)
1610         cp = (epdptr->epd_nbv[sq >> 1] & nybbM);
1611       else
1612         cp = ((epdptr->epd_nbv[sq >> 1] >> nybbW) & nybbM);
1613       if (cp == cp_v0)
1614         ps++;
1615       else {
1616         if (ps != 0) {
1617           bv[bi++] = '0' + ps;
1618           ps = 0;
1619         };
1620         ch = ascpv[cv_p_cpv[cp]];
1621         if (cv_c_cpv[cp] == c_w)
1622           ch = map_upper(ch);
1623         else
1624           ch = map_lower(ch);
1625         bv[bi++] = ch;
1626       };
1627     };
1628     if (ps != 0) {
1629       bv[bi++] = '0' + ps;
1630       ps = 0;
1631     };
1632     if (rank != rank_1)
1633       bv[bi++] = '/';
1634   };
1635   bv[bi++] = ascii_sp;
1636 /* output active color (lower case) */
1637   bv[bi++] = map_lower(asccv[epdptr->epd_actc]);
1638   bv[bi++] = ascii_sp;
1639 /* output castling availablility */
1640   if (epdptr->epd_cast == 0)
1641     bv[bi++] = '-';
1642   else {
1643     if (epdptr->epd_cast & cf_wk)
1644       bv[bi++] = map_upper(ascpv[p_k]);
1645     if (epdptr->epd_cast & cf_wq)
1646       bv[bi++] = map_upper(ascpv[p_q]);
1647     if (epdptr->epd_cast & cf_bk)
1648       bv[bi++] = map_lower(ascpv[p_k]);
1649     if (epdptr->epd_cast & cf_bq)
1650       bv[bi++] = map_lower(ascpv[p_q]);
1651   };
1652   bv[bi++] = ascii_sp;
1653 /* output ep capture square */
1654   if (epdptr->epd_epsq == sq_nil)
1655     bv[bi++] = '-';
1656   else {
1657     bv[bi++] = ascfv[map_file(epdptr->epd_epsq)];
1658     bv[bi++] = ascrv[map_rank(epdptr->epd_epsq)];
1659   };
1660 /* NUL termination */
1661   bv[bi++] = ascii_nul;
1662 /* allocate and copy basic result */
1663   ptr = EPDStringGrab(bv);
1664 /* construct and append operations */
1665   eopptr = epdptr->epd_headeop;
1666   while (eopptr != NULL) {
1667 /* leading space */
1668     s0 = EPDStringGrab(" ");
1669 /* opcode */
1670     s0 = EPDStringAppendStr(s0, eopptr->eop_opsym);
1671 /* construct and append operands */
1672     eovptr = eopptr->eop_headeov;
1673     while (eovptr != NULL) {
1674 /* leading space */
1675       s1 = EPDStringGrab(" ");
1676 /* conjure operand value */
1677       switch (eovptr->eov_eob) {
1678         case eob_string:
1679           s1 = EPDStringAppendChar(s1, '"');
1680           s1 = EPDStringAppendStr(s1, eovptr->eov_str);
1681           s1 = EPDStringAppendChar(s1, '"');
1682           break;
1683         case eob_symbol:
1684           s1 = EPDStringAppendStr(s1, eovptr->eov_str);
1685           break;
1686         default:
1687           EPDSwitchFault("EPDEncode");
1688           break;
1689       };
1690 /* append */
1691       s0 = EPDStringAppendStr(s0, s1);
1692       EPDMemoryFree(s1);
1693 /* next operand */
1694       eovptr = eovptr->eov_next;
1695     };
1696 /* trailing semicolon */
1697     s0 = EPDStringAppendChar(s0, ';');
1698 /* append operation */
1699     ptr = EPDStringAppendStr(ptr, s0);
1700     EPDMemoryFree(s0);
1701 /* advance */
1702     eopptr = eopptr->eop_next;
1703   };
1704   return ptr;
1705 }
1706 
1707 /*--> EPDRealize: set the current position according to EPD */
EPDRealize(epdptrT epdptr)1708 nonstatic void EPDRealize(epdptrT epdptr) {
1709   sqT sq;
1710   cpT cp;
1711   eopptrT eopptr;
1712   eovptrT eovptr;
1713 
1714 /* this changes the current position */
1715   for (sq = sq_a1; sq <= sq_h8; sq++) {
1716     if ((sq % 2) == 0)
1717       cp = (epdptr->epd_nbv[sq >> 1] & nybbM);
1718     else
1719       cp = ((epdptr->epd_nbv[sq >> 1] >> nybbW) & nybbM);
1720     EPDboard.rbv[sq] = cp;
1721   };
1722   ese.ese_actc = epdptr->epd_actc;
1723   ese.ese_cast = epdptr->epd_cast;
1724   ese.ese_epsq = epdptr->epd_epsq;
1725   eopptr = EPDLocateEOPCode(epdptr, epdso_hmvc);
1726   if ((eopptr != NULL) && ((eovptr = eopptr->eop_headeov) != NULL))
1727     ese.ese_hmvc = atoi(eovptr->eov_str);
1728   else
1729     ese.ese_hmvc = 0;
1730   eopptr = EPDLocateEOPCode(epdptr, epdso_fmvn);
1731   if ((eopptr != NULL) && ((eovptr = eopptr->eop_headeov) != NULL))
1732     ese.ese_fmvn = atoi(eovptr->eov_str);
1733   else
1734     ese.ese_fmvn = 1;
1735   EPDSetKings();
1736   return;
1737 }
1738 
1739 /*--> EPDInitArray: set the current position to the initial array */
EPDInitArray(void)1740 nonstatic void EPDInitArray(void) {
1741   sqT sq;
1742 
1743 /* this changes the current position */
1744   for (sq = sq_a1; sq <= sq_h8; sq++)
1745     EPDboard.rbv[sq] = cp_v0;
1746   EPDboard.rbv[sq_a1] = EPDboard.rbv[sq_h1] = cp_wr;
1747   EPDboard.rbv[sq_b1] = EPDboard.rbv[sq_g1] = cp_wn;
1748   EPDboard.rbv[sq_c1] = EPDboard.rbv[sq_f1] = cp_wb;
1749   EPDboard.rbv[sq_d1] = cp_wq;
1750   EPDboard.rbv[sq_e1] = cp_wk;
1751   for (sq = sq_a2; sq <= sq_h2; sq++)
1752     EPDboard.rbv[sq] = cp_wp;
1753   EPDboard.rbv[sq_a8] = EPDboard.rbv[sq_h8] = cp_br;
1754   EPDboard.rbv[sq_b8] = EPDboard.rbv[sq_g8] = cp_bn;
1755   EPDboard.rbv[sq_c8] = EPDboard.rbv[sq_f8] = cp_bb;
1756   EPDboard.rbv[sq_d8] = cp_bq;
1757   EPDboard.rbv[sq_e8] = cp_bk;
1758   for (sq = sq_a7; sq <= sq_h7; sq++)
1759     EPDboard.rbv[sq] = cp_bp;
1760   ese.ese_actc = c_w;
1761   ese.ese_cast = cf_wk | cf_wq | cf_bk | cf_bq;
1762   ese.ese_epsq = sq_nil;
1763   ese.ese_hmvc = 0;
1764   ese.ese_fmvn = 1;
1765   EPDSetKings();
1766   return;
1767 }
1768 
1769 /*--> EPDSANEncodeChar: encode SAN character */
1770 static
EPDSANEncodeChar(char ch)1771 void EPDSANEncodeChar(char ch) {
1772   if ((lsani < (sanL - 1)) || ((ch == '\0') && (lsani < sanL)))
1773     lsan[lsani++] = ch;
1774   else
1775     EPDFatal("EPDSANEncodeChar: overflow");
1776   return;
1777 }
1778 
1779 /*--> EPDSANEncodeStr: encode a SAN string */
1780 static
EPDSANEncodeStr(charptrT s)1781 void EPDSANEncodeStr(charptrT s) {
1782   charptrT p;
1783 
1784   p = s;
1785   while (*p)
1786     EPDSANEncodeChar(*p++);
1787   return;
1788 }
1789 
1790 /*--> EPDSANEncodeFile: encode SAN file from square */
1791 static
EPDSANEncodeFile(sqT sq)1792 void EPDSANEncodeFile(sqT sq) {
1793   EPDSANEncodeChar(ascfv[map_file(sq)]);
1794   return;
1795 }
1796 
1797 /*--> EPDSANEncodeRank: encode SAN rank from square */
1798 static
EPDSANEncodeRank(sqT sq)1799 void EPDSANEncodeRank(sqT sq) {
1800   EPDSANEncodeChar(ascrv[map_rank(sq)]);
1801   return;
1802 }
1803 
1804 /*--> EPDSANEncodeSq: encode SAN square */
1805 static
EPDSANEncodeSq(sqT sq)1806 void EPDSANEncodeSq(sqT sq) {
1807   EPDSANEncodeFile(sq);
1808   EPDSANEncodeRank(sq);
1809   return;
1810 }
1811 
1812 /*--> EPDSANEncodeCI: encode an appropriate capture indicator */
1813 static
EPDSANEncodeCI(siT index)1814 void EPDSANEncodeCI(siT index) {
1815   switch (index) {
1816     case 0:
1817       EPDSANEncodeChar('x');
1818       break;
1819     case 1:
1820       break;
1821     case 2:
1822       EPDSANEncodeChar(':');
1823       break;
1824     case 3:
1825       EPDSANEncodeChar('*');
1826       break;
1827     case 4:
1828       EPDSANEncodeChar('-');
1829       break;
1830   };
1831   return;
1832 }
1833 
1834 /*--> EPDSANEncodeAux: encode SAN format move with variants */
1835 static
EPDSANEncodeAux(mptrT mptr,sanT san,ssavT ssav)1836 void EPDSANEncodeAux(mptrT mptr, sanT san, ssavT ssav) {
1837   siT i;
1838 
1839 /* reset local index */
1840   lsani = 0;
1841 /* busted? */
1842   if (mptr->m_flag & mf_bust)
1843     EPDSANEncodeChar('*');
1844 /* process according to moving piece */
1845   switch (cv_p_cpv[mptr->m_frcp]) {
1846     case p_p:
1847       switch (mptr->m_scmv) {
1848         case scmv_reg:
1849           if (mptr->m_tocp != cp_v0) {
1850             EPDSANEncodeFile(mptr->m_frsq);
1851             if (ssav[ssa_edcr] == 1)
1852               EPDSANEncodeRank(mptr->m_frsq);
1853             EPDSANEncodeCI(ssav[ssa_capt]);
1854             if (ssav[ssa_ptar] == 0)
1855               EPDSANEncodeSq(mptr->m_tosq);
1856             else
1857               EPDSANEncodeFile(mptr->m_tosq);
1858           } else {
1859             EPDSANEncodeFile(mptr->m_frsq);
1860             if (ssav[ssa_edcr] == 1)
1861               EPDSANEncodeRank(mptr->m_frsq);
1862             if (ssav[ssa_move] == 1)
1863               EPDSANEncodeChar('-');
1864             if (ssav[ssa_edcf] == 1)
1865               EPDSANEncodeFile(mptr->m_tosq);
1866             EPDSANEncodeRank(mptr->m_tosq);
1867           };
1868           break;
1869         case scmv_epc:
1870           EPDSANEncodeFile(mptr->m_frsq);
1871           if (ssav[ssa_edcr] == 1)
1872             EPDSANEncodeRank(mptr->m_frsq);
1873           EPDSANEncodeCI(ssav[ssa_capt]);
1874           if (ssav[ssa_ptar] == 0)
1875             EPDSANEncodeSq(mptr->m_tosq);
1876           else
1877             EPDSANEncodeFile(mptr->m_tosq);
1878           if (ssav[ssa_epct] == 1)
1879             EPDSANEncodeStr("ep");
1880           break;
1881         case scmv_ppn:
1882         case scmv_ppb:
1883         case scmv_ppr:
1884         case scmv_ppq:
1885           if (mptr->m_tocp != cp_v0) {
1886             EPDSANEncodeFile(mptr->m_frsq);
1887             if (ssav[ssa_edcr] == 1)
1888               EPDSANEncodeRank(mptr->m_frsq);
1889             EPDSANEncodeCI(ssav[ssa_capt]);
1890             if (ssav[ssa_ptar] == 0)
1891               EPDSANEncodeSq(mptr->m_tosq);
1892             else
1893               EPDSANEncodeFile(mptr->m_tosq);
1894           } else {
1895             EPDSANEncodeFile(mptr->m_frsq);
1896             if (ssav[ssa_edcr] == 1)
1897               EPDSANEncodeRank(mptr->m_frsq);
1898             if (ssav[ssa_move] == 1)
1899               EPDSANEncodeChar('-');
1900             if (ssav[ssa_edcf] == 1)
1901               EPDSANEncodeFile(mptr->m_tosq);
1902             EPDSANEncodeRank(mptr->m_tosq);
1903           };
1904           switch (ssav[ssa_prom]) {
1905             case 0:
1906               EPDSANEncodeChar('=');
1907               EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]);
1908               break;
1909             case 1:
1910               EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]);
1911               break;
1912             case 2:
1913               EPDSANEncodeChar('/');
1914               EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]);
1915               break;
1916             case 3:
1917               EPDSANEncodeChar('(');
1918               EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]);
1919               EPDSANEncodeChar(')');
1920               break;
1921           };
1922           break;
1923       };
1924       break;
1925     case p_n:
1926     case p_b:
1927     case p_r:
1928     case p_q:
1929       EPDSANEncodeChar(ascpv[cv_p_cpv[mptr->m_frcp]]);
1930       if (((mptr->m_flag & mf_sanf) || (ssav[ssa_edcf] == 1))
1931           || ((mptr->m_flag & mf_sanr) && (ssav[ssa_edcf] == 2)))
1932         EPDSANEncodeFile(mptr->m_frsq);
1933       if (((mptr->m_flag & mf_sanr) || (ssav[ssa_edcr] == 1))
1934           || ((mptr->m_flag & mf_sanf) && (ssav[ssa_edcr] == 2)))
1935         EPDSANEncodeRank(mptr->m_frsq);
1936       if (mptr->m_tocp != cp_v0)
1937         EPDSANEncodeCI(ssav[ssa_capt]);
1938       else if (ssav[ssa_move] == 1)
1939         EPDSANEncodeChar('-');
1940       EPDSANEncodeSq(mptr->m_tosq);
1941       break;
1942     case p_k:
1943       switch (mptr->m_scmv) {
1944         case scmv_reg:
1945           EPDSANEncodeChar(ascpv[p_k]);
1946           if (ssav[ssa_edcf] == 1)
1947             EPDSANEncodeFile(mptr->m_frsq);
1948           if (ssav[ssa_edcr] == 1)
1949             EPDSANEncodeRank(mptr->m_frsq);
1950           if (mptr->m_tocp != cp_v0)
1951             EPDSANEncodeCI(ssav[ssa_capt]);
1952           else if (ssav[ssa_move] == 1)
1953             EPDSANEncodeChar('-');
1954           EPDSANEncodeSq(mptr->m_tosq);
1955           break;
1956         case scmv_cks:
1957           switch (ssav[ssa_cast]) {
1958             case 0:
1959               EPDSANEncodeStr("O-O");
1960               break;
1961             case 1:
1962               EPDSANEncodeStr("0-0");
1963               break;
1964             case 2:
1965               EPDSANEncodeStr("OO");
1966               break;
1967             case 3:
1968               EPDSANEncodeStr("00");
1969               break;
1970             case 4:
1971               EPDSANEncodeChar(ascpv[p_k]);
1972               if (ssav[ssa_edcf] == 1)
1973                 EPDSANEncodeFile(mptr->m_frsq);
1974               if (ssav[ssa_edcr] == 1)
1975                 EPDSANEncodeRank(mptr->m_frsq);
1976               if (ssav[ssa_move] == 1)
1977                 EPDSANEncodeChar('-');
1978               EPDSANEncodeSq(mptr->m_tosq);
1979               break;
1980           };
1981           break;
1982         case scmv_cqs:
1983           switch (ssav[ssa_cast]) {
1984             case 0:
1985               EPDSANEncodeStr("O-O-O");
1986               break;
1987             case 1:
1988               EPDSANEncodeStr("0-0-0");
1989               break;
1990             case 2:
1991               EPDSANEncodeStr("OOO");
1992               break;
1993             case 3:
1994               EPDSANEncodeStr("000");
1995               break;
1996             case 4:
1997               EPDSANEncodeChar(ascpv[p_k]);
1998               if (ssav[ssa_edcf] == 1)
1999                 EPDSANEncodeFile(mptr->m_frsq);
2000               if (ssav[ssa_edcr] == 1)
2001                 EPDSANEncodeRank(mptr->m_frsq);
2002               if (ssav[ssa_move] == 1)
2003                 EPDSANEncodeChar('-');
2004               EPDSANEncodeSq(mptr->m_tosq);
2005               break;
2006           };
2007           break;
2008       };
2009       break;
2010   };
2011 /* insert markers */
2012   if ((mptr->m_flag & mf_chec) && !(mptr->m_flag & mf_chmt))
2013     switch (ssav[ssa_chec]) {
2014       case 0:
2015         EPDSANEncodeChar('+');
2016         break;
2017       case 1:
2018         break;
2019       case 2:
2020         EPDSANEncodeStr("ch");
2021         break;
2022     };
2023   if (mptr->m_flag & mf_chmt)
2024     switch (ssav[ssa_chmt]) {
2025       case 0:
2026         EPDSANEncodeChar('#');
2027         break;
2028       case 1:
2029         break;
2030       case 2:
2031         EPDSANEncodeChar('+');
2032         break;
2033       case 3:
2034         EPDSANEncodeStr("++");
2035         break;
2036     };
2037   if (mptr->m_flag & mf_draw)
2038     if (ssav[ssa_draw] == 1)
2039       EPDSANEncodeChar('=');
2040 /* map to lower case if indicated */
2041   if (ssav[ssa_case] == 1)
2042     for (i = 0; i < lsani; i++)
2043       lsan[i] = map_lower(lsan[i]);
2044 /* pad and copy */
2045   while (lsani < sanL)
2046     EPDSANEncodeChar('\0');
2047   for (i = 0; i < sanL; i++)
2048     san[i] = lsan[i];
2049   return;
2050 }
2051 
2052 /*--> EPDSANEncode: encode a move into a SAN string */
EPDSANEncode(mptrT mptr,sanT san)2053 nonstatic void EPDSANEncode(mptrT mptr, sanT san) {
2054   ssaT ssa;
2055   ssavT ssav;
2056 
2057 /* select canonical encoding (zero point in variant space) */
2058   for (ssa = 0; ssa < ssaL; ssa++)
2059     ssav[ssa] = 0;
2060   EPDSANEncodeAux(mptr, san, ssav);
2061   return;
2062 }
2063 
2064 /*--> EPDSANDecodeBump: increment a style vector and return overflow */
EPDSANDecodeBump(ssavT ssav,ssavT bssav)2065 static siT EPDSANDecodeBump(ssavT ssav, ssavT bssav) {
2066   siT flag;
2067   ssaT ssa;
2068 
2069   flag = 1;
2070   ssa = 0;
2071   while (flag && (ssa < ssaL)) {
2072     flag = 0;
2073     ssav[ssa]++;
2074     if (ssav[ssa] == bssav[ssa]) {
2075       flag = 1;
2076       ssav[ssa] = 0;
2077     };
2078     ssa++;
2079   };
2080   return flag;
2081 }
2082 
2083 /*--> EPDSANDecodeFlex: locate a move from SAN (flexible interpretation) */
EPDSANDecodeFlex(sanT san)2084 static mptrT EPDSANDecodeFlex(sanT san) {
2085   mptrT mptr;
2086   ssavT ssav, bssav;
2087   siT i, flag;
2088   mptrT rmptr;
2089   sanT lcsan, rsan;
2090 
2091 /* set default return value */
2092   mptr = NULL;
2093 /* set minimal upper bounds */
2094   for (i = 0; i < ssaL; i++)
2095     bssav[i] = 1;
2096 /* scan for upper bound conditions */
2097   rmptr = tse.tse_base;
2098   for (i = 0; i < tse.tse_count; i++) {
2099 /* letter case */
2100     bssav[ssa_case] = 2;
2101 /* capturing */
2102     if ((rmptr->m_tocp != cp_v0) || (rmptr->m_scmv == scmv_epc))
2103       bssav[ssa_capt] = 5;
2104 /* checking */
2105     if (rmptr->m_flag & mf_chec)
2106       bssav[ssa_chec] = 3;
2107 /* castling */
2108     if ((rmptr->m_scmv == scmv_cks) || (rmptr->m_scmv == scmv_cqs))
2109       bssav[ssa_cast] = 5;
2110 /* promoting */
2111     if ((rmptr->m_scmv == scmv_ppn) || (rmptr->m_scmv == scmv_ppb)
2112         || (rmptr->m_scmv == scmv_ppr) || (rmptr->m_scmv == scmv_ppq))
2113       bssav[ssa_prom] = 4;
2114 /* pawn destination target */
2115     if (cv_p_cpv[rmptr->m_frcp] == p_p)
2116       bssav[ssa_ptar] = 2;
2117 /* checkmating */
2118     if (rmptr->m_flag & mf_chmt)
2119       bssav[ssa_chmt] = 4;
2120 /* en passant capturing */
2121     if (rmptr->m_scmv == scmv_epc)
2122       bssav[ssa_epct] = 2;
2123 /* drawing */
2124     if (rmptr->m_flag & mf_draw)
2125       bssav[ssa_draw] = 2;
2126 /* moving (non-capturing) */
2127     if ((rmptr->m_tocp == cp_v0) && (rmptr->m_scmv != scmv_epc))
2128       bssav[ssa_move] = 2;
2129 /* extra disambiguation: file */
2130     if (!(rmptr->m_flag & mf_sanf))
2131       bssav[ssa_edcf] = 3;
2132 /* extra disambiguation: rank */
2133     if (!(rmptr->m_flag & mf_sanr))
2134       bssav[ssa_edcr] = 3;
2135     rmptr++;
2136   };
2137 /* make a lower case copy of the input */
2138   for (i = 0; i < sanL; i++)
2139     lcsan[i] = map_lower(san[i]);
2140 /* initialize the index style vector */
2141   for (i = 0; i < ssaL; i++)
2142     ssav[i] = 0;
2143 /* search */
2144   flag = 0;
2145   while (!flag && (mptr == NULL)) {
2146     rmptr = tse.tse_base;
2147     i = 0;
2148 /* scan candidate moves */
2149     while ((mptr == NULL) && (i < tse.tse_count)) {
2150 /* encode the current style version of a candidate */
2151       EPDSANEncodeAux(rmptr, rsan, ssav);
2152 /* select either original or lower case comparison */
2153       if (ssav[ssa_case] == 0) {
2154         if (strcmp(san, rsan) == 0)
2155           mptr = rmptr;
2156       } else {
2157         if (strcmp(lcsan, rsan) == 0)
2158           mptr = rmptr;
2159       };
2160 /* next candidate */
2161       rmptr++;
2162       i++;
2163     };
2164 /* update the overflow termination flag */
2165     flag = EPDSANDecodeBump(ssav, bssav);
2166   };
2167   return mptr;
2168 }
2169 
2170 /*--> EPDSANDecode: locate a move from SAN (strict interpretation) */
EPDSANDecode(sanT san)2171 static mptrT EPDSANDecode(sanT san) {
2172   mptrT mptr;
2173   mptrT rmptr;
2174   sanT rsan;
2175   siT i;
2176 
2177 /* set default return value */
2178   mptr = NULL;
2179 /* assume current moveset properly generated */
2180   rmptr = tse.tse_base;
2181   i = 0;
2182 /* search */
2183   while ((mptr == NULL) && (i < tse.tse_count)) {
2184     EPDSANEncode(rmptr, rsan);
2185     if (strcmp(san, rsan) == 0)
2186       mptr = rmptr;
2187     else {
2188       rmptr++;
2189       i++;
2190     };
2191   };
2192   return mptr;
2193 }
2194 
2195 /*--> EPDSANDecodeAux: locate a move from SAN */
EPDSANDecodeAux(sanT san,siT strict)2196 nonstatic mptrT EPDSANDecodeAux(sanT san, siT strict) {
2197   mptrT mptr;
2198 
2199   if (strict)
2200     mptr = EPDSANDecode(san);
2201   else
2202     mptr = EPDSANDecodeFlex(san);
2203   return mptr;
2204 }
2205 
2206 /*--> EPDAttack: determine if a color attacks a square */
EPDAttack(cT c,sqT sq)2207 static siT EPDAttack(cT c, sqT sq) {
2208   siT flag;
2209   dxT dx;
2210   dvT dv;
2211   xdvT xdv;
2212   sqptrT sqptr0, sqptr1;
2213   xsqptrT xsqptr0, xsqptr1;
2214 
2215 /* clear result */
2216   flag = 0;
2217 /* set origin square pointers  */
2218   sqptr0 = &EPDboard.rbv[sq];
2219   xsqptr0 = &xb.xbv[map_xsq_sq(sq)];
2220 /* process according to specified color */
2221   if (c == c_w) {
2222 /* pawn attacks */
2223     if ((*(xsqptr0 + xdv_7) == cp_v0) && (*(sqptr0 + dv_7) == cp_wp))
2224       flag = 1;
2225     else if ((*(xsqptr0 + xdv_6) == cp_v0) && (*(sqptr0 + dv_6) == cp_wp))
2226       flag = 1;
2227 /* knight attacks */
2228     if (!flag) {
2229       dx = dx_8;
2230       while (!flag && (dx <= dx_f))
2231         if ((*(xsqptr0 + xdvv[dx]) == cp_v0)
2232             && (*(sqptr0 + dvv[dx]) == cp_wn))
2233           flag = 1;
2234         else
2235           dx++;
2236     };
2237 /* orthogonal sweeps */
2238     if (!flag) {
2239       dx = dx_0;
2240       while (!flag && (dx <= dx_3)) {
2241         dv = dvv[dx];
2242         xdv = xdvv[dx];
2243         sqptr1 = sqptr0;
2244         xsqptr1 = xsqptr0;
2245         while ((*(xsqptr1 += xdv) == cp_v0) && (*(sqptr1 += dv) == cp_v0));
2246         if ((*xsqptr1 == cp_v0) && ((*sqptr1 == cp_wq) || (*sqptr1 == cp_wr)))
2247           flag = 1;
2248         else
2249           dx++;
2250       };
2251     };
2252 /* diagonal sweeps */
2253     if (!flag) {
2254       dx = dx_4;
2255       while (!flag && (dx <= dx_7)) {
2256         dv = dvv[dx];
2257         xdv = xdvv[dx];
2258         sqptr1 = sqptr0;
2259         xsqptr1 = xsqptr0;
2260         while ((*(xsqptr1 += xdv) == cp_v0) && (*(sqptr1 += dv) == cp_v0));
2261         if ((*xsqptr1 == cp_v0) && ((*sqptr1 == cp_wq) || (*sqptr1 == cp_wb)))
2262           flag = 1;
2263         else
2264           dx++;
2265       };
2266     };
2267 /* king attacks */
2268     if (!flag) {
2269       dx = dx_0;
2270       while (!flag && (dx <= dx_7))
2271         if ((*(xsqptr0 + xdvv[dx]) == cp_v0)
2272             && (*(sqptr0 + dvv[dx]) == cp_wk))
2273           flag = 1;
2274         else
2275           dx++;
2276     };
2277   } else {
2278 /* pawn attacks */
2279     if ((*(xsqptr0 + xdv_4) == cp_v0) && (*(sqptr0 + dv_4) == cp_bp))
2280       flag = 1;
2281     else if ((*(xsqptr0 + xdv_5) == cp_v0) && (*(sqptr0 + dv_5) == cp_bp))
2282       flag = 1;
2283 /* knight attacks */
2284     if (!flag) {
2285       dx = dx_8;
2286       while (!flag && (dx <= dx_f))
2287         if ((*(xsqptr0 + xdvv[dx]) == cp_v0)
2288             && (*(sqptr0 + dvv[dx]) == cp_bn))
2289           flag = 1;
2290         else
2291           dx++;
2292     };
2293 /* orthogonal sweeps */
2294     if (!flag) {
2295       dx = dx_0;
2296       while (!flag && (dx <= dx_3)) {
2297         dv = dvv[dx];
2298         xdv = xdvv[dx];
2299         sqptr1 = sqptr0;
2300         xsqptr1 = xsqptr0;
2301         while ((*(xsqptr1 += xdv) == cp_v0) && (*(sqptr1 += dv) == cp_v0));
2302         if ((*xsqptr1 == cp_v0) && ((*sqptr1 == cp_bq) || (*sqptr1 == cp_br)))
2303           flag = 1;
2304         else
2305           dx++;
2306       };
2307     };
2308 /* diagonal sweeps */
2309     if (!flag) {
2310       dx = dx_4;
2311       while (!flag && (dx <= dx_7)) {
2312         dv = dvv[dx];
2313         xdv = xdvv[dx];
2314         sqptr1 = sqptr0;
2315         xsqptr1 = xsqptr0;
2316         while ((*(xsqptr1 += xdv) == cp_v0) && (*(sqptr1 += dv) == cp_v0));
2317         if ((*xsqptr1 == cp_v0) && ((*sqptr1 == cp_bq) || (*sqptr1 == cp_bb)))
2318           flag = 1;
2319         else
2320           dx++;
2321       };
2322     };
2323 /* king attacks */
2324     if (!flag) {
2325       dx = dx_0;
2326       while (!flag && (dx <= dx_7))
2327         if ((*(xsqptr0 + xdvv[dx]) == cp_v0)
2328             && (*(sqptr0 + dvv[dx]) == cp_bk))
2329           flag = 1;
2330         else
2331           dx++;
2332     };
2333   };
2334   return flag;
2335 }
2336 
2337 /*--> EPDWhiteAttacks: check if White attacks a square */
EPDWhiteAttacks(sqT sq)2338 static siT EPDWhiteAttacks(sqT sq) {
2339   return EPDAttack(c_w, sq);
2340 }
2341 
2342 /*--> EPDBlackAttacks: check if White attacks a square */
EPDBlackAttacks(sqT sq)2343 static siT EPDBlackAttacks(sqT sq) {
2344   return EPDAttack(c_b, sq);
2345 }
2346 
2347 /*--> EPDTestAKIC: test for active king in check */
EPDTestAKIC(void)2348 static siT EPDTestAKIC(void) {
2349   siT flag;
2350 
2351   if (ese.ese_actc == c_w)
2352     flag = EPDBlackAttacks(ese.ese_ksqv[c_w]);
2353   else
2354     flag = EPDWhiteAttacks(ese.ese_ksqv[c_b]);
2355   return flag;
2356 }
2357 
2358 /*--> EPDTestPKIC: test for passive king in check */
EPDTestPKIC(void)2359 static siT EPDTestPKIC(void) {
2360   siT flag;
2361 
2362   if (ese.ese_actc == c_b)
2363     flag = EPDBlackAttacks(ese.ese_ksqv[c_w]);
2364   else
2365     flag = EPDWhiteAttacks(ese.ese_ksqv[c_b]);
2366   return flag;
2367 }
2368 
2369 /*--> EPDCensus: calculate local census vectors */
2370 static
EPDCensus(void)2371 void EPDCensus(void) {
2372   cT c;
2373   pT p;
2374   sqT sq;
2375   cpT cp;
2376 
2377 /* clear census vectors */
2378   for (c = c_w; c <= c_b; c++) {
2379     count_cv[c] = 0;
2380     for (p = p_p; p <= p_k; p++)
2381       count_cpv[c][p] = 0;
2382   };
2383 /* calculate census vectors */
2384   for (sq = sq_a1; sq <= sq_h8; sq++) {
2385     cp = EPDboard.rbv[sq];
2386     if (cp != cp_v0) {
2387       c = cv_c_cpv[cp];
2388       count_cv[c]++;
2389       count_cpv[c][cv_p_cpv[cp]]++;
2390     };
2391   };
2392   return;
2393 }
2394 
2395 /*--> EPDIsLegal: determine if current position is legal */
EPDIsLegal(void)2396 nonstatic siT EPDIsLegal(void) {
2397   siT flag;
2398   cT c;
2399   fileT file;
2400   siT apv[rcL];
2401 
2402 /* set default return value: legal position */
2403   flag = 1;
2404 /* calculate the local census vectors */
2405   EPDCensus();
2406 /* calculate available promoted pawns */
2407   for (c = c_w; c <= c_b; c++)
2408     apv[c] = fileL - count_cpv[c][p_p];
2409 /* check white pawn count */
2410   if (flag && (count_cpv[c_w][p_p] > fileL))
2411     flag = 0;
2412 /* check black pawn count */
2413   if (flag && (count_cpv[c_b][p_p] > fileL))
2414     flag = 0;
2415 /* check white knight count */
2416   if (flag && (count_cpv[c_w][p_n] > 2)) {
2417     apv[c_w] -= (count_cpv[c_w][p_n] - 2);
2418     if (apv[c_w] < 0)
2419       flag = 0;
2420   };
2421 /* check black knight count */
2422   if (flag && (count_cpv[c_b][p_n] > 2)) {
2423     apv[c_b] -= (count_cpv[c_b][p_n] - 2);
2424     if (apv[c_b] < 0)
2425       flag = 0;
2426   };
2427 /* check white bishop count */
2428   if (flag && (count_cpv[c_w][p_b] > 2)) {
2429     apv[c_w] -= (count_cpv[c_w][p_b] - 2);
2430     if (apv[c_w] < 0)
2431       flag = 0;
2432   };
2433 /* check black bishop count */
2434   if (flag && (count_cpv[c_b][p_b] > 2)) {
2435     apv[c_b] -= (count_cpv[c_b][p_b] - 2);
2436     if (apv[c_b] < 0)
2437       flag = 0;
2438   };
2439 /* check white rook count */
2440   if (flag && (count_cpv[c_w][p_r] > 2)) {
2441     apv[c_w] -= (count_cpv[c_w][p_r] - 2);
2442     if (apv[c_w] < 0)
2443       flag = 0;
2444   };
2445 /* check black rook count */
2446   if (flag && (count_cpv[c_b][p_r] > 2)) {
2447     apv[c_b] -= (count_cpv[c_b][p_r] - 2);
2448     if (apv[c_b] < 0)
2449       flag = 0;
2450   };
2451 /* check white queen count */
2452   if (flag && (count_cpv[c_w][p_q] > 1)) {
2453     apv[c_w] -= (count_cpv[c_w][p_q] - 1);
2454     if (apv[c_w] < 0)
2455       flag = 0;
2456   };
2457 /* check black queen count */
2458   if (flag && (count_cpv[c_b][p_q] > 1)) {
2459     apv[c_b] -= (count_cpv[c_b][p_q] - 1);
2460     if (apv[c_b] < 0)
2461       flag = 0;
2462   };
2463 /* check white king count */
2464   if (flag && (count_cpv[c_w][p_k] != 1))
2465     flag = 0;
2466 /* check black king count */
2467   if (flag && (count_cpv[c_b][p_k] != 1))
2468     flag = 0;
2469 /* check pawn placement */
2470   if (flag) {
2471     file = file_a;
2472     while (flag && (file <= file_h))
2473       if ((EPDboard.rbm[rank_1][file] == cp_wp)
2474           || (EPDboard.rbm[rank_1][file] == cp_bp)
2475           || (EPDboard.rbm[rank_8][file] == cp_wp)
2476           || (EPDboard.rbm[rank_8][file] == cp_bp))
2477         flag = 0;
2478       else
2479         file++;
2480   };
2481 /* check white kingside castling availability */
2482   if (flag && (ese.ese_cast & cf_wk))
2483     if ((EPDboard.rbv[sq_e1] != cp_wk) || (EPDboard.rbv[sq_h1] != cp_wr))
2484       flag = 0;
2485 /* check white queenside castling availability */
2486   if (flag && (ese.ese_cast & cf_wq))
2487     if ((EPDboard.rbv[sq_e1] != cp_wk) || (EPDboard.rbv[sq_a1] != cp_wr))
2488       flag = 0;
2489 /* check black kingside castling availability */
2490   if (flag && (ese.ese_cast & cf_bk))
2491     if ((EPDboard.rbv[sq_e8] != cp_bk) || (EPDboard.rbv[sq_h8] != cp_br))
2492       flag = 0;
2493 /* check black queenside castling availability */
2494   if (flag && (ese.ese_cast & cf_bq))
2495     if ((EPDboard.rbv[sq_e8] != cp_bk) || (EPDboard.rbv[sq_a8] != cp_br))
2496       flag = 0;
2497 /* check en passant target square */
2498   if (flag && (ese.ese_epsq != sq_nil)) {
2499     if (ese.ese_actc == c_w) {
2500       if (map_rank(ese.ese_epsq) != rank_6)
2501         flag = 0;
2502       else if (EPDboard.rbv[ese.ese_epsq + dv_3] != cp_bp)
2503         flag = 0;
2504       else if (EPDboard.rbv[ese.ese_epsq] != cp_v0)
2505         flag = 0;
2506       else if (EPDboard.rbv[ese.ese_epsq + dv_1] != cp_v0)
2507         flag = 0;
2508     } else {
2509       if (map_rank(ese.ese_epsq) != rank_3)
2510         flag = 0;
2511       else if (EPDboard.rbv[ese.ese_epsq + dv_1] != cp_wp)
2512         flag = 0;
2513       else if (EPDboard.rbv[ese.ese_epsq] != cp_v0)
2514         flag = 0;
2515       else if (EPDboard.rbv[ese.ese_epsq + dv_3] != cp_v0)
2516         flag = 0;
2517     }
2518   }
2519 /* check for passive king in check */
2520   if (flag && EPDTestPKIC())
2521     flag = 0;
2522   return flag;
2523 }
2524 
2525 /*--> EPDGeneratePL: generate psuedolegal moves */
2526 static
EPDGeneratePL(void)2527 void EPDGeneratePL(void) {
2528   dxT dx;
2529   dvT dv;
2530   xdvT xdv;
2531   xsqptrT xsqptr0, xsqptr1;
2532   fileT frfile;
2533   rankT frrank;
2534   mT gen_m;
2535 
2536 /* set up the generation base */
2537   if (ply == 0)
2538     treeptr = tse.tse_base = treebaseptr;
2539   else
2540     treeptr = tse.tse_base = (tseptr - 1)->tse_base + (tseptr - 1)->tse_count;
2541 /* test against safety margin */
2542   if ((treeptr - treebaseptr) >= (treeL - treemarginL))
2543     EPDFatal("EPDGeneratePL: move tree size safety limit exceeded");
2544 /* set up current generation items */
2545   tse.tse_curr = treeptr;
2546   tse.tse_count = 0;
2547 /* set the psuedoinvariant generated move template components */
2548   gen_m.m_scmv = scmv_reg;
2549   gen_m.m_flag = 0;
2550 /* look at each origin square of the active color */
2551   for (gen_m.m_frsq = sq_a1; gen_m.m_frsq <= sq_h8; gen_m.m_frsq++) {
2552 /* get origin square and moving piece */
2553     gen_m.m_frcp = EPDboard.rbv[gen_m.m_frsq];
2554 /* continue if it is an active piece */
2555     if (cv_c_cpv[gen_m.m_frcp] == ese.ese_actc) {
2556 /* generate moves for active color piece */
2557       xsqptr0 = &xb.xbv[map_xsq_sq(gen_m.m_frsq)];
2558       switch (cv_p_cpv[gen_m.m_frcp]) {
2559         case p_p:
2560 /* pawn moves: a bit tricky; colors done separately */
2561           frfile = map_file(gen_m.m_frsq);
2562           frrank = map_rank(gen_m.m_frsq);
2563           if (ese.ese_actc == c_w) {
2564 /* one square non-capture */
2565             gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq = gen_m.m_frsq + dv_1];
2566             if (gen_m.m_tocp == cp_v0) {
2567               if (frrank != rank_7) {
2568 /* non-promotion */
2569                 *treeptr++ = gen_m;
2570                 tse.tse_count++;
2571               } else {
2572 /* promotion */
2573                 for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq;
2574                     gen_m.m_scmv++) {
2575                   *treeptr++ = gen_m;
2576                   tse.tse_count++;
2577                 }
2578                 gen_m.m_scmv = scmv_reg;
2579               };
2580             }
2581 /* two squares forward */
2582             if ((frrank == rank_2) && Vacant(gen_m.m_frsq + dv_1)
2583                 && Vacant(gen_m.m_frsq + (2 * dv_1))) {
2584               gen_m.m_tosq = gen_m.m_frsq + (2 * dv_1);
2585               gen_m.m_tocp = cp_v0;
2586               *treeptr++ = gen_m;
2587               tse.tse_count++;
2588             };
2589 /* capture to left */
2590             if (frfile != file_a) {
2591               gen_m.m_tosq = gen_m.m_frsq + dv_5;
2592               gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq];
2593               if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]) {
2594                 if (frrank != rank_7) {
2595 /* non-promote */
2596                   *treeptr++ = gen_m;
2597                   tse.tse_count++;
2598                 } else {
2599 /* promote */
2600                   for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq;
2601                       gen_m.m_scmv++) {
2602                     *treeptr++ = gen_m;
2603                     tse.tse_count++;
2604                   };
2605                   gen_m.m_scmv = scmv_reg;
2606                 };
2607               }
2608             };
2609 /* capture to right */
2610             if (frfile != file_h) {
2611               gen_m.m_tosq = gen_m.m_frsq + dv_4;
2612               gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq];
2613               if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]) {
2614                 if (frrank != rank_7) {
2615 /* non-promote */
2616                   *treeptr++ = gen_m;
2617                   tse.tse_count++;
2618                 } else {
2619 /* promote */
2620                   for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq;
2621                       gen_m.m_scmv++) {
2622                     *treeptr++ = gen_m;
2623                     tse.tse_count++;
2624                   };
2625                   gen_m.m_scmv = scmv_reg;
2626                 };
2627               }
2628             };
2629 /* en passant */
2630             if ((frrank == rank_5) && (ese.ese_epsq != sq_nil)) {
2631 /* capture to left */
2632               if ((frfile != file_a)
2633                   && ((gen_m.m_tosq = gen_m.m_frsq + dv_5) == ese.ese_epsq)) {
2634                 gen_m.m_tocp = cp_v0;
2635                 gen_m.m_scmv = scmv_epc;
2636                 *treeptr++ = gen_m;
2637                 tse.tse_count++;
2638                 gen_m.m_scmv = scmv_reg;
2639               };
2640 /* capture to right */
2641               if ((frfile != file_h)
2642                   && ((gen_m.m_tosq = gen_m.m_frsq + dv_4) == ese.ese_epsq)) {
2643                 gen_m.m_tocp = cp_v0;
2644                 gen_m.m_scmv = scmv_epc;
2645                 *treeptr++ = gen_m;
2646                 tse.tse_count++;
2647                 gen_m.m_scmv = scmv_reg;
2648               };
2649             };
2650           } else {
2651 /* one square non-capture */
2652             gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq = gen_m.m_frsq + dv_3];
2653             if (gen_m.m_tocp == cp_v0) {
2654               if (frrank != rank_2) {
2655 /* non-promotion */
2656                 *treeptr++ = gen_m;
2657                 tse.tse_count++;
2658               } else {
2659 /* promotion */
2660                 for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq;
2661                     gen_m.m_scmv++) {
2662                   *treeptr++ = gen_m;
2663                   tse.tse_count++;
2664                 }
2665                 gen_m.m_scmv = scmv_reg;
2666               };
2667             }
2668 /* two squares forward */
2669             if ((frrank == rank_7) && Vacant(gen_m.m_frsq + dv_3)
2670                 && Vacant(gen_m.m_frsq + (2 * dv_3))) {
2671               gen_m.m_tosq = gen_m.m_frsq + (2 * dv_3);
2672               gen_m.m_tocp = cp_v0;
2673               *treeptr++ = gen_m;
2674               tse.tse_count++;
2675             };
2676 /* capture to left */
2677             if (frfile != file_a) {
2678               gen_m.m_tosq = gen_m.m_frsq + dv_6;
2679               gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq];
2680               if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]) {
2681                 if (frrank != rank_2) {
2682 /* non-promote */
2683                   *treeptr++ = gen_m;
2684                   tse.tse_count++;
2685                 } else {
2686 /* promote */
2687                   for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq;
2688                       gen_m.m_scmv++) {
2689                     *treeptr++ = gen_m;
2690                     tse.tse_count++;
2691                   };
2692                   gen_m.m_scmv = scmv_reg;
2693                 };
2694               }
2695             };
2696 /* capture to right */
2697             if (frfile != file_h) {
2698               gen_m.m_tosq = gen_m.m_frsq + dv_7;
2699               gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq];
2700               if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]) {
2701                 if (frrank != rank_2) {
2702 /* non-promote */
2703                   *treeptr++ = gen_m;
2704                   tse.tse_count++;
2705                 } else {
2706 /* promote */
2707                   for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq;
2708                       gen_m.m_scmv++) {
2709                     *treeptr++ = gen_m;
2710                     tse.tse_count++;
2711                   };
2712                   gen_m.m_scmv = scmv_reg;
2713                 };
2714               }
2715             };
2716 /* en passant */
2717             if ((frrank == rank_4) && (ese.ese_epsq != sq_nil)) {
2718 /* capture to left */
2719               if ((frfile != file_a)
2720                   && ((gen_m.m_tosq = gen_m.m_frsq + dv_6) == ese.ese_epsq)) {
2721                 gen_m.m_tocp = cp_v0;
2722                 gen_m.m_scmv = scmv_epc;
2723                 *treeptr++ = gen_m;
2724                 tse.tse_count++;
2725                 gen_m.m_scmv = scmv_reg;
2726               };
2727 /* capture to right */
2728               if ((frfile != file_h)
2729                   && ((gen_m.m_tosq = gen_m.m_frsq + dv_7) == ese.ese_epsq)) {
2730                 gen_m.m_tocp = cp_v0;
2731                 gen_m.m_scmv = scmv_epc;
2732                 *treeptr++ = gen_m;
2733                 tse.tse_count++;
2734                 gen_m.m_scmv = scmv_reg;
2735               };
2736             };
2737           };
2738           break;
2739         case p_n:
2740 /* knight moves: very simple */
2741           for (dx = dx_8; dx <= dx_f; dx++)
2742             if (*(xsqptr0 + xdvv[dx]) == cp_v0) {
2743               gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq =
2744                   gen_m.m_frsq + dvv[dx]];
2745               if (cv_c_cpv[gen_m.m_tocp] != ese.ese_actc) {
2746                 *treeptr++ = gen_m;
2747                 tse.tse_count++;
2748               };
2749             };
2750           break;
2751         case p_b:
2752 /* bishop moves: diagonal sweeper */
2753           for (dx = dx_4; dx <= dx_7; dx++) {
2754             dv = dvv[dx];
2755             xdv = xdvv[dx];
2756             gen_m.m_tosq = gen_m.m_frsq;
2757             xsqptr1 = xsqptr0;
2758             while ((*(xsqptr1 += xdv) == cp_v0)
2759                 && ((gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq +=
2760                             dv]) == cp_v0)) {
2761               *treeptr++ = gen_m;
2762               tse.tse_count++;
2763             };
2764             if ((*xsqptr1 == cp_v0)
2765                 && (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc])) {
2766               *treeptr++ = gen_m;
2767               tse.tse_count++;
2768             };
2769           };
2770           break;
2771         case p_r:
2772 /* rook moves: orthogonal sweeper */
2773           for (dx = dx_0; dx <= dx_3; dx++) {
2774             dv = dvv[dx];
2775             xdv = xdvv[dx];
2776             gen_m.m_tosq = gen_m.m_frsq;
2777             xsqptr1 = xsqptr0;
2778             while ((*(xsqptr1 += xdv) == cp_v0)
2779                 && ((gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq +=
2780                             dv]) == cp_v0)) {
2781               *treeptr++ = gen_m;
2782               tse.tse_count++;
2783             };
2784             if ((*xsqptr1 == cp_v0)
2785                 && (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc])) {
2786               *treeptr++ = gen_m;
2787               tse.tse_count++;
2788             };
2789           };
2790           break;
2791         case p_q:
2792 /* queen moves: orthogonal and diagonal sweeper */
2793           for (dx = dx_0; dx <= dx_7; dx++) {
2794             dv = dvv[dx];
2795             xdv = xdvv[dx];
2796             gen_m.m_tosq = gen_m.m_frsq;
2797             xsqptr1 = xsqptr0;
2798             while ((*(xsqptr1 += xdv) == cp_v0)
2799                 && ((gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq +=
2800                             dv]) == cp_v0)) {
2801               *treeptr++ = gen_m;
2802               tse.tse_count++;
2803             };
2804             if ((*xsqptr1 == cp_v0)
2805                 && (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc])) {
2806               *treeptr++ = gen_m;
2807               tse.tse_count++;
2808             };
2809           };
2810           break;
2811         case p_k:
2812 /* king moves: one square adjacent regular */
2813           for (dx = dx_0; dx <= dx_7; dx++)
2814             if (*(xsqptr0 + xdvv[dx]) == cp_v0) {
2815               gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq =
2816                   gen_m.m_frsq + dvv[dx]];
2817               if (cv_c_cpv[gen_m.m_tocp] != ese.ese_actc) {
2818                 *treeptr++ = gen_m;
2819                 tse.tse_count++;
2820               };
2821             };
2822 /* castling; process according to active color */
2823           if (ese.ese_actc == c_w) {
2824             if ((ese.ese_cast & cf_wk) && !EPDBlackAttacks(sq_e1)
2825                 && Vacant(sq_f1)
2826                 && !EPDBlackAttacks(sq_f1) && Vacant(sq_g1)
2827                 && !EPDBlackAttacks(sq_g1)) {
2828               gen_m.m_tosq = sq_g1;
2829               gen_m.m_tocp = cp_v0;
2830               gen_m.m_scmv = scmv_cks;
2831               *treeptr++ = gen_m;
2832               tse.tse_count++;
2833               gen_m.m_scmv = scmv_reg;
2834             };
2835             if ((ese.ese_cast & cf_wq) && !EPDBlackAttacks(sq_e1)
2836                 && Vacant(sq_d1)
2837                 && !EPDBlackAttacks(sq_d1) && Vacant(sq_c1)
2838                 && !EPDBlackAttacks(sq_c1) && Vacant(sq_b1)) {
2839               gen_m.m_tosq = sq_c1;
2840               gen_m.m_tocp = cp_v0;
2841               gen_m.m_scmv = scmv_cqs;
2842               *treeptr++ = gen_m;
2843               tse.tse_count++;
2844               gen_m.m_scmv = scmv_reg;
2845             };
2846           } else {
2847             if ((ese.ese_cast & cf_bk) && !EPDWhiteAttacks(sq_e8)
2848                 && Vacant(sq_f8)
2849                 && !EPDWhiteAttacks(sq_f8) && Vacant(sq_g8)
2850                 && !EPDWhiteAttacks(sq_g8)) {
2851               gen_m.m_tosq = sq_g8;
2852               gen_m.m_tocp = cp_v0;
2853               gen_m.m_scmv = scmv_cks;
2854               *treeptr++ = gen_m;
2855               tse.tse_count++;
2856               gen_m.m_scmv = scmv_reg;
2857             };
2858             if ((ese.ese_cast & cf_bq) && !EPDWhiteAttacks(sq_e8)
2859                 && Vacant(sq_d8)
2860                 && !EPDWhiteAttacks(sq_d8) && Vacant(sq_c8)
2861                 && !EPDWhiteAttacks(sq_c8) && Vacant(sq_b8)) {
2862               gen_m.m_tosq = sq_c8;
2863               gen_m.m_tocp = cp_v0;
2864               gen_m.m_scmv = scmv_cqs;
2865               *treeptr++ = gen_m;
2866               tse.tse_count++;
2867               gen_m.m_scmv = scmv_reg;
2868             };
2869           };
2870           break;
2871       };
2872     };
2873   };
2874   return;
2875 }
2876 
2877 /*--> EPDSameMoveRef: check if two move references are the same move */
EPDSameMoveRef(mptrT mptr0,mptrT mptr1)2878 static siT EPDSameMoveRef(mptrT mptr0, mptrT mptr1) {
2879   siT flag;
2880 
2881   if ((mptr0->m_tosq == mptr1->m_tosq) && (mptr0->m_frsq == mptr1->m_frsq)
2882       && (mptr0->m_frcp == mptr1->m_frcp) && (mptr0->m_tocp == mptr1->m_tocp)
2883       && (mptr0->m_scmv == mptr1->m_scmv))
2884     flag = 1;
2885   else
2886     flag = 0;
2887   return flag;
2888 }
2889 
2890 /*--> EPDFindMove: locate the move in the current generation set */
EPDFindMove(mptrT mptr)2891 static mptrT EPDFindMove(mptrT mptr) {
2892   mptrT rmptr;
2893   siT flag;
2894   siT index;
2895 
2896   rmptr = tse.tse_base;
2897   flag = 0;
2898   index = 0;
2899   while (!flag && (index < tse.tse_count))
2900     if (EPDSameMoveRef(mptr, rmptr))
2901       flag = 1;
2902     else {
2903       rmptr++;
2904       index++;
2905     };
2906   if (!flag)
2907     rmptr = NULL;
2908   return rmptr;
2909 }
2910 
2911 /*--> EPDExecute: execute the supplied move */
2912 static
EPDExecute(mptrT mptr)2913 void EPDExecute(mptrT mptr) {
2914   sqT pcsq;
2915   cpT ppcp;
2916 
2917 /* test for overflow */
2918   if (ply == (pmhL - 1))
2919     EPDFatal("EPDExecute: played move history overflow");
2920 /* save old environment and generation records */
2921   *eseptr++ = ese;
2922   *tseptr++ = tse;
2923 /* set the legality tested flag */
2924   mptr->m_flag |= mf_exec;
2925 /* process according to move case */
2926   switch (mptr->m_scmv) {
2927     case scmv_reg:
2928       EPDboard.rbv[mptr->m_frsq] = cp_v0;
2929       EPDboard.rbv[mptr->m_tosq] = mptr->m_frcp;
2930       break;
2931     case scmv_epc:
2932       if (ese.ese_actc == c_w)
2933         pcsq = mptr->m_tosq + dv_3;
2934       else
2935         pcsq = mptr->m_tosq + dv_1;
2936       EPDboard.rbv[mptr->m_frsq] = cp_v0;
2937       EPDboard.rbv[mptr->m_tosq] = mptr->m_frcp;
2938       EPDboard.rbv[pcsq] = cp_v0;
2939       break;
2940     case scmv_cks:
2941       if (ese.ese_actc == c_w) {
2942         EPDboard.rbv[sq_e1] = cp_v0;
2943         EPDboard.rbv[sq_g1] = cp_wk;
2944         EPDboard.rbv[sq_h1] = cp_v0;
2945         EPDboard.rbv[sq_f1] = cp_wr;
2946       } else {
2947         EPDboard.rbv[sq_e8] = cp_v0;
2948         EPDboard.rbv[sq_g8] = cp_bk;
2949         EPDboard.rbv[sq_h8] = cp_v0;
2950         EPDboard.rbv[sq_f8] = cp_br;
2951       };
2952       break;
2953     case scmv_cqs:
2954       if (ese.ese_actc == c_w) {
2955         EPDboard.rbv[sq_e1] = cp_v0;
2956         EPDboard.rbv[sq_c1] = cp_wk;
2957         EPDboard.rbv[sq_a1] = cp_v0;
2958         EPDboard.rbv[sq_d1] = cp_wr;
2959       } else {
2960         EPDboard.rbv[sq_e8] = cp_v0;
2961         EPDboard.rbv[sq_c8] = cp_bk;
2962         EPDboard.rbv[sq_a8] = cp_v0;
2963         EPDboard.rbv[sq_d8] = cp_br;
2964       };
2965       break;
2966     case scmv_ppn:
2967       if (ese.ese_actc == c_w)
2968         ppcp = cp_wn;
2969       else
2970         ppcp = cp_bn;
2971       EPDboard.rbv[mptr->m_frsq] = cp_v0;
2972       EPDboard.rbv[mptr->m_tosq] = ppcp;
2973       break;
2974     case scmv_ppb:
2975       if (ese.ese_actc == c_w)
2976         ppcp = cp_wb;
2977       else
2978         ppcp = cp_bb;
2979       EPDboard.rbv[mptr->m_frsq] = cp_v0;
2980       EPDboard.rbv[mptr->m_tosq] = ppcp;
2981       break;
2982     case scmv_ppr:
2983       if (ese.ese_actc == c_w)
2984         ppcp = cp_wr;
2985       else
2986         ppcp = cp_br;
2987       EPDboard.rbv[mptr->m_frsq] = cp_v0;
2988       EPDboard.rbv[mptr->m_tosq] = ppcp;
2989       break;
2990     case scmv_ppq:
2991       if (ese.ese_actc == c_w)
2992         ppcp = cp_wq;
2993       else
2994         ppcp = cp_bq;
2995       EPDboard.rbv[mptr->m_frsq] = cp_v0;
2996       EPDboard.rbv[mptr->m_tosq] = ppcp;
2997       break;
2998   };
2999 /* set values for updated environment record: active color */
3000   ese.ese_actc = inv_cv[ese.ese_actc];
3001 /* set values for updated environment record: castling availablity */
3002   if (ese.ese_cast != 0) {
3003     if (ese.ese_cast & cf_wk)
3004       if ((mptr->m_frsq == sq_e1) || (mptr->m_frsq == sq_h1)
3005           || (mptr->m_tosq == sq_h1))
3006         ese.ese_cast &= ~cf_wk;
3007     if (ese.ese_cast & cf_wq)
3008       if ((mptr->m_frsq == sq_e1) || (mptr->m_frsq == sq_a1)
3009           || (mptr->m_tosq == sq_a1))
3010         ese.ese_cast &= ~cf_wq;
3011     if (ese.ese_cast & cf_bk)
3012       if ((mptr->m_frsq == sq_e8) || (mptr->m_frsq == sq_h8)
3013           || (mptr->m_tosq == sq_h8))
3014         ese.ese_cast &= ~cf_bk;
3015     if (ese.ese_cast & cf_bq)
3016       if ((mptr->m_frsq == sq_e8) || (mptr->m_frsq == sq_a8)
3017           || (mptr->m_tosq == sq_a8))
3018         ese.ese_cast &= ~cf_bq;
3019   };
3020 /* set values for updated environment record: en passant */
3021   if (ese.ese_actc == c_b) {
3022     if ((mptr->m_frcp == cp_wp) && (map_rank(mptr->m_frsq) == rank_2)
3023         && (map_rank(mptr->m_tosq) == rank_4))
3024       ese.ese_epsq = mptr->m_frsq + dv_1;
3025     else
3026       ese.ese_epsq = sq_nil;
3027   } else {
3028     if ((mptr->m_frcp == cp_bp) && (map_rank(mptr->m_frsq) == rank_7)
3029         && (map_rank(mptr->m_tosq) == rank_5))
3030       ese.ese_epsq = mptr->m_frsq + dv_3;
3031     else
3032       ese.ese_epsq = sq_nil;
3033   }
3034 /* set values for updated environment record: halfmove clock */
3035   if ((mptr->m_tocp != cp_v0) || (cv_p_cpv[mptr->m_frcp] == p_p))
3036     ese.ese_hmvc = 0;
3037   else
3038     ese.ese_hmvc++;
3039 /* set values for updated environment record: fullmove number */
3040   if (ese.ese_actc == c_w)
3041     ese.ese_fmvn++;
3042 /* set values for updated environment record: king locations */
3043   switch (mptr->m_frcp) {
3044     case cp_wk:
3045       ese.ese_ksqv[c_w] = mptr->m_tosq;
3046       break;
3047     case cp_bk:
3048       ese.ese_ksqv[c_b] = mptr->m_tosq;
3049       break;
3050     default:
3051       break;
3052   };
3053 /* check/bust flags */
3054   if (EPDTestAKIC())
3055     mptr->m_flag |= mf_chec;
3056   if (EPDTestPKIC())
3057     mptr->m_flag |= mf_bust;
3058 /* increment ply index */
3059   ply++;
3060   return;
3061 }
3062 
3063 /*--> EPDExecuteUpdate: update the current move pointer, then execute */
EPDExecuteUpdate(mptrT mptr)3064 nonstatic void EPDExecuteUpdate(mptrT mptr) {
3065   tse.tse_curr = EPDFindMove(mptr);
3066   if (tse.tse_curr == NULL)
3067     EPDFatal("EPDExecuteUpdate: can't find move");
3068   EPDExecute(tse.tse_curr);
3069   return;
3070 }
3071 
3072 /*--> EPDRetract: retract the supplied move */
3073 static
EPDRetract(mptrT mptr)3074 void EPDRetract(mptrT mptr) {
3075 /* decrement ply */
3076   ply--;
3077 /* restore the current environment and generation */
3078   ese = *--eseptr;
3079   tse = *--tseptr;
3080 /* process by move case */
3081   switch (mptr->m_scmv) {
3082     case scmv_reg:
3083       EPDboard.rbv[mptr->m_tosq] = mptr->m_tocp;
3084       EPDboard.rbv[mptr->m_frsq] = mptr->m_frcp;
3085       break;
3086     case scmv_epc:
3087       EPDboard.rbv[mptr->m_tosq] = cp_v0;
3088       EPDboard.rbv[mptr->m_frsq] = mptr->m_frcp;
3089       if (ese.ese_actc == c_w)
3090         EPDboard.rbv[mptr->m_tosq + dv_3] = cp_bp;
3091       else
3092         EPDboard.rbv[mptr->m_tosq + dv_1] = cp_wp;
3093       break;
3094     case scmv_cks:
3095       if (ese.ese_actc == c_w) {
3096         EPDboard.rbv[sq_g1] = cp_v0;
3097         EPDboard.rbv[sq_e1] = cp_wk;
3098         EPDboard.rbv[sq_f1] = cp_v0;
3099         EPDboard.rbv[sq_h1] = cp_wr;
3100       } else {
3101         EPDboard.rbv[sq_g8] = cp_v0;
3102         EPDboard.rbv[sq_e8] = cp_bk;
3103         EPDboard.rbv[sq_f8] = cp_v0;
3104         EPDboard.rbv[sq_h8] = cp_br;
3105       }
3106       break;
3107     case scmv_cqs:
3108       if (ese.ese_actc == c_w) {
3109         EPDboard.rbv[sq_c1] = cp_v0;
3110         EPDboard.rbv[sq_e1] = cp_wk;
3111         EPDboard.rbv[sq_d1] = cp_v0;
3112         EPDboard.rbv[sq_a1] = cp_wr;
3113       } else {
3114         EPDboard.rbv[sq_c8] = cp_v0;
3115         EPDboard.rbv[sq_e8] = cp_bk;
3116         EPDboard.rbv[sq_d8] = cp_v0;
3117         EPDboard.rbv[sq_a8] = cp_br;
3118       };
3119       break;
3120     case scmv_ppn:
3121     case scmv_ppb:
3122     case scmv_ppr:
3123     case scmv_ppq:
3124       EPDboard.rbv[mptr->m_tosq] = mptr->m_tocp;
3125       EPDboard.rbv[mptr->m_frsq] = mptr->m_frcp;
3126       break;
3127   };
3128   return;
3129 }
3130 
3131 /*--> EPDRetractUpdate: retract last executed move */
EPDRetractUpdate(void)3132 nonstatic void EPDRetractUpdate(void) {
3133   mptrT mptr;
3134 
3135   mptr = (tseptr - 1)->tse_curr;
3136   EPDRetract(mptr);
3137   return;
3138 }
3139 
3140 /*--> EPDRetractAll: retract all moves in current variation */
EPDRetractAll(void)3141 nonstatic void EPDRetractAll(void) {
3142   while (ply > 0)
3143     EPDRetractUpdate();
3144   return;
3145 }
3146 
3147 /*--> EPDCollapse: collapse the played move stack */
EPDCollapse(void)3148 nonstatic void EPDCollapse(void) {
3149 /* process for nonzero ply */
3150   if (ply > 0) {
3151 /* reset the stack pointers */
3152     treeptr = treebaseptr;
3153     eseptr = esebaseptr;
3154     tseptr = tsebaseptr;
3155 /* reset the ply */
3156     ply = 0;
3157   };
3158   return;
3159 }
3160 
3161 /*--> EPDReset: collapse, then reset starting position */
EPDReset(void)3162 nonstatic void EPDReset(void) {
3163   EPDCollapse();
3164   EPDInitArray();
3165   return;
3166 }
3167 
3168 /*--> EPDMLExec: execute the current move list */
3169 static
EPDMLExec(void)3170 void EPDMLExec(void) {
3171   siT i;
3172   mptrT mptr;
3173 
3174 /* test and mark each move for legality and checking status */
3175   mptr = tse.tse_base;
3176   for (i = 0; i < tse.tse_count; i++) {
3177     tse.tse_curr = mptr;
3178     EPDExecute(mptr);
3179     EPDRetract(mptr);
3180     mptr++;
3181   };
3182   return;
3183 }
3184 
3185 /*--> EPDMLPolice: remove illegal moves the current move list */
3186 static
EPDMLPolice(void)3187 void EPDMLPolice(void) {
3188   mptrT tptr, mptr;
3189   siT i, bust;
3190   mT t_m;
3191 
3192 /* move illegal moves to end of list */
3193   mptr = tse.tse_base;
3194   bust = 0;
3195   i = 0;
3196   while (i < (tse.tse_count - bust))
3197     if (mptr->m_flag & mf_bust) {
3198       tptr = (tse.tse_base + (tse.tse_count - 1)) - bust;
3199       t_m = *mptr;
3200       *mptr = *tptr;
3201       *tptr = t_m;
3202       bust++;
3203     } else {
3204       mptr++;
3205       i++;
3206     };
3207 /* shrink */
3208   tse.tse_count -= bust;
3209   return;
3210 }
3211 
3212 /*--> EPDMLDisambiguate: insert disambiguation flags in move list */
3213 static
EPDMLDisambiguate(void)3214 void EPDMLDisambiguate(void) {
3215   siT i, j, tmc, rmc, fmc;
3216   mptrT mptr0, mptr1;
3217   pT p;
3218   rankT rank;
3219   fileT file;
3220 
3221 /* it's magic */
3222   mptr0 = tse.tse_base;
3223   for (i = 0; i < tse.tse_count; i++) {
3224 /* the outer loop disambiguates a single move per cycle */
3225     p = cv_p_cpv[mptr0->m_frcp];
3226     if ((p != p_p) && (p != p_k)) {
3227       rank = map_rank(mptr0->m_frsq);
3228       file = map_file(mptr0->m_frsq);
3229       tmc = rmc = fmc = 0;
3230       mptr1 = tse.tse_base;
3231       for (j = 0; j < tse.tse_count; j++) {
3232 /* the inner loop examines all possible sibling puns */
3233         if ((i != j) && (mptr0->m_frcp == mptr1->m_frcp)
3234             && (mptr0->m_tosq == mptr1->m_tosq)) {
3235           tmc++;
3236           if (map_rank(mptr1->m_frsq) == rank)
3237             rmc++;
3238           if (map_file(mptr1->m_frsq) == file)
3239             fmc++;
3240         };
3241         mptr1++;
3242       };
3243 /* check pun count for outer loop move */
3244       if (tmc > 0) {
3245 /* file disambiguation has priority */
3246         if ((rmc > 0) || ((rmc == 0) && (fmc == 0)))
3247           mptr0->m_flag |= mf_sanf;
3248 /* rank disambiguation may be needed */
3249         if (fmc > 0)
3250           mptr0->m_flag |= mf_sanr;
3251       };
3252     };
3253     mptr0++;
3254   };
3255   return;
3256 }
3257 
3258 /*--> EPDMLScanMate: scan current move list for mating moves */
3259 static
EPDMLScanMate(void)3260 void EPDMLScanMate(void) {
3261   siT i, j, mateflag, drawflag, moveflag;
3262   mptrT mptr0, mptr1;
3263 
3264 /* scan */
3265   mptr0 = tse.tse_base;
3266   for (i = 0; i < tse.tse_count; i++) {
3267     tse.tse_curr = mptr0;
3268     EPDExecute(mptr0);
3269 /* now at next higher ply, generate psuedolegal set */
3270     EPDGeneratePL();
3271 /* try to find at least one legal move */
3272     mptr1 = tse.tse_base;
3273     moveflag = 0;
3274     j = 0;
3275     while (!moveflag && (j < tse.tse_count)) {
3276       tse.tse_curr = mptr1;
3277       EPDExecute(mptr1);
3278       EPDRetract(mptr1);
3279       if (!(mptr1->m_flag & mf_bust))
3280         moveflag = 1;
3281       else {
3282         mptr1++;
3283         j++;
3284       };
3285     };
3286 /* any second level moves detected? */
3287     if (moveflag != 0) {
3288 /* not a mate */
3289       mateflag = drawflag = 0;
3290     } else {
3291 /* a mating move is detected */
3292       if (EPDTestAKIC()) {
3293         mateflag = 1;
3294         drawflag = 0;
3295       } else {
3296         drawflag = 1;
3297         mateflag = 0;
3298       };
3299     };
3300 /* undo execution */
3301     EPDRetract(mptr0);
3302 /* now back at lower ply */
3303     if (mateflag)
3304       mptr0->m_flag |= mf_chmt;
3305     else if (drawflag)
3306       mptr0->m_flag |= (mf_draw | mf_stmt);
3307 /* next move */
3308     mptr0++;
3309   };
3310   return;
3311 }
3312 
3313 /*--> EPDGenClean: generate move list with first level processing */
3314 static
EPDGenClean(void)3315 void EPDGenClean(void) {
3316 /* basic psuedolegal generation */
3317   EPDGeneratePL();
3318 /* set legality flags, remove illegal moves, and disambiguate */
3319   EPDMLExec();
3320   EPDMLPolice();
3321   EPDMLDisambiguate();
3322   return;
3323 }
3324 
3325 /*--> EPDGenMoves: generate legal moves and set mate flags */
EPDGenMoves(void)3326 nonstatic void EPDGenMoves(void) {
3327 /* perform basic first level generation */
3328   EPDGenClean();
3329 /* handle two ply draw and checkmate detection */
3330   EPDMLScanMate();
3331   return;
3332 }
3333 
3334 /*--> EPDFetchMoveCount: fetch the move count */
EPDFetchMoveCount(void)3335 nonstatic siT EPDFetchMoveCount(void) {
3336   return tse.tse_count;
3337 }
3338 
3339 /*--> EPDFetchMove: fetch the nth move */
EPDFetchMove(siT index)3340 nonstatic mptrT EPDFetchMove(siT index) {
3341   ret_m = *(tse.tse_base + index);
3342   return &ret_m;
3343 }
3344 
3345 /*--> EPDSetMoveFlags: set move flags from current generation set */
EPDSetMoveFlags(mptrT mptr)3346 nonstatic void EPDSetMoveFlags(mptrT mptr) {
3347   mptrT rmptr;
3348 
3349   rmptr = EPDFindMove(mptr);
3350   if (rmptr != NULL)
3351     mptr->m_flag = rmptr->m_flag;
3352   return;
3353 }
3354 
3355 /*--> EPDSortSAN: ASCII SAN sort move list */
EPDSortSAN(void)3356 nonstatic void EPDSortSAN(void) {
3357   mptrT mptr, mptr0, mptr1;
3358   siT i, j, pair, pass, flag;
3359   sanptrT sanptr, sptr0, sptr1;
3360   char t_ch;
3361   mT t_m;
3362 
3363 /* allocate the SAN string vector */
3364   sanptr = (sanptrT) EPDMemoryGrab(sizeof(sanT) * tse.tse_count);
3365 /* construct the SAN string entries */
3366   mptr = tse.tse_base;
3367   for (i = 0; i < tse.tse_count; i++)
3368     EPDSANEncode(mptr++, *(sanptr + i));
3369 /* a low tech bubble sort */
3370   flag = 1;
3371   pass = 0;
3372   while (flag && (pass < (tse.tse_count - 1))) {
3373     sptr0 = sanptr;
3374     sptr1 = sanptr + 1;
3375     mptr0 = tse.tse_base;
3376     mptr1 = tse.tse_base + 1;
3377     flag = 0;
3378     pair = 0;
3379     while (pair < (tse.tse_count - pass - 1)) {
3380 /* case sensitive ascending order */
3381       if (strcmp((charptrT) sptr0, (charptrT) sptr1) > 0) {
3382         flag = 1;
3383         for (j = 0; j < sanL; j++) {
3384           t_ch = (*sptr0)[j];
3385           (*sptr0)[j] = (*sptr1)[j];
3386           (*sptr1)[j] = t_ch;
3387         };
3388         t_m = *mptr0;
3389         *mptr0 = *mptr1;
3390         *mptr1 = t_m;
3391       };
3392       sptr0++;
3393       sptr1++;
3394       mptr0++;
3395       mptr1++;
3396       pair++;
3397     };
3398     pass++;
3399   };
3400   EPDMemoryFree(sanptr);
3401   return;
3402 }
3403 
3404 /*--> EPDRepairMove: repair a move operation */
3405 static
EPDRepairMove(eopptrT eopptr)3406 void EPDRepairMove(eopptrT eopptr) {
3407   eovptrT eovptr;
3408   mptrT mptr;
3409   mT m;
3410   sanT san;
3411 
3412 /* repair a single move from the current position */
3413   eovptr = eopptr->eop_headeov;
3414   if (eovptr != NULL) {
3415     mptr = EPDSANDecodeAux(eovptr->eov_str, 0);
3416     if (mptr != NULL) {
3417       m = *mptr;
3418       EPDSANEncode(&m, san);
3419       if (strcmp(eovptr->eov_str, san) != 0)
3420         EPDReplaceEOVStr(eovptr, san);
3421     };
3422   };
3423   return;
3424 }
3425 
3426 /*--> EPDRepairMoveset: repair a moveset operation */
3427 static
EPDRepairMoveset(eopptrT eopptr)3428 void EPDRepairMoveset(eopptrT eopptr) {
3429   eovptrT eovptr;
3430   mptrT mptr;
3431   mT m;
3432   sanT san;
3433 
3434 /* check each move from the current position */
3435   eovptr = eopptr->eop_headeov;
3436   while (eovptr != NULL) {
3437     mptr = EPDSANDecodeAux(eovptr->eov_str, 0);
3438     if (mptr != NULL) {
3439       m = *mptr;
3440       EPDSANEncode(&m, san);
3441       if (strcmp(eovptr->eov_str, san) != 0)
3442         EPDReplaceEOVStr(eovptr, san);
3443     };
3444     eovptr = eovptr->eov_next;
3445   };
3446   return;
3447 }
3448 
3449 /*--> EPDRepairVariation: repair a variation operation */
3450 static
EPDRepairVariation(eopptrT eopptr)3451 void EPDRepairVariation(eopptrT eopptr) {
3452   eovptrT eovptr;
3453   mptrT mptr;
3454   mT m;
3455   sanT san;
3456 
3457 /* play move sequence from the current position */
3458   eovptr = eopptr->eop_headeov;
3459   while (eovptr != NULL) {
3460     mptr = EPDSANDecodeAux(eovptr->eov_str, 0);
3461     if (mptr == NULL)
3462       eovptr = NULL;
3463     else {
3464       m = *mptr;
3465       EPDSANEncode(&m, san);
3466       if (strcmp(eovptr->eov_str, san) != 0)
3467         EPDReplaceEOVStr(eovptr, san);
3468       tse.tse_curr = EPDFindMove(mptr);
3469       if (tse.tse_curr == NULL)
3470         EPDFatal("EPDRepairVariation: can't find move");
3471       EPDExecute(mptr);
3472       EPDGenMoves();
3473       eovptr = eovptr->eov_next;
3474     }
3475   };
3476 /* retract any executed moves */
3477   EPDRetractAll();
3478   return;
3479 }
3480 
3481 /*--> EPDPurgeOpFile: purge operation from input file to output file */
EPDPurgeOpFile(charptrT opsym,charptrT fn0,charptrT fn1)3482 nonstatic siT EPDPurgeOpFile(charptrT opsym, charptrT fn0, charptrT fn1) {
3483   siT flag;
3484   fptrT fptr0, fptr1;
3485   epdptrT epdptr;
3486   eopptrT eopptr;
3487   charptrT eptr;
3488   char ev[epdL];
3489 
3490 /* set default return value (success) */
3491   flag = 1;
3492 /* clear the input and output file pointers */
3493   fptr0 = fptr1 = NULL;
3494 /* open the input file for reading */
3495   if (flag) {
3496     fptr0 = fopen(fn0, "r");
3497     if (fptr0 == NULL)
3498       flag = 0;
3499   };
3500 /* open the output file for writing */
3501   if (flag) {
3502     fptr1 = fopen(fn1, "w");
3503     if (fptr1 == NULL)
3504       flag = 0;
3505   };
3506 /* scan entire file */
3507   while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL)) {
3508 /* decode a record */
3509     epdptr = EPDDecode(ev);
3510 /* check record decode validity */
3511     if (epdptr == NULL)
3512       flag = 0;
3513     else {
3514 /* locate the operation to be purged */
3515       eopptr = EPDLocateEOP(epdptr, opsym);
3516       if (eopptr != NULL) {
3517         EPDUnthreadEOP(epdptr, eopptr);
3518         EPDReleaseEOP(eopptr);
3519       };
3520 /* encode the record (includes normalization) */
3521       eptr = EPDEncode(epdptr);
3522 /* release EPD structure */
3523       EPDReleaseEPD(epdptr);
3524 /* check result */
3525       if (eptr == NULL)
3526         flag = 0;
3527       else {
3528         fprintf(fptr1, "%s\n", eptr);
3529         EPDMemoryFree(eptr);
3530       };
3531     };
3532   };
3533 /* close input and output files */
3534   if (fptr0 != NULL)
3535     fclose(fptr0);
3536   if (fptr1 != NULL)
3537     fclose(fptr1);
3538   return flag;
3539 }
3540 
3541 /*--> EPDRepairEPD: repair an EPD structure */
EPDRepairEPD(epdptrT epdptr)3542 nonstatic siT EPDRepairEPD(epdptrT epdptr) {
3543   siT flag;
3544   eopptrT eopptr;
3545 
3546 /* set default return value: repair successful */
3547   flag = 1;
3548 /* set up the position as the current position */
3549   EPDRealize(epdptr);
3550 /* check legality */
3551   if (!EPDIsLegal())
3552     flag = 0;
3553   else {
3554 /* generate moves and notation */
3555     EPDGenMoves();
3556 /* repair moveset "am" */
3557     eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_am]);
3558     if (eopptr != NULL)
3559       EPDRepairMoveset(eopptr);
3560 /* repair moveset "bm" */
3561     eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_bm]);
3562     if (eopptr != NULL)
3563       EPDRepairMoveset(eopptr);
3564 /* repair move "pm" */
3565     eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_pm]);
3566     if (eopptr != NULL)
3567       EPDRepairMove(eopptr);
3568 /* repair variation "pv" */
3569     eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_pv]);
3570     if (eopptr != NULL)
3571       EPDRepairVariation(eopptr);
3572 /* repair move "sm" */
3573     eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_sm]);
3574     if (eopptr != NULL)
3575       EPDRepairMove(eopptr);
3576 /* repair variation "sv" */
3577     eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_sv]);
3578     if (eopptr != NULL)
3579       EPDRepairVariation(eopptr);
3580   };
3581   return flag;
3582 }
3583 
3584 /*--> EPDRepairFile: repair input file to output file */
EPDRepairFile(charptrT fn0,charptrT fn1)3585 nonstatic siT EPDRepairFile(charptrT fn0, charptrT fn1) {
3586   siT flag;
3587   fptrT fptr0, fptr1;
3588   epdptrT epdptr;
3589   charptrT eptr;
3590   char ev[epdL];
3591 
3592 /* set default return value (success) */
3593   flag = 1;
3594 /* clear the input and output file pointers */
3595   fptr0 = fptr1 = NULL;
3596 /* open the input file for reading */
3597   if (flag) {
3598     fptr0 = fopen(fn0, "r");
3599     if (fptr0 == NULL)
3600       flag = 0;
3601   };
3602 /* open the output file for writing */
3603   if (flag) {
3604     fptr1 = fopen(fn1, "w");
3605     if (fptr1 == NULL)
3606       flag = 0;
3607   };
3608 /* scan entire file */
3609   while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL)) {
3610 /* decode a record */
3611     epdptr = EPDDecode(ev);
3612 /* check record decode validity */
3613     if (epdptr == NULL)
3614       flag = 0;
3615     else {
3616 /* make repairs */
3617       flag = EPDRepairEPD(epdptr);
3618 /* continue if repair okay */
3619       if (flag) {
3620 /* encode the normalized record */
3621         eptr = EPDEncode(epdptr);
3622 /* check result */
3623         if (eptr == NULL)
3624           flag = 0;
3625         else {
3626           fprintf(fptr1, "%s\n", eptr);
3627           EPDMemoryFree(eptr);
3628         };
3629       };
3630 /* release EPD structure */
3631       EPDReleaseEPD(epdptr);
3632     };
3633   };
3634 /* close input and output files */
3635   if (fptr0 != NULL)
3636     fclose(fptr0);
3637   if (fptr1 != NULL)
3638     fclose(fptr1);
3639   return flag;
3640 }
3641 
3642 /*--> EPDNormalizeFile: normalize input file to output file */
EPDNormalizeFile(charptrT fn0,charptrT fn1)3643 nonstatic siT EPDNormalizeFile(charptrT fn0, charptrT fn1) {
3644   siT flag;
3645   fptrT fptr0, fptr1;
3646   epdptrT epdptr;
3647   charptrT eptr;
3648   char ev[epdL];
3649 
3650 /* set default return value (success) */
3651   flag = 1;
3652 /* clear the input and output file pointers */
3653   fptr0 = fptr1 = NULL;
3654 /* open the input file for reading */
3655   if (flag) {
3656     fptr0 = fopen(fn0, "r");
3657     if (fptr0 == NULL)
3658       flag = 0;
3659   };
3660 /* open the output file for writing */
3661   if (flag) {
3662     fptr1 = fopen(fn1, "w");
3663     if (fptr1 == NULL)
3664       flag = 0;
3665   };
3666 /* scan entire file */
3667   while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL)) {
3668 /* decode a record */
3669     epdptr = EPDDecode(ev);
3670 /* check record decode validity */
3671     if (epdptr == NULL)
3672       flag = 0;
3673     else {
3674 /* encode the record (this includes normalization) */
3675       eptr = EPDEncode(epdptr);
3676 /* release EPD structure */
3677       EPDReleaseEPD(epdptr);
3678 /* check result */
3679       if (eptr == NULL)
3680         flag = 0;
3681       else {
3682         fprintf(fptr1, "%s\n", eptr);
3683         EPDMemoryFree(eptr);
3684       };
3685     };
3686   };
3687 /* close input and output files */
3688   if (fptr0 != NULL)
3689     fclose(fptr0);
3690   if (fptr1 != NULL)
3691     fclose(fptr1);
3692   return flag;
3693 }
3694 
3695 /*--> EPDScoreFile: score a benchmark file */
EPDScoreFile(charptrT fn,bmsptrT bmsptr)3696 nonstatic siT EPDScoreFile(charptrT fn, bmsptrT bmsptr) {
3697   siT flag;
3698   siT skipflag;
3699   siT am_flag, bm_flag;
3700   siT solved = 0;
3701   fptrT fptr;
3702   epdptrT epdptr;
3703   eopptrT am_eopptr, bm_eopptr, acd_eopptr, acn_eopptr, acs_eopptr;
3704   eopptrT sm_eopptr, sv_eopptr, pm_eopptr, pv_eopptr;
3705   charptrT result;
3706   char ev[epdL];
3707 
3708 /* set default return value (success) */
3709   flag = 1;
3710 /* clear the input file pointer */
3711   fptr = NULL;
3712 /* preset the summary structure */
3713   bmsptr->bms_acdflag = bmsptr->bms_acnflag = bmsptr->bms_acsflag = 1;
3714   bmsptr->bms_total = bmsptr->bms_solve = bmsptr->bms_unsol = 0;
3715   bmsptr->bms_total_acd = bmsptr->bms_solve_acd = bmsptr->bms_unsol_acd = 0;
3716   bmsptr->bms_total_acn = bmsptr->bms_solve_acn = bmsptr->bms_unsol_acn = 0;
3717   bmsptr->bms_total_acs = bmsptr->bms_solve_acs = bmsptr->bms_unsol_acs = 0;
3718 /* open the input file for reading */
3719   if (flag) {
3720     fptr = fopen(fn, "r");
3721     if (fptr == NULL)
3722       flag = 0;
3723   };
3724 /* scan entire file */
3725   while (flag && (fgets(ev, (epdL - 1), fptr) != NULL)) {
3726 /* decode a record */
3727     epdptr = EPDDecode(ev);
3728 /* check record decode validity */
3729     if (epdptr == NULL)
3730       flag = 0;
3731     else {
3732 /* clear the move result pointer */
3733       result = NULL;
3734 /* initialize various operation pointers */
3735       am_eopptr = EPDLocateEOPCode(epdptr, epdso_am);
3736       bm_eopptr = EPDLocateEOPCode(epdptr, epdso_bm);
3737       acd_eopptr = EPDLocateEOPCode(epdptr, epdso_acd);
3738       acn_eopptr = EPDLocateEOPCode(epdptr, epdso_acn);
3739       acs_eopptr = EPDLocateEOPCode(epdptr, epdso_acs);
3740       sm_eopptr = EPDLocateEOPCode(epdptr, epdso_sm);
3741       sv_eopptr = EPDLocateEOPCode(epdptr, epdso_sv);
3742       pm_eopptr = EPDLocateEOPCode(epdptr, epdso_pm);
3743       pv_eopptr = EPDLocateEOPCode(epdptr, epdso_pv);
3744 /* test for am/bm existence */
3745       if ((am_eopptr == NULL) && (bm_eopptr == NULL))
3746         skipflag = 1;
3747       else
3748         skipflag = 0;
3749 /* try to locate a result move (note priority) */
3750       if (!skipflag) {
3751         if (result == NULL)
3752           if ((pv_eopptr != NULL) && (pv_eopptr->eop_headeov != NULL))
3753             result = pv_eopptr->eop_headeov->eov_str;
3754         if (result == NULL)
3755           if ((pm_eopptr != NULL) && (pm_eopptr->eop_headeov != NULL))
3756             result = pm_eopptr->eop_headeov->eov_str;
3757         if (result == NULL)
3758           if ((sv_eopptr != NULL) && (sv_eopptr->eop_headeov != NULL))
3759             result = sv_eopptr->eop_headeov->eov_str;
3760         if (result == NULL)
3761           if ((sm_eopptr != NULL) && (sm_eopptr->eop_headeov != NULL))
3762             result = sm_eopptr->eop_headeov->eov_str;
3763         if (result == NULL)
3764           skipflag = 1;
3765       };
3766 /* determine solve status */
3767       if (!skipflag) {
3768 /* check for clearance with the am set */
3769         if ((am_eopptr == NULL) || (EPDLocateEOV(am_eopptr, result) == NULL))
3770           am_flag = 1;
3771         else
3772           am_flag = 0;
3773 /* check for clearance with the bm set */
3774         if ((bm_eopptr == NULL) || (EPDLocateEOV(bm_eopptr, result) != NULL))
3775           bm_flag = 1;
3776         else
3777           bm_flag = 0;
3778 /* set solution flag */
3779         solved = am_flag && bm_flag;
3780       };
3781 /* update statistics block */
3782       if (!skipflag) {
3783 /* clear acd flag if acd is missing */
3784         if ((acd_eopptr == NULL) || (acd_eopptr->eop_headeov == NULL))
3785           bmsptr->bms_acdflag = 0;
3786 /* clear acn flag if acn is missing */
3787         if ((acn_eopptr == NULL) || (acn_eopptr->eop_headeov == NULL))
3788           bmsptr->bms_acnflag = 0;
3789 /* clear acs flag if acs is missing */
3790         if ((acs_eopptr == NULL) || (acs_eopptr->eop_headeov == NULL))
3791           bmsptr->bms_acsflag = 0;
3792 /* increment record count */
3793         bmsptr->bms_total++;
3794 /* fold in acd value */
3795         if (bmsptr->bms_acdflag) {
3796           bmsptr->bms_total_acd += atoi(acd_eopptr->eop_headeov->eov_str);
3797           if (solved)
3798             bmsptr->bms_solve_acd += atoi(acd_eopptr->eop_headeov->eov_str);
3799           else
3800             bmsptr->bms_unsol_acd += atoi(acd_eopptr->eop_headeov->eov_str);
3801         };
3802 /* fold in acn value */
3803         if (bmsptr->bms_acnflag) {
3804           bmsptr->bms_total_acn += atoi(acn_eopptr->eop_headeov->eov_str);
3805           if (solved)
3806             bmsptr->bms_solve_acn += atoi(acn_eopptr->eop_headeov->eov_str);
3807           else
3808             bmsptr->bms_unsol_acn += atoi(acn_eopptr->eop_headeov->eov_str);
3809         };
3810 /* fold in acs value */
3811         if (bmsptr->bms_acsflag) {
3812           bmsptr->bms_total_acs += atoi(acs_eopptr->eop_headeov->eov_str);
3813           if (solved)
3814             bmsptr->bms_solve_acs += atoi(acs_eopptr->eop_headeov->eov_str);
3815           else
3816             bmsptr->bms_unsol_acs += atoi(acs_eopptr->eop_headeov->eov_str);
3817         };
3818 /* update remaining items according to solved status */
3819         if (solved)
3820           bmsptr->bms_solve++;
3821         else
3822           bmsptr->bms_unsol++;
3823       };
3824 /* release EPD structure */
3825       EPDReleaseEPD(epdptr);
3826     };
3827   };
3828 /* close input file */
3829   if (fptr != NULL)
3830     fclose(fptr);
3831   return flag;
3832 }
3833 
3834 /*--> EPDEnumerate: enumeration of current position */
EPDEnumerate(siT depth)3835 static liT EPDEnumerate(siT depth) {
3836   liT total;
3837   mptrT mptr;
3838   siT i;
3839 
3840 /* enumerate current position to the indicated depth */
3841   if (depth == 0)
3842     total = 1;
3843   else {
3844     total = 0;
3845     EPDGeneratePL();
3846     mptr = tse.tse_base;
3847     for (i = 0; i < tse.tse_count; i++) {
3848       tse.tse_curr = mptr;
3849       EPDExecute(mptr);
3850       if (!(mptr->m_flag & mf_bust))
3851         total += EPDEnumerate((siT) (depth - 1));
3852       EPDRetract(mptr);
3853       mptr++;
3854     };
3855   };
3856   return total;
3857 }
3858 
3859 /*--> EPDEnumerateFile: enumerate input file to output file */
EPDEnumerateFile(siT depth,charptrT fn0,charptrT fn1,liptrT totalptr)3860 nonstatic siT EPDEnumerateFile(siT depth, charptrT fn0, charptrT fn1,
3861     liptrT totalptr) {
3862   siT flag;
3863   fptrT fptr0, fptr1;
3864   time_t start_time;
3865   liT acn, acs;
3866   epdptrT epdptr;
3867   charptrT eptr;
3868   char ev[epdL];
3869 
3870 /* set default return value (success) */
3871   flag = 1;
3872 /* clear the grand total */
3873   *totalptr = 0;
3874 /* clear the input and output file pointers */
3875   fptr0 = fptr1 = NULL;
3876 /* open the input file for reading */
3877   if (flag) {
3878     fptr0 = fopen(fn0, "r");
3879     if (fptr0 == NULL)
3880       flag = 0;
3881   };
3882 /* open the output file for writing */
3883   if (flag) {
3884     fptr1 = fopen(fn1, "w");
3885     if (fptr1 == NULL)
3886       flag = 0;
3887   };
3888 /* scan entire file */
3889   while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL)) {
3890 /* decode a record */
3891     epdptr = EPDDecode(ev);
3892 /* check record decode validity */
3893     if (epdptr == NULL)
3894       flag = 0;
3895     else {
3896 /* set up the current position */
3897       EPDRealize(epdptr);
3898 /* check legality */
3899       if (!EPDIsLegal())
3900         flag = 0;
3901       else {
3902 /* perform enumeration */
3903         start_time = time(NULL);
3904         acn = EPDEnumerate(depth);
3905         acs = time(NULL) - start_time;
3906 /* update the grand total */
3907         *totalptr += acn;
3908 /* record the updated field: acd */
3909         EPDAddOpInt(epdptr, epdso_acd, depth);
3910 /* record the updated field: acn */
3911         EPDAddOpInt(epdptr, epdso_acn, acn);
3912 /* record the updated field: acs */
3913         EPDAddOpInt(epdptr, epdso_acs, acs);
3914 /* encode the record */
3915         EPDNormalize(epdptr);
3916         eptr = EPDEncode(epdptr);
3917 /* check result */
3918         if (eptr == NULL)
3919           flag = 0;
3920         else {
3921           fprintf(fptr1, "%s\n", eptr);
3922           EPDMemoryFree(eptr);
3923         };
3924       };
3925 /* release EPD structure */
3926       EPDReleaseEPD(epdptr);
3927     };
3928   };
3929 /* close input and output files */
3930   if (fptr0 != NULL)
3931     fclose(fptr0);
3932   if (fptr1 != NULL)
3933     fclose(fptr1);
3934   return flag;
3935 }
3936 
3937 /*--> EPDMoveList: generate a string representation of a move list */
EPDMoveList(gamptrT gamptr)3938 nonstatic charptrT EPDMoveList(gamptrT gamptr) {
3939   charptrT s;
3940   charptrT b;
3941   siT count;
3942   gpmptrT gpmptr;
3943   mT m;
3944   siT sn;
3945   cT sc, c;
3946   siT pi, index, limit, length, n, column;
3947   sanT san;
3948   char tv[tL];
3949 
3950 /* calculate upper bound on storage requirement */
3951   count = EPDGamePlyCount(gamptr);
3952   limit = (((count + 1) / 2) * 5) + 4 + (count * 8) + 8 + 1;
3953   b = (charptrT) EPDMemoryGrab(limit);
3954 /* set the inital played move pointer */
3955   gpmptr = gamptr->gam_headgpm;
3956 /* set up starting color and starting move number */
3957   if (count == 0)
3958     sc = c_w;
3959   else
3960     sc = gpmptr->gpm_ese.ese_actc;
3961   if (count == 0)
3962     sn = 1;
3963   else
3964     sn = gpmptr->gpm_ese.ese_fmvn;
3965 /* more set up */
3966   pi = 0;
3967   index = 0;
3968   c = sc;
3969   n = sn;
3970   column = 0;
3971 /* loop through moves */
3972   for (pi = 0; pi < count; pi++) {
3973 /* handle move number indication */
3974     if ((c == c_w) || ((pi == 0) && (sc == c_b))) {
3975       sprintf(tv, "%hd.", n);
3976       length = strlen(tv);
3977       if ((column + 1 + length) >= columnL) {
3978         strcpy((b + index), "\n");
3979         index++;
3980         column = 0;
3981       };
3982       if (column != 0) {
3983         strcpy((b + index), " ");
3984         index++;
3985         column++;
3986       };
3987       strcpy((b + index), tv);
3988       index += length;
3989       column += length;
3990       n++;
3991     };
3992 /* handle ellipsis */
3993     if ((pi == 0) && (sc == c_b)) {
3994       sprintf(tv, "...");
3995       length = strlen(tv);
3996       if ((column + 1 + length) >= columnL) {
3997         strcpy((b + index), "\n");
3998         index++;
3999         column = 0;
4000       };
4001       if (column != 0) {
4002         strcpy((b + index), " ");
4003         index++;
4004         column++;
4005       };
4006       strcpy((b + index), tv);
4007       index += length;
4008       column += length;
4009     };
4010 /* handle move */
4011     m = gpmptr->gpm_m;
4012     EPDSANEncode(&m, san);
4013     length = strlen(san);
4014     if ((column + 1 + length) >= columnL) {
4015       strcpy((b + index), "\n");
4016       index++;
4017       column = 0;
4018     };
4019     if (column != 0) {
4020       strcpy((b + index), " ");
4021       index++;
4022       column++;
4023     };
4024     strcpy((b + index), san);
4025     index += length;
4026     column += length;
4027     gpmptr = gpmptr->gpm_next;
4028     c = inv_cv[c];
4029   };
4030 /* append game termination marker */
4031   sprintf(tv, "%s", gtimstrv[gamptr->gam_gtim]);
4032   length = strlen(tv);
4033   if ((column + 1 + length) >= columnL) {
4034     strcpy((b + index), "\n");
4035     index++;
4036     column = 0;
4037   };
4038   if (column != 0) {
4039     strcpy((b + index), " ");
4040     index++;
4041     column++;
4042   };
4043   strcpy((b + index), tv);
4044   index += length;
4045   column += length;
4046 /* closing newline */
4047   if (column != 0)
4048     strcpy((b + index), "\n");
4049 /* allocate and copy to result */
4050   s = EPDStringGrab(b);
4051   EPDMemoryFree(b);
4052   return s;
4053 }
4054 
4055 /*--> EPDPGNFetchTagIndex: return a PGN Seven Tag Roster tag index */
EPDPGNFetchTagIndex(charptrT s)4056 nonstatic pgnstrT EPDPGNFetchTagIndex(charptrT s) {
4057   pgnstrT pgnstr;
4058   pgnstrT rstr;
4059 
4060   pgnstr = pgnstr_nil;
4061   rstr = 0;
4062   while ((pgnstr == pgnstr_nil) && (rstr < pgnstrL))
4063     if (strcmp(s, EPDPGNFetchTagName(rstr)) == 0)
4064       pgnstr = rstr;
4065     else
4066       rstr++;
4067   return pgnstr;
4068 }
4069 
4070 /*--> EPDPGNFetchTagName: return a PGN Seven Tag Roster tag name */
EPDPGNFetchTagName(pgnstrT pgnstr)4071 nonstatic charptrT EPDPGNFetchTagName(pgnstrT pgnstr) {
4072   return pgnstrstrv[pgnstr];
4073 }
4074 
4075 /*--> EPDPGNGetSTR: return a string from the Seven Tag Roster */
EPDPGNGetSTR(gamptrT gamptr,pgnstrT pgnstr)4076 nonstatic charptrT EPDPGNGetSTR(gamptrT gamptr, pgnstrT pgnstr) {
4077   return gamptr->gam_strv[pgnstr];
4078 }
4079 
4080 /*--> EPDPGNPutSTR: enter a string into the Seven Tag Roster */
EPDPGNPutSTR(gamptrT gamptr,pgnstrT pgnstr,charptrT s)4081 nonstatic void EPDPGNPutSTR(gamptrT gamptr, pgnstrT pgnstr, charptrT s) {
4082   if (gamptr->gam_strv[pgnstr] != NULL)
4083     EPDMemoryFree(gamptr->gam_strv[pgnstr]);
4084   gamptr->gam_strv[pgnstr] = EPDStringGrab(s);
4085   return;
4086 }
4087 
4088 /*--> EPDPGNGenSTR: return a string with the entire STR */
EPDPGNGenSTR(gamptrT gamptr)4089 nonstatic charptrT EPDPGNGenSTR(gamptrT gamptr) {
4090   charptrT s;
4091   pgnstrT pgnstr;
4092   char tv[tL];
4093 
4094   s = EPDStringGrab("");
4095   for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++) {
4096     sprintf(tv, "[%s \"%s\"]\n", pgnstrstrv[pgnstr],
4097         gamptr->gam_strv[pgnstr]);
4098     s = EPDStringAppendStr(s, tv);
4099   };
4100   return s;
4101 }
4102 
4103 /*--> EPDPGNHistory: generate a string for PGN version of history */
EPDPGNHistory(gamptrT gamptr)4104 nonstatic charptrT EPDPGNHistory(gamptrT gamptr) {
4105   charptrT s;
4106   charptrT ms;
4107 
4108   s = EPDPGNGenSTR(gamptr);
4109   s = EPDStringAppendChar(s, '\n');
4110   ms = EPDMoveList(gamptr);
4111   s = EPDStringAppendStr(s, ms);
4112   EPDMemoryFree(ms);
4113   s = EPDStringAppendChar(s, '\n');
4114   return s;
4115 }
4116 
4117 /*--> EPDCopyOutPTP: copy STR from an EDP structure (ptp operation) */
EPDCopyOutPTP(gamptrT gamptr,epdptrT epdptr)4118 nonstatic void EPDCopyOutPTP(gamptrT gamptr, epdptrT epdptr) {
4119   eopptrT eopptr;
4120   eovptrT eovptr;
4121   pgnstrT pgnstr;
4122 
4123   if (epdptr != NULL) {
4124     eopptr = EPDLocateEOPCode(epdptr, epdso_ptp);
4125     eovptr = eopptr->eop_headeov;
4126     while ((eovptr != NULL) && (eovptr->eov_next != NULL)) {
4127       pgnstr = EPDPGNFetchTagIndex(eovptr->eov_str);
4128       if (pgnstr != pgnstr_nil)
4129         EPDPGNPutSTR(gamptr, pgnstr, eovptr->eov_next->eov_str);
4130       eovptr = eovptr->eov_next->eov_next;
4131     };
4132   };
4133   return;
4134 }
4135 
4136 /*--> EPDFetchRefcomStr: return  pointer of indicated refcom string */
EPDFetchRefcomStr(refcomT refcom)4137 nonstatic charptrT EPDFetchRefcomStr(refcomT refcom) {
4138   return refcomstrv[refcom];
4139 }
4140 
4141 /*--> EPDFetchRefreqStr: return  pointer of indicated refreq string */
EPDFetchRefreqStr(refreqT refreq)4142 nonstatic charptrT EPDFetchRefreqStr(refreqT refreq) {
4143   return refreqstrv[refreq];
4144 }
4145 
4146 /*--> EPDFetchRefcomIndex: return a referee command index */
EPDFetchRefcomIndex(charptrT s)4147 nonstatic refcomT EPDFetchRefcomIndex(charptrT s) {
4148   refcomT refcom;
4149   refcomT rcom;
4150 
4151   refcom = refcom_nil;
4152   rcom = 0;
4153   while ((refcom == refcom_nil) && (rcom < refcomL))
4154     if (strcmp(s, EPDFetchRefcomStr(rcom)) == 0)
4155       refcom = rcom;
4156     else
4157       rcom++;
4158   return refcom;
4159 }
4160 
4161 /*--> EPDExtractRefcomIndex: extract a referee command index */
EPDExtractRefcomIndex(epdptrT epdptr)4162 nonstatic refreqT EPDExtractRefcomIndex(epdptrT epdptr) {
4163   refcomT refcom;
4164   eopptrT eopptr;
4165   eovptrT eovptr;
4166 
4167 /* set default return value */
4168   refcom = refreq_nil;
4169   if (epdptr != NULL)
4170     if ((eopptr = EPDLocateEOPCode(epdptr, epdso_refcom)) != NULL)
4171       if ((eovptr = eopptr->eop_headeov) != NULL)
4172         refcom = EPDFetchRefcomIndex(eovptr->eov_str);
4173   return refcom;
4174 }
4175 
4176 /*--> EPDComm: slave to Duplex autoplay program */
EPDComm(refintptrT refintptr,charptrT pipebase)4177 nonstatic siT EPDComm(refintptrT refintptr, charptrT pipebase) {
4178   siT flag;
4179   siT done;
4180   siT flow;
4181   refcomT refcom;
4182   charptrT pfnv[flowL];
4183   fptrT pfptrv[flowL];
4184   epdptrT epdptr0, epdptr1;
4185   charptrT eptr;
4186   char ev[epdL];
4187 
4188 /* set default result: success */
4189   flag = 1;
4190 /* set up the EPD Kit for a new game */
4191   EPDInitArray();
4192 /* generate pipe file names and clear their pointers */
4193   for (flow = 0; flow < flowL; flow++) {
4194     pfnv[flow] = EPDStringGrab(pipebase);
4195     pfnv[flow] = EPDStringAppendStr(pfnv[flow], ".pc");
4196     pfnv[flow] = EPDStringAppendChar(pfnv[flow], (char) (flow + '0'));
4197     pfptrv[flow] = NULL;
4198   };
4199 /* pipe files already created by Duplex, attempt open */
4200   flow = 0;
4201   while (flag && (flow < flowL)) {
4202     pfptrv[flow] = fopen(pfnv[flow], "a+");
4203     if (pfptrv[flow] == NULL)
4204       flag = 0;
4205     else
4206       flow++;
4207   };
4208 /* sign on to Duplex */
4209   if (flag) {
4210     epdptr0 = EPDGetCurrentPosition();
4211     EPDAddOpSym(epdptr0, epdso_refreq, refreqstrv[refreq_sign_on]);
4212     eptr = EPDEncode(epdptr0);
4213     EPDReleaseEPD(epdptr0);
4214     fprintf(pfptrv[0], "%s\n", eptr);
4215     fflush(pfptrv[0]);
4216     EPDMemoryFree(eptr);
4217   };
4218 /* run event cycle loop */
4219   done = 0;
4220   while (flag && !done) {
4221 /* read an incoming EPD message */
4222     if (fgets(ev, (epdL - 1), pfptrv[1]) == NULL)
4223       flag = 0;
4224     else {
4225 /* decode the message */
4226       epdptr1 = EPDDecode(ev);
4227       if ((epdptr1 == NULL)
4228           || ((refcom = EPDExtractRefcomIndex(epdptr1)) == refcom_nil))
4229         flag = 0;
4230       else {
4231 /* send the message to the callback routine */
4232         epdptr0 = (*refintptr) (epdptr1, &flag);
4233 /* release input storage */
4234         EPDReleaseEPD(epdptr1);
4235 /* construct and transmit output string */
4236         if (flag && (epdptr0 != NULL)) {
4237           eptr = EPDEncode(epdptr0);
4238           fprintf(pfptrv[0], "%s\n", eptr);
4239           fflush(pfptrv[0]);
4240           EPDMemoryFree(eptr);
4241         };
4242 /* release output storage */
4243         if (epdptr0 != NULL)
4244           EPDReleaseEPD(epdptr0);
4245 /* set the completion flag on disconnect */
4246         if (flag && !done && (refcom == refcom_disconnect))
4247           done = 1;
4248       };
4249     };
4250   };
4251 /* close pipes and release pipe file names */
4252   for (flow = 0; flow < flowL; flow++) {
4253     if (pfptrv[flow] != NULL)
4254       fclose(pfptrv[flow]);
4255     EPDMemoryFree(pfnv[flow]);
4256   };
4257   return flag;
4258 }
4259 
4260 /*--> EPDInit: one time initialization for EPD */
EPDInit(void)4261 nonstatic void EPDInit(void) {
4262   cpT cp;
4263   sqT sq;
4264   xsqT xsq;
4265 
4266 /* this sets up the current position */
4267 /* initialize ascii color conversion vector */
4268   asccv[c_w] = 'w';
4269   asccv[c_b] = 'b';
4270 /* initialize ascii piece conversion vector */
4271   ascpv[p_p] = 'P';
4272   ascpv[p_n] = 'N';
4273   ascpv[p_b] = 'B';
4274   ascpv[p_r] = 'R';
4275   ascpv[p_q] = 'Q';
4276   ascpv[p_k] = 'K';
4277 /* initialize ascii rank conversion vector */
4278   ascrv[rank_1] = '1';
4279   ascrv[rank_2] = '2';
4280   ascrv[rank_3] = '3';
4281   ascrv[rank_4] = '4';
4282   ascrv[rank_5] = '5';
4283   ascrv[rank_6] = '6';
4284   ascrv[rank_7] = '7';
4285   ascrv[rank_8] = '8';
4286 /* initialize ascii file conversion vector */
4287   ascfv[file_a] = 'a';
4288   ascfv[file_b] = 'b';
4289   ascfv[file_c] = 'c';
4290   ascfv[file_d] = 'd';
4291   ascfv[file_e] = 'e';
4292   ascfv[file_f] = 'f';
4293   ascfv[file_g] = 'g';
4294   ascfv[file_h] = 'h';
4295 /* initialize piece letter from special case move indicator */
4296   cv_p_scmvv[scmv_reg] = p_nil;
4297   cv_p_scmvv[scmv_epc] = p_nil;
4298   cv_p_scmvv[scmv_cks] = p_nil;
4299   cv_p_scmvv[scmv_cqs] = p_nil;
4300   cv_p_scmvv[scmv_ppn] = p_n;
4301   cv_p_scmvv[scmv_ppb] = p_b;
4302   cv_p_scmvv[scmv_ppr] = p_r;
4303   cv_p_scmvv[scmv_ppq] = p_q;
4304 /* initialize various color piece conversion arrays */
4305   for (cp = cp_wp; cp <= cp_wk; cp++)
4306     cv_c_cpv[cp] = c_w;
4307   for (cp = cp_bp; cp <= cp_bk; cp++)
4308     cv_c_cpv[cp] = c_b;
4309   cv_c_cpv[cp_v0] = c_v;
4310   cv_c_cpv[cp_x0] = cv_c_cpv[cp_x1] = cv_c_cpv[cp_x2] = c_x;
4311   cv_p_cpv[cp_wp] = cv_p_cpv[cp_bp] = p_p;
4312   cv_p_cpv[cp_wn] = cv_p_cpv[cp_bn] = p_n;
4313   cv_p_cpv[cp_wb] = cv_p_cpv[cp_bb] = p_b;
4314   cv_p_cpv[cp_wr] = cv_p_cpv[cp_br] = p_r;
4315   cv_p_cpv[cp_wq] = cv_p_cpv[cp_bq] = p_q;
4316   cv_p_cpv[cp_wk] = cv_p_cpv[cp_bk] = p_k;
4317   cv_p_cpv[cp_v0] = p_v;
4318   cv_p_cpv[cp_x0] = cv_p_cpv[cp_x1] = cv_p_cpv[cp_x2] = p_x;
4319   cv_cp_c_pv[c_w][p_p] = cp_wp;
4320   cv_cp_c_pv[c_w][p_n] = cp_wn;
4321   cv_cp_c_pv[c_w][p_b] = cp_wb;
4322   cv_cp_c_pv[c_w][p_r] = cp_wr;
4323   cv_cp_c_pv[c_w][p_q] = cp_wq;
4324   cv_cp_c_pv[c_w][p_k] = cp_wk;
4325   cv_cp_c_pv[c_b][p_p] = cp_bp;
4326   cv_cp_c_pv[c_b][p_n] = cp_bn;
4327   cv_cp_c_pv[c_b][p_b] = cp_bb;
4328   cv_cp_c_pv[c_b][p_r] = cp_br;
4329   cv_cp_c_pv[c_b][p_q] = cp_bq;
4330   cv_cp_c_pv[c_b][p_k] = cp_bk;
4331   inv_cv[c_w] = c_b;
4332   inv_cv[c_b] = c_w;
4333 /* initialize directional vectors */
4334   dvv[dx_0] = dv_0;
4335   dvv[dx_1] = dv_1;
4336   dvv[dx_2] = dv_2;
4337   dvv[dx_3] = dv_3;
4338   dvv[dx_4] = dv_4;
4339   dvv[dx_5] = dv_5;
4340   dvv[dx_6] = dv_6;
4341   dvv[dx_7] = dv_7;
4342   dvv[dx_8] = dv_8;
4343   dvv[dx_9] = dv_9;
4344   dvv[dx_a] = dv_a;
4345   dvv[dx_b] = dv_b;
4346   dvv[dx_c] = dv_c;
4347   dvv[dx_d] = dv_d;
4348   dvv[dx_e] = dv_e;
4349   dvv[dx_f] = dv_f;
4350   xdvv[dx_0] = xdv_0;
4351   xdvv[dx_1] = xdv_1;
4352   xdvv[dx_2] = xdv_2;
4353   xdvv[dx_3] = xdv_3;
4354   xdvv[dx_4] = xdv_4;
4355   xdvv[dx_5] = xdv_5;
4356   xdvv[dx_6] = xdv_6;
4357   xdvv[dx_7] = xdv_7;
4358   xdvv[dx_8] = xdv_8;
4359   xdvv[dx_9] = xdv_9;
4360   xdvv[dx_a] = xdv_a;
4361   xdvv[dx_b] = xdv_b;
4362   xdvv[dx_c] = xdv_c;
4363   xdvv[dx_d] = xdv_d;
4364   xdvv[dx_e] = xdv_e;
4365   xdvv[dx_f] = xdv_f;
4366 /* initialize the extended board */
4367   for (xsq = 0; xsq < xsqL; xsq++)
4368     xb.xbv[xsq] = cp_x0;
4369   for (sq = sq_a1; sq <= sq_h8; sq++)
4370     xb.xbv[map_xsq_sq(sq)] = cp_v0;
4371 /* initialize the standard opcode string vector */
4372   epdsostrv[epdso_acd] = "acd";
4373   epdsostrv[epdso_acn] = "acn";
4374   epdsostrv[epdso_acs] = "acs";
4375   epdsostrv[epdso_am] = "am";
4376   epdsostrv[epdso_bm] = "bm";
4377   epdsostrv[epdso_c0] = "c0";
4378   epdsostrv[epdso_c1] = "c1";
4379   epdsostrv[epdso_c2] = "c2";
4380   epdsostrv[epdso_c3] = "c3";
4381   epdsostrv[epdso_c4] = "c4";
4382   epdsostrv[epdso_c5] = "c5";
4383   epdsostrv[epdso_c6] = "c6";
4384   epdsostrv[epdso_c7] = "c7";
4385   epdsostrv[epdso_c8] = "c8";
4386   epdsostrv[epdso_c9] = "c9";
4387   epdsostrv[epdso_cc] = "cc";
4388   epdsostrv[epdso_ce] = "ce";
4389   epdsostrv[epdso_dm] = "dm";
4390   epdsostrv[epdso_draw_accept] = "draw_accept";
4391   epdsostrv[epdso_draw_claim] = "draw_claim";
4392   epdsostrv[epdso_draw_offer] = "draw_offer";
4393   epdsostrv[epdso_draw_reject] = "draw_reject";
4394   epdsostrv[epdso_eco] = "eco";
4395   epdsostrv[epdso_fmvn] = "fmvn";
4396   epdsostrv[epdso_hmvc] = "hmvc";
4397   epdsostrv[epdso_id] = "id";
4398   epdsostrv[epdso_nic] = "nic";
4399   epdsostrv[epdso_noop] = "noop";
4400   epdsostrv[epdso_pm] = "pm";
4401   epdsostrv[epdso_ptp] = "ptp";
4402   epdsostrv[epdso_pv] = "pv";
4403   epdsostrv[epdso_rc] = "rc";
4404   epdsostrv[epdso_refcom] = "refcom";
4405   epdsostrv[epdso_refreq] = "refreq";
4406   epdsostrv[epdso_resign] = "resign";
4407   epdsostrv[epdso_sm] = "sm";
4408   epdsostrv[epdso_sv] = "sv";
4409   epdsostrv[epdso_tcgs] = "tcgs";
4410   epdsostrv[epdso_tcri] = "tcri";
4411   epdsostrv[epdso_tcsi] = "tcsi";
4412   epdsostrv[epdso_ts] = "ts";
4413   epdsostrv[epdso_v0] = "v0";
4414   epdsostrv[epdso_v1] = "v1";
4415   epdsostrv[epdso_v2] = "v2";
4416   epdsostrv[epdso_v3] = "v3";
4417   epdsostrv[epdso_v4] = "v4";
4418   epdsostrv[epdso_v5] = "v5";
4419   epdsostrv[epdso_v6] = "v6";
4420   epdsostrv[epdso_v7] = "v7";
4421   epdsostrv[epdso_v8] = "v8";
4422   epdsostrv[epdso_v9] = "v9";
4423 /* set the EPD refcom operand strings */
4424   refcomstrv[refcom_conclude] = "conclude";
4425   refcomstrv[refcom_disconnect] = "disconnect";
4426   refcomstrv[refcom_execute] = "execute";
4427   refcomstrv[refcom_fault] = "fault";
4428   refcomstrv[refcom_inform] = "inform";
4429   refcomstrv[refcom_respond] = "respond";
4430   refcomstrv[refcom_reset] = "reset";
4431 /* set the EPD refreq operand strings */
4432   refreqstrv[refreq_fault] = "fault";
4433   refreqstrv[refreq_reply] = "reply";
4434   refreqstrv[refreq_sign_on] = "sign_on";
4435   refreqstrv[refreq_sign_off] = "sign_off";
4436 /* set the PGN Seven Tag Roster names */
4437   pgnstrstrv[pgnstr_event] = "Event";
4438   pgnstrstrv[pgnstr_site] = "Site";
4439   pgnstrstrv[pgnstr_date] = "Date";
4440   pgnstrstrv[pgnstr_round] = "Round";
4441   pgnstrstrv[pgnstr_white] = "White";
4442   pgnstrstrv[pgnstr_black] = "Black";
4443   pgnstrstrv[pgnstr_result] = "Result";
4444 /* set the game termination indication marker vector */
4445   gtimstrv[gtim_w] = "1-0";
4446   gtimstrv[gtim_b] = "0-1";
4447   gtimstrv[gtim_d] = "1/2-1/2";
4448   gtimstrv[gtim_u] = "*";
4449 /* clear the global game chain anchor pointers */
4450   head_gamptr = tail_gamptr = NULL;
4451 /* clear the token chain anchor pointers */
4452   head_tknptr = tail_tknptr = NULL;
4453 /* clear the current ply */
4454   ply = 0;
4455 /* allocate the move tree */
4456   treeptr = treebaseptr = (mptrT) EPDMemoryGrab(sizeof(mT) * treeL);
4457 /* allocate the tree stack entry stack */
4458   tseptr = tsebaseptr = (tseptrT) EPDMemoryGrab(sizeof(tseT) * pmhL);
4459 /* allocate the environment stack entry stack */
4460   eseptr = esebaseptr = (eseptrT) EPDMemoryGrab(sizeof(eseT) * pmhL);
4461 /* set the current position to be the initial array */
4462   EPDInitArray();
4463 /* generation */
4464   EPDGenMoves();
4465   return;
4466 }
4467 
4468 /*--> EPDTerm: one time termination for EPD */
EPDTerm(void)4469 nonstatic void EPDTerm(void) {
4470 /* release any existing game chain */
4471   EPDReleaseGameChain();
4472 /* release any existing token chain */
4473   EPDReleaseTokenChain();
4474 /* deallocate various stacks */
4475   EPDMemoryFree(esebaseptr);
4476   EPDMemoryFree(tsebaseptr);
4477   EPDMemoryFree(treebaseptr);
4478 /* "Wanna see my sprocket collection?" */
4479   return;
4480 }
4481 #endif
4482 /*<<< epd.c: EOF */
4483