1 /*>>> epd.c: Extended Position Description routines */
2 
3 /* Revised: 1996.06.23 */
4 
5 /*
6 Copyright (C) 1996 by Steven J. Edwards (sje@mv.mv.com)
7 All rights reserved.  This code may be freely redistibuted and used by
8 both research and commerical applications.  No warranty exists.
9 */
10 
11 /*
12 Everything in this source file is independent of the host program, as
13 are the prototypes in the epd.h include file.
14 
15 *** Not quite true---relies on tb_path from the host program
16 
17 Requests for changes
18 and additions should be communicated to the author via the e-mail
19 address given above.
20 */
21 
22 /*
23 This file was originally prepared on an Apple Macintosh using the
24 Metrowerks CodeWarrior 6 ANSI C compiler.  Tabs are set at every
25 four columns.  Further testing and development was performed on a
26 generic PC running Linux 1.3.20 and using the gcc 2.7.0 compiler.
27 */
28 
29 /* system includes */
30 
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <string.h>
35 #include <time.h>
36 
37 /* EPD definitions (host independent) */
38 
39 extern char *tb_path;
40 #include "epddefs.h"
41 
42 
43 /* EPD routine prototypes (host independent) */
44 
45 #include "epd.h"
46 
47 /* ASCII character constants */
48 
49 #define ascii_nul ((char) 0x00)
50 #define ascii_sp  ((char) 0x20)
51 
52 /* tree limit; adjust according to memory availability */
53 
54 #define treeL 16384
55 
56 /* tree overrun safety margin */
57 
58 #define treemarginL 256
59 
60 /* played moves history limit; adjust according to memory availability */
61 
62 #define pmhL 512
63 
64 /* data flows (input and output) */
65 
66 #define flowL 2
67 
68 /* character case mapping */
69 
70 #define map_lower(ch) (isupper((ch)) ? tolower((ch)) : (ch))
71 #define map_upper(ch) (islower((ch)) ? toupper((ch)) : (ch))
72 
73 /* identifier character check */
74 
75 #define IdentChar(ch) (isalpha((ch)) || isdigit((ch)) || ((ch) == '_'))
76 
77 /* vacancy check */
78 
79 #define Vacant(sq) (EPDboard.rbv[(sq)] == cp_v0)
80 
81 /* token record type (for token chain) */
82 
83 typedef struct tknS
84 	{
85 	charptrT     tkn_str;  /* allocated token string value */
86 	struct tknS *tkn_prev; /* previous record */
87 	struct tknS *tkn_next; /* next record */
88 	} tknT, *tknptrT;
89 
90 /* tree stack entry record type */
91 
92 typedef struct tseS
93 	{
94 	siT   tse_count; /* entry count for this level */
95 	mptrT tse_base;  /* first move in moveset */
96 	mptrT tse_curr;  /* current move of interest in moveset */
97 	} tseT, *tseptrT;
98 
99 /* color to move strings */
100 
101 static charptrT ctmext_strv[rcL];
102 
103 /* global game chain anchors */
104 
105 static gamptrT head_gamptr;
106 static gamptrT tail_gamptr;
107 
108 /* EPD standard opcode mnemonics */
109 
110 static charptrT epdsostrv[epdsoL];
111 
112 /* EPD refcom operand strings */
113 
114 static charptrT refcomstrv[refcomL];
115 
116 /* EPD refreq operand strings */
117 
118 static charptrT refreqstrv[refreqL];
119 
120 /* PGN Seven Tag Roster names */
121 
122 static charptrT pgnstrstrv[pgnstrL];
123 
124 /* game termination indication marker strings */
125 
126 static charptrT gtimstrv[gtimL];
127 
128 /* player name strings */
129 
130 static charptrT playerstrv[rcL];
131 
132 /* character conversion vectors (colors and pieces) */
133 
134 static char asccv[rcL];
135 static char ascpv[rpL];
136 
137 /* character conversion vectors (ranks and files) */
138 
139 static char ascrv[rankL];
140 static char ascfv[fileL];
141 
142 /* promotion piece from special case move code coversion vector */
143 
144 static pT cv_p_scmvv[scmvL];
145 
146 /* various color and piece conversion vectors */
147 
148 static cpT cv_cp_c_pv[rcL][rpL];
149 static cT cv_c_cpv[cpL];
150 static pT cv_p_cpv[cpL];
151 static cT inv_cv[rcL];
152 
153 /* direction vectors */
154 
155 static dvT dvv[dxL];
156 static xdvT xdvv[dxL];
157 
158 /* extension board (border detection) */
159 
160 static xbT xb;
161 
162 /* maps */
163 
164 static siT flank_mapv[sqL];
165 static siT triangle_mapv[sqL];
166 
167 /* token chain anchors */
168 
169 static tknptrT head_tknptr;
170 static tknptrT tail_tknptr;
171 
172 /* local SAN vector and its index */
173 
174 static sanT lsan;
175 static siT lsani;
176 
177 /* census vectors */
178 
179 static siT count_cv[rcL];
180 static siT count_cpv[rcL][rpL];
181 
182 /* the current board */
183 
184 static rbT EPDboard;
185 
186 /* the current environment stack entry  */
187 
188 static eseT ese;
189 
190 /* the current tree stack entry */
191 
192 static tseT tse;
193 
194 /* the master ply index */
195 
196 static siT ply;
197 
198 /* the base of the move tree and its current pointer */
199 
200 static mptrT treebaseptr;
201 static mptrT treeptr;
202 
203 /* the base of the tree stack entry stack and its current pointer */
204 
205 static tseptrT tsebaseptr;
206 static tseptrT tseptr;
207 
208 /* base of the environment stack and its current pointer */
209 
210 static eseptrT esebaseptr;
211 static eseptrT eseptr;
212 
213 /* tablebase information record vector storage base */
214 
215 static tbptrT tbbaseptr;
216 
217 /* tablebase file pointer cache vector */
218 
219 static tbcT tbcv[tbcL];
220 
221 /* return area for board data */
222 
223 static rbT ret_rb;
224 
225 /* return area for move data */
226 
227 static mT ret_m;
228 
229 /*--> EPDFatal: emit fatal diagnostic and quit */
230 nonstatic
231 void
EPDFatal(charptrT s)232 EPDFatal(charptrT s)
233 {
234 fprintf(stderr, "EPD Fatal error: %s.\n", s);
235 exit(1);
236 }
237 
238 /*--> EPDSwitchFault: emit switch fault diagnostic and quit */
239 nonstatic
240 void
EPDSwitchFault(charptrT s)241 EPDSwitchFault(charptrT s)
242 {
243 fprintf(stderr, "Switch fault detected.\n");
244 EPDFatal(s);
245 
246 return;
247 }
248 
249 /*--> EPDMemoryGrab: allocate memory */
250 nonstatic
251 voidptrT
EPDMemoryGrab(liT n)252 EPDMemoryGrab(liT n)
253 {
254 voidptrT ptr;
255 
256 ptr = (voidptrT) malloc((n == 0) ? 1 : n);
257 if (ptr == NULL)
258 	EPDFatal("EPDMemoryGrab");
259 
260 return (ptr);
261 }
262 
263 /*--> EPDMemoryFree: deallocate memory */
264 nonstatic
265 void
EPDMemoryFree(voidptrT ptr)266 EPDMemoryFree(voidptrT ptr)
267 {
268 if (ptr != NULL)
269 	free(ptr);
270 
271 return;
272 }
273 
274 /*--> EPDStringGrab: allocate and copy a string */
275 nonstatic
276 charptrT
EPDStringGrab(charptrT s)277 EPDStringGrab(charptrT s)
278 {
279 charptrT ptr;
280 
281 ptr = (charptrT) EPDMemoryGrab(strlen(s) + 1);
282 strcpy(ptr, s);
283 
284 return (ptr);
285 }
286 
287 /*--> EPDStringFree: deallocate a string */
288 nonstatic
289 void
EPDStringFree(charptrT s)290 EPDStringFree(charptrT s)
291 {
292 EPDMemoryFree(s);
293 
294 return;
295 }
296 
297 /*--> EPDStringAppendChar: append a character to a string */
298 nonstatic
299 charptrT
EPDStringAppendChar(charptrT s,char c)300 EPDStringAppendChar(charptrT s, char c)
301 {
302 charptrT ptr;
303 liT length;
304 
305 /* the first argument is deallocated */
306 
307 length = strlen(s);
308 ptr = (charptrT) EPDMemoryGrab(length + 2);
309 strcpy(ptr, s);
310 EPDMemoryFree(s);
311 *(ptr + length) = c;
312 *(ptr + length + 1) = ascii_nul;
313 
314 return (ptr);
315 }
316 
317 /*--> EPDStringAppendStr: append a string to a string */
318 nonstatic
319 charptrT
EPDStringAppendStr(charptrT s0,charptrT s1)320 EPDStringAppendStr(charptrT s0, charptrT s1)
321 {
322 charptrT ptr;
323 liT length;
324 
325 /* the first argument is deallocated */
326 
327 length = strlen(s0) + strlen(s1);
328 ptr = (charptrT) EPDMemoryGrab(length + 1);
329 strcpy(ptr, s0);
330 strcat(ptr, s1);
331 EPDMemoryFree(s0);
332 
333 return (ptr);
334 }
335 
336 /*--> EPDMapFromDuration: convert from duration to seconds */
337 nonstatic
338 liT
EPDMapFromDuration(charptrT s)339 EPDMapFromDuration(charptrT s)
340 {
341 liT seconds;
342 siT scs, mns, hrs, dys;
343 
344 sscanf(s, "%04hd:%02hd:%02hd:%02hd", &dys, &hrs, &mns, &scs);
345 
346 seconds = ((liT) dys * 86400) +
347 	((liT) hrs * 3600) + ((liT) mns * 60) + (liT) scs;
348 
349 return (seconds);
350 }
351 
352 /*--> EPDMapToDuration: convert from seconds to duration */
353 nonstatic
354 charptrT
EPDMapToDuration(liT seconds)355 EPDMapToDuration(liT seconds)
356 {
357 charptrT s;
358 siT scs, mns, hrs, dys;
359 
360 s = (charptrT) EPDMemoryGrab(durationL);
361 
362 scs = seconds % 60;
363 mns = (seconds / 60) % 60;
364 hrs = (seconds / 3600) % 24;
365 dys = (seconds / 86400) % 10000;
366 
367 sprintf(s, "%04hd:%02hd:%02hd:%02hd", dys, hrs, mns, scs);
368 
369 return (s);
370 }
371 
372 /*--> EPDNewGPM: allocate and initialize a new GPM record */
373 static
374 gpmptrT
EPDNewGPM(mptrT mptr)375 EPDNewGPM(mptrT mptr)
376 {
377 gpmptrT gpmptr;
378 cT c;
379 sqT sq;
380 cpT cp0, cp1;
381 
382 gpmptr = (gpmptrT) EPDMemoryGrab(sizeof(gpmT));
383 
384 gpmptr->gpm_m = *mptr;
385 
386 gpmptr->gpm_ese.ese_actc = ese.ese_actc;
387 gpmptr->gpm_ese.ese_cast = ese.ese_cast;
388 gpmptr->gpm_ese.ese_epsq = ese.ese_epsq;
389 gpmptr->gpm_ese.ese_hmvc = ese.ese_hmvc;
390 gpmptr->gpm_ese.ese_fmvn = ese.ese_fmvn;
391 
392 for (c = c_w; c <= c_b; c++)
393 	gpmptr->gpm_ese.ese_ksqv[c] = ese.ese_ksqv[c];
394 
395 for (sq = sq_a1; sq <= sq_h8; sq += 2)
396 	{
397 	cp0 = EPDboard.rbv[sq + 0];
398 	cp1 = EPDboard.rbv[sq + 1];
399 	gpmptr->gpm_nbv[sq >> 1] = ((cp1 << nybbW) | cp0);
400 	};
401 
402 gpmptr->gpm_prev = gpmptr->gpm_next = NULL;
403 
404 return (gpmptr);
405 }
406 
407 /*--> EPDReleaseGPM: release a GPM record */
408 static
409 void
EPDReleaseGPM(gpmptrT gpmptr)410 EPDReleaseGPM(gpmptrT gpmptr)
411 {
412 if (gpmptr != NULL)
413 	EPDMemoryFree(gpmptr);
414 
415 return;
416 }
417 
418 /*--> EPDAppendGPM: append a GPM record to a game  */
419 static
420 void
EPDAppendGPM(gamptrT gamptr,gpmptrT gpmptr)421 EPDAppendGPM(gamptrT gamptr, gpmptrT gpmptr)
422 {
423 if (gamptr->gam_tailgpm == NULL)
424 	gamptr->gam_headgpm = gpmptr;
425 else
426 	gamptr->gam_tailgpm->gpm_next = gpmptr;
427 
428 gpmptr->gpm_prev = gamptr->gam_tailgpm;
429 gpmptr->gpm_next = NULL;
430 
431 gamptr->gam_tailgpm = gpmptr;
432 
433 return;
434 }
435 
436 /*--> EPDUnthreadGPM: unthread a GPM record from a game */
437 static
438 void
EPDUnthreadGPM(gamptrT gamptr,gpmptrT gpmptr)439 EPDUnthreadGPM(gamptrT gamptr, gpmptrT gpmptr)
440 {
441 if (gpmptr->gpm_prev == NULL)
442 	gamptr->gam_headgpm = gpmptr->gpm_next;
443 else
444 	gpmptr->gpm_prev->gpm_next = gpmptr->gpm_next;
445 
446 if (gpmptr->gpm_next == NULL)
447 	gamptr->gam_tailgpm = gpmptr->gpm_prev;
448 else
449 	gpmptr->gpm_next->gpm_prev = gpmptr->gpm_prev;
450 
451 return;
452 }
453 
454 /*--> EPDReleaseGPMoveChain: release the game played moves chain */
455 static
456 void
EPDReleaseGPMoveChain(gamptrT gamptr)457 EPDReleaseGPMoveChain(gamptrT gamptr)
458 {
459 gpmptrT gpmptr;
460 
461 while (gamptr->gam_headgpm != NULL)
462 	{
463 	gpmptr = gamptr->gam_tailgpm;
464 	EPDUnthreadGPM(gamptr, gpmptr);
465 	EPDReleaseGPM(gpmptr);
466 	};
467 
468 return;
469 }
470 
471 /*--> EPDNewGAM: allocate and initialize a new GAM record */
472 static
473 gamptrT
EPDNewGAM(void)474 EPDNewGAM(void)
475 {
476 gamptrT gamptr;
477 pgnstrT pgnstr;
478 
479 gamptr = (gamptrT) EPDMemoryGrab(sizeof(gamT));
480 
481 for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++)
482 	gamptr->gam_strv[pgnstr] = EPDStringGrab("");
483 
484 gamptr->gam_gtim = gtim_u;
485 
486 gamptr->gam_headgpm = gamptr->gam_tailgpm = NULL;
487 gamptr->gam_prev = gamptr->gam_next = NULL;
488 
489 return (gamptr);
490 }
491 
492 /*--> EPDReleaseGAM: release a GAM record */
493 static
494 void
EPDReleaseGAM(gamptrT gamptr)495 EPDReleaseGAM(gamptrT gamptr)
496 {
497 pgnstrT pgnstr;
498 
499 if (gamptr != NULL)
500 	{
501 	for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++)
502 		if (gamptr->gam_strv[pgnstr] != NULL)
503 			EPDMemoryFree(gamptr->gam_strv[pgnstr]);
504 	EPDReleaseGPMoveChain(gamptr);
505 	EPDMemoryFree(gamptr);
506 	};
507 
508 return;
509 }
510 
511 /*--> EPDAppendGAM: append a GAM record to the game chain */
512 static
513 void
EPDAppendGAM(gamptrT gamptr)514 EPDAppendGAM(gamptrT gamptr)
515 {
516 if (tail_gamptr == NULL)
517 	head_gamptr = gamptr;
518 else
519 	tail_gamptr->gam_next = gamptr;
520 
521 gamptr->gam_prev = tail_gamptr;
522 gamptr->gam_next = NULL;
523 
524 tail_gamptr = gamptr;
525 
526 return;
527 }
528 
529 /*--> EPDUnthreadGAM: unthread a GAM record from the game chain */
530 static
531 void
EPDUnthreadGAM(gamptrT gamptr)532 EPDUnthreadGAM(gamptrT gamptr)
533 {
534 if (gamptr->gam_prev == NULL)
535 	head_gamptr = gamptr->gam_next;
536 else
537 	gamptr->gam_prev->gam_next = gamptr->gam_next;
538 
539 if (gamptr->gam_next == NULL)
540 	tail_gamptr = gamptr->gam_prev;
541 else
542 	gamptr->gam_next->gam_prev = gamptr->gam_prev;
543 
544 return;
545 }
546 
547 /*--> EPDReleaseGameChain: release the game chain */
548 static
549 void
EPDReleaseGameChain(void)550 EPDReleaseGameChain(void)
551 {
552 gamptrT gamptr;
553 
554 while (head_gamptr != NULL)
555 	{
556 	gamptr = tail_gamptr;
557 	EPDUnthreadGAM(gamptr);
558 	EPDReleaseGAM(gamptr);
559 	};
560 
561 return;
562 }
563 
564 /*--> EPDGamePlyCount: return ply count of a game */
565 static
566 siT
EPDGamePlyCount(gamptrT gamptr)567 EPDGamePlyCount(gamptrT gamptr)
568 {
569 siT count;
570 gpmptrT gpmptr;
571 
572 count = 0;
573 gpmptr = gamptr->gam_headgpm;
574 
575 while (gpmptr != NULL)
576 	{
577 	count++;
578 	gpmptr = gpmptr->gpm_next;
579 	};
580 
581 return (count);
582 }
583 
584 /*--> EPDGameOpen: create/open a new game structure */
585 nonstatic
586 gamptrT
EPDGameOpen(void)587 EPDGameOpen(void)
588 {
589 gamptrT gamptr;
590 
591 gamptr = EPDNewGAM();
592 EPDAppendGAM(gamptr);
593 
594 return (gamptr);
595 }
596 
597 /*--> EPDGameClose: close/destroy a game structure */
598 nonstatic
599 void
EPDGameClose(gamptrT gamptr)600 EPDGameClose(gamptrT gamptr)
601 {
602 if (gamptr != NULL)
603 	{
604 	EPDUnthreadGAM(gamptr);
605 	EPDReleaseGAM(gamptr);
606 	};
607 
608 return;
609 }
610 
611 /*--> EPDGameAppendMove: append a move to a game structure */
612 nonstatic
613 void
EPDGameAppendMove(gamptrT gamptr,mptrT mptr)614 EPDGameAppendMove(gamptrT gamptr, mptrT mptr)
615 {
616 gpmptrT gpmptr;
617 
618 gpmptr = EPDNewGPM(mptr);
619 EPDAppendGPM(gamptr, gpmptr);
620 
621 return;
622 }
623 
624 /*--> EPDNewTKN: allocate and initialize a new TKN record */
625 static
626 tknptrT
EPDNewTKN(charptrT s)627 EPDNewTKN(charptrT s)
628 {
629 tknptrT tknptr;
630 
631 tknptr = (tknptrT) EPDMemoryGrab(sizeof(tknT));
632 
633 tknptr->tkn_str = EPDStringGrab(s);
634 tknptr->tkn_prev = tknptr->tkn_next = NULL;
635 
636 return (tknptr);
637 }
638 
639 /*--> EPDReleaseTKN: release a TKN record */
640 static
641 void
EPDReleaseTKN(tknptrT tknptr)642 EPDReleaseTKN(tknptrT tknptr)
643 {
644 if (tknptr != NULL)
645 	{
646 	if (tknptr->tkn_str != NULL)
647 		EPDMemoryFree(tknptr->tkn_str);
648 	EPDMemoryFree(tknptr);
649 	};
650 
651 return;
652 }
653 
654 /*--> EPDAppendTKN: append a TKN record to the token chain */
655 static
656 void
EPDAppendTKN(tknptrT tknptr)657 EPDAppendTKN(tknptrT tknptr)
658 {
659 if (tail_tknptr == NULL)
660 	head_tknptr = tknptr;
661 else
662 	tail_tknptr->tkn_next = tknptr;
663 
664 tknptr->tkn_prev = tail_tknptr;
665 tknptr->tkn_next = NULL;
666 
667 tail_tknptr = tknptr;
668 
669 return;
670 }
671 
672 /*--> EPDUnthreadTKN: unthread a TKN record from the token chain */
673 static
674 void
EPDUnthreadTKN(tknptrT tknptr)675 EPDUnthreadTKN(tknptrT tknptr)
676 {
677 if (tknptr->tkn_prev == NULL)
678 	head_tknptr = tknptr->tkn_next;
679 else
680 	tknptr->tkn_prev->tkn_next = tknptr->tkn_next;
681 
682 if (tknptr->tkn_next == NULL)
683 	tail_tknptr = tknptr->tkn_prev;
684 else
685 	tknptr->tkn_next->tkn_prev = tknptr->tkn_prev;
686 
687 return;
688 }
689 
690 /*--> EPDReleaseTokenChain: release the token chain */
691 static
692 void
EPDReleaseTokenChain(void)693 EPDReleaseTokenChain(void)
694 {
695 tknptrT tknptr;
696 
697 while (head_tknptr != NULL)
698 	{
699 	tknptr = tail_tknptr;
700 	EPDUnthreadTKN(tknptr);
701 	EPDReleaseTKN(tknptr);
702 	};
703 
704 return;
705 }
706 
707 /*--> EPDTokenize: create the token chain */
708 nonstatic
709 void
EPDTokenize(charptrT s)710 EPDTokenize(charptrT s)
711 {
712 siT i;
713 char c;
714 tknptrT tknptr;
715 charptrT str;
716 
717 /* first, release any existing chain */
718 
719 EPDReleaseTokenChain();
720 
721 /* scan the input until end of string */
722 
723 i = 0;
724 c = *(s + i++);
725 while (c != ascii_nul)
726 	{
727 	/* skip leading whitespace */
728 
729 	while ((c != ascii_nul) && isspace(c))
730 		c = *(s + i++);
731 
732 	/* if not at end of string, then a token has started */
733 
734 	if (c != ascii_nul)
735 		{
736 		str = EPDStringGrab("");
737 
738 		while ((c != ascii_nul) && !isspace(c))
739 			{
740 			str = EPDStringAppendChar(str, c);
741 			c = *(s + i++);
742 			};
743 
744 		tknptr = EPDNewTKN(str);
745 		EPDAppendTKN(tknptr);
746 		EPDMemoryFree(str);
747 		};
748 	};
749 
750 return;
751 }
752 
753 /*--> EPDTokenCount: count the tokens in the token chain */
754 nonstatic
755 siT
EPDTokenCount(void)756 EPDTokenCount(void)
757 {
758 siT n;
759 tknptrT tknptr;
760 
761 n = 0;
762 tknptr = head_tknptr;
763 while (tknptr != NULL)
764 	{
765 	n++;
766 	tknptr = tknptr->tkn_next;
767 	};
768 
769 return (n);
770 }
771 
772 /*--> EPDTokenFetch: fetch n-th (zero origin) token from the token chain */
773 nonstatic
774 charptrT
EPDTokenFetch(siT n)775 EPDTokenFetch(siT n)
776 {
777 charptrT s;
778 siT i;
779 tknptrT tknptr;
780 
781 i = 0;
782 tknptr = head_tknptr;
783 while ((tknptr != NULL) && (i < n))
784 	{
785 	i++;
786 	tknptr = tknptr->tkn_next;
787 	};
788 
789 if (tknptr == NULL)
790 	s = NULL;
791 else
792 	s = tknptr->tkn_str;
793 
794 return (s);
795 }
796 
797 /*--> EPDCICharEqual: test for case independent character equality */
798 nonstatic
799 siT
EPDCICharEqual(char ch0,char ch1)800 EPDCICharEqual(char ch0, char ch1)
801 {
802 siT flag;
803 
804 if (map_lower(ch0) == map_lower(ch1))
805 	flag = 1;
806 else
807 	flag = 0;
808 
809 return (flag);
810 }
811 
812 /*--> EPDPieceFromCP: fetch piece from color-piece */
813 nonstatic
814 pT
EPDPieceFromCP(cpT cp)815 EPDPieceFromCP(cpT cp)
816 {
817 pT p;
818 
819 p = cv_p_cpv[cp];
820 
821 return (p);
822 }
823 
824 /*--> EPDCheckPiece: test if a character is a piece letter */
825 nonstatic
826 siT
EPDCheckPiece(char ch)827 EPDCheckPiece(char ch)
828 {
829 siT flag;
830 pT p;
831 
832 flag = 0;
833 p = p_p;
834 while (!flag && (p <= p_k))
835 	if (EPDCICharEqual(ch, ascpv[p]))
836 		flag = 1;
837 	else
838 		p++;
839 
840 return (flag);
841 }
842 
843 /*--> EPDEvaluatePiece: evaluate a piece letter character */
844 nonstatic
845 pT
EPDEvaluatePiece(char ch)846 EPDEvaluatePiece(char ch)
847 {
848 pT p;
849 siT flag;
850 
851 flag = 0;
852 p = p_p;
853 while (!flag && (p <= p_k))
854 	if (EPDCICharEqual(ch, ascpv[p]))
855 		flag = 1;
856 	else
857 		p++;
858 
859 if (!flag)
860 	p = p_nil;
861 
862 return (p);
863 }
864 
865 /*--> EPDCheckColor: test if a character is a color letter */
866 nonstatic
867 siT
EPDCheckColor(char ch)868 EPDCheckColor(char ch)
869 {
870 siT flag;
871 cT c;
872 
873 flag = 0;
874 c = c_w;
875 while (!flag && (c <= c_b))
876 	if (EPDCICharEqual(ch, asccv[c]))
877 		flag = 1;
878 	else
879 		c++;
880 
881 return (flag);
882 }
883 
884 /*--> EPDEvaluateColor: evaluate a color letter character */
885 nonstatic
886 cT
EPDEvaluateColor(char ch)887 EPDEvaluateColor(char ch)
888 {
889 cT c;
890 siT flag;
891 
892 flag = 0;
893 c = c_w;
894 while (!flag && (c <= c_b))
895 	if (EPDCICharEqual(ch, asccv[c]))
896 		flag = 1;
897 	else
898 		c++;
899 
900 if (!flag)
901 	c = c_nil;
902 
903 return (c);
904 }
905 
906 /*--> EPDCheckRank: test if a character is a rank character */
907 nonstatic
908 siT
EPDCheckRank(char ch)909 EPDCheckRank(char ch)
910 {
911 siT flag;
912 rankT rank;
913 
914 flag = 0;
915 rank = rank_1;
916 while (!flag && (rank <= rank_8))
917 	if (EPDCICharEqual(ch, ascrv[rank]))
918 		flag = 1;
919 	else
920 		rank++;
921 
922 return (flag);
923 }
924 
925 /*--> EPDEvaluateRank: evaluate a color rank character */
926 nonstatic
927 rankT
EPDEvaluateRank(char ch)928 EPDEvaluateRank(char ch)
929 {
930 rankT rank;
931 siT flag;
932 
933 flag = 0;
934 rank = rank_1;
935 while (!flag && (rank <= rank_8))
936 	if (EPDCICharEqual(ch, ascrv[rank]))
937 		flag = 1;
938 	else
939 		rank++;
940 
941 if (!flag)
942 	rank = rank_nil;
943 
944 return (rank);
945 }
946 
947 /*--> EPDCheckFile: test if a character is a file character */
948 nonstatic
949 siT
EPDCheckFile(char ch)950 EPDCheckFile(char ch)
951 {
952 siT flag;
953 fileT file;
954 
955 flag = 0;
956 file = file_a;
957 while (!flag && (file <= file_h))
958 	if (EPDCICharEqual(ch, ascfv[file]))
959 		flag = 1;
960 	else
961 		file++;
962 
963 return (flag);
964 }
965 
966 /*--> EPDEvaluateFile: evaluate a color file character */
967 nonstatic
968 rankT
EPDEvaluateFile(char ch)969 EPDEvaluateFile(char ch)
970 {
971 fileT file;
972 siT flag;
973 
974 flag = 0;
975 file = file_a;
976 while (!flag && (file <= file_h))
977 	if (EPDCICharEqual(ch, ascfv[file]))
978 		flag = 1;
979 	else
980 		file++;
981 
982 if (!flag)
983 	file = file_nil;
984 
985 return (file);
986 }
987 
988 /*--> EPDNewEOV: allocate a new EOV record */
989 nonstatic
990 eovptrT
EPDNewEOV(void)991 EPDNewEOV(void)
992 {
993 eovptrT eovptr;
994 
995 eovptr = (eovptrT) EPDMemoryGrab(sizeof(eovT));
996 
997 eovptr->eov_eob = eob_nil;
998 eovptr->eov_str = NULL;
999 eovptr->eov_prev = eovptr->eov_next = NULL;
1000 
1001 return (eovptr);
1002 }
1003 
1004 /*--> EPDReleaseEOV: release an EOV record */
1005 nonstatic
1006 void
EPDReleaseEOV(eovptrT eovptr)1007 EPDReleaseEOV(eovptrT eovptr)
1008 {
1009 if (eovptr != NULL)
1010 	{
1011 	if (eovptr->eov_str != NULL)
1012 		EPDMemoryFree(eovptr->eov_str);
1013 	EPDMemoryFree(eovptr);
1014 	};
1015 
1016 return;
1017 }
1018 
1019 /*--> EPDAppendEOV: append an EOV record */
1020 nonstatic
1021 void
EPDAppendEOV(eopptrT eopptr,eovptrT eovptr)1022 EPDAppendEOV(eopptrT eopptr, eovptrT eovptr)
1023 {
1024 if (eopptr->eop_taileov == NULL)
1025 	eopptr->eop_headeov = eovptr;
1026 else
1027 	eopptr->eop_taileov->eov_next = eovptr;
1028 
1029 eovptr->eov_prev = eopptr->eop_taileov;
1030 eovptr->eov_next = NULL;
1031 
1032 eopptr->eop_taileov = eovptr;
1033 
1034 return;
1035 }
1036 
1037 /*--> EPDUnthreadEOV: unthread an EOV record */
1038 static
1039 void
EPDUnthreadEOV(eopptrT eopptr,eovptrT eovptr)1040 EPDUnthreadEOV(eopptrT eopptr, eovptrT eovptr)
1041 {
1042 if (eovptr->eov_prev == NULL)
1043 	eopptr->eop_headeov = eovptr->eov_next;
1044 else
1045 	eovptr->eov_prev->eov_next = eovptr->eov_next;
1046 
1047 if (eovptr->eov_next == NULL)
1048 	eopptr->eop_taileov = eovptr->eov_prev;
1049 else
1050 	eovptr->eov_next->eov_prev = eovptr->eov_prev;
1051 
1052 return;
1053 }
1054 
1055 /*--> EPDCreateEOVStr: create a new EOV record with a string value */
1056 nonstatic
1057 eovptrT
EPDCreateEOVStr(charptrT str)1058 EPDCreateEOVStr(charptrT str)
1059 {
1060 eovptrT eovptr;
1061 
1062 eovptr = EPDNewEOV();
1063 eovptr->eov_eob = eob_string;
1064 eovptr->eov_str = EPDStringGrab(str);
1065 
1066 return (eovptr);
1067 }
1068 
1069 /*--> EPDCreateEOVSym: create a new EOV record with a symbol value */
1070 nonstatic
1071 eovptrT
EPDCreateEOVSym(charptrT sym)1072 EPDCreateEOVSym(charptrT sym)
1073 {
1074 eovptrT eovptr;
1075 
1076 eovptr = EPDNewEOV();
1077 eovptr->eov_eob = eob_symbol;
1078 eovptr->eov_str = EPDStringGrab(sym);
1079 
1080 return (eovptr);
1081 }
1082 
1083 /*--> EPDCreateEOVInt: create a new EOV record with an integer value */
1084 nonstatic
1085 eovptrT
EPDCreateEOVInt(liT lval)1086 EPDCreateEOVInt(liT lval)
1087 {
1088 eovptrT eovptr;
1089 char tv[tL];
1090 
1091 sprintf(tv, "%ld", lval);
1092 eovptr = EPDNewEOV();
1093 eovptr->eov_eob = eob_symbol;
1094 eovptr->eov_str = EPDStringGrab(tv);
1095 
1096 return (eovptr);
1097 }
1098 
1099 /*--> EPDLocateEOV: try to locate 1st EOV record with given string value */
1100 nonstatic
1101 eovptrT
EPDLocateEOV(eopptrT eopptr,charptrT strval)1102 EPDLocateEOV(eopptrT eopptr, charptrT strval)
1103 {
1104 eovptrT eovptr;
1105 siT flag;
1106 
1107 flag = 0;
1108 eovptr = eopptr->eop_headeov;
1109 while (!flag && (eovptr != NULL))
1110 	if (strcmp(strval, eovptr->eov_str) == 0)
1111 		flag = 1;
1112 	else
1113 		eovptr = eovptr->eov_next;
1114 
1115 if (!flag)
1116 	eovptr = NULL;
1117 
1118 return (eovptr);
1119 }
1120 
1121 /*--> EPDCountEOV: count EOV entries in EOP */
1122 nonstatic
1123 siT
EPDCountEOV(eopptrT eopptr)1124 EPDCountEOV(eopptrT eopptr)
1125 {
1126 eovptrT eovptr;
1127 siT count;
1128 
1129 count = 0;
1130 eovptr = eopptr->eop_headeov;
1131 while (eovptr != NULL)
1132 	{
1133 	count++;
1134 	eovptr = eovptr->eov_next;
1135 	};
1136 
1137 return (count);
1138 }
1139 
1140 /*--> EPDReplaceEOVStr: replace EOV string value with given string value */
1141 nonstatic
1142 void
EPDReplaceEOVStr(eovptrT eovptr,charptrT str)1143 EPDReplaceEOVStr(eovptrT eovptr, charptrT str)
1144 {
1145 if (eovptr->eov_str != NULL)
1146 	{
1147 	EPDMemoryFree(eovptr->eov_str);
1148 	eovptr->eov_str = NULL;
1149 	};
1150 
1151 if (str != NULL)
1152 	eovptr->eov_str = EPDStringGrab(str);
1153 
1154 return;
1155 }
1156 
1157 /*--> EPDNewEOP: allocate a new EOP record */
1158 nonstatic
1159 eopptrT
EPDNewEOP(void)1160 EPDNewEOP(void)
1161 {
1162 eopptrT eopptr;
1163 
1164 eopptr = (eopptrT) EPDMemoryGrab(sizeof(eopT));
1165 
1166 eopptr->eop_opsym = NULL;
1167 eopptr->eop_headeov = eopptr->eop_taileov = NULL;
1168 eopptr->eop_prev = eopptr->eop_next = NULL;
1169 
1170 return (eopptr);
1171 }
1172 
1173 /*--> EPDReleaseEOP: release an EOP record */
1174 nonstatic
1175 void
EPDReleaseEOP(eopptrT eopptr)1176 EPDReleaseEOP(eopptrT eopptr)
1177 {
1178 eovptrT eovptr0, eovptr1;
1179 
1180 if (eopptr != NULL)
1181 	{
1182 	if (eopptr->eop_opsym != NULL)
1183 		EPDMemoryFree(eopptr->eop_opsym);
1184 	eovptr0 = eopptr->eop_headeov;
1185 	while (eovptr0 != NULL)
1186 		{
1187 		eovptr1 = eovptr0->eov_next;
1188 		EPDUnthreadEOV(eopptr, eovptr0);
1189 		EPDReleaseEOV(eovptr0);
1190 		eovptr0 = eovptr1;
1191 		};
1192 	EPDMemoryFree(eopptr);
1193 	};
1194 
1195 return;
1196 }
1197 
1198 /*--> EPDAppendEOP: append an EOP record */
1199 nonstatic
1200 void
EPDAppendEOP(epdptrT epdptr,eopptrT eopptr)1201 EPDAppendEOP(epdptrT epdptr, eopptrT eopptr)
1202 {
1203 if (epdptr->epd_taileop == NULL)
1204 	epdptr->epd_headeop = eopptr;
1205 else
1206 	epdptr->epd_taileop->eop_next = eopptr;
1207 
1208 eopptr->eop_prev = epdptr->epd_taileop;
1209 eopptr->eop_next = NULL;
1210 
1211 epdptr->epd_taileop = eopptr;
1212 
1213 return;
1214 }
1215 
1216 /*--> EPDUnthreadEOP: unthread an EOP record */
1217 static
1218 void
EPDUnthreadEOP(epdptrT epdptr,eopptrT eopptr)1219 EPDUnthreadEOP(epdptrT epdptr, eopptrT eopptr)
1220 {
1221 if (eopptr->eop_prev == NULL)
1222 	epdptr->epd_headeop = eopptr->eop_next;
1223 else
1224 	eopptr->eop_prev->eop_next = eopptr->eop_next;
1225 
1226 if (eopptr->eop_next == NULL)
1227 	epdptr->epd_taileop = eopptr->eop_prev;
1228 else
1229 	eopptr->eop_next->eop_prev = eopptr->eop_prev;
1230 
1231 return;
1232 }
1233 
1234 /*--> EPDCreateEOP: create a new EOP record with opsym */
1235 nonstatic
1236 eopptrT
EPDCreateEOP(charptrT opsym)1237 EPDCreateEOP(charptrT opsym)
1238 {
1239 eopptrT eopptr;
1240 
1241 eopptr = EPDNewEOP();
1242 eopptr->eop_opsym = EPDStringGrab(opsym);
1243 
1244 return (eopptr);
1245 }
1246 
1247 /*--> EPDCreateEOPCode: create a new EOP record using opsym index */
1248 nonstatic
1249 eopptrT
EPDCreateEOPCode(epdsoT epdso)1250 EPDCreateEOPCode(epdsoT epdso)
1251 {
1252 eopptrT eopptr;
1253 
1254 eopptr = EPDCreateEOP(EPDFetchOpsym(epdso));
1255 
1256 return (eopptr);
1257 }
1258 
1259 /*--> EPDLocateEOP: attempt to locate EOP record with given opsym */
1260 nonstatic
1261 eopptrT
EPDLocateEOP(epdptrT epdptr,charptrT opsym)1262 EPDLocateEOP(epdptrT epdptr, charptrT opsym)
1263 {
1264 eopptrT eopptr;
1265 siT flag;
1266 
1267 flag = 0;
1268 eopptr = epdptr->epd_headeop;
1269 while (!flag && (eopptr != NULL))
1270 	if (strcmp(opsym, eopptr->eop_opsym) == 0)
1271 		flag = 1;
1272 	else
1273 		eopptr = eopptr->eop_next;
1274 
1275 if (!flag)
1276 	eopptr = NULL;
1277 
1278 return (eopptr);
1279 }
1280 
1281 /*--> EPDLocateEOPCode: attempt to locate EOP record with given code */
1282 nonstatic
1283 eopptrT
EPDLocateEOPCode(epdptrT epdptr,epdsoT epdso)1284 EPDLocateEOPCode(epdptrT epdptr, epdsoT epdso)
1285 {
1286 
1287 return (EPDLocateEOP(epdptr, epdsostrv[epdso]));
1288 }
1289 
1290 /*--> EPDCountEOP: count EOP entries in EPD */
1291 nonstatic
1292 siT
EPDCountEOP(epdptrT epdptr)1293 EPDCountEOP(epdptrT epdptr)
1294 {
1295 eopptrT eopptr;
1296 siT count;
1297 
1298 count = 0;
1299 eopptr = epdptr->epd_headeop;
1300 while (eopptr != NULL)
1301 	{
1302 	count++;
1303 	eopptr = eopptr->eop_next;
1304 	};
1305 
1306 return (count);
1307 }
1308 
1309 /*--> EPDDropIfLocEOP: try to locate/drop EOP record with given opsym */
1310 nonstatic
1311 void
EPDDropIfLocEOP(epdptrT epdptr,charptrT opsym)1312 EPDDropIfLocEOP(epdptrT epdptr, charptrT opsym)
1313 {
1314 eopptrT eopptr;
1315 
1316 eopptr = EPDLocateEOP(epdptr, opsym);
1317 if (eopptr != NULL)
1318 	{
1319 	EPDUnthreadEOP(epdptr, eopptr);
1320 	EPDReleaseEOP(eopptr);
1321 	};
1322 
1323 return;
1324 }
1325 
1326 /*--> EPDDropIfLocEOPCode: try to locate/drop EOP record with given code */
1327 nonstatic
1328 void
EPDDropIfLocEOPCode(epdptrT epdptr,epdsoT epdso)1329 EPDDropIfLocEOPCode(epdptrT epdptr, epdsoT epdso)
1330 {
1331 eopptrT eopptr;
1332 
1333 eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso]);
1334 if (eopptr != NULL)
1335 	{
1336 	EPDUnthreadEOP(epdptr, eopptr);
1337 	EPDReleaseEOP(eopptr);
1338 	};
1339 
1340 return;
1341 }
1342 
1343 /*--> EPDAddOpInt: add a single integer operand operation */
1344 nonstatic
1345 void
EPDAddOpInt(epdptrT epdptr,epdsoT epdso,liT val)1346 EPDAddOpInt(epdptrT epdptr, epdsoT epdso, liT val)
1347 {
1348 eopptrT eopptr;
1349 eovptrT eovptr;
1350 
1351 eovptr = EPDCreateEOVInt(val);
1352 eopptr = EPDCreateEOPCode(epdso);
1353 EPDAppendEOV(eopptr, eovptr);
1354 EPDDropIfLocEOPCode(epdptr, epdso);
1355 EPDAppendEOP(epdptr, eopptr);
1356 
1357 return;
1358 }
1359 
1360 /*--> EPDAddOpStr: add a single string operand operation */
1361 nonstatic
1362 void
EPDAddOpStr(epdptrT epdptr,epdsoT epdso,charptrT s)1363 EPDAddOpStr(epdptrT epdptr, epdsoT epdso, charptrT s)
1364 {
1365 eopptrT eopptr;
1366 eovptrT eovptr;
1367 
1368 eovptr = EPDCreateEOVStr(s);
1369 eopptr = EPDCreateEOPCode(epdso);
1370 EPDAppendEOV(eopptr, eovptr);
1371 EPDDropIfLocEOPCode(epdptr, epdso);
1372 EPDAppendEOP(epdptr, eopptr);
1373 
1374 return;
1375 }
1376 
1377 /*--> EPDAddOpSym: add a single symbol operand operation */
1378 nonstatic
1379 void
EPDAddOpSym(epdptrT epdptr,epdsoT epdso,charptrT s)1380 EPDAddOpSym(epdptrT epdptr, epdsoT epdso, charptrT s)
1381 {
1382 eopptrT eopptr;
1383 eovptrT eovptr;
1384 
1385 eovptr = EPDCreateEOVSym(s);
1386 eopptr = EPDCreateEOPCode(epdso);
1387 EPDAppendEOV(eopptr, eovptr);
1388 EPDDropIfLocEOPCode(epdptr, epdso);
1389 EPDAppendEOP(epdptr, eopptr);
1390 
1391 return;
1392 }
1393 
1394 /*--> EPDNewEPD: allocate a new EPD record */
1395 nonstatic
1396 epdptrT
EPDNewEPD(void)1397 EPDNewEPD(void)
1398 {
1399 epdptrT epdptr;
1400 siT i;
1401 
1402 epdptr = (epdptrT) EPDMemoryGrab(sizeof(epdT));
1403 
1404 for (i = 0; i < nbL; i++)
1405 	epdptr->epd_nbv[i] = ((cp_v0 << nybbW) | cp_v0);
1406 
1407 epdptr->epd_actc = c_v;
1408 epdptr->epd_cast = 0;
1409 epdptr->epd_epsq = sq_nil;
1410 epdptr->epd_headeop = epdptr->epd_taileop = NULL;
1411 
1412 return (epdptr);
1413 }
1414 
1415 /*--> EPDReleaseOperations: release EPD operation list */
1416 nonstatic
1417 void
EPDReleaseOperations(epdptrT epdptr)1418 EPDReleaseOperations(epdptrT epdptr)
1419 {
1420 eopptrT eopptr0, eopptr1;
1421 
1422 if (epdptr != NULL)
1423 	{
1424 	eopptr0 = epdptr->epd_headeop;
1425 	while (eopptr0 != NULL)
1426 		{
1427 		eopptr1 = eopptr0->eop_next;
1428 		EPDUnthreadEOP(epdptr, eopptr0);
1429 		EPDReleaseEOP(eopptr0);
1430 		eopptr0 = eopptr1;
1431 		};
1432 	epdptr->epd_headeop = NULL;
1433 	epdptr->epd_taileop = NULL;
1434 	};
1435 
1436 return;
1437 }
1438 
1439 /*--> EPDReleaseEPD: release an EPD record */
1440 nonstatic
1441 void
EPDReleaseEPD(epdptrT epdptr)1442 EPDReleaseEPD(epdptrT epdptr)
1443 {
1444 if (epdptr != NULL)
1445 	{
1446 	EPDReleaseOperations(epdptr);
1447 	EPDMemoryFree(epdptr);
1448 	};
1449 
1450 return;
1451 }
1452 
1453 /*--> EPDFetchOpsym: return a pointer to the indicated mnemonic */
1454 nonstatic
1455 charptrT
EPDFetchOpsym(epdsoT epdso)1456 EPDFetchOpsym(epdsoT epdso)
1457 {
1458 return (epdsostrv[epdso]);
1459 }
1460 
1461 /*--> EPDCountOperands: count operands */
1462 static
1463 siT
EPDCountOperands(eopptrT eopptr)1464 EPDCountOperands(eopptrT eopptr)
1465 {
1466 siT count;
1467 eovptrT eovptr;
1468 
1469 count = 0;
1470 eovptr = eopptr->eop_headeov;
1471 while (eovptr != NULL)
1472 	{
1473 	count++;
1474 	eovptr = eovptr->eov_next;
1475 	};
1476 
1477 return (count);
1478 }
1479 
1480 /*--> EPDCountOperations: count operations */
1481 static
1482 siT
EPDCountOperations(epdptrT epdptr)1483 EPDCountOperations(epdptrT epdptr)
1484 {
1485 siT count;
1486 eopptrT eopptr;
1487 
1488 count = 0;
1489 eopptr = epdptr->epd_headeop;
1490 while (eopptr != NULL)
1491 	{
1492 	count++;
1493 	eopptr = eopptr->eop_next;
1494 	};
1495 
1496 return (count);
1497 }
1498 
1499 /*--> EPDSortOperands: sort operands according to string value */
1500 static
1501 void
EPDSortOperands(eopptrT eopptr)1502 EPDSortOperands(eopptrT eopptr)
1503 {
1504 siT count;
1505 siT pass, flag;
1506 eovptrT ptr0, ptr1, ptr2, ptr3;
1507 
1508 count = EPDCountOperands(eopptr);
1509 if (count > 1)
1510 	{
1511 	flag = 1;
1512 	pass = 0;
1513 	while (flag && (pass < (count - 1)))
1514 		{
1515 		flag = 0;
1516 		ptr0 = eopptr->eop_headeov;
1517 		ptr1 = ptr0->eov_next;
1518 		while (ptr1 != NULL)
1519 			{
1520 			if (strcmp(ptr0->eov_str, ptr1->eov_str) > 0)
1521 				{
1522 				flag = 1;
1523 
1524 				ptr2 = ptr0->eov_prev;
1525 				ptr3 = ptr1->eov_next;
1526 
1527 				ptr0->eov_prev = ptr1;
1528 				ptr0->eov_next = ptr3;
1529 
1530 				ptr1->eov_prev = ptr2;
1531 				ptr1->eov_next = ptr0;
1532 
1533 				if (ptr2 == NULL)
1534 					eopptr->eop_headeov = ptr1;
1535 				else
1536 					ptr2->eov_next = ptr1;
1537 
1538 				if (ptr3 == NULL)
1539 					eopptr->eop_taileov = ptr0;
1540 				else
1541 					ptr3->eov_prev = ptr0;
1542 				}
1543 			else
1544 				ptr0 = ptr1;
1545 
1546 			ptr1 = ptr0->eov_next;
1547 			};
1548 		pass++;
1549 		};
1550 	};
1551 
1552 return;
1553 }
1554 
1555 /*--> EPDSortOperations: sort operations according to opcode */
1556 static
1557 void
EPDSortOperations(epdptrT epdptr)1558 EPDSortOperations(epdptrT epdptr)
1559 {
1560 siT count;
1561 siT pass, flag;
1562 eopptrT ptr0, ptr1, ptr2, ptr3;
1563 
1564 count = EPDCountOperations(epdptr);
1565 if (count > 1)
1566 	{
1567 	flag = 1;
1568 	pass = 0;
1569 	while (flag && (pass < (count - 1)))
1570 		{
1571 		flag = 0;
1572 		ptr0 = epdptr->epd_headeop;
1573 		ptr1 = ptr0->eop_next;
1574 		while (ptr1 != NULL)
1575 			{
1576 			if (strcmp(ptr0->eop_opsym, ptr1->eop_opsym) > 0)
1577 				{
1578 				flag = 1;
1579 
1580 				ptr2 = ptr0->eop_prev;
1581 				ptr3 = ptr1->eop_next;
1582 
1583 				ptr0->eop_prev = ptr1;
1584 				ptr0->eop_next = ptr3;
1585 
1586 				ptr1->eop_prev = ptr2;
1587 				ptr1->eop_next = ptr0;
1588 
1589 				if (ptr2 == NULL)
1590 					epdptr->epd_headeop = ptr1;
1591 				else
1592 					ptr2->eop_next = ptr1;
1593 
1594 				if (ptr3 == NULL)
1595 					epdptr->epd_taileop = ptr0;
1596 				else
1597 					ptr3->eop_prev = ptr0;
1598 				}
1599 			else
1600 				ptr0 = ptr1;
1601 
1602 			ptr1 = ptr0->eop_next;
1603 			};
1604 		pass++;
1605 		};
1606 	};
1607 
1608 return;
1609 }
1610 
1611 /*--> EPDNormalize: apply normalizing sorts */
1612 static
1613 void
EPDNormalize(epdptrT epdptr)1614 EPDNormalize(epdptrT epdptr)
1615 {
1616 eopptrT eopptr;
1617 charptrT opsym;
1618 siT flag;
1619 
1620 /* sort all operations */
1621 
1622 EPDSortOperations(epdptr);
1623 
1624 /* sort operands for selected standard operations */
1625 
1626 eopptr = epdptr->epd_headeop;
1627 while (eopptr != NULL)
1628 	{
1629 	flag = 0;
1630 	opsym = eopptr->eop_opsym;
1631 
1632 	if (!flag && (strcmp(opsym, epdsostrv[epdso_am]) == 0))
1633 		{
1634 		EPDSortOperands(eopptr);
1635 		flag = 1;
1636 		};
1637 
1638 	if (!flag && (strcmp(opsym, epdsostrv[epdso_bm]) == 0))
1639 		{
1640 		EPDSortOperands(eopptr);
1641 		flag = 1;
1642 		};
1643 
1644 	eopptr = eopptr->eop_next;
1645 	};
1646 
1647 return;
1648 }
1649 
1650 /*--> EPDCloneEPDBase: clone an EPD structure, base items only */
1651 nonstatic
1652 epdptrT
EPDCloneEPDBase(epdptrT epdptr)1653 EPDCloneEPDBase(epdptrT epdptr)
1654 {
1655 epdptrT nptr;
1656 siT index;
1657 
1658 nptr = EPDNewEPD();
1659 
1660 for (index = 0; index < nbL; index++)
1661 	nptr->epd_nbv[index] = epdptr->epd_nbv[index];
1662 
1663 nptr->epd_actc = epdptr->epd_actc;
1664 nptr->epd_cast = epdptr->epd_cast;
1665 nptr->epd_epsq = epdptr->epd_epsq;
1666 
1667 return (nptr);
1668 }
1669 
1670 /*--> EPDCloneEOV: clone an EOV structure */
1671 nonstatic
1672 eovptrT
EPDCloneEOV(eovptrT eovptr)1673 EPDCloneEOV(eovptrT eovptr)
1674 {
1675 eovptrT nptr;
1676 
1677 nptr = EPDNewEOV();
1678 
1679 nptr->eov_eob = eovptr->eov_eob;
1680 
1681 if (eovptr->eov_str != NULL)
1682 	nptr->eov_str = EPDStringGrab(eovptr->eov_str);
1683 
1684 return (nptr);
1685 }
1686 
1687 /*--> EPDCloneEOP: clone an EOP structure */
1688 nonstatic
1689 eopptrT
EPDCloneEOP(eopptrT eopptr)1690 EPDCloneEOP(eopptrT eopptr)
1691 {
1692 eopptrT nptr;
1693 eovptrT eovptr, rptr;
1694 
1695 nptr = EPDNewEOP();
1696 
1697 if (eopptr->eop_opsym != NULL)
1698 	nptr->eop_opsym = EPDStringGrab(eopptr->eop_opsym);
1699 
1700 rptr = eopptr->eop_headeov;
1701 while (rptr != NULL)
1702 	{
1703 	eovptr = EPDCloneEOV(rptr);
1704 	EPDAppendEOV(nptr, eovptr);
1705 	rptr = rptr->eov_next;
1706 	};
1707 
1708 return (nptr);
1709 }
1710 
1711 /*--> EPDCloneEPD: clone an EPD structure */
1712 nonstatic
1713 epdptrT
EPDCloneEPD(epdptrT epdptr)1714 EPDCloneEPD(epdptrT epdptr)
1715 {
1716 epdptrT nptr;
1717 eopptrT eopptr, rptr;
1718 
1719 nptr = EPDCloneEPDBase(epdptr);
1720 
1721 rptr = epdptr->epd_headeop;
1722 while (rptr != NULL)
1723 	{
1724 	eopptr = EPDCloneEOP(rptr);
1725 	EPDAppendEOP(nptr, eopptr);
1726 	rptr = rptr->eop_next;
1727 	};
1728 
1729 return (nptr);
1730 }
1731 
1732 /*--> EPDSetKings: set the king location vector */
1733 static
1734 void
EPDSetKings(void)1735 EPDSetKings(void)
1736 {
1737 sqT sq;
1738 
1739 /* this operates only on the local environment */
1740 
1741 ese.ese_ksqv[c_w] = ese.ese_ksqv[c_b] = sq_nil;
1742 
1743 for (sq = sq_a1; sq <= sq_h8; sq++)
1744 	switch (EPDboard.rbv[sq])
1745 		{
1746 		case cp_wk:
1747 			ese.ese_ksqv[c_w] = sq;
1748 			break;
1749 		case cp_bk:
1750 			ese.ese_ksqv[c_b] = sq;
1751 			break;
1752 		default:
1753 			break;
1754 		};
1755 
1756 return;
1757 }
1758 
1759 /*--> EPDSet: set up an EPD structure for the given position */
1760 nonstatic
1761 epdptrT
EPDSet(rbptrT rbptr,cT actc,castT cast,sqT epsq)1762 EPDSet(rbptrT rbptr, cT actc, castT cast, sqT epsq)
1763 {
1764 epdptrT epdptr;
1765 sqT sq;
1766 cpT cp0, cp1;
1767 
1768 /* this does not reference the current position */
1769 
1770 epdptr = EPDNewEPD();
1771 
1772 for (sq = sq_a1; sq <= sq_h8; sq += 2)
1773 	{
1774 	cp0 = rbptr->rbv[sq + 0];
1775 	cp1 = rbptr->rbv[sq + 1];
1776 	epdptr->epd_nbv[sq >> 1] = ((cp1 << nybbW) | cp0);
1777 	};
1778 
1779 epdptr->epd_actc = actc;
1780 epdptr->epd_cast = cast;
1781 epdptr->epd_epsq = epsq;
1782 
1783 return (epdptr);
1784 }
1785 
1786 /*--> EPDSetCurrentPosition: set current position */
1787 nonstatic
1788 void
EPDSetCurrentPosition(rbptrT rbptr,cT actc,castT cast,sqT epsq,siT hmvc,siT fmvn)1789 EPDSetCurrentPosition(rbptrT rbptr, cT actc, castT cast, sqT epsq, siT hmvc, siT fmvn)
1790 {
1791 sqT sq;
1792 
1793 /* this changes the current position */
1794 
1795 for (sq = sq_a1; sq <= sq_h8; sq++)
1796 	EPDboard.rbv[sq] = rbptr->rbv[sq];
1797 
1798 ese.ese_actc = actc;
1799 ese.ese_cast = cast;
1800 ese.ese_epsq = epsq;
1801 ese.ese_hmvc = hmvc;
1802 ese.ese_fmvn = fmvn;
1803 
1804 EPDSetKings();
1805 
1806 return;
1807 }
1808 
1809 /*--> EPDGetCurrentPosition: return EPD structure for current position */
1810 nonstatic
1811 epdptrT
EPDGetCurrentPosition(void)1812 EPDGetCurrentPosition(void)
1813 {
1814 epdptrT epdptr;
1815 sqT sq;
1816 cpT cp0, cp1;
1817 
1818 epdptr = EPDNewEPD();
1819 
1820 for (sq = sq_a1; sq <= sq_h8; sq += 2)
1821 	{
1822 	cp0 = EPDboard.rbv[sq + 0];
1823 	cp1 = EPDboard.rbv[sq + 1];
1824 	epdptr->epd_nbv[sq >> 1] = ((cp1 << nybbW) | cp0);
1825 	};
1826 
1827 epdptr->epd_actc = ese.ese_actc;
1828 epdptr->epd_cast = ese.ese_cast;
1829 epdptr->epd_epsq = ese.ese_epsq;
1830 
1831 return (epdptr);
1832 }
1833 
1834 /*--> EPDFetchACTC: fetch current active color */
1835 nonstatic
1836 cT
EPDFetchACTC(void)1837 EPDFetchACTC(void)
1838 {
1839 /* return the value of the current active color */
1840 
1841 return (ese.ese_actc);
1842 }
1843 
1844 /*--> EPDFetchCAST: fetch current castling availability */
1845 nonstatic
1846 castT
EPDFetchCAST(void)1847 EPDFetchCAST(void)
1848 {
1849 /* return the value of the current castling availability */
1850 
1851 return (ese.ese_cast);
1852 }
1853 
1854 /*--> EPDFetchEPSQ: fetch current en passant target square */
1855 nonstatic
1856 sqT
EPDFetchEPSQ(void)1857 EPDFetchEPSQ(void)
1858 {
1859 /* return the value of the current en passant target square */
1860 
1861 return (ese.ese_epsq);
1862 }
1863 
1864 /*--> EPDFetchHMVC: fetch current halfmove clock */
1865 nonstatic
1866 siT
EPDFetchHMVC(void)1867 EPDFetchHMVC(void)
1868 {
1869 /* return the value of the current halfmove clock */
1870 
1871 return (ese.ese_hmvc);
1872 }
1873 
1874 /*--> EPDFetchFMVN: fetch current fullmove number */
1875 nonstatic
1876 siT
EPDFetchFMVN(void)1877 EPDFetchFMVN(void)
1878 {
1879 /* return the value of the current fullmove number */
1880 
1881 return (ese.ese_fmvn);
1882 }
1883 
1884 /*--> EPDFetchBoard: fetch current board */
1885 nonstatic
1886 rbptrT
EPDFetchBoard(void)1887 EPDFetchBoard(void)
1888 {
1889 /* copy from the local board into the designated static return area */
1890 
1891 ret_rb = EPDboard;
1892 
1893 return (&ret_rb);
1894 }
1895 
1896 /*--> EPDFetchCP: fetch color-piece */
1897 nonstatic
1898 cpT
EPDFetchCP(sqT sq)1899 EPDFetchCP(sqT sq)
1900 {
1901 cpT cp;
1902 
1903 /* fetch from the local board */
1904 
1905 cp = EPDboard.rbv[sq];
1906 
1907 return (cp);
1908 }
1909 
1910 /*--> EPDFetchBoardString: create and return a board diagram */
1911 nonstatic
1912 charptrT
EPDFetchBoardString(void)1913 EPDFetchBoardString(void)
1914 {
1915 charptrT s;
1916 charptrT r;
1917 rankT rank;
1918 fileT file;
1919 cpT cp;
1920 
1921 /* allocate */
1922 
1923 s = (charptrT) EPDMemoryGrab((rankL * ((fileL * 2) + 1)) + 1);
1924 
1925 /* fill */
1926 
1927 r = s;
1928 for (rank = rank_8; rank >= rank_1; rank--)
1929 	{
1930 	for (file = file_a; file <= file_h; file++)
1931 		{
1932 		cp = EPDboard.rbm[rank][file];
1933 		if (cp == cp_v0)
1934 			if ((rank % 2) == (file % 2))
1935 				{
1936 				*r++ = ':';
1937 				*r++ = ':';
1938 				}
1939 			else
1940 				{
1941 				*r++ = ascii_sp;
1942 				*r++ = ascii_sp;
1943 				}
1944 		else
1945 			{
1946 			*r++ = asccv[cv_c_cpv[cp]];
1947 			*r++ = ascpv[cv_p_cpv[cp]];
1948 			};
1949 		};
1950 	*r++ = '\n';
1951 	};
1952 
1953 /* terminating NUL */
1954 
1955 *r = ascii_nul;
1956 
1957 return (s);
1958 }
1959 
1960 /*--> EPDGetGTIM: get game termination marker indicator */
1961 nonstatic
1962 gtimT
EPDGetGTIM(gamptrT gamptr)1963 EPDGetGTIM(gamptrT gamptr)
1964 {
1965 
1966 return (gamptr->gam_gtim);
1967 }
1968 
1969 /*--> EPDPutGTIM: put game termination marker indicator */
1970 nonstatic
1971 void
EPDPutGTIM(gamptrT gamptr,gtimT gtim)1972 EPDPutGTIM(gamptrT gamptr, gtimT gtim)
1973 {
1974 gamptr->gam_gtim = gtim;
1975 
1976 return;
1977 }
1978 
1979 /*--> EPDGenBasic: generate basic EPD notation for a given position */
1980 nonstatic
1981 charptrT
EPDGenBasic(rbptrT rbptr,cT actc,castT cast,sqT epsq)1982 EPDGenBasic(rbptrT rbptr, cT actc, castT cast, sqT epsq)
1983 {
1984 charptrT ptr;
1985 epdptrT epdptr;
1986 
1987 /* this does not reference the current position */
1988 
1989 epdptr = EPDSet(rbptr, actc, cast, epsq);
1990 ptr = EPDEncode(epdptr);
1991 
1992 EPDReleaseEPD(epdptr);
1993 
1994 return (ptr);
1995 }
1996 
1997 /*--> EPDGenBasicCurrent: generate basic EPD for current position */
1998 nonstatic
1999 charptrT
EPDGenBasicCurrent(void)2000 EPDGenBasicCurrent(void)
2001 {
2002 charptrT ptr;
2003 
2004 /* this references but does not change the current position */
2005 
2006 ptr = EPDGenBasic(&EPDboard, ese.ese_actc, ese.ese_cast, ese.ese_epsq);
2007 
2008 return (ptr);
2009 }
2010 
2011 /*--> EPDDecodeFEN: read a FEN string to make an EPD structure */
2012 nonstatic
2013 epdptrT
EPDDecodeFEN(charptrT s)2014 EPDDecodeFEN(charptrT s)
2015 {
2016 epdptrT epdptr;
2017 siT flag;
2018 tknptrT save_head_tknptr, save_tail_tknptr;
2019 charptrT tptr;
2020 
2021 /* this does not reference the current position */
2022 
2023 flag = 1;
2024 epdptr = NULL;
2025 tptr = NULL;
2026 
2027 /* save the initial token chain pointers */
2028 
2029 save_head_tknptr = head_tknptr;
2030 save_tail_tknptr = tail_tknptr;
2031 
2032 /* clear the token chain pointers */
2033 
2034 head_tknptr = NULL;
2035 tail_tknptr = NULL;
2036 
2037 /* tokenize the input */
2038 
2039 EPDTokenize(s);
2040 
2041 /* check for six tokens */
2042 
2043 if (flag)
2044 	if (EPDTokenCount() != 6)
2045 		flag = 0;
2046 
2047 /* construct an input string from the tokens */
2048 
2049 if (flag)
2050 	{
2051 	/* handle the first four common fields */
2052 
2053 	tptr = EPDStringGrab("");
2054 	tptr = EPDStringAppendStr(tptr, EPDTokenFetch(0));
2055 	tptr = EPDStringAppendChar(tptr, ascii_sp);
2056 	tptr = EPDStringAppendStr(tptr, EPDTokenFetch(1));
2057 	tptr = EPDStringAppendChar(tptr, ascii_sp);
2058 	tptr = EPDStringAppendStr(tptr, EPDTokenFetch(2));
2059 	tptr = EPDStringAppendChar(tptr, ascii_sp);
2060 	tptr = EPDStringAppendStr(tptr, EPDTokenFetch(3));
2061 	tptr = EPDStringAppendChar(tptr, ascii_sp);
2062 
2063 	/* append the halfmove clock operation */
2064 
2065 	tptr = EPDStringAppendStr(tptr, epdsostrv[epdso_hmvc]);
2066 	tptr = EPDStringAppendChar(tptr, ascii_sp);
2067 	tptr = EPDStringAppendStr(tptr, EPDTokenFetch(4));
2068 	tptr = EPDStringAppendChar(tptr, ';');
2069 	tptr = EPDStringAppendChar(tptr, ascii_sp);
2070 
2071 	/* append the fullmove number operation */
2072 
2073 	tptr = EPDStringAppendStr(tptr, epdsostrv[epdso_fmvn]);
2074 	tptr = EPDStringAppendChar(tptr, ascii_sp);
2075 	tptr = EPDStringAppendStr(tptr, EPDTokenFetch(5));
2076 	tptr = EPDStringAppendChar(tptr, ';');
2077 	};
2078 
2079 /* release the temporary token chain */
2080 
2081 EPDReleaseTokenChain();
2082 
2083 /* restore the initial token chain pointers */
2084 
2085 head_tknptr = save_head_tknptr;
2086 tail_tknptr = save_tail_tknptr;
2087 
2088 /* read the resulting EPD input string */
2089 
2090 if (flag)
2091 	{
2092 	epdptr = EPDDecode(tptr);
2093 	if (epdptr == NULL)
2094 		flag = 0;
2095 	};
2096 
2097 /* cancellations if a problem occurred */
2098 
2099 if (!flag)
2100 	{
2101 	if (tptr != NULL)
2102 		EPDMemoryFree(tptr);
2103 
2104 	if (epdptr != NULL)
2105 		{
2106 		EPDReleaseEPD(epdptr);
2107 		epdptr = NULL;
2108 		};
2109 	};
2110 
2111 return (epdptr);
2112 }
2113 
2114 /*--> EPDEncodeFEN: make a FEN string from an EPD structure */
2115 nonstatic
2116 charptrT
EPDEncodeFEN(epdptrT epdptr)2117 EPDEncodeFEN(epdptrT epdptr)
2118 {
2119 charptrT s;
2120 char ch;
2121 siT bi;
2122 siT ps;
2123 sqT sq;
2124 cpT cp;
2125 rankT rank;
2126 fileT file;
2127 eopptrT eopptr;
2128 char nv[tL];
2129 char bv[tL];
2130 
2131 /* this does not reference the current position */
2132 
2133 bi = 0;
2134 
2135 /* output board */
2136 
2137 for (rank = rank_8; rank >= rank_1; rank--)
2138 	{
2139 	ps = 0;
2140 	for (file = file_a; file <= file_h; file++)
2141 		{
2142 		sq = map_sq(rank, file);
2143 		if ((sq % 2) == 0)
2144 			cp = (epdptr->epd_nbv[sq >> 1] & nybbM);
2145 		else
2146 			cp = ((epdptr->epd_nbv[sq >> 1] >> nybbW) & nybbM);
2147 
2148 		if (cp == cp_v0)
2149 			ps++;
2150 		else
2151 			{
2152 			if (ps != 0)
2153 				{
2154 				bv[bi++] = '0' + ps;
2155 				ps = 0;
2156 				};
2157 			ch = ascpv[cv_p_cpv[cp]];
2158 			if (cv_c_cpv[cp] == c_w)
2159 				ch = map_upper(ch);
2160 			else
2161 				ch = map_lower(ch);
2162 			bv[bi++] = ch;
2163 			};
2164 		};
2165 	if (ps != 0)
2166 		{
2167 		bv[bi++] = '0' + ps;
2168 		ps = 0;
2169 		};
2170 	if (rank != rank_1)
2171 		bv[bi++] = '/';
2172 	};
2173 bv[bi++] = ascii_sp;
2174 
2175 /* output active color (lower case) */
2176 
2177 bv[bi++] = map_lower(asccv[epdptr->epd_actc]);
2178 bv[bi++] = ascii_sp;
2179 
2180 /* output castling availablility */
2181 
2182 if (epdptr->epd_cast == 0)
2183 	bv[bi++] = '-';
2184 else
2185 	{
2186 	if (epdptr->epd_cast & cf_wk)
2187 		bv[bi++] = map_upper(ascpv[p_k]);
2188 	if (epdptr->epd_cast & cf_wq)
2189 		bv[bi++] = map_upper(ascpv[p_q]);
2190 	if (epdptr->epd_cast & cf_bk)
2191 		bv[bi++] = map_lower(ascpv[p_k]);
2192 	if (epdptr->epd_cast & cf_bq)
2193 		bv[bi++] = map_lower(ascpv[p_q]);
2194 	};
2195 bv[bi++] = ascii_sp;
2196 
2197 /* output ep capture square */
2198 
2199 if (epdptr->epd_epsq == sq_nil)
2200 	bv[bi++] = '-';
2201 else
2202 	{
2203 	bv[bi++] = ascfv[map_file(epdptr->epd_epsq)];
2204 	bv[bi++] = ascrv[map_rank(epdptr->epd_epsq)];
2205 	};
2206 bv[bi++] = ascii_sp;
2207 
2208 /* output halfmove clock */
2209 
2210 eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_hmvc]);
2211 if ((eopptr != NULL) && (eopptr->eop_headeov != NULL) &&
2212 	(eopptr->eop_headeov->eov_str != NULL))
2213 	sprintf(nv, "%ld", atol(eopptr->eop_headeov->eov_str));
2214 else
2215 	sprintf(nv, "0");
2216 strcpy(&bv[bi], nv);
2217 bi += strlen(nv);
2218 bv[bi++] = ascii_sp;
2219 
2220 /* output fullmove number */
2221 
2222 eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_fmvn]);
2223 if ((eopptr != NULL) && (eopptr->eop_headeov != NULL) &&
2224 	(eopptr->eop_headeov->eov_str != NULL))
2225 	sprintf(nv, "%ld", atol(eopptr->eop_headeov->eov_str));
2226 else
2227 	sprintf(nv, "1");
2228 strcpy(&bv[bi], nv);
2229 bi += strlen(nv);
2230 
2231 /* NUL termination */
2232 
2233 bv[bi++] = ascii_nul;
2234 
2235 /* allocate result */
2236 
2237 s = EPDStringGrab(bv);
2238 
2239 return (s);
2240 }
2241 
2242 /*--> EPDDecode: read an EPD structure from a string */
2243 nonstatic
2244 epdptrT
EPDDecode(charptrT s)2245 EPDDecode(charptrT s)
2246 {
2247 epdptrT epdptr;
2248 eopptrT eopptr;
2249 eovptrT eovptr;
2250 siT flag, quoteflag;
2251 siT ch;
2252 liT i;
2253 siT j, d;
2254 byteptrT bptr;
2255 fileT file;
2256 rankT rank;
2257 sqT sq;
2258 cT c;
2259 pT p;
2260 cpT cp;
2261 
2262 /* this does not reference the current position */
2263 
2264 /* set up */
2265 
2266 flag = 1;
2267 i = 0;
2268 ch = *(s + i++);
2269 
2270 /* initialize the return structure */
2271 
2272 epdptr = EPDNewEPD();
2273 
2274 /* skip whitespace */
2275 
2276 if (flag)
2277 	{
2278 	while (flag && (ch != ascii_nul) && isspace(ch))
2279 		ch = *(s + i++);
2280 	if (ch == ascii_nul)
2281 		flag = 0;
2282 	};
2283 
2284 /* process piece placement data */
2285 
2286 if (flag)
2287 	{
2288 	rank = rank_8;
2289 	file = file_a;
2290 
2291 	while (flag && (ch != ascii_nul) && !isspace(ch))
2292 		{
2293 		switch (ch)
2294 			{
2295 			case '/':
2296 				if ((file != fileL) || (rank == rank_1))
2297 					flag = 0;
2298 				else
2299 					{
2300 					rank--;
2301 					file = file_a;
2302 					};
2303 				break;
2304 
2305 			case '1':
2306 			case '2':
2307 			case '3':
2308 			case '4':
2309 			case '5':
2310 			case '6':
2311 			case '7':
2312 			case '8':
2313 				d = ch - '0';
2314 				if ((file + d) > fileL)
2315 					flag = 0;
2316 				else
2317 					for (j = 0; j < d; j++)
2318 						{
2319 						sq = map_sq(rank, file);
2320 						bptr = &epdptr->epd_nbv[sq >> 1];
2321 						if ((sq % 2) == 0)
2322 							{
2323 							*bptr &= ~nybbM;
2324 							*bptr |= cp_v0;
2325 							}
2326 						else
2327 							{
2328 							*bptr &= ~(nybbM << nybbW);
2329 							*bptr |= (cp_v0 << nybbW);
2330 							};
2331 						file++;
2332 						};
2333 				break;
2334 
2335 			default:
2336 				if (!EPDCheckPiece(ch) || (file >= fileL))
2337 					flag = 0;
2338 				else
2339 					{
2340 					p = EPDEvaluatePiece(ch);
2341 					if (isupper(ch))
2342 						c = c_w;
2343 					else
2344 						c = c_b;
2345 					sq = map_sq(rank, file);
2346 					bptr = &epdptr->epd_nbv[sq >> 1];
2347 					cp = cv_cp_c_pv[c][p];
2348 					if ((sq % 2) == 0)
2349 						{
2350 						*bptr &= ~nybbM;
2351 						*bptr |= cp;
2352 						}
2353 					else
2354 						{
2355 						*bptr &= ~(nybbM << nybbW);
2356 						*bptr |= (cp << nybbW);
2357 						};
2358 					file++;
2359 					};
2360 				break;
2361 			};
2362 
2363 		ch = *(s + i++);
2364 		};
2365 
2366 	if (flag)
2367 		if ((file != fileL) || (rank != rank_1))
2368 			flag = 0;
2369 	};
2370 
2371 /* need at least one whitespace character */
2372 
2373 if (flag)
2374 	if ((ch == ascii_nul) || !isspace(ch))
2375 		flag = 0;
2376 
2377 /* skip whitespace */
2378 
2379 if (flag)
2380 	{
2381 	while (flag && (ch != ascii_nul) && isspace(ch))
2382 		ch = *(s + i++);
2383 	if (ch == ascii_nul)
2384 		flag = 0;
2385 	};
2386 
2387 /* process active color */
2388 
2389 if (flag)
2390 	{
2391 	if (!EPDCheckColor(ch))
2392 		flag = 0;
2393 	else
2394 		{
2395 		epdptr->epd_actc = EPDEvaluateColor(ch);
2396 		ch = *(s + i++);
2397 		};
2398 	};
2399 
2400 /* need at least one whitespace character */
2401 
2402 if (flag)
2403 	if ((ch == ascii_nul) || !isspace(ch))
2404 		flag = 0;
2405 
2406 /* skip whitespace */
2407 
2408 if (flag)
2409 	{
2410 	while (flag && (ch != ascii_nul) && isspace(ch))
2411 		ch = *(s + i++);
2412 	if (ch == ascii_nul)
2413 		flag = 0;
2414 	};
2415 
2416 /* process castling availability */
2417 
2418 if (flag)
2419 	{
2420 	epdptr->epd_cast = 0;
2421 	if (ch == '-')
2422 		ch = *(s + i++);
2423 	else
2424 		{
2425 		/* white kingside castling availability */
2426 
2427 		if (flag && (ch == map_upper(ascpv[p_k])))
2428 			{
2429 			epdptr->epd_cast |= cf_wk;
2430 			ch = *(s + i++);
2431 			if (ch == ascii_nul)
2432 				flag = 0;
2433 			};
2434 
2435 		/* white queenside castling availability */
2436 
2437 		if (flag && (ch == map_upper(ascpv[p_q])))
2438 			{
2439 			epdptr->epd_cast |= cf_wq;
2440 			ch = *(s + i++);
2441 			if (ch == ascii_nul)
2442 				flag = 0;
2443 			};
2444 
2445 		/* black kingside castling availability */
2446 
2447 		if (flag && (ch == map_lower(ascpv[p_k])))
2448 			{
2449 			epdptr->epd_cast |= cf_bk;
2450 			ch = *(s + i++);
2451 			if (ch == ascii_nul)
2452 				flag = 0;
2453 			};
2454 
2455 		/* black queenside castling availability */
2456 
2457 		if (flag && (ch == map_lower(ascpv[p_q])))
2458 			{
2459 			epdptr->epd_cast |= cf_bq;
2460 			ch = *(s + i++);
2461 			if (ch == ascii_nul)
2462 				flag = 0;
2463 			};
2464 		};
2465 	};
2466 
2467 /* need at least one whitespace character */
2468 
2469 if (flag)
2470 	if ((ch == ascii_nul) || !isspace(ch))
2471 		flag = 0;
2472 
2473 /* skip whitespace */
2474 
2475 if (flag)
2476 	{
2477 	while (flag && (ch != ascii_nul) && isspace(ch))
2478 		ch = *(s + i++);
2479 	if (ch == ascii_nul)
2480 		flag = 0;
2481 	};
2482 
2483 /* process en passant target */
2484 
2485 if (flag)
2486 	if (ch == '-')
2487 		{
2488 		epdptr->epd_epsq = sq_nil;
2489 		ch = *(s + i++);
2490 		if ((ch != ascii_nul) && !isspace(ch))
2491 			flag = 0;
2492 		}
2493 	else
2494 		if (!EPDCheckFile(ch))
2495 			flag = 0;
2496 		else
2497 			{
2498 			file = EPDEvaluateFile(ch);
2499 			ch = *(s + i++);
2500 			if ((ch == ascii_nul) || !EPDCheckRank(ch))
2501 				flag = 0;
2502 			else
2503 				{
2504 				epdptr->epd_epsq = map_sq(EPDEvaluateRank(ch), file);
2505 				ch = *(s + i++);
2506 				if ((ch != ascii_nul) && !isspace(ch))
2507 					flag = 0;
2508 				};
2509 			};
2510 
2511 /* skip whitespace (end-of-line is not an error) */
2512 
2513 if (flag)
2514 	while ((ch != ascii_nul) && isspace(ch))
2515 		ch = *(s + i++);
2516 
2517 /* process operation sequence (if any) */
2518 
2519 if (flag)
2520 	{
2521 	while (flag && (ch != ascii_nul))
2522 		{
2523 		/* allocate a new operation */
2524 
2525 		eopptr = EPDNewEOP();
2526 
2527 		/* form opsym (first character) */
2528 
2529 		if (IdentChar(ch))
2530 			{
2531 			eopptr->eop_opsym = EPDStringGrab("");
2532 			eopptr->eop_opsym = EPDStringAppendChar(eopptr->eop_opsym, ch);
2533 			ch = *(s + i++);
2534 			}
2535 		else
2536 			flag = 0;
2537 
2538 		/* form remainder of opsym */
2539 
2540 		while (IdentChar(ch))
2541 			{
2542 			eopptr->eop_opsym = EPDStringAppendChar(eopptr->eop_opsym, ch);
2543 			ch = *(s + i++);
2544 			};
2545 
2546 		/* skip whitespace */
2547 
2548 		if (flag)
2549 			{
2550 			while (flag && (ch != ascii_nul) && isspace(ch))
2551 				ch = *(s + i++);
2552 			if (ch == ascii_nul)
2553 				flag = 0;
2554 			};
2555 
2556 		/* process operand list */
2557 
2558 		while (flag && (ch != ';'))
2559 			{
2560 			/* allocate operand value */
2561 
2562 			eovptr = EPDNewEOV();
2563 
2564 			/* set quoted string as appropriate */
2565 
2566 			if (ch == '"')
2567 				{
2568 				quoteflag = 1;
2569 				eovptr->eov_eob = eob_string;
2570 				ch = *(s + i++);
2571 				}
2572 			else
2573 				{
2574 				quoteflag = 0;
2575 				eovptr->eov_eob = eob_symbol;
2576 				};
2577 
2578 			eovptr->eov_str = EPDStringGrab("");
2579 
2580 			if (quoteflag)
2581 				{
2582 				while (flag && (ch != '"'))
2583 					{
2584 					if (ch == ascii_nul)
2585 						flag = 0;
2586 					else
2587 						{
2588 						eovptr->eov_str =
2589 							EPDStringAppendChar(eovptr->eov_str, ch);
2590 						ch = *(s + i++);
2591 						};
2592 					};
2593 				if (ch == '"')
2594 					ch = *(s + i++);
2595 				}
2596 			else
2597 				{
2598 				while (flag && !isspace(ch) && (ch != ';'))
2599 					{
2600 					if (ch == ascii_nul)
2601 						flag = 0;
2602 					else
2603 						{
2604 						eovptr->eov_str =
2605 							EPDStringAppendChar(eovptr->eov_str, ch);
2606 						ch = *(s + i++);
2607 						};
2608 					};
2609 				};
2610 
2611 			/* append operand onto operation */
2612 
2613 			if (flag)
2614 				EPDAppendEOV(eopptr, eovptr);
2615 			else
2616 				EPDReleaseEOV(eovptr);
2617 
2618 			/* skip whitespace */
2619 
2620 			while (flag && (ch != ascii_nul) && isspace(ch))
2621 				ch = *(s + i++);
2622 			};
2623 
2624 		/* process semicolon */
2625 
2626 		if (flag)
2627 			if (ch == ';')
2628 				ch = *(s + i++);
2629 			else
2630 				flag = 0;
2631 
2632 		/* append operation */
2633 
2634 		if (flag)
2635 			EPDAppendEOP(epdptr, eopptr);
2636 		else
2637 			EPDReleaseEOP(eopptr);
2638 
2639 		/* skip whitespace (end-of-line is not an error) */
2640 
2641 		if (flag)
2642 			while (flag && (ch != ascii_nul) && isspace(ch))
2643 				ch = *(s + i++);
2644 		};
2645 	};
2646 
2647 /* check for fault */
2648 
2649 if (!flag)
2650 	{
2651 	EPDReleaseEPD(epdptr);
2652 	epdptr = NULL;
2653 	};
2654 
2655 /* normalize */
2656 
2657 if (epdptr != NULL)
2658 	EPDNormalize(epdptr);
2659 
2660 return (epdptr);
2661 }
2662 
2663 /*--> EPDEncode: write an EPD structure to a string */
2664 nonstatic
2665 charptrT
EPDEncode(epdptrT epdptr)2666 EPDEncode(epdptrT epdptr)
2667 {
2668 charptrT ptr;
2669 sqT sq;
2670 cpT cp;
2671 rankT rank;
2672 fileT file;
2673 siT bi, ps, ch;
2674 char bv[tL];
2675 eopptrT eopptr;
2676 eovptrT eovptr;
2677 charptrT s0, s1;
2678 
2679 /* this does not reference the current position */
2680 
2681 bi = 0;
2682 
2683 /* normalize */
2684 
2685 EPDNormalize(epdptr);
2686 
2687 /* output board */
2688 
2689 for (rank = rank_8; rank >= rank_1; rank--)
2690 	{
2691 	ps = 0;
2692 	for (file = file_a; file <= file_h; file++)
2693 		{
2694 		sq = map_sq(rank, file);
2695 		if ((sq % 2) == 0)
2696 			cp = (epdptr->epd_nbv[sq >> 1] & nybbM);
2697 		else
2698 			cp = ((epdptr->epd_nbv[sq >> 1] >> nybbW) & nybbM);
2699 
2700 		if (cp == cp_v0)
2701 			ps++;
2702 		else
2703 			{
2704 			if (ps != 0)
2705 				{
2706 				bv[bi++] = '0' + ps;
2707 				ps = 0;
2708 				};
2709 			ch = ascpv[cv_p_cpv[cp]];
2710 			if (cv_c_cpv[cp] == c_w)
2711 				ch = map_upper(ch);
2712 			else
2713 				ch = map_lower(ch);
2714 			bv[bi++] = ch;
2715 			};
2716 		};
2717 	if (ps != 0)
2718 		{
2719 		bv[bi++] = '0' + ps;
2720 		ps = 0;
2721 		};
2722 	if (rank != rank_1)
2723 		bv[bi++] = '/';
2724 	};
2725 bv[bi++] = ascii_sp;
2726 
2727 /* output active color (lower case) */
2728 
2729 bv[bi++] = map_lower(asccv[epdptr->epd_actc]);
2730 bv[bi++] = ascii_sp;
2731 
2732 /* output castling availablility */
2733 
2734 if (epdptr->epd_cast == 0)
2735 	bv[bi++] = '-';
2736 else
2737 	{
2738 	if (epdptr->epd_cast & cf_wk)
2739 		bv[bi++] = map_upper(ascpv[p_k]);
2740 	if (epdptr->epd_cast & cf_wq)
2741 		bv[bi++] = map_upper(ascpv[p_q]);
2742 	if (epdptr->epd_cast & cf_bk)
2743 		bv[bi++] = map_lower(ascpv[p_k]);
2744 	if (epdptr->epd_cast & cf_bq)
2745 		bv[bi++] = map_lower(ascpv[p_q]);
2746 	};
2747 bv[bi++] = ascii_sp;
2748 
2749 /* output ep capture square */
2750 
2751 if (epdptr->epd_epsq == sq_nil)
2752 	bv[bi++] = '-';
2753 else
2754 	{
2755 	bv[bi++] = ascfv[map_file(epdptr->epd_epsq)];
2756 	bv[bi++] = ascrv[map_rank(epdptr->epd_epsq)];
2757 	};
2758 
2759 /* NUL termination */
2760 
2761 bv[bi++] = ascii_nul;
2762 
2763 /* allocate and copy basic result */
2764 
2765 ptr = EPDStringGrab(bv);
2766 
2767 /* construct and append operations */
2768 
2769 eopptr = epdptr->epd_headeop;
2770 while (eopptr != NULL)
2771 	{
2772 	/* leading space */
2773 
2774 	s0 = EPDStringGrab(" ");
2775 
2776 	/* opcode */
2777 
2778 	s0 = EPDStringAppendStr(s0, eopptr->eop_opsym);
2779 
2780 	/* construct and append operands */
2781 
2782 	eovptr = eopptr->eop_headeov;
2783 	while (eovptr != NULL)
2784 		{
2785 		/* leading space */
2786 
2787 		s1 = EPDStringGrab(" ");
2788 
2789 		/* conjure operand value */
2790 
2791 		switch (eovptr->eov_eob)
2792 			{
2793 			case eob_string:
2794 				s1 = EPDStringAppendChar(s1, '"');
2795 				s1 = EPDStringAppendStr(s1, eovptr->eov_str);
2796 				s1 = EPDStringAppendChar(s1, '"');
2797 				break;
2798 
2799 			case eob_symbol:
2800 				s1 = EPDStringAppendStr(s1, eovptr->eov_str);
2801 				break;
2802 
2803 			default:
2804 				EPDSwitchFault("EPDEncode");
2805 				break;
2806 			};
2807 
2808 		/* append */
2809 
2810 		s0 = EPDStringAppendStr(s0, s1);
2811 		EPDMemoryFree(s1);
2812 
2813 		/* next operand */
2814 
2815 		eovptr = eovptr->eov_next;
2816 		};
2817 
2818 	/* trailing semicolon */
2819 
2820 	s0 = EPDStringAppendChar(s0, ';');
2821 
2822 	/* append operation */
2823 
2824 	ptr = EPDStringAppendStr(ptr, s0);
2825 	EPDMemoryFree(s0);
2826 
2827 	/* advance */
2828 
2829 	eopptr = eopptr->eop_next;
2830 	};
2831 
2832 return (ptr);
2833 }
2834 
2835 /*--> EPDRealize: set the current position according to EPD */
2836 nonstatic
2837 void
EPDRealize(epdptrT epdptr)2838 EPDRealize(epdptrT epdptr)
2839 {
2840 sqT sq;
2841 cpT cp;
2842 eopptrT eopptr;
2843 eovptrT eovptr;
2844 
2845 /* this changes the current position */
2846 
2847 for (sq = sq_a1; sq <= sq_h8; sq++)
2848 	{
2849 	if ((sq % 2) == 0)
2850 		cp = (epdptr->epd_nbv[sq >> 1] & nybbM);
2851 	else
2852 		cp = ((epdptr->epd_nbv[sq >> 1] >> nybbW) & nybbM);
2853 	EPDboard.rbv[sq] = cp;
2854 	};
2855 
2856 ese.ese_actc = epdptr->epd_actc;
2857 ese.ese_cast = epdptr->epd_cast;
2858 ese.ese_epsq = epdptr->epd_epsq;
2859 
2860 eopptr = EPDLocateEOPCode(epdptr, epdso_hmvc);
2861 if ((eopptr != NULL) && ((eovptr = eopptr->eop_headeov) != NULL))
2862 	ese.ese_hmvc = atoi(eovptr->eov_str);
2863 else
2864 	ese.ese_hmvc = 0;
2865 
2866 eopptr = EPDLocateEOPCode(epdptr, epdso_fmvn);
2867 if ((eopptr != NULL) && ((eovptr = eopptr->eop_headeov) != NULL))
2868 	ese.ese_fmvn = atoi(eovptr->eov_str);
2869 else
2870 	ese.ese_fmvn = 1;
2871 
2872 EPDSetKings();
2873 
2874 return;
2875 }
2876 
2877 /*--> EPDInitArray: set the current position to the initial array */
2878 nonstatic
2879 void
EPDInitArray(void)2880 EPDInitArray(void)
2881 {
2882 sqT sq;
2883 
2884 /* this changes the current position */
2885 
2886 for (sq = sq_a1; sq <= sq_h8; sq++)
2887 	EPDboard.rbv[sq] = cp_v0;
2888 
2889 EPDboard.rbv[sq_a1] = EPDboard.rbv[sq_h1] = cp_wr;
2890 EPDboard.rbv[sq_b1] = EPDboard.rbv[sq_g1] = cp_wn;
2891 EPDboard.rbv[sq_c1] = EPDboard.rbv[sq_f1] = cp_wb;
2892 EPDboard.rbv[sq_d1] = cp_wq;
2893 EPDboard.rbv[sq_e1] = cp_wk;
2894 
2895 for (sq = sq_a2; sq <= sq_h2; sq++)
2896 	EPDboard.rbv[sq] = cp_wp;
2897 
2898 EPDboard.rbv[sq_a8] = EPDboard.rbv[sq_h8] = cp_br;
2899 EPDboard.rbv[sq_b8] = EPDboard.rbv[sq_g8] = cp_bn;
2900 EPDboard.rbv[sq_c8] = EPDboard.rbv[sq_f8] = cp_bb;
2901 EPDboard.rbv[sq_d8] = cp_bq;
2902 EPDboard.rbv[sq_e8] = cp_bk;
2903 
2904 for (sq = sq_a7; sq <= sq_h7; sq++)
2905 	EPDboard.rbv[sq] = cp_bp;
2906 
2907 ese.ese_actc = c_w;
2908 ese.ese_cast = cf_wk | cf_wq | cf_bk | cf_bq;
2909 ese.ese_epsq = sq_nil;
2910 ese.ese_hmvc = 0;
2911 ese.ese_fmvn = 1;
2912 
2913 EPDSetKings();
2914 
2915 return;
2916 }
2917 
2918 /*--> EPDPlayerString: return a pointer to the player name string */
2919 nonstatic
2920 charptrT
EPDPlayerString(cT c)2921 EPDPlayerString(cT c)
2922 {
2923 
2924 return (playerstrv[c]);
2925 }
2926 
2927 /*--> EPDSANEncodeChar: encode SAN character */
2928 static
2929 void
EPDSANEncodeChar(char ch)2930 EPDSANEncodeChar(char ch)
2931 {
2932 if ((lsani < (sanL - 1)) || ((ch == '\0') && (lsani < sanL)))
2933 	lsan[lsani++] = ch;
2934 else
2935 	EPDFatal("EPDSANEncodeChar: overflow");
2936 
2937 return;
2938 }
2939 
2940 /*--> EPDSANEncodeStr: encode a SAN string */
2941 static
2942 void
EPDSANEncodeStr(charptrT s)2943 EPDSANEncodeStr(charptrT s)
2944 {
2945 charptrT p;
2946 
2947 p = s;
2948 while (*p)
2949 	EPDSANEncodeChar(*p++);
2950 
2951 return;
2952 }
2953 
2954 /*--> EPDSANEncodeFile: encode SAN file from square */
2955 static
2956 void
EPDSANEncodeFile(sqT sq)2957 EPDSANEncodeFile(sqT sq)
2958 {
2959 EPDSANEncodeChar(ascfv[map_file(sq)]);
2960 
2961 return;
2962 }
2963 
2964 /*--> EPDSANEncodeRank: encode SAN rank from square */
2965 static
2966 void
EPDSANEncodeRank(sqT sq)2967 EPDSANEncodeRank(sqT sq)
2968 {
2969 EPDSANEncodeChar(ascrv[map_rank(sq)]);
2970 
2971 return;
2972 }
2973 
2974 /*--> EPDSANEncodeSq: encode SAN square */
2975 static
2976 void
EPDSANEncodeSq(sqT sq)2977 EPDSANEncodeSq(sqT sq)
2978 {
2979 EPDSANEncodeFile(sq);
2980 EPDSANEncodeRank(sq);
2981 
2982 return;
2983 }
2984 
2985 /*--> EPDSANEncodeCI: encode an appropriate capture indicator */
2986 static
2987 void
EPDSANEncodeCI(siT index)2988 EPDSANEncodeCI(siT index)
2989 {
2990 switch (index)
2991 	{
2992 	case 0:
2993 		EPDSANEncodeChar('x');
2994 		break;
2995 
2996 	case 1:
2997 		break;
2998 
2999 	case 2:
3000 		EPDSANEncodeChar(':');
3001 		break;
3002 
3003 	case 3:
3004 		EPDSANEncodeChar('*');
3005 		break;
3006 
3007 	case 4:
3008 		EPDSANEncodeChar('-');
3009 		break;
3010 	};
3011 
3012 return;
3013 }
3014 
3015 /*--> EPDSANEncodeAux: encode SAN format move with variants */
3016 static
3017 void
EPDSANEncodeAux(mptrT mptr,sanT san,ssavT ssav)3018 EPDSANEncodeAux(mptrT mptr, sanT san, ssavT ssav)
3019 {
3020 siT i;
3021 
3022 /* reset local index */
3023 
3024 lsani = 0;
3025 
3026 /* busted? */
3027 
3028 if (mptr->m_flag & mf_bust)
3029 	EPDSANEncodeChar('*');
3030 
3031 /* process according to moving piece */
3032 
3033 switch (cv_p_cpv[mptr->m_frcp])
3034 	{
3035 	case p_p:
3036 		switch (mptr->m_scmv)
3037 			{
3038 			case scmv_reg:
3039 				if (mptr->m_tocp != cp_v0)
3040 					{
3041 					EPDSANEncodeFile(mptr->m_frsq);
3042 					if (ssav[ssa_edcr] == 1)
3043 						EPDSANEncodeRank(mptr->m_frsq);
3044 					EPDSANEncodeCI(ssav[ssa_capt]);
3045 					if (ssav[ssa_ptar] == 0)
3046 						EPDSANEncodeSq(mptr->m_tosq);
3047 					else
3048 						EPDSANEncodeFile(mptr->m_tosq);
3049 					}
3050 				else
3051 					{
3052 					EPDSANEncodeFile(mptr->m_frsq);
3053 					if (ssav[ssa_edcr] == 1)
3054 						EPDSANEncodeRank(mptr->m_frsq);
3055 					if (ssav[ssa_move] == 1)
3056 						EPDSANEncodeChar('-');
3057 					if (ssav[ssa_edcf] == 1)
3058 						EPDSANEncodeFile(mptr->m_tosq);
3059 					EPDSANEncodeRank(mptr->m_tosq);
3060 					};
3061 				break;
3062 
3063 			case scmv_epc:
3064 				EPDSANEncodeFile(mptr->m_frsq);
3065 				if (ssav[ssa_edcr] == 1)
3066 					EPDSANEncodeRank(mptr->m_frsq);
3067 				EPDSANEncodeCI(ssav[ssa_capt]);
3068 				if (ssav[ssa_ptar] == 0)
3069 					EPDSANEncodeSq(mptr->m_tosq);
3070 				else
3071 					EPDSANEncodeFile(mptr->m_tosq);
3072 				if (ssav[ssa_epct] == 1)
3073 					EPDSANEncodeStr("ep");
3074 				break;
3075 
3076 			case scmv_ppn:
3077 			case scmv_ppb:
3078 			case scmv_ppr:
3079 			case scmv_ppq:
3080 				if (mptr->m_tocp != cp_v0)
3081 					{
3082 					EPDSANEncodeFile(mptr->m_frsq);
3083 					if (ssav[ssa_edcr] == 1)
3084 						EPDSANEncodeRank(mptr->m_frsq);
3085 					EPDSANEncodeCI(ssav[ssa_capt]);
3086 					if (ssav[ssa_ptar] == 0)
3087 						EPDSANEncodeSq(mptr->m_tosq);
3088 					else
3089 						EPDSANEncodeFile(mptr->m_tosq);
3090 					}
3091 				else
3092 					{
3093 					EPDSANEncodeFile(mptr->m_frsq);
3094 					if (ssav[ssa_edcr] == 1)
3095 						EPDSANEncodeRank(mptr->m_frsq);
3096 					if (ssav[ssa_move] == 1)
3097 						EPDSANEncodeChar('-');
3098 					if (ssav[ssa_edcf] == 1)
3099 						EPDSANEncodeFile(mptr->m_tosq);
3100 					EPDSANEncodeRank(mptr->m_tosq);
3101 					};
3102 				switch (ssav[ssa_prom])
3103 					{
3104 					case 0:
3105 						EPDSANEncodeChar('=');
3106 						EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]);
3107 						break;
3108 					case 1:
3109 						EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]);
3110 						break;
3111 					case 2:
3112 						EPDSANEncodeChar('/');
3113 						EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]);
3114 						break;
3115 					case 3:
3116 						EPDSANEncodeChar('(');
3117 						EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]);
3118 						EPDSANEncodeChar(')');
3119 						break;
3120 					};
3121 				break;
3122 			};
3123 		break;
3124 
3125 	case p_n:
3126 	case p_b:
3127 	case p_r:
3128 	case p_q:
3129 		EPDSANEncodeChar(ascpv[cv_p_cpv[mptr->m_frcp]]);
3130 
3131 		if (((mptr->m_flag & mf_sanf) || (ssav[ssa_edcf] == 1)) ||
3132 			((mptr->m_flag & mf_sanr) && (ssav[ssa_edcf] == 2)))
3133 			EPDSANEncodeFile(mptr->m_frsq);
3134 
3135 		if (((mptr->m_flag & mf_sanr) || (ssav[ssa_edcr] == 1)) ||
3136 			((mptr->m_flag & mf_sanf) && (ssav[ssa_edcr] == 2)))
3137 			EPDSANEncodeRank(mptr->m_frsq);
3138 
3139 		if (mptr->m_tocp != cp_v0)
3140 			EPDSANEncodeCI(ssav[ssa_capt]);
3141 		else
3142 			if (ssav[ssa_move] == 1)
3143 				EPDSANEncodeChar('-');
3144 		EPDSANEncodeSq(mptr->m_tosq);
3145 		break;
3146 
3147 	case p_k:
3148 		switch (mptr->m_scmv)
3149 			{
3150 			case scmv_reg:
3151 				EPDSANEncodeChar(ascpv[p_k]);
3152 				if (ssav[ssa_edcf] == 1)
3153 					EPDSANEncodeFile(mptr->m_frsq);
3154 				if (ssav[ssa_edcr] == 1)
3155 					EPDSANEncodeRank(mptr->m_frsq);
3156 				if (mptr->m_tocp != cp_v0)
3157 					EPDSANEncodeCI(ssav[ssa_capt]);
3158 				else
3159 					if (ssav[ssa_move] == 1)
3160 						EPDSANEncodeChar('-');
3161 				EPDSANEncodeSq(mptr->m_tosq);
3162 				break;
3163 
3164 			case scmv_cks:
3165 				switch (ssav[ssa_cast])
3166 					{
3167 					case 0:
3168 						EPDSANEncodeStr("O-O");
3169 						break;
3170 					case 1:
3171 						EPDSANEncodeStr("0-0");
3172 						break;
3173 					case 2:
3174 						EPDSANEncodeStr("OO");
3175 						break;
3176 					case 3:
3177 						EPDSANEncodeStr("00");
3178 						break;
3179 					case 4:
3180 						EPDSANEncodeChar(ascpv[p_k]);
3181 						if (ssav[ssa_edcf] == 1)
3182 							EPDSANEncodeFile(mptr->m_frsq);
3183 						if (ssav[ssa_edcr] == 1)
3184 							EPDSANEncodeRank(mptr->m_frsq);
3185 						if (ssav[ssa_move] == 1)
3186 							EPDSANEncodeChar('-');
3187 						EPDSANEncodeSq(mptr->m_tosq);
3188 						break;
3189 					};
3190 				break;
3191 
3192 			case scmv_cqs:
3193 				switch (ssav[ssa_cast])
3194 					{
3195 					case 0:
3196 						EPDSANEncodeStr("O-O-O");
3197 						break;
3198 					case 1:
3199 						EPDSANEncodeStr("0-0-0");
3200 						break;
3201 					case 2:
3202 						EPDSANEncodeStr("OOO");
3203 						break;
3204 					case 3:
3205 						EPDSANEncodeStr("000");
3206 						break;
3207 					case 4:
3208 						EPDSANEncodeChar(ascpv[p_k]);
3209 						if (ssav[ssa_edcf] == 1)
3210 							EPDSANEncodeFile(mptr->m_frsq);
3211 						if (ssav[ssa_edcr] == 1)
3212 							EPDSANEncodeRank(mptr->m_frsq);
3213 						if (ssav[ssa_move] == 1)
3214 							EPDSANEncodeChar('-');
3215 						EPDSANEncodeSq(mptr->m_tosq);
3216 						break;
3217 					};
3218 				break;
3219 			};
3220 		break;
3221 	};
3222 
3223 /* insert markers */
3224 
3225 if ((mptr->m_flag & mf_chec) && !(mptr->m_flag & mf_chmt))
3226 	switch (ssav[ssa_chec])
3227 		{
3228 		case 0:
3229 			EPDSANEncodeChar('+');
3230 			break;
3231 		case 1:
3232 			break;
3233 		case 2:
3234 			EPDSANEncodeStr("ch");
3235 			break;
3236 		};
3237 
3238 if (mptr->m_flag & mf_chmt)
3239 	switch (ssav[ssa_chmt])
3240 		{
3241 		case 0:
3242 			EPDSANEncodeChar('#');
3243 			break;
3244 		case 1:
3245 			break;
3246 		case 2:
3247 			EPDSANEncodeChar('+');
3248 			break;
3249 		case 3:
3250 			EPDSANEncodeStr("++");
3251 			break;
3252 		};
3253 
3254 if (mptr->m_flag & mf_draw)
3255 	if (ssav[ssa_draw] == 1)
3256 		EPDSANEncodeChar('=');
3257 
3258 /* map to lower case if indicated */
3259 
3260 if (ssav[ssa_case] == 1)
3261 	for (i = 0; i < lsani; i++)
3262 		lsan[i] = map_lower(lsan[i]);
3263 
3264 /* pad and copy */
3265 
3266 while (lsani < sanL)
3267 	EPDSANEncodeChar('\0');
3268 
3269 for (i = 0; i < sanL; i++)
3270 	san[i] = lsan[i];
3271 
3272 return;
3273 }
3274 
3275 /*--> EPDSANEncode: encode a move into a SAN string */
3276 nonstatic
3277 void
EPDSANEncode(mptrT mptr,sanT san)3278 EPDSANEncode(mptrT mptr, sanT san)
3279 {
3280 ssaT ssa;
3281 ssavT ssav;
3282 
3283 /* select canonical encoding (zero point in variant space) */
3284 
3285 for (ssa = 0; ssa < ssaL; ssa++)
3286 	ssav[ssa] = 0;
3287 EPDSANEncodeAux(mptr, san, ssav);
3288 
3289 return;
3290 }
3291 
3292 /*--> EPDSANDecodeBump: increment a style vector and return overflow */
3293 static
3294 siT
EPDSANDecodeBump(ssavT ssav,ssavT bssav)3295 EPDSANDecodeBump(ssavT ssav, ssavT bssav)
3296 {
3297 siT flag;
3298 ssaT ssa;
3299 
3300 flag = 1;
3301 ssa = 0;
3302 while (flag && (ssa < ssaL))
3303 	{
3304 	flag = 0;
3305 	ssav[ssa]++;
3306 	if (ssav[ssa] == bssav[ssa])
3307 		{
3308 		flag = 1;
3309 		ssav[ssa] = 0;
3310 		};
3311 	ssa++;
3312 	};
3313 
3314 return (flag);
3315 }
3316 
3317 /*--> EPDSANDecodeFlex: locate a move from SAN (flexible interpretation) */
3318 static
3319 mptrT
EPDSANDecodeFlex(sanT san)3320 EPDSANDecodeFlex(sanT san)
3321 {
3322 mptrT mptr;
3323 ssavT ssav, bssav;
3324 siT i, flag;
3325 mptrT rmptr;
3326 sanT lcsan, rsan;
3327 
3328 /* set default return value */
3329 
3330 mptr = NULL;
3331 
3332 /* set minimal upper bounds */
3333 
3334 for (i = 0; i < ssaL; i++)
3335 	bssav[i] = 1;
3336 
3337 /* scan for upper bound conditions */
3338 
3339 rmptr = tse.tse_base;
3340 for (i = 0; i < tse.tse_count; i++)
3341 	{
3342 	/* letter case */
3343 
3344 	bssav[ssa_case] = 2;
3345 
3346 	/* capturing */
3347 
3348 	if ((rmptr->m_tocp != cp_v0) || (rmptr->m_scmv == scmv_epc))
3349 		bssav[ssa_capt] = 5;
3350 
3351 	/* checking */
3352 
3353 	if (rmptr->m_flag & mf_chec)
3354 		bssav[ssa_chec] = 3;
3355 
3356 	/* castling */
3357 
3358 	if ((rmptr->m_scmv == scmv_cks) || (rmptr->m_scmv == scmv_cqs))
3359 		bssav[ssa_cast] = 5;
3360 
3361 	/* promoting */
3362 
3363 	if ((rmptr->m_scmv == scmv_ppn) || (rmptr->m_scmv == scmv_ppb) ||
3364 		(rmptr->m_scmv == scmv_ppr) || (rmptr->m_scmv == scmv_ppq))
3365 		bssav[ssa_prom] = 4;
3366 
3367 	/* pawn destination target */
3368 
3369 	if (cv_p_cpv[rmptr->m_frcp] == p_p)
3370 		bssav[ssa_ptar] = 2;
3371 
3372 	/* checkmating */
3373 
3374 	if (rmptr->m_flag & mf_chmt)
3375 		bssav[ssa_chmt] = 4;
3376 
3377 	/* en passant capturing */
3378 
3379 	if (rmptr->m_scmv == scmv_epc)
3380 		bssav[ssa_epct] = 2;
3381 
3382 	/* drawing */
3383 
3384 	if (rmptr->m_flag & mf_draw)
3385 		bssav[ssa_draw] = 2;
3386 
3387 	/* moving (non-capturing) */
3388 
3389 	if ((rmptr->m_tocp == cp_v0) &&
3390 		(rmptr->m_scmv != scmv_epc))
3391 		bssav[ssa_move] = 2;
3392 
3393 	/* extra disambiguation: file */
3394 
3395 	if (!(rmptr->m_flag & mf_sanf))
3396 		bssav[ssa_edcf] = 3;
3397 
3398 	/* extra disambiguation: rank */
3399 
3400 	if (!(rmptr->m_flag & mf_sanr))
3401 		bssav[ssa_edcr] = 3;
3402 
3403 	rmptr++;
3404 	};
3405 
3406 /* make a lower case copy of the input */
3407 
3408 for (i = 0; i < sanL; i++)
3409 	lcsan[i] = map_lower(san[i]);
3410 
3411 /* initialize the index style vector */
3412 
3413 for (i = 0; i < ssaL; i++)
3414 	ssav[i] = 0;
3415 
3416 /* search */
3417 
3418 flag = 0;
3419 while (!flag && (mptr == NULL))
3420 	{
3421 	rmptr = tse.tse_base;
3422 	i = 0;
3423 
3424 	/* scan candidate moves */
3425 
3426 	while ((mptr == NULL) && (i < tse.tse_count))
3427 		{
3428 		/* encode the current style version of a candidate */
3429 
3430 		EPDSANEncodeAux(rmptr, rsan, ssav);
3431 
3432 		/* select either original or lower case comparison */
3433 
3434 		if (ssav[ssa_case] == 0)
3435 			{
3436 			if (strcmp(san, rsan) == 0)
3437 				mptr = rmptr;
3438 			}
3439 		else
3440 			{
3441 			if (strcmp(lcsan, rsan) == 0)
3442 				mptr = rmptr;
3443 			};
3444 
3445 		/* next candidate */
3446 
3447 		rmptr++;
3448 		i++;
3449 		};
3450 
3451 	/* update the overflow termination flag	*/
3452 
3453 	flag = EPDSANDecodeBump(ssav, bssav);
3454 	};
3455 
3456 return (mptr);
3457 }
3458 
3459 /*--> EPDSANDecode: locate a move from SAN (strict interpretation) */
3460 static
3461 mptrT
EPDSANDecode(sanT san)3462 EPDSANDecode(sanT san)
3463 {
3464 mptrT mptr;
3465 mptrT rmptr;
3466 sanT rsan;
3467 siT i;
3468 
3469 /* set default return value */
3470 
3471 mptr = NULL;
3472 
3473 /* assume current moveset properly generated */
3474 
3475 rmptr = tse.tse_base;
3476 i = 0;
3477 
3478 /* search */
3479 
3480 while ((mptr == NULL) && (i < tse.tse_count))
3481 	{
3482 	EPDSANEncode(rmptr, rsan);
3483 	if (strcmp(san, rsan) == 0)
3484 		mptr = rmptr;
3485 	else
3486 		{
3487 		rmptr++;
3488 		i++;
3489 		};
3490 	};
3491 
3492 return (mptr);
3493 }
3494 
3495 /*--> EPDSANDecodeAux: locate a move from SAN */
3496 nonstatic
3497 mptrT
EPDSANDecodeAux(sanT san,siT strict)3498 EPDSANDecodeAux(sanT san, siT strict)
3499 {
3500 mptrT mptr;
3501 
3502 if (strict)
3503 	mptr = EPDSANDecode(san);
3504 else
3505 	mptr = EPDSANDecodeFlex(san);
3506 
3507 return (mptr);
3508 }
3509 
3510 /*--> EPDAttack: determine if a color attacks a square */
3511 static
3512 siT
EPDAttack(cT c,sqT sq)3513 EPDAttack(cT c, sqT sq)
3514 {
3515 siT flag;
3516 dxT dx;
3517 dvT dv;
3518 xdvT xdv;
3519 sqptrT sqptr0, sqptr1;
3520 xsqptrT xsqptr0, xsqptr1;
3521 
3522 /* clear result */
3523 
3524 flag = 0;
3525 
3526 /* set origin square pointers  */
3527 
3528 sqptr0 = &EPDboard.rbv[sq];
3529 xsqptr0 = &xb.xbv[map_xsq_sq(sq)];
3530 
3531 /* process according to specified color */
3532 
3533 if (c == c_w)
3534 	{
3535 	/* pawn attacks */
3536 
3537 	if ((*(xsqptr0 + xdv_7) == cp_v0) && (*(sqptr0 + dv_7) == cp_wp))
3538 		flag = 1;
3539 	else
3540 		if ((*(xsqptr0 + xdv_6) == cp_v0) && (*(sqptr0 + dv_6) == cp_wp))
3541 			flag = 1;
3542 
3543 	/* knight attacks */
3544 
3545 	if (!flag)
3546 		{
3547 		dx = dx_8;
3548 		while (!flag && (dx <= dx_f))
3549 			if ((*(xsqptr0 + xdvv[dx]) == cp_v0) &&
3550 				(*(sqptr0 + dvv[dx]) == cp_wn))
3551 				flag = 1;
3552 			else
3553 				dx++;
3554 		};
3555 
3556 	/* orthogonal sweeps */
3557 
3558 	if (!flag)
3559 		{
3560 		dx = dx_0;
3561 		while (!flag && (dx <= dx_3))
3562 			{
3563 			dv = dvv[dx];
3564 			xdv = xdvv[dx];
3565 			sqptr1 = sqptr0;
3566 			xsqptr1 = xsqptr0;
3567 			while ((*(xsqptr1 += xdv) == cp_v0) &&
3568 				(*(sqptr1 += dv) == cp_v0))
3569 				;
3570 			if ((*xsqptr1 == cp_v0) &&
3571 				((*sqptr1 == cp_wq) || (*sqptr1 == cp_wr)))
3572 				flag = 1;
3573 			else
3574 				dx++;
3575 			};
3576 		};
3577 
3578 	/* diagonal sweeps */
3579 
3580 	if (!flag)
3581 		{
3582 		dx = dx_4;
3583 		while (!flag && (dx <= dx_7))
3584 			{
3585 			dv = dvv[dx];
3586 			xdv = xdvv[dx];
3587 			sqptr1 = sqptr0;
3588 			xsqptr1 = xsqptr0;
3589 			while ((*(xsqptr1 += xdv) == cp_v0) &&
3590 				(*(sqptr1 += dv) == cp_v0))
3591 				;
3592 			if ((*xsqptr1 == cp_v0) &&
3593 				((*sqptr1 == cp_wq) || (*sqptr1 == cp_wb)))
3594 				flag = 1;
3595 			else
3596 				dx++;
3597 			};
3598 		};
3599 
3600 	/* king attacks */
3601 
3602 	if (!flag)
3603 		{
3604 		dx = dx_0;
3605 		while (!flag && (dx <= dx_7))
3606 			if ((*(xsqptr0 + xdvv[dx]) == cp_v0) &&
3607 				(*(sqptr0 + dvv[dx]) == cp_wk))
3608 				flag = 1;
3609 			else
3610 				dx++;
3611 		};
3612 	}
3613 else
3614 	{
3615 	/* pawn attacks */
3616 
3617 	if ((*(xsqptr0 + xdv_4) == cp_v0) && (*(sqptr0 + dv_4) == cp_bp))
3618 		flag = 1;
3619 	else
3620 		if ((*(xsqptr0 + xdv_5) == cp_v0) && (*(sqptr0 + dv_5) == cp_bp))
3621 			flag = 1;
3622 
3623 	/* knight attacks */
3624 
3625 	if (!flag)
3626 		{
3627 		dx = dx_8;
3628 		while (!flag && (dx <= dx_f))
3629 			if ((*(xsqptr0 + xdvv[dx]) == cp_v0) &&
3630 				(*(sqptr0 + dvv[dx]) == cp_bn))
3631 				flag = 1;
3632 			else
3633 				dx++;
3634 		};
3635 
3636 	/* orthogonal sweeps */
3637 
3638 	if (!flag)
3639 		{
3640 		dx = dx_0;
3641 		while (!flag && (dx <= dx_3))
3642 			{
3643 			dv = dvv[dx];
3644 			xdv = xdvv[dx];
3645 			sqptr1 = sqptr0;
3646 			xsqptr1 = xsqptr0;
3647 			while ((*(xsqptr1 += xdv) == cp_v0) &&
3648 				(*(sqptr1 += dv) == cp_v0))
3649 				;
3650 			if ((*xsqptr1 == cp_v0) &&
3651 				((*sqptr1 == cp_bq) || (*sqptr1 == cp_br)))
3652 				flag = 1;
3653 			else
3654 				dx++;
3655 			};
3656 		};
3657 
3658 	/* diagonal sweeps */
3659 
3660 	if (!flag)
3661 		{
3662 		dx = dx_4;
3663 		while (!flag && (dx <= dx_7))
3664 			{
3665 			dv = dvv[dx];
3666 			xdv = xdvv[dx];
3667 			sqptr1 = sqptr0;
3668 			xsqptr1 = xsqptr0;
3669 			while ((*(xsqptr1 += xdv) == cp_v0) &&
3670 				(*(sqptr1 += dv) == cp_v0))
3671 				;
3672 			if ((*xsqptr1 == cp_v0) &&
3673 				((*sqptr1 == cp_bq) || (*sqptr1 == cp_bb)))
3674 				flag = 1;
3675 			else
3676 				dx++;
3677 			};
3678 		};
3679 
3680 	/* king attacks */
3681 
3682 	if (!flag)
3683 		{
3684 		dx = dx_0;
3685 		while (!flag && (dx <= dx_7))
3686 			if ((*(xsqptr0 + xdvv[dx]) == cp_v0) &&
3687 				(*(sqptr0 + dvv[dx]) == cp_bk))
3688 				flag = 1;
3689 			else
3690 				dx++;
3691 		};
3692 	};
3693 
3694 return (flag);
3695 }
3696 
3697 /*--> EPDWhiteAttacks: check if White attacks a square */
3698 static
3699 siT
EPDWhiteAttacks(sqT sq)3700 EPDWhiteAttacks(sqT sq)
3701 {
3702 
3703 return (EPDAttack(c_w, sq));
3704 }
3705 
3706 /*--> EPDBlackAttacks: check if White attacks a square */
3707 static
3708 siT
EPDBlackAttacks(sqT sq)3709 EPDBlackAttacks(sqT sq)
3710 {
3711 
3712 return (EPDAttack(c_b, sq));
3713 }
3714 
3715 /*--> EPDTestAKIC: test for active king in check */
3716 static
3717 siT
EPDTestAKIC(void)3718 EPDTestAKIC(void)
3719 {
3720 siT flag;
3721 
3722 if (ese.ese_actc == c_w)
3723 	flag = EPDBlackAttacks(ese.ese_ksqv[c_w]);
3724 else
3725 	flag = EPDWhiteAttacks(ese.ese_ksqv[c_b]);
3726 
3727 return (flag);
3728 }
3729 
3730 /*--> EPDTestPKIC: test for passive king in check */
3731 static
3732 siT
EPDTestPKIC(void)3733 EPDTestPKIC(void)
3734 {
3735 siT flag;
3736 
3737 if (ese.ese_actc == c_b)
3738 	flag = EPDBlackAttacks(ese.ese_ksqv[c_w]);
3739 else
3740 	flag = EPDWhiteAttacks(ese.ese_ksqv[c_b]);
3741 
3742 return (flag);
3743 }
3744 
3745 /*--> EPDCensus: calculate local census vectors */
3746 static
3747 void
EPDCensus(void)3748 EPDCensus(void)
3749 {
3750 cT c;
3751 pT p;
3752 sqT sq;
3753 cpT cp;
3754 
3755 /* clear census vectors */
3756 
3757 for (c = c_w; c <= c_b; c++)
3758 	{
3759 	count_cv[c] = 0;
3760 	for (p = p_p; p <= p_k; p++)
3761 		count_cpv[c][p] = 0;
3762 	};
3763 
3764 /* calculate census vectors */
3765 
3766 for (sq = sq_a1; sq <= sq_h8; sq++)
3767 	{
3768 	cp = EPDboard.rbv[sq];
3769 	if (cp != cp_v0)
3770 		{
3771 		c = cv_c_cpv[cp];
3772 		count_cv[c]++;
3773 		count_cpv[c][cv_p_cpv[cp]]++;
3774 		};
3775 	};
3776 
3777 return;
3778 }
3779 
3780 /*--> EPDIsLegal: determine if current position is legal */
3781 nonstatic
3782 siT
EPDIsLegal(void)3783 EPDIsLegal(void)
3784 {
3785 siT flag;
3786 cT c;
3787 fileT file;
3788 siT apv[rcL];
3789 
3790 /* set default return value: legal position */
3791 
3792 flag = 1;
3793 
3794 /* calculate the local census vectors */
3795 
3796 EPDCensus();
3797 
3798 /* calculate available promoted pawns */
3799 
3800 for (c = c_w; c <= c_b; c++)
3801 	apv[c] = fileL - count_cpv[c][p_p];
3802 
3803 /* check white pawn count */
3804 
3805 if (flag && (count_cpv[c_w][p_p] > fileL))
3806 	flag = 0;
3807 
3808 /* check black pawn count */
3809 
3810 if (flag && (count_cpv[c_b][p_p] > fileL))
3811 	flag = 0;
3812 
3813 /* check white knight count */
3814 
3815 if (flag && (count_cpv[c_w][p_n] > 2))
3816 	{
3817 	apv[c_w] -= (count_cpv[c_w][p_n] - 2);
3818 	if (apv[c_w] < 0)
3819 		flag = 0;
3820 	};
3821 
3822 /* check black knight count */
3823 
3824 if (flag && (count_cpv[c_b][p_n] > 2))
3825 	{
3826 	apv[c_b] -= (count_cpv[c_b][p_n] - 2);
3827 	if (apv[c_b] < 0)
3828 		flag = 0;
3829 	};
3830 
3831 /* check white bishop count */
3832 
3833 if (flag && (count_cpv[c_w][p_b] > 2))
3834 	{
3835 	apv[c_w] -= (count_cpv[c_w][p_b] - 2);
3836 	if (apv[c_w] < 0)
3837 		flag = 0;
3838 	};
3839 
3840 /* check black bishop count */
3841 
3842 if (flag && (count_cpv[c_b][p_b] > 2))
3843 	{
3844 	apv[c_b] -= (count_cpv[c_b][p_b] - 2);
3845 	if (apv[c_b] < 0)
3846 		flag = 0;
3847 	};
3848 
3849 /* check white rook count */
3850 
3851 if (flag && (count_cpv[c_w][p_r] > 2))
3852 	{
3853 	apv[c_w] -= (count_cpv[c_w][p_r] - 2);
3854 	if (apv[c_w] < 0)
3855 		flag = 0;
3856 	};
3857 
3858 /* check black rook count */
3859 
3860 if (flag && (count_cpv[c_b][p_r] > 2))
3861 	{
3862 	apv[c_b] -= (count_cpv[c_b][p_r] - 2);
3863 	if (apv[c_b] < 0)
3864 		flag = 0;
3865 	};
3866 
3867 /* check white queen count */
3868 
3869 if (flag && (count_cpv[c_w][p_q] > 1))
3870 	{
3871 	apv[c_w] -= (count_cpv[c_w][p_q] - 1);
3872 	if (apv[c_w] < 0)
3873 		flag = 0;
3874 	};
3875 
3876 /* check black queen count */
3877 
3878 if (flag && (count_cpv[c_b][p_q] > 1))
3879 	{
3880 	apv[c_b] -= (count_cpv[c_b][p_q] - 1);
3881 	if (apv[c_b] < 0)
3882 		flag = 0;
3883 	};
3884 
3885 /* check white king count */
3886 
3887 if (flag && (count_cpv[c_w][p_k] != 1))
3888 	flag = 0;
3889 
3890 /* check black king count */
3891 
3892 if (flag && (count_cpv[c_b][p_k] != 1))
3893 	flag = 0;
3894 
3895 /* check pawn placement */
3896 
3897 if (flag)
3898 	{
3899 	file = file_a;
3900 	while (flag && (file <= file_h))
3901 		if ((EPDboard.rbm[rank_1][file] == cp_wp) ||
3902 			(EPDboard.rbm[rank_1][file] == cp_bp) ||
3903 			(EPDboard.rbm[rank_8][file] == cp_wp) ||
3904 			(EPDboard.rbm[rank_8][file] == cp_bp))
3905 			flag = 0;
3906 		else
3907 			file++;
3908 	};
3909 
3910 /* check white kingside castling availability */
3911 
3912 if (flag && (ese.ese_cast & cf_wk))
3913 	if ((EPDboard.rbv[sq_e1] != cp_wk) || (EPDboard.rbv[sq_h1] != cp_wr))
3914 		flag = 0;
3915 
3916 /* check white queenside castling availability */
3917 
3918 if (flag && (ese.ese_cast & cf_wq))
3919 	if ((EPDboard.rbv[sq_e1] != cp_wk) || (EPDboard.rbv[sq_a1] != cp_wr))
3920 		flag = 0;
3921 
3922 /* check black kingside castling availability */
3923 
3924 if (flag && (ese.ese_cast & cf_bk))
3925 	if ((EPDboard.rbv[sq_e8] != cp_bk) || (EPDboard.rbv[sq_h8] != cp_br))
3926 		flag = 0;
3927 
3928 /* check black queenside castling availability */
3929 
3930 if (flag && (ese.ese_cast & cf_bq))
3931 	if ((EPDboard.rbv[sq_e8] != cp_bk) || (EPDboard.rbv[sq_a8] != cp_br))
3932 		flag = 0;
3933 
3934 /* check en passant target square */
3935 
3936 if (flag && (ese.ese_epsq != sq_nil))
3937 	if (ese.ese_actc == c_w)
3938 		{
3939 		if (map_rank(ese.ese_epsq) != rank_6)
3940 			flag = 0;
3941 		else
3942 			if (EPDboard.rbv[ese.ese_epsq + dv_3] != cp_bp)
3943 				flag = 0;
3944 			else
3945 				if (EPDboard.rbv[ese.ese_epsq] != cp_v0)
3946 					flag = 0;
3947 				else
3948 					if (EPDboard.rbv[ese.ese_epsq + dv_1] != cp_v0)
3949 						flag = 0;
3950 		}
3951 	else
3952 		{
3953 		if (map_rank(ese.ese_epsq) != rank_3)
3954 			flag = 0;
3955 		else
3956 			if (EPDboard.rbv[ese.ese_epsq + dv_1] != cp_wp)
3957 				flag = 0;
3958 			else
3959 				if (EPDboard.rbv[ese.ese_epsq] != cp_v0)
3960 					flag = 0;
3961 				else
3962 					if (EPDboard.rbv[ese.ese_epsq + dv_3] != cp_v0)
3963 						flag = 0;
3964 		};
3965 
3966 /* check for passive king in check */
3967 
3968 if (flag && EPDTestPKIC())
3969 	flag = 0;
3970 
3971 return (flag);
3972 }
3973 
3974 /*--> EPDIsCheckmate: test for checkmate status */
3975 nonstatic
3976 siT
EPDIsCheckmate(void)3977 EPDIsCheckmate(void)
3978 {
3979 siT flag;
3980 
3981 /* set default return value: no checkmate */
3982 
3983 flag = 0;
3984 
3985 /* generate legal moves (assume legal position) */
3986 
3987 EPDGenMoves();
3988 
3989 /* no legal moves and in check? */
3990 
3991 if ((tse.tse_count == 0) && EPDTestAKIC())
3992 	flag = 1;
3993 
3994 return (flag);
3995 }
3996 
3997 /*--> EPDIsStalemate: test for stalemate status */
3998 nonstatic
3999 siT
EPDIsStalemate(void)4000 EPDIsStalemate(void)
4001 {
4002 siT flag;
4003 
4004 /* set default return value: no stalemate */
4005 
4006 flag = 0;
4007 
4008 /* generate legal moves (assume legal position) */
4009 
4010 EPDGenMoves();
4011 
4012 /* no legal moves and not in check? */
4013 
4014 if ((tse.tse_count == 0) && !EPDTestAKIC())
4015 	flag = 1;
4016 
4017 return (flag);
4018 }
4019 
4020 /*--> EPDIsInsufficientMaterial: test for insufficient material */
4021 nonstatic
4022 siT
EPDIsInsufficientMaterial(void)4023 EPDIsInsufficientMaterial(void)
4024 {
4025 siT flag;
4026 
4027 /* set default return value: no draw by insufficient material */
4028 
4029 flag = 0;
4030 
4031 /* calculate local census (assume legal position) */
4032 
4033 EPDCensus();
4034 
4035 /* only K vs K, K+N vs K, and K+B vs K are considered draws here */
4036 
4037 if ((count_cv[c_w] == 1) && (count_cv[c_b] == 1))
4038 	flag = 1;
4039 else
4040 	if ((count_cv[c_w] == 2) && (count_cv[c_b] == 1) &&
4041 		((count_cpv[c_w][p_n] == 1) || (count_cpv[c_w][p_b] == 1)))
4042 		flag = 1;
4043 	else
4044 		if ((count_cv[c_b] == 2) && (count_cv[c_w] == 1) &&
4045 			((count_cpv[c_b][p_n] == 1) || (count_cpv[c_b][p_b] == 1)))
4046 			flag = 1;
4047 
4048 return (flag);
4049 }
4050 
4051 /*--> EPDIsFiftyMoveDraw: test for 50 move draw */
4052 nonstatic
4053 siT
EPDIsFiftyMoveDraw(void)4054 EPDIsFiftyMoveDraw(void)
4055 {
4056 siT flag;
4057 
4058 if (ese.ese_hmvc >= 100)
4059 	flag = 1;
4060 else
4061 	flag = 0;
4062 
4063 return (flag);
4064 }
4065 
4066 /*--> EPDIsThirdRepetition: test for third repetition */
4067 nonstatic
4068 siT
EPDIsThirdRepetition(gamptrT gamptr)4069 EPDIsThirdRepetition(gamptrT gamptr)
4070 {
4071 siT flag;
4072 gpmptrT gpmptr;
4073 siT count, limit, index, match;
4074 sqT sq;
4075 cpT cp0, cp1;
4076 nbvT nbv;
4077 
4078 /* point to the last game played move record */
4079 
4080 gpmptr = gamptr->gam_tailgpm;
4081 
4082 /* set the repetion count (current position counts as one) */
4083 
4084 count = 1;
4085 
4086 /* set the limit on the number of records to check */
4087 
4088 limit = ese.ese_hmvc;
4089 
4090 /* construct the nybble board for the current position */
4091 
4092 for (sq = sq_a1; sq <= sq_h8; sq += 2)
4093 	{
4094 	cp0 = EPDboard.rbv[sq + 0];
4095 	cp1 = EPDboard.rbv[sq + 1];
4096 	nbv[sq >> 1] = ((cp1 << nybbW) | cp0);
4097 	};
4098 
4099 /* loop backwards */
4100 
4101 while ((gpmptr != NULL) && (limit > 0) && (count < 3))
4102 	{
4103 	/* check for match against current position */
4104 
4105 	if ((ese.ese_actc == gpmptr->gpm_ese.ese_actc) &&
4106 		(ese.ese_cast == gpmptr->gpm_ese.ese_cast) &&
4107 		(ese.ese_epsq == gpmptr->gpm_ese.ese_epsq))
4108 		{
4109 		/* scalars matched, check for board match */
4110 
4111 		match = 1;
4112 		index = 0;
4113 		while (match && (index < nbL))
4114 			{
4115 			if (nbv[index] == gpmptr->gpm_nbv[index])
4116 				index++;
4117 			else
4118 				match = 0;
4119 			};
4120 
4121 		/* complete match? */
4122 
4123 		if (match)
4124 			count++;
4125 		};
4126 
4127 	/* retreat to previous played move record */
4128 
4129 	gpmptr = gpmptr->gpm_prev;
4130 
4131 	/* one less to go */
4132 
4133 	limit--;
4134 	};
4135 
4136 /* set return value */
4137 
4138 if (count == 3)
4139 	flag = 1;
4140 else
4141 	flag = 0;
4142 
4143 return (flag);
4144 }
4145 
4146 /*--> EPDIsDraw: determine if the current position is a draw */
4147 nonstatic
4148 siT
EPDIsDraw(gamptrT gamptr)4149 EPDIsDraw(gamptrT gamptr)
4150 {
4151 siT flag;
4152 
4153 if (EPDIsFiftyMoveDraw() ||
4154 	EPDIsInsufficientMaterial() ||
4155 	EPDIsStalemate() ||
4156 	EPDIsThirdRepetition(gamptr))
4157 	flag = 1;
4158 else
4159 	flag = 0;
4160 
4161 return (flag);
4162 }
4163 
4164 /*--> EPDMateInOne: return a mating move if one exists */
4165 nonstatic
4166 mptrT
EPDMateInOne(void)4167 EPDMateInOne(void)
4168 {
4169 mptrT mptr;
4170 mptrT rmptr;
4171 siT index;
4172 
4173 /* set default return value (no mate in one) */
4174 
4175 mptr = NULL;
4176 
4177 /* generate legal moves (assume legal position) */
4178 
4179 EPDGenMoves();
4180 
4181 /* try to locate a mating move */
4182 
4183 rmptr = tse.tse_base;
4184 index = 0;
4185 while ((mptr == NULL) && (index < tse.tse_count))
4186 	if (rmptr->m_flag & mf_chmt)
4187 		{
4188 		ret_m = *rmptr;
4189 		mptr = &ret_m;
4190 		}
4191 	else
4192 		{
4193 		rmptr++;
4194 		index++;
4195 		};
4196 
4197 return (mptr);
4198 }
4199 
4200 /*--> EPDGeneratePL: generate psuedolegal moves */
4201 static
4202 void
EPDGeneratePL(void)4203 EPDGeneratePL(void)
4204 {
4205 dxT dx;
4206 dvT dv;
4207 xdvT xdv;
4208 xsqptrT xsqptr0, xsqptr1;
4209 fileT frfile;
4210 rankT frrank;
4211 mT gen_m;
4212 
4213 /* set up the generation base */
4214 
4215 if (ply == 0)
4216 	treeptr = tse.tse_base = treebaseptr;
4217 else
4218 	treeptr = tse.tse_base =
4219 		(tseptr - 1)->tse_base + (tseptr - 1)->tse_count;
4220 
4221 /* test against safety margin */
4222 
4223 if ((treeptr - treebaseptr) >= (treeL - treemarginL))
4224 	EPDFatal("EPDGeneratePL: move tree size safety limit exceeded");
4225 
4226 /* set up current generation items */
4227 
4228 tse.tse_curr = treeptr;
4229 tse.tse_count = 0;
4230 
4231 /* set the psuedoinvariant generated move template components */
4232 
4233 gen_m.m_scmv = scmv_reg;
4234 gen_m.m_flag = 0;
4235 
4236 /* look at each origin square of the active color */
4237 
4238 for (gen_m.m_frsq = sq_a1; gen_m.m_frsq <= sq_h8; gen_m.m_frsq++)
4239 	{
4240 	/* get origin square and moving piece */
4241 
4242 	gen_m.m_frcp = EPDboard.rbv[gen_m.m_frsq];
4243 
4244 	/* continue if it is an active piece */
4245 
4246 	if (cv_c_cpv[gen_m.m_frcp] == ese.ese_actc)
4247 		{
4248 
4249 		/* generate moves for active color piece */
4250 
4251 		xsqptr0 = &xb.xbv[map_xsq_sq(gen_m.m_frsq)];
4252 		switch (cv_p_cpv[gen_m.m_frcp])
4253 			{
4254 			case p_p:
4255 				/* pawn moves: a bit tricky; colors done separately */
4256 
4257 				frfile = map_file(gen_m.m_frsq);
4258 				frrank = map_rank(gen_m.m_frsq);
4259 				if (ese.ese_actc == c_w)
4260 					{
4261 					/* one square non-capture */
4262 
4263 					gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq = gen_m.m_frsq + dv_1];
4264 					if (gen_m.m_tocp == cp_v0)
4265 						if (frrank != rank_7)
4266 							{
4267 							/* non-promotion */
4268 
4269 							*treeptr++ = gen_m;
4270 							tse.tse_count++;
4271 							}
4272 						else
4273 							{
4274 							/* promotion */
4275 
4276 							for (gen_m.m_scmv = scmv_ppn;
4277 								gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++)
4278 								{
4279 								*treeptr++ = gen_m;
4280 								tse.tse_count++;
4281 								}
4282 							gen_m.m_scmv = scmv_reg;
4283 							};
4284 
4285 					/* two squares forward */
4286 
4287 					if ((frrank == rank_2) &&
4288 						Vacant(gen_m.m_frsq + dv_1) &&
4289 						Vacant(gen_m.m_frsq + (2 * dv_1)))
4290 						{
4291 						gen_m.m_tosq = gen_m.m_frsq + (2 * dv_1);
4292 						gen_m.m_tocp = cp_v0;
4293 						*treeptr++ = gen_m;
4294 						tse.tse_count++;
4295 						};
4296 
4297 					/* capture to left */
4298 
4299 					if (frfile != file_a)
4300 						{
4301 						gen_m.m_tosq = gen_m.m_frsq + dv_5;
4302 						gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq];
4303 						if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc])
4304 							if (frrank != rank_7)
4305 								{
4306 								/* non-promote */
4307 
4308 								*treeptr++ = gen_m;
4309 								tse.tse_count++;
4310 								}
4311 							else
4312 								{
4313 								/* promote */
4314 
4315 								for (gen_m.m_scmv = scmv_ppn;
4316 									gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++)
4317 									{
4318 									*treeptr++ = gen_m;
4319 									tse.tse_count++;
4320 									};
4321 								gen_m.m_scmv = scmv_reg;
4322 								};
4323 						};
4324 
4325 					/* capture to right */
4326 
4327 					if (frfile != file_h)
4328 						{
4329 						gen_m.m_tosq = gen_m.m_frsq + dv_4;
4330 						gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq];
4331 						if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc])
4332 							if (frrank != rank_7)
4333 								{
4334 								/* non-promote */
4335 
4336 								*treeptr++ = gen_m;
4337 								tse.tse_count++;
4338 								}
4339 							else
4340 								{
4341 								/* promote */
4342 
4343 								for (gen_m.m_scmv = scmv_ppn;
4344 									gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++)
4345 									{
4346 									*treeptr++ = gen_m;
4347 									tse.tse_count++;
4348 									};
4349 								gen_m.m_scmv = scmv_reg;
4350 								};
4351 						};
4352 
4353 					/* en passant */
4354 
4355 					if ((frrank == rank_5) && (ese.ese_epsq != sq_nil))
4356 						{
4357 						/* capture to left */
4358 
4359 						if ((frfile != file_a) &&
4360 							((gen_m.m_tosq = gen_m.m_frsq + dv_5) ==
4361 							ese.ese_epsq))
4362 							{
4363 							gen_m.m_tocp = cp_v0;
4364 							gen_m.m_scmv = scmv_epc;
4365 							*treeptr++ = gen_m;
4366 							tse.tse_count++;
4367 							gen_m.m_scmv = scmv_reg;
4368 							};
4369 
4370 						/* capture to right */
4371 
4372 						if ((frfile != file_h) &&
4373 							((gen_m.m_tosq = gen_m.m_frsq + dv_4) ==
4374 							ese.ese_epsq))
4375 							{
4376 							gen_m.m_tocp = cp_v0;
4377 							gen_m.m_scmv = scmv_epc;
4378 							*treeptr++ = gen_m;
4379 							tse.tse_count++;
4380 							gen_m.m_scmv = scmv_reg;
4381 							};
4382 						};
4383 					}
4384 				else
4385 					{
4386 					/* one square non-capture */
4387 
4388 					gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq = gen_m.m_frsq + dv_3];
4389 					if (gen_m.m_tocp == cp_v0)
4390 						if (frrank != rank_2)
4391 							{
4392 							/* non-promotion */
4393 
4394 							*treeptr++ = gen_m;
4395 							tse.tse_count++;
4396 							}
4397 						else
4398 							{
4399 							/* promotion */
4400 
4401 							for (gen_m.m_scmv = scmv_ppn;
4402 								gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++)
4403 								{
4404 								*treeptr++ = gen_m;
4405 								tse.tse_count++;
4406 								}
4407 							gen_m.m_scmv = scmv_reg;
4408 							};
4409 
4410 					/* two squares forward */
4411 
4412 					if ((frrank == rank_7) &&
4413 						Vacant(gen_m.m_frsq + dv_3) &&
4414 						Vacant(gen_m.m_frsq + (2 * dv_3)))
4415 						{
4416 						gen_m.m_tosq = gen_m.m_frsq + (2 * dv_3);
4417 						gen_m.m_tocp = cp_v0;
4418 						*treeptr++ = gen_m;
4419 						tse.tse_count++;
4420 						};
4421 
4422 					/* capture to left */
4423 
4424 					if (frfile != file_a)
4425 						{
4426 						gen_m.m_tosq = gen_m.m_frsq + dv_6;
4427 						gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq];
4428 						if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc])
4429 							if (frrank != rank_2)
4430 								{
4431 								/* non-promote */
4432 
4433 								*treeptr++ = gen_m;
4434 								tse.tse_count++;
4435 								}
4436 							else
4437 								{
4438 								/* promote */
4439 
4440 								for (gen_m.m_scmv = scmv_ppn;
4441 									gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++)
4442 									{
4443 									*treeptr++ = gen_m;
4444 									tse.tse_count++;
4445 									};
4446 								gen_m.m_scmv = scmv_reg;
4447 								};
4448 						};
4449 
4450 					/* capture to right */
4451 
4452 					if (frfile != file_h)
4453 						{
4454 						gen_m.m_tosq = gen_m.m_frsq + dv_7;
4455 						gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq];
4456 						if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc])
4457 							if (frrank != rank_2)
4458 								{
4459 								/* non-promote */
4460 
4461 								*treeptr++ = gen_m;
4462 								tse.tse_count++;
4463 								}
4464 							else
4465 								{
4466 								/* promote */
4467 
4468 								for (gen_m.m_scmv = scmv_ppn;
4469 									gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++)
4470 									{
4471 									*treeptr++ = gen_m;
4472 									tse.tse_count++;
4473 									};
4474 								gen_m.m_scmv = scmv_reg;
4475 								};
4476 						};
4477 
4478 					/* en passant */
4479 
4480 					if ((frrank == rank_4) && (ese.ese_epsq != sq_nil))
4481 						{
4482 						/* capture to left */
4483 
4484 						if ((frfile != file_a) &&
4485 							((gen_m.m_tosq = gen_m.m_frsq + dv_6) ==
4486 							ese.ese_epsq))
4487 							{
4488 							gen_m.m_tocp = cp_v0;
4489 							gen_m.m_scmv = scmv_epc;
4490 							*treeptr++ = gen_m;
4491 							tse.tse_count++;
4492 							gen_m.m_scmv = scmv_reg;
4493 							};
4494 
4495 						/* capture to right */
4496 
4497 						if ((frfile != file_h) &&
4498 							((gen_m.m_tosq = gen_m.m_frsq + dv_7) ==
4499 							ese.ese_epsq))
4500 							{
4501 							gen_m.m_tocp = cp_v0;
4502 							gen_m.m_scmv = scmv_epc;
4503 							*treeptr++ = gen_m;
4504 							tse.tse_count++;
4505 							gen_m.m_scmv = scmv_reg;
4506 							};
4507 						};
4508 					};
4509 				break;
4510 
4511 			case p_n:
4512 				/* knight moves: very simple */
4513 
4514 				for (dx = dx_8; dx <= dx_f; dx++)
4515 					if (*(xsqptr0 + xdvv[dx]) == cp_v0)
4516 						{
4517 						gen_m.m_tocp =
4518 							EPDboard.rbv[gen_m.m_tosq = gen_m.m_frsq + dvv[dx]];
4519 						if (cv_c_cpv[gen_m.m_tocp] != ese.ese_actc)
4520 							{
4521 							*treeptr++ = gen_m;
4522 							tse.tse_count++;
4523 							};
4524 						};
4525 				break;
4526 
4527 			case p_b:
4528 				/* bishop moves: diagonal sweeper */
4529 
4530 				for (dx = dx_4; dx <= dx_7; dx++)
4531 					{
4532 					dv = dvv[dx];
4533 					xdv = xdvv[dx];
4534 					gen_m.m_tosq = gen_m.m_frsq;
4535 					xsqptr1 = xsqptr0;
4536 					while ((*(xsqptr1 += xdv) == cp_v0) &&
4537 						((gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq += dv]) ==
4538 						cp_v0))
4539 						{
4540 						*treeptr++ = gen_m;
4541 						tse.tse_count++;
4542 						};
4543 					if ((*xsqptr1 == cp_v0) &&
4544 						(cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]))
4545 						{
4546 						*treeptr++ = gen_m;
4547 						tse.tse_count++;
4548 						};
4549 					};
4550 				break;
4551 
4552 			case p_r:
4553 				/* rook moves: orthogonal sweeper */
4554 
4555 				for (dx = dx_0; dx <= dx_3; dx++)
4556 					{
4557 					dv = dvv[dx];
4558 					xdv = xdvv[dx];
4559 					gen_m.m_tosq = gen_m.m_frsq;
4560 					xsqptr1 = xsqptr0;
4561 					while ((*(xsqptr1 += xdv) == cp_v0) &&
4562 						((gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq += dv]) ==
4563 						cp_v0))
4564 						{
4565 						*treeptr++ = gen_m;
4566 						tse.tse_count++;
4567 						};
4568 					if ((*xsqptr1 == cp_v0) &&
4569 						(cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]))
4570 						{
4571 						*treeptr++ = gen_m;
4572 						tse.tse_count++;
4573 						};
4574 					};
4575 				break;
4576 
4577 			case p_q:
4578 				/* queen moves: orthogonal and diagonal sweeper */
4579 
4580 				for (dx = dx_0; dx <= dx_7; dx++)
4581 					{
4582 					dv = dvv[dx];
4583 					xdv = xdvv[dx];
4584 					gen_m.m_tosq = gen_m.m_frsq;
4585 					xsqptr1 = xsqptr0;
4586 					while ((*(xsqptr1 += xdv) == cp_v0) &&
4587 						((gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq += dv]) ==
4588 						cp_v0))
4589 						{
4590 						*treeptr++ = gen_m;
4591 						tse.tse_count++;
4592 						};
4593 					if ((*xsqptr1 == cp_v0) &&
4594 						(cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]))
4595 						{
4596 						*treeptr++ = gen_m;
4597 						tse.tse_count++;
4598 						};
4599 					};
4600 				break;
4601 
4602 			case p_k:
4603 				/* king moves: one square adjacent regular */
4604 
4605 				for (dx = dx_0; dx <= dx_7; dx++)
4606 					if (*(xsqptr0 + xdvv[dx]) == cp_v0)
4607 						{
4608 						gen_m.m_tocp =
4609 							EPDboard.rbv[gen_m.m_tosq = gen_m.m_frsq + dvv[dx]];
4610 						if (cv_c_cpv[gen_m.m_tocp] != ese.ese_actc)
4611 							{
4612 							*treeptr++ = gen_m;
4613 							tse.tse_count++;
4614 							};
4615 						};
4616 
4617 				/* castling; process according to active color */
4618 
4619 				if (ese.ese_actc == c_w)
4620 					{
4621 					if ((ese.ese_cast & cf_wk) && !EPDBlackAttacks(sq_e1) &&
4622 						Vacant(sq_f1) && !EPDBlackAttacks(sq_f1) &&
4623 						Vacant(sq_g1) && !EPDBlackAttacks(sq_g1))
4624 						{
4625 						gen_m.m_tosq = sq_g1;
4626 						gen_m.m_tocp = cp_v0;
4627 						gen_m.m_scmv = scmv_cks;
4628 						*treeptr++ = gen_m;
4629 						tse.tse_count++;
4630 						gen_m.m_scmv = scmv_reg;
4631 						};
4632 
4633 					if ((ese.ese_cast & cf_wq) && !EPDBlackAttacks(sq_e1) &&
4634 						Vacant(sq_d1) && !EPDBlackAttacks(sq_d1) &&
4635 						Vacant(sq_c1) && !EPDBlackAttacks(sq_c1) &&
4636 						Vacant(sq_b1))
4637 						{
4638 						gen_m.m_tosq = sq_c1;
4639 						gen_m.m_tocp = cp_v0;
4640 						gen_m.m_scmv = scmv_cqs;
4641 						*treeptr++ = gen_m;
4642 						tse.tse_count++;
4643 						gen_m.m_scmv = scmv_reg;
4644 						};
4645 					}
4646 				else
4647 					{
4648 					if ((ese.ese_cast & cf_bk) && !EPDWhiteAttacks(sq_e8) &&
4649 						Vacant(sq_f8) && !EPDWhiteAttacks(sq_f8) &&
4650 						Vacant(sq_g8) && !EPDWhiteAttacks(sq_g8))
4651 						{
4652 						gen_m.m_tosq = sq_g8;
4653 						gen_m.m_tocp = cp_v0;
4654 						gen_m.m_scmv = scmv_cks;
4655 						*treeptr++ = gen_m;
4656 						tse.tse_count++;
4657 						gen_m.m_scmv = scmv_reg;
4658 						};
4659 
4660 					if ((ese.ese_cast & cf_bq) && !EPDWhiteAttacks(sq_e8) &&
4661 						Vacant(sq_d8) && !EPDWhiteAttacks(sq_d8) &&
4662 						Vacant(sq_c8) && !EPDWhiteAttacks(sq_c8) &&
4663 						Vacant(sq_b8))
4664 						{
4665 						gen_m.m_tosq = sq_c8;
4666 						gen_m.m_tocp = cp_v0;
4667 						gen_m.m_scmv = scmv_cqs;
4668 						*treeptr++ = gen_m;
4669 						tse.tse_count++;
4670 						gen_m.m_scmv = scmv_reg;
4671 						};
4672 					};
4673 				break;
4674 			};
4675 		};
4676 	};
4677 
4678 return;
4679 }
4680 
4681 /*--> EPDSameMoveRef: check if two move references are the same move */
4682 static
4683 siT
EPDSameMoveRef(mptrT mptr0,mptrT mptr1)4684 EPDSameMoveRef(mptrT mptr0, mptrT mptr1)
4685 {
4686 siT flag;
4687 
4688 if ((mptr0->m_tosq == mptr1->m_tosq) &&
4689 	(mptr0->m_frsq == mptr1->m_frsq) &&
4690 	(mptr0->m_frcp == mptr1->m_frcp) &&
4691 	(mptr0->m_tocp == mptr1->m_tocp) &&
4692 	(mptr0->m_scmv == mptr1->m_scmv))
4693 	flag = 1;
4694 else
4695 	flag = 0;
4696 
4697 return (flag);
4698 }
4699 
4700 /*--> EPDFindMove: locate the move in the current generation set */
4701 static
4702 mptrT
EPDFindMove(mptrT mptr)4703 EPDFindMove(mptrT mptr)
4704 {
4705 mptrT rmptr;
4706 siT flag;
4707 siT index;
4708 
4709 rmptr = tse.tse_base;
4710 flag = 0;
4711 index = 0;
4712 
4713 while (!flag && (index < tse.tse_count))
4714 	if (EPDSameMoveRef(mptr, rmptr))
4715 		flag = 1;
4716 	else
4717 		{
4718 		rmptr++;
4719 		index++;
4720 		};
4721 
4722 if (!flag)
4723 	rmptr = NULL;
4724 
4725 return (rmptr);
4726 }
4727 
4728 /*--> EPDExecute: execute the supplied move */
4729 static
4730 void
EPDExecute(mptrT mptr)4731 EPDExecute(mptrT mptr)
4732 {
4733 sqT pcsq;
4734 cpT ppcp;
4735 
4736 /* test for overflow */
4737 
4738 if (ply == (pmhL - 1))
4739 	EPDFatal("EPDExecute: played move history overflow");
4740 
4741 /* save old environment and generation records */
4742 
4743 *eseptr++ = ese;
4744 *tseptr++ = tse;
4745 
4746 /* set the legality tested flag */
4747 
4748 mptr->m_flag |= mf_exec;
4749 
4750 /* process according to move case */
4751 
4752 switch (mptr->m_scmv)
4753 	{
4754 	case scmv_reg:
4755 		EPDboard.rbv[mptr->m_frsq] = cp_v0;
4756 		EPDboard.rbv[mptr->m_tosq] = mptr->m_frcp;
4757 		break;
4758 
4759 	case scmv_epc:
4760 		if (ese.ese_actc == c_w)
4761 			pcsq = mptr->m_tosq + dv_3;
4762 		else
4763 			pcsq = mptr->m_tosq + dv_1;
4764 		EPDboard.rbv[mptr->m_frsq] = cp_v0;
4765 		EPDboard.rbv[mptr->m_tosq] = mptr->m_frcp;
4766 		EPDboard.rbv[pcsq] = cp_v0;
4767 		break;
4768 
4769 	case scmv_cks:
4770 		if (ese.ese_actc == c_w)
4771 			{
4772 			EPDboard.rbv[sq_e1] = cp_v0;
4773 			EPDboard.rbv[sq_g1] = cp_wk;
4774 			EPDboard.rbv[sq_h1] = cp_v0;
4775 			EPDboard.rbv[sq_f1] = cp_wr;
4776 			}
4777 		else
4778 			{
4779 			EPDboard.rbv[sq_e8] = cp_v0;
4780 			EPDboard.rbv[sq_g8] = cp_bk;
4781 			EPDboard.rbv[sq_h8] = cp_v0;
4782 			EPDboard.rbv[sq_f8] = cp_br;
4783 			};
4784 		break;
4785 
4786 	case scmv_cqs:
4787 		if (ese.ese_actc == c_w)
4788 			{
4789 			EPDboard.rbv[sq_e1] = cp_v0;
4790 			EPDboard.rbv[sq_c1] = cp_wk;
4791 			EPDboard.rbv[sq_a1] = cp_v0;
4792 			EPDboard.rbv[sq_d1] = cp_wr;
4793 			}
4794 		else
4795 			{
4796 			EPDboard.rbv[sq_e8] = cp_v0;
4797 			EPDboard.rbv[sq_c8] = cp_bk;
4798 			EPDboard.rbv[sq_a8] = cp_v0;
4799 			EPDboard.rbv[sq_d8] = cp_br;
4800 			};
4801 		break;
4802 
4803 	case scmv_ppn:
4804 		if (ese.ese_actc == c_w)
4805 			ppcp = cp_wn;
4806 		else
4807 			ppcp = cp_bn;
4808 		EPDboard.rbv[mptr->m_frsq] = cp_v0;
4809 		EPDboard.rbv[mptr->m_tosq] = ppcp;
4810 		break;
4811 
4812 	case scmv_ppb:
4813 		if (ese.ese_actc == c_w)
4814 			ppcp = cp_wb;
4815 		else
4816 			ppcp = cp_bb;
4817 		EPDboard.rbv[mptr->m_frsq] = cp_v0;
4818 		EPDboard.rbv[mptr->m_tosq] = ppcp;
4819 		break;
4820 
4821 	case scmv_ppr:
4822 		if (ese.ese_actc == c_w)
4823 			ppcp = cp_wr;
4824 		else
4825 			ppcp = cp_br;
4826 		EPDboard.rbv[mptr->m_frsq] = cp_v0;
4827 		EPDboard.rbv[mptr->m_tosq] = ppcp;
4828 		break;
4829 
4830 	case scmv_ppq:
4831 		if (ese.ese_actc == c_w)
4832 			ppcp = cp_wq;
4833 		else
4834 			ppcp = cp_bq;
4835 		EPDboard.rbv[mptr->m_frsq] = cp_v0;
4836 		EPDboard.rbv[mptr->m_tosq] = ppcp;
4837 		break;
4838 	};
4839 
4840 /* set values for updated environment record: active color */
4841 
4842 ese.ese_actc = inv_cv[ese.ese_actc];
4843 
4844 /* set values for updated environment record: castling availablity */
4845 
4846 if (ese.ese_cast != 0)
4847 	{
4848 	if (ese.ese_cast & cf_wk)
4849 		if ((mptr->m_frsq == sq_e1) || (mptr->m_frsq == sq_h1) ||
4850 			(mptr->m_tosq == sq_h1))
4851 			ese.ese_cast &= ~cf_wk;
4852 
4853 	if (ese.ese_cast & cf_wq)
4854 		if ((mptr->m_frsq == sq_e1) || (mptr->m_frsq == sq_a1) ||
4855 			(mptr->m_tosq == sq_a1))
4856 			ese.ese_cast &= ~cf_wq;
4857 
4858 	if (ese.ese_cast & cf_bk)
4859 		if ((mptr->m_frsq == sq_e8) || (mptr->m_frsq == sq_h8) ||
4860 			(mptr->m_tosq == sq_h8))
4861 			ese.ese_cast &= ~cf_bk;
4862 
4863 	if (ese.ese_cast & cf_bq)
4864 		if ((mptr->m_frsq == sq_e8) || (mptr->m_frsq == sq_a8) ||
4865 			(mptr->m_tosq == sq_a8))
4866 			ese.ese_cast &= ~cf_bq;
4867 	};
4868 
4869 /* set values for updated environment record: en passant */
4870 
4871 if (ese.ese_actc == c_b)
4872 	if ((mptr->m_frcp == cp_wp) &&
4873 		(map_rank(mptr->m_frsq) == rank_2) &&
4874 		(map_rank(mptr->m_tosq) == rank_4))
4875 		ese.ese_epsq = mptr->m_frsq + dv_1;
4876 	else
4877 		ese.ese_epsq = sq_nil;
4878 else
4879 	if ((mptr->m_frcp == cp_bp) &&
4880 		(map_rank(mptr->m_frsq) == rank_7) &&
4881 		(map_rank(mptr->m_tosq) == rank_5))
4882 		ese.ese_epsq = mptr->m_frsq + dv_3;
4883 	else
4884 		ese.ese_epsq = sq_nil;
4885 
4886 /* set values for updated environment record: halfmove clock */
4887 
4888 if ((mptr->m_tocp != cp_v0) || (cv_p_cpv[mptr->m_frcp] == p_p))
4889 	ese.ese_hmvc = 0;
4890 else
4891 	ese.ese_hmvc++;
4892 
4893 /* set values for updated environment record: fullmove number */
4894 
4895 if (ese.ese_actc == c_w)
4896 	ese.ese_fmvn++;
4897 
4898 /* set values for updated environment record: king locations */
4899 
4900 switch (mptr->m_frcp)
4901 	{
4902 	case cp_wk:
4903 		ese.ese_ksqv[c_w] = mptr->m_tosq;
4904 		break;
4905 	case cp_bk:
4906 		ese.ese_ksqv[c_b] = mptr->m_tosq;
4907 		break;
4908 	default:
4909 		break;
4910 	};
4911 
4912 /* check/bust flags */
4913 
4914 if (EPDTestAKIC())
4915 	mptr->m_flag |= mf_chec;
4916 if (EPDTestPKIC())
4917 	mptr->m_flag |= mf_bust;
4918 
4919 /* increment ply index */
4920 
4921 ply++;
4922 
4923 return;
4924 }
4925 
4926 /*--> EPDExecuteUpdate: update the current move pointer, then execute */
4927 nonstatic
4928 void
EPDExecuteUpdate(mptrT mptr)4929 EPDExecuteUpdate(mptrT mptr)
4930 {
4931 tse.tse_curr = EPDFindMove(mptr);
4932 if (tse.tse_curr == NULL)
4933 	EPDFatal("EPDExecuteUpdate: can't find move");
4934 
4935 EPDExecute(tse.tse_curr);
4936 
4937 return;
4938 }
4939 
4940 /*--> EPDRetract: retract the supplied move */
4941 static
4942 void
EPDRetract(mptrT mptr)4943 EPDRetract(mptrT mptr)
4944 {
4945 /* decrement ply */
4946 
4947 ply--;
4948 
4949 /* restore the current environment and generation */
4950 
4951 ese = *--eseptr;
4952 tse = *--tseptr;
4953 
4954 /* process by move case */
4955 
4956 switch (mptr->m_scmv)
4957 	{
4958 	case scmv_reg:
4959 		EPDboard.rbv[mptr->m_tosq] = mptr->m_tocp;
4960 		EPDboard.rbv[mptr->m_frsq] = mptr->m_frcp;
4961 		break;
4962 
4963 	case scmv_epc:
4964 		EPDboard.rbv[mptr->m_tosq] = cp_v0;
4965 		EPDboard.rbv[mptr->m_frsq] = mptr->m_frcp;
4966 		if (ese.ese_actc == c_w)
4967 			EPDboard.rbv[mptr->m_tosq + dv_3] = cp_bp;
4968 		else
4969 			EPDboard.rbv[mptr->m_tosq + dv_1] = cp_wp;
4970 		break;
4971 
4972 	case scmv_cks:
4973 		if (ese.ese_actc == c_w)
4974 			{
4975 			EPDboard.rbv[sq_g1] = cp_v0;
4976 			EPDboard.rbv[sq_e1] = cp_wk;
4977 			EPDboard.rbv[sq_f1] = cp_v0;
4978 			EPDboard.rbv[sq_h1] = cp_wr;
4979 			}
4980 		else
4981 			{
4982 			EPDboard.rbv[sq_g8] = cp_v0;
4983 			EPDboard.rbv[sq_e8] = cp_bk;
4984 			EPDboard.rbv[sq_f8] = cp_v0;
4985 			EPDboard.rbv[sq_h8] = cp_br;
4986 			}
4987 		break;
4988 
4989 	case scmv_cqs:
4990 		if (ese.ese_actc == c_w)
4991 			{
4992 			EPDboard.rbv[sq_c1] = cp_v0;
4993 			EPDboard.rbv[sq_e1] = cp_wk;
4994 			EPDboard.rbv[sq_d1] = cp_v0;
4995 			EPDboard.rbv[sq_a1] = cp_wr;
4996 			}
4997 		else
4998 			{
4999 			EPDboard.rbv[sq_c8] = cp_v0;
5000 			EPDboard.rbv[sq_e8] = cp_bk;
5001 			EPDboard.rbv[sq_d8] = cp_v0;
5002 			EPDboard.rbv[sq_a8] = cp_br;
5003 			};
5004 		break;
5005 
5006 	case scmv_ppn:
5007 	case scmv_ppb:
5008 	case scmv_ppr:
5009 	case scmv_ppq:
5010 		EPDboard.rbv[mptr->m_tosq] = mptr->m_tocp;
5011 		EPDboard.rbv[mptr->m_frsq] = mptr->m_frcp;
5012 		break;
5013 	};
5014 
5015 return;
5016 }
5017 
5018 /*--> EPDRetractUpdate: retract last executed move */
5019 nonstatic
5020 void
EPDRetractUpdate(void)5021 EPDRetractUpdate(void)
5022 {
5023 mptrT mptr;
5024 
5025 mptr = (tseptr - 1)->tse_curr;
5026 EPDRetract(mptr);
5027 
5028 return;
5029 }
5030 
5031 /*--> EPDRetractAll: retract all moves in current variation */
5032 nonstatic
5033 void
EPDRetractAll(void)5034 EPDRetractAll(void)
5035 {
5036 while (ply > 0)
5037 	EPDRetractUpdate();
5038 
5039 return;
5040 }
5041 
5042 /*--> EPDCollapse: collapse the played move stack */
5043 nonstatic
5044 void
EPDCollapse(void)5045 EPDCollapse(void)
5046 {
5047 /* process for nonzero ply */
5048 
5049 if (ply > 0)
5050 	{
5051 	/* reset the stack pointers */
5052 
5053 	treeptr = treebaseptr;
5054 	eseptr = esebaseptr;
5055 	tseptr = tsebaseptr;
5056 
5057 	/* reset the ply */
5058 
5059 	ply = 0;
5060 	};
5061 
5062 return;
5063 }
5064 
5065 /*--> EPDReset: collapse, then reset starting position */
5066 nonstatic
5067 void
EPDReset(void)5068 EPDReset(void)
5069 {
5070 EPDCollapse();
5071 EPDInitArray();
5072 
5073 return;
5074 }
5075 
5076 /*--> EPDMLExec: execute the current move list */
5077 static
5078 void
EPDMLExec(void)5079 EPDMLExec(void)
5080 {
5081 siT i;
5082 mptrT mptr;
5083 
5084 /* test and mark each move for legality and checking status */
5085 
5086 mptr = tse.tse_base;
5087 for (i = 0; i < tse.tse_count; i++)
5088 	{
5089 	tse.tse_curr = mptr;
5090 	EPDExecute(mptr);
5091 	EPDRetract(mptr);
5092 	mptr++;
5093 	};
5094 
5095 return;
5096 }
5097 
5098 /*--> EPDMLPolice: remove illegal moves the current move list */
5099 static
5100 void
EPDMLPolice(void)5101 EPDMLPolice(void)
5102 {
5103 mptrT tptr, mptr;
5104 siT i, bust;
5105 mT t_m;
5106 
5107 /* move illegal moves to end of list */
5108 
5109 mptr = tse.tse_base;
5110 bust = 0;
5111 i = 0;
5112 while (i < (tse.tse_count - bust))
5113 	if (mptr->m_flag & mf_bust)
5114 		{
5115 		tptr = (tse.tse_base + (tse.tse_count - 1)) - bust;
5116 		t_m = *mptr;
5117 		*mptr = *tptr;
5118 		*tptr = t_m;
5119 		bust++;
5120 		}
5121 	else
5122 		{
5123 		mptr++;
5124 		i++;
5125 		};
5126 
5127 /* shrink */
5128 
5129 tse.tse_count -= bust;
5130 
5131 return;
5132 }
5133 
5134 /*--> EPDMLDisambiguate: insert disambiguation flags in move list */
5135 static
5136 void
EPDMLDisambiguate(void)5137 EPDMLDisambiguate(void)
5138 {
5139 siT i, j, tmc, rmc, fmc;
5140 mptrT mptr0, mptr1;
5141 pT p;
5142 rankT rank;
5143 fileT file;
5144 
5145 /* it's magic */
5146 
5147 mptr0 = tse.tse_base;
5148 for (i = 0; i < tse.tse_count; i++)
5149 	{
5150 	/* the outer loop disambiguates a single move per cycle */
5151 
5152 	p = cv_p_cpv[mptr0->m_frcp];
5153 	if ((p != p_p) && (p != p_k))
5154 		{
5155 		rank = map_rank(mptr0->m_frsq);
5156 		file = map_file(mptr0->m_frsq);
5157 		tmc = rmc = fmc = 0;
5158 		mptr1 = tse.tse_base;
5159 		for (j = 0; j < tse.tse_count; j++)
5160 			{
5161 			/* the inner loop examines all possible sibling puns */
5162 
5163 			if ((i != j) && (mptr0->m_frcp == mptr1->m_frcp) &&
5164 				(mptr0->m_tosq == mptr1->m_tosq))
5165 				{
5166 				tmc++;
5167 				if (map_rank(mptr1->m_frsq) == rank)
5168 					rmc++;
5169 				if (map_file(mptr1->m_frsq) == file)
5170 					fmc++;
5171 				};
5172 			mptr1++;
5173 			};
5174 
5175 		/* check pun count for outer loop move */
5176 
5177 		if (tmc > 0)
5178 			{
5179 			/* file disambiguation has priority */
5180 
5181 			if ((rmc > 0) || ((rmc == 0) && (fmc == 0)))
5182 				mptr0->m_flag |= mf_sanf;
5183 
5184 			/* rank disambiguation may be needed */
5185 
5186 			if (fmc > 0)
5187 				mptr0->m_flag |= mf_sanr;
5188 			};
5189 		};
5190 	mptr0++;
5191 	};
5192 
5193 return;
5194 }
5195 
5196 /*--> EPDMLScanMate: scan current move list for mating moves */
5197 static
5198 void
EPDMLScanMate(void)5199 EPDMLScanMate(void)
5200 {
5201 siT i, j, mateflag, drawflag, moveflag;
5202 mptrT mptr0, mptr1;
5203 
5204 /* scan */
5205 
5206 mptr0 = tse.tse_base;
5207 for (i = 0; i < tse.tse_count; i++)
5208 	{
5209 	tse.tse_curr = mptr0;
5210 	EPDExecute(mptr0);
5211 
5212 	/* now at next higher ply, generate psuedolegal set */
5213 
5214 	EPDGeneratePL();
5215 
5216 	/* try to find at least one legal move */
5217 
5218 	mptr1 = tse.tse_base;
5219 	moveflag = 0;
5220 	j = 0;
5221 	while (!moveflag && (j < tse.tse_count))
5222 		{
5223 		tse.tse_curr = mptr1;
5224 		EPDExecute(mptr1);
5225 		EPDRetract(mptr1);
5226 		if (!(mptr1->m_flag & mf_bust))
5227 			moveflag = 1;
5228 		else
5229 			{
5230 			mptr1++;
5231 			j++;
5232 			};
5233 		};
5234 
5235 	/* any second level moves detected? */
5236 
5237 	if (moveflag != 0)
5238 		{
5239 		/* not a mate */
5240 
5241 		mateflag = drawflag = 0;
5242 		}
5243 	else
5244 		{
5245 		/* a mating move is detected */
5246 
5247 		if (EPDTestAKIC())
5248 			{
5249 			mateflag = 1;
5250 			drawflag = 0;
5251 			}
5252 		else
5253 			{
5254 			drawflag = 1;
5255 			mateflag = 0;
5256 			};
5257 		};
5258 
5259 	/* undo execution */
5260 
5261 	EPDRetract(mptr0);
5262 
5263 	/* now back at lower ply */
5264 
5265 	if (mateflag)
5266 		mptr0->m_flag |= mf_chmt;
5267 	else
5268 		if (drawflag)
5269 			mptr0->m_flag |= (mf_draw | mf_stmt);
5270 
5271 	/* next move */
5272 
5273 	mptr0++;
5274 	};
5275 
5276 return;
5277 }
5278 
5279 /*--> EPDGenClean: generate move list with first level processing */
5280 static
5281 void
EPDGenClean(void)5282 EPDGenClean(void)
5283 {
5284 /* basic psuedolegal generation */
5285 
5286 EPDGeneratePL();
5287 
5288 /* set legality flags, remove illegal moves, and disambiguate */
5289 
5290 EPDMLExec();
5291 EPDMLPolice();
5292 EPDMLDisambiguate();
5293 
5294 return;
5295 }
5296 
5297 /*--> EPDGenMoves: generate legal moves and set mate flags */
5298 nonstatic
5299 void
EPDGenMoves(void)5300 EPDGenMoves(void)
5301 {
5302 /* perform basic first level generation */
5303 
5304 EPDGenClean();
5305 
5306 /* handle two ply draw and checkmate detection */
5307 
5308 EPDMLScanMate();
5309 
5310 return;
5311 }
5312 
5313 /*--> EPDFetchMoveCount: fetch the move count */
5314 nonstatic
5315 siT
EPDFetchMoveCount(void)5316 EPDFetchMoveCount(void)
5317 {
5318 
5319 return (tse.tse_count);
5320 }
5321 
5322 /*--> EPDFetchMove: fetch the nth move */
5323 nonstatic
5324 mptrT
EPDFetchMove(siT index)5325 EPDFetchMove(siT index)
5326 {
5327 ret_m = *(tse.tse_base + index);
5328 
5329 return (&ret_m);
5330 }
5331 
5332 /*--> EPDSetMoveFlags: set move flags from current generation set */
5333 nonstatic
5334 void
EPDSetMoveFlags(mptrT mptr)5335 EPDSetMoveFlags(mptrT mptr)
5336 {
5337 mptrT rmptr;
5338 
5339 rmptr = EPDFindMove(mptr);
5340 if (rmptr != NULL)
5341 	mptr->m_flag = rmptr->m_flag;
5342 
5343 return;
5344 }
5345 
5346 /*--> EPDSortSAN: ASCII SAN sort move list */
5347 nonstatic
5348 void
EPDSortSAN(void)5349 EPDSortSAN(void)
5350 {
5351 mptrT mptr, mptr0, mptr1;
5352 siT i, j, pair, pass, flag;
5353 sanptrT sanptr, sptr0, sptr1;
5354 char t_ch;
5355 mT t_m;
5356 
5357 /* allocate the SAN string vector */
5358 
5359 sanptr = (sanptrT) EPDMemoryGrab(sizeof(sanT) * tse.tse_count);
5360 
5361 /* construct the SAN string entries */
5362 
5363 mptr = tse.tse_base;
5364 for (i = 0; i < tse.tse_count; i++)
5365 	EPDSANEncode(mptr++, *(sanptr + i));
5366 
5367 /* a low tech bubble sort */
5368 
5369 flag = 1;
5370 pass = 0;
5371 while (flag && (pass < (tse.tse_count - 1)))
5372 	{
5373 	sptr0 = sanptr;
5374 	sptr1 = sanptr + 1;
5375 	mptr0 = tse.tse_base;
5376 	mptr1 = tse.tse_base + 1;
5377 	flag = 0;
5378 	pair = 0;
5379 	while (pair < (tse.tse_count - pass - 1))
5380 		{
5381 		/* case sensitive ascending order */
5382 
5383 		if (strcmp((charptrT) sptr0, (charptrT) sptr1) > 0)
5384 			{
5385 			flag = 1;
5386 			for (j = 0; j < sanL; j++)
5387 				{
5388 				t_ch = (*sptr0)[j];
5389 				(*sptr0)[j] = (*sptr1)[j];
5390 				(*sptr1)[j] = t_ch;
5391 				};
5392 			t_m = *mptr0;
5393 			*mptr0 = *mptr1;
5394 			*mptr1 = t_m;
5395 			};
5396 		sptr0++;
5397 		sptr1++;
5398 		mptr0++;
5399 		mptr1++;
5400 		pair++;
5401 		};
5402 	pass++;
5403 	};
5404 
5405 EPDMemoryFree(sanptr);
5406 
5407 return;
5408 }
5409 
5410 /*--> EPDRepairMove: repair a move operation */
5411 static
5412 void
EPDRepairMove(eopptrT eopptr)5413 EPDRepairMove(eopptrT eopptr)
5414 {
5415 eovptrT eovptr;
5416 mptrT mptr;
5417 mT m;
5418 sanT san;
5419 
5420 /* repair a single move from the current position */
5421 
5422 eovptr = eopptr->eop_headeov;
5423 if (eovptr != NULL)
5424 	{
5425 	mptr = EPDSANDecodeAux(eovptr->eov_str, 0);
5426 	if (mptr != NULL)
5427 		{
5428 		m = *mptr;
5429 		EPDSANEncode(&m, san);
5430 		if (strcmp(eovptr->eov_str, san) != 0)
5431 			EPDReplaceEOVStr(eovptr, san);
5432 		};
5433 	};
5434 
5435 return;
5436 }
5437 
5438 /*--> EPDRepairMoveset: repair a moveset operation */
5439 static
5440 void
EPDRepairMoveset(eopptrT eopptr)5441 EPDRepairMoveset(eopptrT eopptr)
5442 {
5443 eovptrT eovptr;
5444 mptrT mptr;
5445 mT m;
5446 sanT san;
5447 
5448 /* check each move from the current position */
5449 
5450 eovptr = eopptr->eop_headeov;
5451 while (eovptr != NULL)
5452 	{
5453 	mptr = EPDSANDecodeAux(eovptr->eov_str, 0);
5454 	if (mptr != NULL)
5455 		{
5456 		m = *mptr;
5457 		EPDSANEncode(&m, san);
5458 		if (strcmp(eovptr->eov_str, san) != 0)
5459 			EPDReplaceEOVStr(eovptr, san);
5460 		};
5461 
5462 	eovptr = eovptr->eov_next;
5463 	};
5464 
5465 return;
5466 }
5467 
5468 /*--> EPDRepairVariation: repair a variation operation */
5469 static
5470 void
EPDRepairVariation(eopptrT eopptr)5471 EPDRepairVariation(eopptrT eopptr)
5472 {
5473 eovptrT eovptr;
5474 mptrT mptr;
5475 mT m;
5476 sanT san;
5477 
5478 /* play move sequence from the current position */
5479 
5480 eovptr = eopptr->eop_headeov;
5481 while (eovptr != NULL)
5482 	{
5483 	mptr = EPDSANDecodeAux(eovptr->eov_str, 0);
5484 	if (mptr == NULL)
5485 		eovptr = NULL;
5486 	else
5487 		{
5488 		m = *mptr;
5489 		EPDSANEncode(&m, san);
5490 		if (strcmp(eovptr->eov_str, san) != 0)
5491 			EPDReplaceEOVStr(eovptr, san);
5492 
5493 		tse.tse_curr = EPDFindMove(mptr);
5494 		if (tse.tse_curr == NULL)
5495 			EPDFatal("EPDRepairVariation: can't find move");
5496 
5497 		EPDExecute(mptr);
5498 		EPDGenMoves();
5499 
5500 		eovptr = eovptr->eov_next;
5501 		}
5502 	};
5503 
5504 /* retract any executed moves */
5505 
5506 EPDRetractAll();
5507 
5508 return;
5509 }
5510 
5511 /*--> EPDPurgeOpFile: purge operation from input file to output file */
5512 nonstatic
5513 siT
EPDPurgeOpFile(charptrT opsym,charptrT fn0,charptrT fn1)5514 EPDPurgeOpFile(charptrT opsym, charptrT fn0, charptrT fn1)
5515 {
5516 siT flag;
5517 fptrT fptr0, fptr1;
5518 epdptrT epdptr;
5519 eopptrT eopptr;
5520 charptrT eptr;
5521 char ev[epdL];
5522 
5523 /* set default return value (success) */
5524 
5525 flag = 1;
5526 
5527 /* clear the input and output file pointers */
5528 
5529 fptr0 = fptr1 = NULL;
5530 
5531 /* open the input file for reading */
5532 
5533 if (flag)
5534 	{
5535 	fptr0 = fopen(fn0, "r");
5536 	if (fptr0 == NULL)
5537 		flag = 0;
5538 	};
5539 
5540 /* open the output file for writing */
5541 
5542 if (flag)
5543 	{
5544 	fptr1 = fopen(fn1, "w");
5545 	if (fptr1 == NULL)
5546 		flag = 0;
5547 	};
5548 
5549 /* scan entire file */
5550 
5551 while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL))
5552 	{
5553 	/* decode a record */
5554 
5555 	epdptr = EPDDecode(ev);
5556 
5557 	/* check record decode validity */
5558 
5559 	if (epdptr == NULL)
5560 		flag = 0;
5561 	else
5562 		{
5563 		/* locate the operation to be purged */
5564 
5565 		eopptr = EPDLocateEOP(epdptr, opsym);
5566 		if (eopptr != NULL)
5567 			{
5568 			EPDUnthreadEOP(epdptr, eopptr);
5569 			EPDReleaseEOP(eopptr);
5570 			};
5571 
5572 		/* encode the record (includes normalization) */
5573 
5574 		eptr = EPDEncode(epdptr);
5575 
5576 		/* release EPD structure */
5577 
5578 		EPDReleaseEPD(epdptr);
5579 
5580 		/* check result */
5581 
5582 		if (eptr == NULL)
5583 			flag = 0;
5584 		else
5585 			{
5586 			fprintf(fptr1, "%s\n", eptr);
5587 			EPDMemoryFree(eptr);
5588 			};
5589 		};
5590 	};
5591 
5592 /* close input and output files */
5593 
5594 if (fptr0 != NULL)
5595 	fclose(fptr0);
5596 
5597 if (fptr1 != NULL)
5598 	fclose(fptr1);
5599 
5600 return (flag);
5601 }
5602 
5603 /*--> EPDRepairEPD: repair an EPD structure */
5604 nonstatic
5605 siT
EPDRepairEPD(epdptrT epdptr)5606 EPDRepairEPD(epdptrT epdptr)
5607 {
5608 siT flag;
5609 eopptrT eopptr;
5610 
5611 /* set default return value: repair successful */
5612 
5613 flag = 1;
5614 
5615 /* set up the position as the current position */
5616 
5617 EPDRealize(epdptr);
5618 
5619 /* check legality */
5620 
5621 if (!EPDIsLegal())
5622 	flag = 0;
5623 else
5624 	{
5625 	/* generate moves and notation */
5626 
5627 	EPDGenMoves();
5628 
5629 	/* repair moveset "am" */
5630 
5631 	eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_am]);
5632 	if (eopptr != NULL)
5633 		EPDRepairMoveset(eopptr);
5634 
5635 	/* repair moveset "bm" */
5636 
5637 	eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_bm]);
5638 	if (eopptr != NULL)
5639 		EPDRepairMoveset(eopptr);
5640 
5641 	/* repair move "pm" */
5642 
5643 	eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_pm]);
5644 	if (eopptr != NULL)
5645 		EPDRepairMove(eopptr);
5646 
5647 	/* repair variation "pv" */
5648 
5649 	eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_pv]);
5650 	if (eopptr != NULL)
5651 		EPDRepairVariation(eopptr);
5652 
5653 	/* repair move "sm" */
5654 
5655 	eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_sm]);
5656 	if (eopptr != NULL)
5657 		EPDRepairMove(eopptr);
5658 
5659 	/* repair variation "sv" */
5660 
5661 	eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_sv]);
5662 	if (eopptr != NULL)
5663 		EPDRepairVariation(eopptr);
5664 	};
5665 
5666 return (flag);
5667 }
5668 
5669 /*--> EPDRepairFile: repair input file to output file */
5670 nonstatic
5671 siT
EPDRepairFile(charptrT fn0,charptrT fn1)5672 EPDRepairFile(charptrT fn0, charptrT fn1)
5673 {
5674 siT flag;
5675 fptrT fptr0, fptr1;
5676 epdptrT epdptr;
5677 charptrT eptr;
5678 char ev[epdL];
5679 
5680 /* set default return value (success) */
5681 
5682 flag = 1;
5683 
5684 /* clear the input and output file pointers */
5685 
5686 fptr0 = fptr1 = NULL;
5687 
5688 /* open the input file for reading */
5689 
5690 if (flag)
5691 	{
5692 	fptr0 = fopen(fn0, "r");
5693 	if (fptr0 == NULL)
5694 		flag = 0;
5695 	};
5696 
5697 /* open the output file for writing */
5698 
5699 if (flag)
5700 	{
5701 	fptr1 = fopen(fn1, "w");
5702 	if (fptr1 == NULL)
5703 		flag = 0;
5704 	};
5705 
5706 /* scan entire file */
5707 
5708 while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL))
5709 	{
5710 	/* decode a record */
5711 
5712 	epdptr = EPDDecode(ev);
5713 
5714 	/* check record decode validity */
5715 
5716 	if (epdptr == NULL)
5717 		flag = 0;
5718 	else
5719 		{
5720 		/* make repairs */
5721 
5722 		flag = EPDRepairEPD(epdptr);
5723 
5724 		/* continue if repair okay */
5725 
5726 		if (flag)
5727 			{
5728 			/* encode the normalized record */
5729 
5730 			eptr = EPDEncode(epdptr);
5731 
5732 			/* check result */
5733 
5734 			if (eptr == NULL)
5735 				flag = 0;
5736 			else
5737 				{
5738 				fprintf(fptr1, "%s\n", eptr);
5739 				EPDMemoryFree(eptr);
5740 				};
5741 			};
5742 
5743 		/* release EPD structure */
5744 
5745 		EPDReleaseEPD(epdptr);
5746 		};
5747 	};
5748 
5749 /* close input and output files */
5750 
5751 if (fptr0 != NULL)
5752 	fclose(fptr0);
5753 
5754 if (fptr1 != NULL)
5755 	fclose(fptr1);
5756 
5757 return (flag);
5758 }
5759 
5760 /*--> EPDNormalizeFile: normalize input file to output file */
5761 nonstatic
5762 siT
EPDNormalizeFile(charptrT fn0,charptrT fn1)5763 EPDNormalizeFile(charptrT fn0, charptrT fn1)
5764 {
5765 siT flag;
5766 fptrT fptr0, fptr1;
5767 epdptrT epdptr;
5768 charptrT eptr;
5769 char ev[epdL];
5770 
5771 /* set default return value (success) */
5772 
5773 flag = 1;
5774 
5775 /* clear the input and output file pointers */
5776 
5777 fptr0 = fptr1 = NULL;
5778 
5779 /* open the input file for reading */
5780 
5781 if (flag)
5782 	{
5783 	fptr0 = fopen(fn0, "r");
5784 	if (fptr0 == NULL)
5785 		flag = 0;
5786 	};
5787 
5788 /* open the output file for writing */
5789 
5790 if (flag)
5791 	{
5792 	fptr1 = fopen(fn1, "w");
5793 	if (fptr1 == NULL)
5794 		flag = 0;
5795 	};
5796 
5797 /* scan entire file */
5798 
5799 while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL))
5800 	{
5801 	/* decode a record */
5802 
5803 	epdptr = EPDDecode(ev);
5804 
5805 	/* check record decode validity */
5806 
5807 	if (epdptr == NULL)
5808 		flag = 0;
5809 	else
5810 		{
5811 		/* encode the record (this includes normalization) */
5812 
5813 		eptr = EPDEncode(epdptr);
5814 
5815 		/* release EPD structure */
5816 
5817 		EPDReleaseEPD(epdptr);
5818 
5819 		/* check result */
5820 
5821 		if (eptr == NULL)
5822 			flag = 0;
5823 		else
5824 			{
5825 			fprintf(fptr1, "%s\n", eptr);
5826 			EPDMemoryFree(eptr);
5827 			};
5828 		};
5829 	};
5830 
5831 /* close input and output files */
5832 
5833 if (fptr0 != NULL)
5834 	fclose(fptr0);
5835 
5836 if (fptr1 != NULL)
5837 	fclose(fptr1);
5838 
5839 return (flag);
5840 }
5841 
5842 /*--> EPDScoreFile: score a benchmark file */
5843 nonstatic
5844 siT
EPDScoreFile(charptrT fn,bmsptrT bmsptr)5845 EPDScoreFile(charptrT fn, bmsptrT bmsptr)
5846 {
5847 siT flag;
5848 siT skipflag;
5849 siT am_flag, bm_flag;
5850 siT solved;
5851 fptrT fptr;
5852 epdptrT epdptr;
5853 eopptrT am_eopptr, bm_eopptr, acd_eopptr, acn_eopptr, acs_eopptr;
5854 eopptrT sm_eopptr, sv_eopptr, pm_eopptr, pv_eopptr;
5855 charptrT result;
5856 char ev[epdL];
5857 
5858 /* set default return value (success) */
5859 
5860 flag = 1;
5861 
5862 /* clear the input file pointer */
5863 
5864 fptr = NULL;
5865 
5866 /* preset the summary structure */
5867 
5868 bmsptr->bms_acdflag = bmsptr->bms_acnflag = bmsptr->bms_acsflag = 1;
5869 bmsptr->bms_total = bmsptr->bms_solve = bmsptr->bms_unsol = 0;
5870 bmsptr->bms_total_acd = bmsptr->bms_solve_acd = bmsptr->bms_unsol_acd = 0;
5871 bmsptr->bms_total_acn = bmsptr->bms_solve_acn = bmsptr->bms_unsol_acn = 0;
5872 bmsptr->bms_total_acs = bmsptr->bms_solve_acs = bmsptr->bms_unsol_acs = 0;
5873 
5874 /* open the input file for reading */
5875 
5876 if (flag)
5877 	{
5878 	fptr = fopen(fn, "r");
5879 	if (fptr == NULL)
5880 		flag = 0;
5881 	};
5882 
5883 /* scan entire file */
5884 
5885 while (flag && (fgets(ev, (epdL - 1), fptr) != NULL))
5886 	{
5887 	/* decode a record */
5888 
5889 	epdptr = EPDDecode(ev);
5890 
5891 	/* check record decode validity */
5892 
5893 	if (epdptr == NULL)
5894 		flag = 0;
5895 	else
5896 		{
5897 		/* clear the move result pointer */
5898 
5899 		result = NULL;
5900 
5901 		/* initialize various operation pointers */
5902 
5903 		am_eopptr = EPDLocateEOPCode(epdptr, epdso_am);
5904 		bm_eopptr = EPDLocateEOPCode(epdptr, epdso_bm);
5905 		acd_eopptr = EPDLocateEOPCode(epdptr, epdso_acd);
5906 		acn_eopptr = EPDLocateEOPCode(epdptr, epdso_acn);
5907 		acs_eopptr = EPDLocateEOPCode(epdptr, epdso_acs);
5908 		sm_eopptr = EPDLocateEOPCode(epdptr, epdso_sm);
5909 		sv_eopptr = EPDLocateEOPCode(epdptr, epdso_sv);
5910 		pm_eopptr = EPDLocateEOPCode(epdptr, epdso_pm);
5911 		pv_eopptr = EPDLocateEOPCode(epdptr, epdso_pv);
5912 
5913 		/* test for am/bm existence */
5914 
5915 		if ((am_eopptr == NULL) && (bm_eopptr == NULL))
5916 			skipflag = 1;
5917 		else
5918 			skipflag = 0;
5919 
5920 		/* try to locate a result move (note priority) */
5921 
5922 		if (!skipflag)
5923 			{
5924 			if (result == NULL)
5925 				if ((pv_eopptr != NULL) && (pv_eopptr->eop_headeov != NULL))
5926 					result = pv_eopptr->eop_headeov->eov_str;
5927 
5928 			if (result == NULL)
5929 				if ((pm_eopptr != NULL) && (pm_eopptr->eop_headeov != NULL))
5930 					result = pm_eopptr->eop_headeov->eov_str;
5931 
5932 			if (result == NULL)
5933 				if ((sv_eopptr != NULL) && (sv_eopptr->eop_headeov != NULL))
5934 					result = sv_eopptr->eop_headeov->eov_str;
5935 
5936 			if (result == NULL)
5937 				if ((sm_eopptr != NULL) && (sm_eopptr->eop_headeov != NULL))
5938 					result = sm_eopptr->eop_headeov->eov_str;
5939 
5940 			if (result == NULL)
5941 				skipflag = 1;
5942 			};
5943 
5944 		/* determine solve status */
5945 
5946 		if (!skipflag)
5947 			{
5948 			/* check for clearance with the am set */
5949 
5950 			if ((am_eopptr == NULL) ||
5951 				(EPDLocateEOV(am_eopptr, result) == NULL))
5952 				am_flag = 1;
5953 			else
5954 				am_flag = 0;
5955 
5956 			/* check for clearance with the bm set */
5957 
5958 			if ((bm_eopptr == NULL) ||
5959 				(EPDLocateEOV(bm_eopptr, result) != NULL))
5960 				bm_flag = 1;
5961 			else
5962 				bm_flag = 0;
5963 
5964 			/* set solution flag */
5965 
5966 			solved = am_flag && bm_flag;
5967 			};
5968 
5969 		/* update statistics block */
5970 
5971 		if (!skipflag)
5972 			{
5973 			/* clear acd flag if acd is missing */
5974 
5975 			if ((acd_eopptr == NULL) || (acd_eopptr->eop_headeov == NULL))
5976 				bmsptr->bms_acdflag = 0;
5977 
5978 			/* clear acn flag if acn is missing */
5979 
5980 			if ((acn_eopptr == NULL) || (acn_eopptr->eop_headeov == NULL))
5981 				bmsptr->bms_acnflag = 0;
5982 
5983 			/* clear acs flag if acs is missing */
5984 
5985 			if ((acs_eopptr == NULL) || (acs_eopptr->eop_headeov == NULL))
5986 				bmsptr->bms_acsflag = 0;
5987 
5988 			/* increment record count */
5989 
5990 			bmsptr->bms_total++;
5991 
5992 			/* fold in acd value */
5993 
5994 			if (bmsptr->bms_acdflag)
5995 				{
5996 				bmsptr->bms_total_acd +=
5997 					atoi(acd_eopptr->eop_headeov->eov_str);
5998 				if (solved)
5999 					bmsptr->bms_solve_acd +=
6000 						atoi(acd_eopptr->eop_headeov->eov_str);
6001 				else
6002 					bmsptr->bms_unsol_acd +=
6003 						atoi(acd_eopptr->eop_headeov->eov_str);
6004 				};
6005 
6006 			/* fold in acn value */
6007 
6008 			if (bmsptr->bms_acnflag)
6009 				{
6010 				bmsptr->bms_total_acn +=
6011 					atoi(acn_eopptr->eop_headeov->eov_str);
6012 				if (solved)
6013 					bmsptr->bms_solve_acn +=
6014 						atoi(acn_eopptr->eop_headeov->eov_str);
6015 				else
6016 					bmsptr->bms_unsol_acn +=
6017 						atoi(acn_eopptr->eop_headeov->eov_str);
6018 				};
6019 
6020 			/* fold in acs value */
6021 
6022 			if (bmsptr->bms_acsflag)
6023 				{
6024 				bmsptr->bms_total_acs +=
6025 					atoi(acs_eopptr->eop_headeov->eov_str);
6026 				if (solved)
6027 					bmsptr->bms_solve_acs +=
6028 						atoi(acs_eopptr->eop_headeov->eov_str);
6029 				else
6030 					bmsptr->bms_unsol_acs +=
6031 						atoi(acs_eopptr->eop_headeov->eov_str);
6032 				};
6033 
6034 			/* update remaining items according to solved status */
6035 
6036 			if (solved)
6037 				bmsptr->bms_solve++;
6038 			else
6039 				bmsptr->bms_unsol++;
6040 			};
6041 
6042 		/* release EPD structure */
6043 
6044 		EPDReleaseEPD(epdptr);
6045 		};
6046 	};
6047 
6048 /* close input file */
6049 
6050 if (fptr != NULL)
6051 	fclose(fptr);
6052 
6053 return (flag);
6054 }
6055 
6056 /*--> EPDEnumerate: enumeration of current position */
6057 static
6058 liT
EPDEnumerate(siT depth)6059 EPDEnumerate(siT depth)
6060 {
6061 liT total;
6062 mptrT mptr;
6063 siT i;
6064 
6065 /* enumerate current position to the indicated depth */
6066 
6067 if (depth == 0)
6068 	total = 1;
6069 else
6070 	{
6071 	total = 0;
6072 	EPDGeneratePL();
6073 	mptr = tse.tse_base;
6074 	for (i = 0; i < tse.tse_count; i++)
6075 		{
6076 		tse.tse_curr = mptr;
6077 		EPDExecute(mptr);
6078 		if (!(mptr->m_flag & mf_bust))
6079 			total += EPDEnumerate(depth - 1);
6080 		EPDRetract(mptr);
6081 		mptr++;
6082 		};
6083 	};
6084 
6085 return (total);
6086 }
6087 
6088 /*--> EPDEnumerateFile: enumerate input file to output file */
6089 nonstatic
6090 siT
EPDEnumerateFile(siT depth,charptrT fn0,charptrT fn1,liptrT totalptr)6091 EPDEnumerateFile(siT depth, charptrT fn0, charptrT fn1, liptrT totalptr)
6092 {
6093 siT flag;
6094 fptrT fptr0, fptr1;
6095 time_t start_time;
6096 liT acn, acs;
6097 epdptrT epdptr;
6098 charptrT eptr;
6099 char ev[epdL];
6100 
6101 /* set default return value (success) */
6102 
6103 flag = 1;
6104 
6105 /* clear the grand total */
6106 
6107 *totalptr = 0;
6108 
6109 /* clear the input and output file pointers */
6110 
6111 fptr0 = fptr1 = NULL;
6112 
6113 /* open the input file for reading */
6114 
6115 if (flag)
6116 	{
6117 	fptr0 = fopen(fn0, "r");
6118 	if (fptr0 == NULL)
6119 		flag = 0;
6120 	};
6121 
6122 /* open the output file for writing */
6123 
6124 if (flag)
6125 	{
6126 	fptr1 = fopen(fn1, "w");
6127 	if (fptr1 == NULL)
6128 		flag = 0;
6129 	};
6130 
6131 /* scan entire file */
6132 
6133 while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL))
6134 	{
6135 	/* decode a record */
6136 
6137 	epdptr = EPDDecode(ev);
6138 
6139 	/* check record decode validity */
6140 
6141 	if (epdptr == NULL)
6142 		flag = 0;
6143 	else
6144 		{
6145 		/* set up the current position */
6146 
6147 		EPDRealize(epdptr);
6148 
6149 		/* check legality */
6150 
6151 		if (!EPDIsLegal())
6152 			flag = 0;
6153 		else
6154 			{
6155 			/* perform enumeration */
6156 
6157 			start_time = time(NULL);
6158 			acn = EPDEnumerate(depth);
6159 			acs = time(NULL) - start_time;
6160 
6161 			/* update the grand total */
6162 
6163 			*totalptr += acn;
6164 
6165 			/* record the updated field: acd */
6166 
6167 			EPDAddOpInt(epdptr, epdso_acd, depth);
6168 
6169 			/* record the updated field: acn */
6170 
6171 			EPDAddOpInt(epdptr, epdso_acn, acn);
6172 
6173 			/* record the updated field: acs */
6174 
6175 			EPDAddOpInt(epdptr, epdso_acs, acs);
6176 
6177 			/* encode the record */
6178 
6179 			EPDNormalize(epdptr);
6180 			eptr = EPDEncode(epdptr);
6181 
6182 			/* check result */
6183 
6184 			if (eptr == NULL)
6185 				flag = 0;
6186 			else
6187 				{
6188 				fprintf(fptr1, "%s\n", eptr);
6189 				EPDMemoryFree(eptr);
6190 				};
6191 			};
6192 
6193 		/* release EPD structure */
6194 
6195 		EPDReleaseEPD(epdptr);
6196 		};
6197 	};
6198 
6199 /* close input and output files */
6200 
6201 if (fptr0 != NULL)
6202 	fclose(fptr0);
6203 
6204 if (fptr1 != NULL)
6205 	fclose(fptr1);
6206 
6207 return (flag);
6208 }
6209 
6210 /*--> EPDMoveList: generate a string representation of a move list */
6211 nonstatic
6212 charptrT
EPDMoveList(gamptrT gamptr)6213 EPDMoveList(gamptrT gamptr)
6214 {
6215 charptrT s;
6216 charptrT b;
6217 siT count;
6218 gpmptrT gpmptr;
6219 mT m;
6220 siT sn;
6221 cT sc, c;
6222 siT pi, index, limit, length, n, column;
6223 sanT san;
6224 char tv[tL];
6225 
6226 /* calculate upper bound on storage requirement */
6227 
6228 count = EPDGamePlyCount(gamptr);
6229 limit = (((count + 1) / 2) * 5) + 4 + (count * 8) + 8 + 1;
6230 b = (charptrT) EPDMemoryGrab(limit);
6231 
6232 /* set the inital played move pointer */
6233 
6234 gpmptr = gamptr->gam_headgpm;
6235 
6236 /* set up starting color and starting move number */
6237 
6238 if (count == 0)
6239 	sc = c_w;
6240 else
6241 	sc = gpmptr->gpm_ese.ese_actc;
6242 
6243 if (count == 0)
6244 	sn = 1;
6245 else
6246 	sn = gpmptr->gpm_ese.ese_fmvn;
6247 
6248 /* more set up */
6249 
6250 pi = 0;
6251 index = 0;
6252 c = sc;
6253 n = sn;
6254 column = 0;
6255 
6256 /* loop through moves */
6257 
6258 for (pi = 0; pi < count; pi++)
6259 	{
6260 	/* handle move number indication */
6261 
6262 	if ((c == c_w) || ((pi == 0) && (sc == c_b)))
6263 		{
6264 		sprintf(tv, "%hd.", n);
6265 		length = strlen(tv);
6266 
6267 		if ((column + 1 + length) >= columnL)
6268 			{
6269 			strcpy((b + index), "\n");
6270 			index++;
6271 			column = 0;
6272 			};
6273 
6274 		if (column != 0)
6275 			{
6276 			strcpy((b + index), " ");
6277 			index++;
6278 			column++;
6279 			};
6280 
6281 		strcpy((b + index), tv);
6282 		index += length;
6283 		column += length;
6284 
6285 		n++;
6286 		};
6287 
6288 	/* handle ellipsis */
6289 
6290 	if ((pi == 0) && (sc == c_b))
6291 		{
6292 		sprintf(tv, "...");
6293 		length = strlen(tv);
6294 
6295 		if ((column + 1 + length) >= columnL)
6296 			{
6297 			strcpy((b + index), "\n");
6298 			index++;
6299 			column = 0;
6300 			};
6301 
6302 		if (column != 0)
6303 			{
6304 			strcpy((b + index), " ");
6305 			index++;
6306 			column++;
6307 			};
6308 
6309 		strcpy((b + index), tv);
6310 		index += length;
6311 		column += length;
6312 		};
6313 
6314 	/* handle move */
6315 
6316 	m = gpmptr->gpm_m;
6317 	EPDSANEncode(&m, san);
6318 	length = strlen(san);
6319 
6320 	if ((column + 1 + length) >= columnL)
6321 		{
6322 		strcpy((b + index), "\n");
6323 		index++;
6324 		column = 0;
6325 		};
6326 
6327 	if (column != 0)
6328 		{
6329 		strcpy((b + index), " ");
6330 		index++;
6331 		column++;
6332 		};
6333 
6334 	strcpy((b + index), san);
6335 	index += length;
6336 	column += length;
6337 
6338 	gpmptr = gpmptr->gpm_next;
6339 	c = inv_cv[c];
6340 	};
6341 
6342 /* append game termination marker */
6343 
6344 sprintf(tv, "%s", gtimstrv[gamptr->gam_gtim]);
6345 length = strlen(tv);
6346 
6347 if ((column + 1 + length) >= columnL)
6348 	{
6349 	strcpy((b + index), "\n");
6350 	index++;
6351 	column = 0;
6352 	};
6353 
6354 if (column != 0)
6355 	{
6356 	strcpy((b + index), " ");
6357 	index++;
6358 	column++;
6359 	};
6360 
6361 strcpy((b + index), tv);
6362 index += length;
6363 column += length;
6364 
6365 /* closing newline */
6366 
6367 if (column != 0)
6368 	strcpy((b + index), "\n");
6369 
6370 /* allocate and copy to result */
6371 
6372 s = EPDStringGrab(b);
6373 EPDMemoryFree(b);
6374 
6375 return (s);
6376 }
6377 
6378 /*--> EPDPGNFetchTagIndex: return a PGN Seven Tag Roster tag index */
6379 nonstatic
6380 pgnstrT
EPDPGNFetchTagIndex(charptrT s)6381 EPDPGNFetchTagIndex(charptrT s)
6382 {
6383 pgnstrT pgnstr;
6384 pgnstrT rstr;
6385 
6386 pgnstr = pgnstr_nil;
6387 rstr = 0;
6388 while ((pgnstr == pgnstr_nil) && (rstr < pgnstrL))
6389 	if (strcmp(s, EPDPGNFetchTagName(rstr)) == 0)
6390 		pgnstr = rstr;
6391 	else
6392 		rstr++;
6393 
6394 return (pgnstr);
6395 }
6396 
6397 /*--> EPDPGNFetchTagName: return a PGN Seven Tag Roster tag name */
6398 nonstatic
6399 charptrT
EPDPGNFetchTagName(pgnstrT pgnstr)6400 EPDPGNFetchTagName(pgnstrT pgnstr)
6401 {
6402 
6403 return (pgnstrstrv[pgnstr]);
6404 }
6405 
6406 /*--> EPDPGNGetSTR: return a string from the Seven Tag Roster */
6407 nonstatic
6408 charptrT
EPDPGNGetSTR(gamptrT gamptr,pgnstrT pgnstr)6409 EPDPGNGetSTR(gamptrT gamptr, pgnstrT pgnstr)
6410 {
6411 
6412 return (gamptr->gam_strv[pgnstr]);
6413 }
6414 
6415 /*--> EPDPGNPutSTR: enter a string into the Seven Tag Roster */
6416 nonstatic
6417 void
EPDPGNPutSTR(gamptrT gamptr,pgnstrT pgnstr,charptrT s)6418 EPDPGNPutSTR(gamptrT gamptr, pgnstrT pgnstr, charptrT s)
6419 {
6420 if (gamptr->gam_strv[pgnstr] != NULL)
6421 	EPDMemoryFree(gamptr->gam_strv[pgnstr]);
6422 
6423 gamptr->gam_strv[pgnstr] = EPDStringGrab(s);
6424 
6425 return;
6426 }
6427 
6428 /*--> EPDPGNGenSTR: return a string with the entire STR */
6429 nonstatic
6430 charptrT
EPDPGNGenSTR(gamptrT gamptr)6431 EPDPGNGenSTR(gamptrT gamptr)
6432 {
6433 charptrT s;
6434 pgnstrT pgnstr;
6435 char tv[tL];
6436 
6437 s = EPDStringGrab("");
6438 
6439 for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++)
6440 	{
6441 	sprintf(tv, "[%s \"%s\"]\n",
6442 		pgnstrstrv[pgnstr], gamptr->gam_strv[pgnstr]);
6443 	s = EPDStringAppendStr(s, tv);
6444 	};
6445 
6446 return (s);
6447 }
6448 
6449 /*--> EPDPGNHistory: generate a string for PGN version of history */
6450 nonstatic
6451 charptrT
EPDPGNHistory(gamptrT gamptr)6452 EPDPGNHistory(gamptrT gamptr)
6453 {
6454 charptrT s;
6455 charptrT ms;
6456 
6457 s = EPDPGNGenSTR(gamptr);
6458 s = EPDStringAppendChar(s, '\n');
6459 ms = EPDMoveList(gamptr);
6460 s = EPDStringAppendStr(s, ms);
6461 EPDMemoryFree(ms);
6462 s = EPDStringAppendChar(s, '\n');
6463 
6464 return (s);
6465 }
6466 
6467 /*--> EPDCopyInPTP: copy STR into an EDP structure (ptp operation) */
6468 nonstatic
6469 void
EPDCopyInPTP(gamptrT gamptr,epdptrT epdptr)6470 EPDCopyInPTP(gamptrT gamptr, epdptrT epdptr)
6471 {
6472 eopptrT eopptr;
6473 pgnstrT pgnstr;
6474 
6475 if (epdptr != NULL)
6476 	{
6477 	EPDDropIfLocEOPCode(epdptr, epdso_ptp);
6478 	eopptr = EPDCreateEOPCode(epdso_ptp);
6479 
6480 	for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++)
6481 		{
6482 		EPDAppendEOV(eopptr,
6483 			EPDCreateEOVSym(EPDPGNFetchTagName(pgnstr)));
6484 		EPDAppendEOV(eopptr,
6485 			EPDCreateEOVStr(EPDPGNGetSTR(gamptr, pgnstr)));
6486 		};
6487 
6488 	EPDAppendEOP(epdptr, eopptr);
6489 	};
6490 
6491 return;
6492 }
6493 
6494 /*--> EPDCopyOutPTP: copy STR from an EDP structure (ptp operation) */
6495 nonstatic
6496 void
EPDCopyOutPTP(gamptrT gamptr,epdptrT epdptr)6497 EPDCopyOutPTP(gamptrT gamptr, epdptrT epdptr)
6498 {
6499 eopptrT eopptr;
6500 eovptrT eovptr;
6501 pgnstrT pgnstr;
6502 
6503 if (epdptr != NULL)
6504 	{
6505 	eopptr = EPDLocateEOPCode(epdptr, epdso_ptp);
6506 	eovptr = eopptr->eop_headeov;
6507 	while ((eovptr != NULL) && (eovptr->eov_next != NULL))
6508 		{
6509 		pgnstr = EPDPGNFetchTagIndex(eovptr->eov_str);
6510 		if (pgnstr != pgnstr_nil)
6511 			EPDPGNPutSTR(gamptr, pgnstr, eovptr->eov_next->eov_str);
6512 		eovptr = eovptr->eov_next->eov_next;
6513 		};
6514 	};
6515 
6516 return;
6517 }
6518 
6519 /*--> EPDFetchRefcomStr: return  pointer of indicated refcom string */
6520 nonstatic
6521 charptrT
EPDFetchRefcomStr(refcomT refcom)6522 EPDFetchRefcomStr(refcomT refcom)
6523 {
6524 
6525 return (refcomstrv[refcom]);
6526 }
6527 
6528 /*--> EPDFetchRefreqStr: return  pointer of indicated refreq string */
6529 nonstatic
6530 charptrT
EPDFetchRefreqStr(refreqT refreq)6531 EPDFetchRefreqStr(refreqT refreq)
6532 {
6533 
6534 return (refreqstrv[refreq]);
6535 }
6536 
6537 /*--> EPDFetchRefcomIndex: return a referee command index */
6538 nonstatic
6539 refcomT
EPDFetchRefcomIndex(charptrT s)6540 EPDFetchRefcomIndex(charptrT s)
6541 {
6542 refcomT refcom;
6543 refcomT rcom;
6544 
6545 refcom = refcom_nil;
6546 rcom = 0;
6547 while ((refcom == refcom_nil) && (rcom < refcomL))
6548 	if (strcmp(s, EPDFetchRefcomStr(rcom)) == 0)
6549 		refcom = rcom;
6550 	else
6551 		rcom++;
6552 
6553 return (refcom);
6554 }
6555 
6556 /*--> EPDFetchRefreqIndex: return a referee request index */
6557 nonstatic
6558 refreqT
EPDFetchRefreqIndex(charptrT s)6559 EPDFetchRefreqIndex(charptrT s)
6560 {
6561 refreqT refreq;
6562 refreqT rreq;
6563 
6564 refreq = refreq_nil;
6565 rreq = 0;
6566 while ((refreq == refreq_nil) && (rreq < refreqL))
6567 	if (strcmp(s, EPDFetchRefreqStr(rreq)) == 0)
6568 		refreq = rreq;
6569 	else
6570 		rreq++;
6571 
6572 return (refreq);
6573 }
6574 
6575 /*--> EPDExtractRefcomIndex: extract a referee command index */
6576 nonstatic
6577 refreqT
EPDExtractRefcomIndex(epdptrT epdptr)6578 EPDExtractRefcomIndex(epdptrT epdptr)
6579 {
6580 refcomT refcom;
6581 eopptrT eopptr;
6582 eovptrT eovptr;
6583 
6584 /* set default return value */
6585 
6586 refcom = refreq_nil;
6587 
6588 if (epdptr != NULL)
6589 	if ((eopptr = EPDLocateEOPCode(epdptr, epdso_refcom)) != NULL)
6590 		if ((eovptr = eopptr->eop_headeov) != NULL)
6591 			refcom = EPDFetchRefcomIndex(eovptr->eov_str);
6592 
6593 return (refcom);
6594 }
6595 
6596 /*--> EPDExtractRefreqIndex: extract a referee request index */
6597 nonstatic
6598 refreqT
EPDExtractRefreqIndex(epdptrT epdptr)6599 EPDExtractRefreqIndex(epdptrT epdptr)
6600 {
6601 refreqT refreq;
6602 eopptrT eopptr;
6603 eovptrT eovptr;
6604 
6605 /* set default return value */
6606 
6607 refreq = refreq_nil;
6608 
6609 if (epdptr != NULL)
6610 	if ((eopptr = EPDLocateEOPCode(epdptr, epdso_refreq)) != NULL)
6611 		if ((eovptr = eopptr->eop_headeov) != NULL)
6612 			refreq = EPDFetchRefreqIndex(eovptr->eov_str);
6613 
6614 return (refreq);
6615 }
6616 
6617 /*--> EPDComm: slave to Duplex autoplay program */
6618 nonstatic
6619 siT
EPDComm(refintptrT refintptr,charptrT pipebase)6620 EPDComm(refintptrT refintptr, charptrT pipebase)
6621 {
6622 siT flag;
6623 siT done;
6624 siT flow;
6625 refcomT refcom;
6626 charptrT pfnv[flowL];
6627 fptrT pfptrv[flowL];
6628 epdptrT epdptr0, epdptr1;
6629 charptrT eptr;
6630 char ev[epdL];
6631 
6632 /* set default result: success */
6633 
6634 flag = 1;
6635 
6636 /* set up the EPD Kit for a new game */
6637 
6638 EPDInitArray();
6639 
6640 /* generate pipe file names and clear their pointers */
6641 
6642 for (flow = 0; flow < flowL; flow++)
6643 	{
6644 	pfnv[flow] = EPDStringGrab(pipebase);
6645 	pfnv[flow] = EPDStringAppendStr(pfnv[flow], ".pc");
6646 	pfnv[flow] = EPDStringAppendChar(pfnv[flow], (flow + '0'));
6647 	pfptrv[flow] = NULL;
6648 	};
6649 
6650 /* pipe files already created by Duplex, attempt open */
6651 
6652 flow = 0;
6653 while (flag && (flow < flowL))
6654 	{
6655 	pfptrv[flow] = fopen(pfnv[flow], "a+");
6656 	if (pfptrv[flow] == NULL)
6657 		flag = 0;
6658 	else
6659 		flow++;
6660 	};
6661 
6662 /* sign on to Duplex */
6663 
6664 if (flag)
6665 	{
6666 	epdptr0 = EPDGetCurrentPosition();
6667 	EPDAddOpSym(epdptr0, epdso_refreq, refreqstrv[refreq_sign_on]);
6668 	eptr = EPDEncode(epdptr0);
6669 	EPDReleaseEPD(epdptr0);
6670 	fprintf(pfptrv[0], "%s\n", eptr);
6671 	fflush(pfptrv[0]);
6672 	EPDMemoryFree(eptr);
6673 	};
6674 
6675 /* run event cycle loop */
6676 
6677 done = 0;
6678 while (flag && !done)
6679 	{
6680 	/* read an incoming EPD message */
6681 
6682 	if (fgets(ev, (epdL - 1), pfptrv[1]) == NULL)
6683 		flag = 0;
6684 	else
6685 		{
6686 		/* decode the message */
6687 
6688 		epdptr1 = EPDDecode(ev);
6689 		if ((epdptr1 == NULL) ||
6690 			((refcom = EPDExtractRefcomIndex(epdptr1)) == refcom_nil))
6691 			flag = 0;
6692 		else
6693 			{
6694 			/* send the message to the callback routine */
6695 
6696 			epdptr0 = (*refintptr)(epdptr1, &flag);
6697 
6698 			/* release input storage */
6699 
6700 			EPDReleaseEPD(epdptr1);
6701 
6702 			/* construct and transmit output string */
6703 
6704 			if (flag && (epdptr0 != NULL))
6705 				{
6706 				eptr = EPDEncode(epdptr0);
6707 				fprintf(pfptrv[0], "%s\n", eptr);
6708 				fflush(pfptrv[0]);
6709 				EPDMemoryFree(eptr);
6710 				};
6711 
6712 			/* release output storage */
6713 
6714 			if (epdptr0 != NULL)
6715 				EPDReleaseEPD(epdptr0);
6716 
6717 			/* set the completion flag on disconnect */
6718 
6719 			if (flag && !done && (refcom == refcom_disconnect))
6720 				done = 1;
6721 			};
6722 		};
6723 	};
6724 
6725 /* close pipes and release pipe file names */
6726 
6727 for (flow = 0; flow < flowL; flow++)
6728 	{
6729 	if (pfptrv[flow] != NULL)
6730 		fclose(pfptrv[flow]);
6731 	EPDMemoryFree(pfnv[flow]);
6732 	};
6733 
6734 return (flag);
6735 }
6736 
6737 /*--> EPDTBClassFileName: return an allocated class name */
6738 static
6739 charptrT
EPDTBClassFileName(charptrT dirstr,tbidT tbid,cT c)6740 EPDTBClassFileName(charptrT dirstr, tbidT tbid, cT c)
6741 {
6742 charptrT name;
6743 
6744 #if (!defined(__MWERKS__))
6745 if (dirstr == NULL)
6746 	name = EPDStringGrab("");
6747 else
6748 	{
6749 	name = EPDStringGrab(dirstr);
6750 	name = EPDStringAppendChar(name, '/');
6751 	};
6752 #else
6753 if (dirstr == NULL)
6754 	name = EPDStringGrab("");
6755 else
6756 	{
6757 	name = EPDStringGrab(":");
6758 	name = EPDStringAppendStr(name, dirstr);
6759 	name = EPDStringAppendChar(name, ':');
6760 	};
6761 #endif
6762 
6763 name = EPDStringAppendStr(name, (tbbaseptr + tbid)->tb_name);
6764 name = EPDStringAppendStr(name, ctmext_strv[c]);
6765 
6766 return (name);
6767 }
6768 
6769 /*--> EPDTBGetSignature: get the signature for a distribution */
6770 static
6771 liT
EPDTBGetSignature(distvT distv)6772 EPDTBGetSignature(distvT distv)
6773 {
6774 liT sig;
6775 cT c;
6776 pT p;
6777 
6778 sig = 0;
6779 for (c = c_w; c <= c_b; c++)
6780 	for (p = p_p; p <= p_q; p++)
6781 		sig = (sig << 3) | distv[c][p];
6782 
6783 return (sig);
6784 }
6785 
6786 /*--> EPDTBGetInvertedSignature: get the inverted signature for a distribution */
6787 static
6788 liT
EPDTBGetInvertedSignature(distvT distv)6789 EPDTBGetInvertedSignature(distvT distv)
6790 {
6791 liT sig;
6792 cT c;
6793 pT p;
6794 
6795 sig = 0;
6796 for (c = c_w; c <= c_b; c++)
6797 	for (p = p_p; p <= p_q; p++)
6798 		sig = (sig << 3) | distv[inv_cv[c]][p];
6799 
6800 return (sig);
6801 }
6802 
6803 /*--> EPDTBLocateClass: locate a class for a piece distribution */
6804 static
6805 tbidT
EPDTBLocateClass(distvT distv,siptrT invertptr)6806 EPDTBLocateClass(distvT distv, siptrT invertptr)
6807 {
6808 tbidT tbid;
6809 siT flag;
6810 tbptrT classptr;
6811 liT sig;
6812 
6813 /* set "not found" */
6814 
6815 flag = 0;
6816 
6817 /* get the piece distribution signature */
6818 
6819 sig = EPDTBGetSignature(distv);
6820 
6821 /* search for signature match */
6822 
6823 classptr = tbbaseptr;
6824 tbid = 0;
6825 while (!flag && (tbid < tbidL))
6826 	if (sig == classptr->tb_sig0)
6827 		{
6828 		flag = 1;
6829 		*invertptr = 0;
6830 		}
6831 	else
6832 		if (sig == classptr->tb_sig1)
6833 			{
6834 			flag = 1;
6835 			*invertptr = 1;
6836 			}
6837 		else
6838 			{
6839 			classptr++;
6840 			tbid++;
6841 			};
6842 
6843 /* if not found, set return to nil */
6844 
6845 if (!flag)
6846 	tbid = tbid_nil;
6847 
6848 return (tbid);
6849 }
6850 
6851 /*--> EPDTBCopyPosition: copy a position vector */
6852 static
6853 void
EPDTBCopyPosition(posvT posv0,posvT posv1)6854 EPDTBCopyPosition(posvT posv0, posvT posv1)
6855 {
6856 cT c;
6857 siT i;
6858 
6859 for (c = c_w; c <= c_b; c++)
6860 	for (i = 0; i < tbmecL; i++)
6861 		posv1[c][i] = posv0[c][i];
6862 
6863 return;
6864 }
6865 
6866 /*--> EPDTBReflectX: reflect a position along the X axis */
6867 static
6868 void
EPDTBReflectX(tbptrT classptr,posvT posv)6869 EPDTBReflectX(tbptrT classptr, posvT posv)
6870 {
6871 cT c;
6872 siT i;
6873 
6874 for (c = c_w; c <= c_b; c++)
6875 	for (i = 0; i < classptr->tb_mcv[c]; i++)
6876 		posv[c][i] ^= 0x38;
6877 
6878 return;
6879 }
6880 
6881 /*--> EPDTBReflectY: reflect a position along the Y axis */
6882 static
6883 void
EPDTBReflectY(tbptrT classptr,posvT posv)6884 EPDTBReflectY(tbptrT classptr, posvT posv)
6885 {
6886 cT c;
6887 siT i;
6888 
6889 for (c = c_w; c <= c_b; c++)
6890 	for (i = 0; i < classptr->tb_mcv[c]; i++)
6891 		posv[c][i] ^= 0x07;
6892 
6893 return;
6894 }
6895 
6896 /*--> EPDTBReflectXY: reflect a position along the X=Y axis */
6897 static
6898 void
EPDTBReflectXY(tbptrT classptr,posvT posv)6899 EPDTBReflectXY(tbptrT classptr, posvT posv)
6900 {
6901 cT c;
6902 siT i;
6903 rankT rank;
6904 fileT file;
6905 
6906 for (c = c_w; c <= c_b; c++)
6907 	for (i = 0; i < classptr->tb_mcv[c]; i++)
6908 		{
6909 		rank = map_rank(posv[c][i]);
6910 		file = map_file(posv[c][i]);
6911 		posv[c][i] = map_sq(file, rank);
6912 		};
6913 
6914 return;
6915 }
6916 
6917 /*--> EPDTBNormalize: normalize a position */
6918 static
6919 void
EPDTBNormalize(tbptrT classptr,posvT posv)6920 EPDTBNormalize(tbptrT classptr, posvT posv)
6921 {
6922 sqT sq;
6923 cT pivot_c;
6924 siT pivot_slot;
6925 
6926 /* get pivot color and slot */
6927 
6928 pivot_c = classptr->tb_pivot_c;
6929 pivot_slot = classptr->tb_pivot_slot;
6930 
6931 /* determine normalization mode */
6932 
6933 if (classptr->tb_fold == fold_flank)
6934 	{
6935 	/* class has at least one pawn */
6936 
6937 	sq = posv[pivot_c][pivot_slot];
6938 	if (map_file(sq) > file_d)
6939 		EPDTBReflectY(classptr, posv);
6940 	}
6941 else
6942 	{
6943 	/* class has no pawns */
6944 
6945 	sq = posv[pivot_c][pivot_slot];
6946 	if (map_rank(sq) > rank_4)
6947 		EPDTBReflectX(classptr, posv);
6948 
6949 	sq = posv[pivot_c][pivot_slot];
6950 	if (map_file(sq) > file_d)
6951 		EPDTBReflectY(classptr, posv);
6952 
6953 	sq = posv[pivot_c][pivot_slot];
6954 	if (map_rank(sq) > map_file(sq))
6955 		EPDTBReflectXY(classptr, posv);
6956 	};
6957 
6958 return;
6959 }
6960 
6961 /*--> EPDTBGenIndex: generate a file index for a class and position */
6962 static
6963 indexT
EPDTBGenIndex(tbptrT classptr,posvT posv)6964 EPDTBGenIndex(tbptrT classptr, posvT posv)
6965 {
6966 indexT index;
6967 liT factor=0;
6968 posvT nposv;
6969 cT c;
6970 siT i;
6971 
6972 EPDTBCopyPosition(posv, nposv);
6973 EPDTBNormalize(classptr, nposv);
6974 
6975 index = 0;
6976 for (c = c_w; c <= c_b; c++)
6977 	for (i = 0; i < classptr->tb_mcv[c]; i++)
6978 		{
6979 		switch (classptr->tb_scalev[c][i])
6980 			{
6981 			case sqL:
6982 				factor = nposv[c][i];
6983 				break;
6984 			case ff_flankL:
6985 				factor = flank_mapv[nposv[c][i]];
6986 				break;
6987 			case ff_triangleL:
6988 				factor = triangle_mapv[nposv[c][i]];
6989 				break;
6990 			default:
6991 				EPDSwitchFault("EPDTBGenIndex");
6992 				break;
6993 			};
6994 		index += factor * classptr->tb_multv[c][i];
6995 		};
6996 
6997 return (index);
6998 }
6999 
7000 /*--> EPDTBGenInvertIndex: generate a file index for a class and position (inverted) */
7001 static
7002 indexT
EPDTBGenInvertIndex(tbptrT classptr,posvT posv)7003 EPDTBGenInvertIndex(tbptrT classptr, posvT posv)
7004 {
7005 indexT index;
7006 liT factor=0;
7007 posvT nposv;
7008 cT c, invc;
7009 siT i;
7010 
7011 for (c = c_w; c <= c_b; c++)
7012 	{
7013 	invc = inv_cv[c];
7014 	for (i = 0; i < classptr->tb_mcv[invc]; i++)
7015 		nposv[invc][i] = posv[c][i];
7016 	};
7017 
7018 if (classptr->tb_flags & tbf_has_pawns)
7019 	EPDTBReflectX(classptr, nposv);
7020 
7021 EPDTBNormalize(classptr, nposv);
7022 
7023 index = 0;
7024 for (c = c_w; c <= c_b; c++)
7025 	{
7026 	for (i = 0; i < classptr->tb_mcv[c]; i++)
7027 		{
7028 		switch (classptr->tb_scalev[c][i])
7029 			{
7030 			case sqL:
7031 				factor = nposv[c][i];
7032 				break;
7033 			case ff_flankL:
7034 				factor = flank_mapv[nposv[c][i]];
7035 				break;
7036 			case ff_triangleL:
7037 				factor = triangle_mapv[nposv[c][i]];
7038 				break;
7039 			default:
7040 				EPDSwitchFault("EPDTBGenInvertIndex");
7041 				break;
7042 			};
7043 		index += factor * classptr->tb_multv[c][i];
7044 		};
7045 	};
7046 
7047 return (index);
7048 }
7049 
7050 /*--> EPDTBMapFromBEV: convert to centipawns from byte evaluation */
7051 static
7052 cpevT
EPDTBMapFromBEV(bevT bev)7053 EPDTBMapFromBEV(bevT bev)
7054 {
7055 cpevT cpev;
7056 siT distance;
7057 
7058 switch (bev)
7059 	{
7060 	case bev_broken:
7061 	case bev_reserved:
7062 	case bev_unknown:
7063 		cpev = cpev_wrck;
7064 		break;
7065 
7066 	case bev_draw:
7067 		cpev = cpev_draw;
7068 		break;
7069 
7070 	default:
7071 		if (tbe_mating(bev))
7072 			{
7073 			distance = ((bev_mi1 - bev) * 2) + 1;
7074 			cpev = cpev_best - distance;
7075 			}
7076 		else
7077 			{
7078 			distance = -((bev_li0 - bev) * 2);
7079 			cpev = cpev_bust + distance;
7080 			};
7081 		break;
7082 	};
7083 
7084 return (cpev);
7085 }
7086 
7087 /*--> EPDTBProbeFile: return a centipawn value from a probe */
7088 static
7089 cpevT
EPDTBProbeFile(tbidT tbid,cT c,liT index)7090 EPDTBProbeFile(tbidT tbid, cT c, liT index)
7091 {
7092 cpevT cpev;
7093 siT i, slot;
7094 bevT bev;
7095 tbcT tbc;
7096 charptrT fnptr;
7097 
7098 /* set default return value: no evaluation found */
7099 
7100 cpev = cpev_wrck;
7101 
7102 /* search cache for a slot with currently open file */
7103 
7104 slot = -1;
7105 i = 0;
7106 while ((slot == -1) && (i < tbcL))
7107 	if (tbcv[i].tbc_inuse &&
7108 		(tbcv[i].tbc_tbid == tbid) && (tbcv[i].tbc_c == c))
7109 		slot = i;
7110 	else
7111 		i++;
7112 
7113 /* if no slot was found, try to find an empty one */
7114 
7115 if (slot == -1)
7116 	{
7117 	/* look for a free slot */
7118 
7119 	i = 0;
7120 	while ((slot == -1) && (i < tbcL))
7121 		if (!tbcv[i].tbc_inuse)
7122 			slot = i;
7123 		else
7124 			i++;
7125 
7126 	/* if no empty slot, drop the bottom (LRU) entry */
7127 
7128 	if (slot == -1)
7129 		{
7130 		slot = tbcL - 1;
7131 		if (tbcv[slot].tbc_fptr != NULL)
7132 			fclose(tbcv[slot].tbc_fptr);
7133 		};
7134 
7135 	/* initialize the slot */
7136 
7137 	tbcv[slot].tbc_inuse = 1;
7138 	tbcv[slot].tbc_tbid = tbid;
7139 	tbcv[slot].tbc_c = c;
7140 	fnptr = EPDTBClassFileName(tb_path, tbid, c);
7141 	tbcv[slot].tbc_fptr = fopen(fnptr, "rb");
7142 	EPDStringFree(fnptr);
7143 	};
7144 
7145 /* move slot entry to top */
7146 
7147 if (slot != 0)
7148 	{
7149 	tbc = tbcv[slot];
7150 	for (i = slot; i > 0; i--)
7151 		tbcv[i] = tbcv[i - 1];
7152 	slot = 0;
7153 	tbcv[slot] = tbc;
7154 	};
7155 
7156 /* file probe */
7157 
7158 if (tbcv[slot].tbc_fptr != NULL)
7159 	if (fseek(tbcv[slot].tbc_fptr, index, SEEK_SET) == 0)
7160 		if (fread(&bev, sizeof(bevT), 1, tbcv[slot].tbc_fptr) ==
7161 			sizeof(bevT))
7162 			cpev = EPDTBMapFromBEV(bev);
7163 
7164 return (cpev);
7165 }
7166 
7167 /*--> EPDTBIsFilePresent: test if the given TB file is readable */
7168 nonstatic
7169 siT
EPDTBIsFilePresent(tbidT tbid,cT c)7170 EPDTBIsFilePresent(tbidT tbid, cT c)
7171 {
7172 siT flag;
7173 fptrT fptr;
7174 charptrT fnptr;
7175 
7176 fnptr = EPDTBClassFileName(tb_path, tbid, c);
7177 fptr = fopen(fnptr, "rb");
7178 EPDStringFree(fnptr);
7179 if (fptr == NULL)
7180 	flag = 0;
7181 else
7182 	{
7183 	fclose(fptr);
7184 	flag = 1;
7185 	};
7186 
7187 return (flag);
7188 }
7189 
7190 /*--> EPDTBScore: return tablebase certain score (if possible) */
7191 nonstatic
7192 cpevT
EPDTBScore(void)7193 EPDTBScore(void)
7194 {
7195 cpevT cpev;
7196 tbidT tbid;
7197 siT invert;
7198 cT probe_c;
7199 liT index;
7200 distvT distv;
7201 cT c;
7202 pT p;
7203 sqT sq;
7204 cpT cp;
7205 cT invc;
7206 siT flag;
7207 siT i;
7208 tbptrT classptr;
7209 posvT posv, nposv;
7210 rbT rb;
7211 
7212 /* set default return value: score unfound */
7213 
7214 cpev = cpev_wrck;
7215 
7216 /* clear the distribution */
7217 
7218 for (c = c_w; c <= c_b; c++)
7219 	for (p = p_p; p <= p_k; p++)
7220 		distv[c][p] = 0;
7221 
7222 /* calculate the distribution */
7223 
7224 for (sq = sq_a1; sq <= sq_h8; sq++)
7225 	if ((cp = EPDboard.rbv[sq]) != cp_v0)
7226 		distv[cv_c_cpv[cp]][cv_p_cpv[cp]]++;
7227 
7228 /* locate the class */
7229 
7230 tbid = EPDTBLocateClass(distv, &invert);
7231 
7232 /* was a class identified? */
7233 
7234 if (tbid != tbid_nil)
7235 	{
7236 	/* get the class pointer */
7237 
7238 	classptr = tbbaseptr + tbid;
7239 
7240 	/* calculate probe color */
7241 
7242 	if (!invert)
7243 		probe_c = ese.ese_actc;
7244 	else
7245 		probe_c = inv_cv[ese.ese_actc];
7246 
7247 	/* set up the position vector */
7248 
7249 	for (sq = sq_a1; sq <= sq_h8; sq++)
7250 		{
7251 		cp = EPDboard.rbv[sq];
7252 		if ((cp != cp_v0) && invert)
7253 			cp = cv_cp_c_pv[inv_cv[cv_c_cpv[cp]]][cv_p_cpv[cp]];
7254 		rb.rbv[sq] = cp;
7255 		};
7256 
7257 	for (c = c_w; c <= c_b; c++)
7258 		for (i = 0; i < classptr->tb_mcv[c]; i++)
7259 			{
7260 			/* which color-piece to match? */
7261 
7262 			cp = classptr->tb_cpv[c][i];
7263 
7264 			/* find it */
7265 
7266 			flag = 0;
7267 			sq = sq_a1;
7268 			while (!flag)
7269 				if (rb.rbv[sq] == cp)
7270 					{
7271 					posv[c][i] = sq;
7272 					rb.rbv[sq] = cp_v0;
7273 					flag = 1;
7274 					}
7275 				else
7276 					sq++;
7277 			};
7278 
7279 	/* calculate index */
7280 
7281 	if (!invert)
7282 		index = EPDTBGenIndex(classptr, posv);
7283 	else
7284 		{
7285 		for (c = c_w; c <= c_b; c++)
7286 			{
7287 			invc = inv_cv[c];
7288 			for (i = 0; i < classptr->tb_mcv[c]; i++)
7289 				nposv[invc][i] = posv[c][i];
7290 			};
7291 
7292 		index = EPDTBGenInvertIndex(classptr, nposv);
7293 		};
7294 
7295 	/* probe */
7296 
7297 	cpev = EPDTBProbeFile(tbid, probe_c, index);
7298 	};
7299 
7300 return (cpev);
7301 }
7302 
7303 /*--> EPDTBInitTBID: initialize an entry in the tablebase vector */
7304 static
7305 void
EPDTBInitTBID(tbidT tbid,charptrT name)7306 EPDTBInitTBID(tbidT tbid, charptrT name)
7307 {
7308 cT c;
7309 pT p;
7310 siT i, slot;
7311 liT mult;
7312 char ch;
7313 tbptrT classptr;
7314 
7315 classptr = tbbaseptr + tbid;
7316 
7317 /* clear flags and set name items */
7318 
7319 classptr->tb_flags = 0;
7320 classptr->tb_name = EPDStringGrab(name);
7321 classptr->tb_count = strlen(name);
7322 
7323 /* clear various vectors */
7324 
7325 for (c = c_w; c <= c_b; c++)
7326 	{
7327 	classptr->tb_mcv[c] = 0;
7328 	for (p = p_p; p <= p_k; p++)
7329 		classptr->tb_distv[c][p] = 0;
7330 	};
7331 
7332 /* scan through pieces in class names */
7333 
7334 c = c_b;
7335 for (i = 0; i < classptr->tb_count; i++)
7336 	{
7337 	/* identify current piece */
7338 
7339 	ch = *(name + i);
7340 	switch (ch)
7341 		{
7342 		case 'P':
7343 			p = p_p;
7344 			break;
7345 		case 'N':
7346 			p = p_n;
7347 			break;
7348 		case 'B':
7349 			p = p_b;
7350 			break;
7351 		case 'R':
7352 			p = p_r;
7353 			break;
7354 		case 'Q':
7355 			p = p_q;
7356 			break;
7357 		case 'K':
7358 			p = p_k;
7359 			break;
7360 		default:
7361 			EPDSwitchFault("EPDTBInitTBID");
7362 			break;
7363 		};
7364 
7365 	/* swap color if current piece is a king */
7366 
7367 	if (p == p_k)
7368 		c = inv_cv[c];
7369 
7370 	/* set various flags if current piece is a pawn */
7371 
7372 	if (p == p_p)
7373 		{
7374 		classptr->tb_flags |= tbf_has_pawns;
7375 		if (c == c_w)
7376 			{
7377 			classptr->tb_flags |= tbf_has_white_pawn;
7378 			if (classptr->tb_flags & tbf_has_black_pawn)
7379 				classptr->tb_flags |= tbf_ep_captures;
7380 			}
7381 		else
7382 			{
7383 			classptr->tb_flags |= tbf_has_black_pawn;
7384 			if (classptr->tb_flags & tbf_has_white_pawn)
7385 				classptr->tb_flags |= tbf_ep_captures;
7386 			};
7387 		};
7388 
7389 	/* adjust count and distribution for this color */
7390 
7391 	classptr->tb_mcv[c]++;
7392 	classptr->tb_distv[c][p]++;
7393 
7394 	/* set piece and color-piece vector for this color */
7395 
7396 	if (c == c_w)
7397 		slot = i;
7398 	else
7399 		slot = i - classptr->tb_mcv[c_w];
7400 	classptr->tb_pv[c][slot] = p;
7401 	classptr->tb_cpv[c][slot] = cv_cp_c_pv[c][p];
7402 	};
7403 
7404 /* set the distribution signatures */
7405 
7406 classptr->tb_sig0 = EPDTBGetSignature(classptr->tb_distv);
7407 classptr->tb_sig1 = EPDTBGetInvertedSignature(classptr->tb_distv);
7408 
7409 /* set fold mode information */
7410 
7411 if (classptr->tb_flags & tbf_has_pawns)
7412 	{
7413 	classptr->tb_flags |= tbf_fold_flank;
7414 	classptr->tb_fold = fold_flank;
7415 	}
7416 else
7417 	{
7418 	classptr->tb_flags |= tbf_fold_triangle;
7419 	classptr->tb_fold = fold_triangle;
7420 	};
7421 
7422 /* calculate file length */
7423 
7424 classptr->tb_length = 1;
7425 for (i = 1; i < classptr->tb_count; i++)
7426 	classptr->tb_length *= sqL;
7427 if (classptr->tb_fold == fold_flank)
7428 	classptr->tb_length *= ff_flankL;
7429 else
7430 	classptr->tb_length *= ff_triangleL;
7431 
7432 /* calculate pivot color and slot */
7433 
7434 if (classptr->tb_fold == fold_triangle)
7435 	{
7436 	classptr->tb_pivot_c = c_b;
7437 	classptr->tb_pivot_slot = classptr->tb_mcv[c_b] - 1;
7438 	}
7439 else
7440 	{
7441 	if (classptr->tb_flags & tbf_has_black_pawn)
7442 		{
7443 		classptr->tb_pivot_c = c_b;
7444 		i = classptr->tb_count - 1;
7445 		while (*(name + i) != ascpv[p_p])
7446 			i--;
7447 		classptr->tb_pivot_slot = i - classptr->tb_mcv[c_w];
7448 		}
7449 	else
7450 		{
7451 		classptr->tb_pivot_c = c_w;
7452 		i = classptr->tb_mcv[c_w] - 1;
7453 		while (*(name + i) != ascpv[p_p])
7454 			i--;
7455 		classptr->tb_pivot_slot = i;
7456 		};
7457 	};
7458 
7459 /* calculate scale factors */
7460 
7461 for (c = c_w; c <= c_b; c++)
7462 	for (i = 0; i < classptr->tb_mcv[c]; i++)
7463 		if ((c != classptr->tb_pivot_c) || (i != classptr->tb_pivot_slot))
7464 			classptr->tb_scalev[c][i] = sqL;
7465 		else
7466 			if (classptr->tb_fold == fold_triangle)
7467 				classptr->tb_scalev[c][i] = ff_triangleL;
7468 			else
7469 				classptr->tb_scalev[c][i] = ff_flankL;
7470 
7471 /* calculate multipliers */
7472 
7473 mult = 1;
7474 for (c = c_w; c <= c_b; c++)
7475 	for (i = 0; i < classptr->tb_mcv[c]; i++)
7476 		{
7477 		classptr->tb_multv[c][i] = mult;
7478 		mult *= classptr->tb_scalev[c][i];
7479 		};
7480 
7481 return;
7482 }
7483 
7484 /*--> EPDTBCacheFlush: flush the tablebase file pointer cache */
7485 nonstatic
7486 void
EPDTBCacheFlush(void)7487 EPDTBCacheFlush(void)
7488 {
7489 siT i;
7490 
7491 for (i = 0; i < tbcL; i++)
7492 	if (tbcv[i].tbc_inuse)
7493 		{
7494 		if (tbcv[i].tbc_fptr != NULL)
7495 			fclose(tbcv[i].tbc_fptr);
7496 		tbcv[i].tbc_inuse = 0;
7497 		};
7498 
7499 return;
7500 }
7501 
7502 /*--> EPDTBInit: one time initialization for the tablebase subsystem */
7503 static
7504 void
EPDTBInit(void)7505 EPDTBInit(void)
7506 {
7507 siT i;
7508 sqT sq;
7509 
7510 /* initialize the flank map */
7511 
7512 for (sq = sq_a1; sq <= sq_h8; sq++)
7513 	flank_mapv[sq] = -1;
7514 
7515 flank_mapv[sq_a1] =  0;
7516 flank_mapv[sq_b1] =  1;
7517 flank_mapv[sq_c1] =  2;
7518 flank_mapv[sq_d1] =  3;
7519 flank_mapv[sq_a2] =  4;
7520 flank_mapv[sq_b2] =  5;
7521 flank_mapv[sq_c2] =  6;
7522 flank_mapv[sq_d2] =  7;
7523 flank_mapv[sq_a3] =  8;
7524 flank_mapv[sq_b3] =  9;
7525 flank_mapv[sq_c3] = 10;
7526 flank_mapv[sq_d3] = 11;
7527 flank_mapv[sq_a4] = 12;
7528 flank_mapv[sq_b4] = 13;
7529 flank_mapv[sq_c4] = 14;
7530 flank_mapv[sq_d4] = 15;
7531 flank_mapv[sq_a5] = 16;
7532 flank_mapv[sq_b5] = 17;
7533 flank_mapv[sq_c5] = 18;
7534 flank_mapv[sq_d5] = 19;
7535 flank_mapv[sq_a6] = 20;
7536 flank_mapv[sq_b6] = 21;
7537 flank_mapv[sq_c6] = 22;
7538 flank_mapv[sq_d6] = 23;
7539 flank_mapv[sq_a7] = 24;
7540 flank_mapv[sq_b7] = 25;
7541 flank_mapv[sq_c7] = 26;
7542 flank_mapv[sq_d7] = 27;
7543 flank_mapv[sq_a8] = 28;
7544 flank_mapv[sq_b8] = 29;
7545 flank_mapv[sq_c8] = 30;
7546 flank_mapv[sq_d8] = 31;
7547 
7548 /* initialize the triangle map */
7549 
7550 for (sq = sq_a1; sq <= sq_h8; sq++)
7551 	triangle_mapv[sq] = -1;
7552 
7553 triangle_mapv[sq_a1] = 0;
7554 triangle_mapv[sq_b1] = 1;
7555 triangle_mapv[sq_c1] = 2;
7556 triangle_mapv[sq_d1] = 3;
7557 triangle_mapv[sq_b2] = 4;
7558 triangle_mapv[sq_c2] = 5;
7559 triangle_mapv[sq_d2] = 6;
7560 triangle_mapv[sq_c3] = 7;
7561 triangle_mapv[sq_d3] = 8;
7562 triangle_mapv[sq_d4] = 9;
7563 
7564 /* set the color to move tablebase file name suffixes */
7565 
7566 ctmext_strv[c_w] = ".tbw";
7567 ctmext_strv[c_b] = ".tbb";
7568 
7569 /* allocate tablebase information vector */
7570 
7571 tbbaseptr = (tbptrT) EPDMemoryGrab(sizeof(tbT) * tbidL);
7572 
7573 /* initialize the tablebase vector */
7574 
7575 EPDTBInitTBID(tbid_kk,    "KK");
7576 EPDTBInitTBID(tbid_kpk,   "KPK");
7577 EPDTBInitTBID(tbid_knk,   "KNK");
7578 EPDTBInitTBID(tbid_kbk,   "KBK");
7579 EPDTBInitTBID(tbid_krk,   "KRK");
7580 EPDTBInitTBID(tbid_kqk,   "KQK");
7581 EPDTBInitTBID(tbid_kpkp,  "KPKP");
7582 EPDTBInitTBID(tbid_knkp,  "KNKP");
7583 EPDTBInitTBID(tbid_knkn,  "KNKN");
7584 EPDTBInitTBID(tbid_kbkp,  "KBKP");
7585 EPDTBInitTBID(tbid_kbkn,  "KBKN");
7586 EPDTBInitTBID(tbid_kbkb,  "KBKB");
7587 EPDTBInitTBID(tbid_krkp,  "KRKP");
7588 EPDTBInitTBID(tbid_krkn,  "KRKN");
7589 EPDTBInitTBID(tbid_krkb,  "KRKB");
7590 EPDTBInitTBID(tbid_krkr,  "KRKR");
7591 EPDTBInitTBID(tbid_kqkp,  "KQKP");
7592 EPDTBInitTBID(tbid_kqkn,  "KQKN");
7593 EPDTBInitTBID(tbid_kqkb,  "KQKB");
7594 EPDTBInitTBID(tbid_kqkr,  "KQKR");
7595 EPDTBInitTBID(tbid_kqkq,  "KQKQ");
7596 EPDTBInitTBID(tbid_kppk,  "KPPK");
7597 EPDTBInitTBID(tbid_knpk,  "KNPK");
7598 EPDTBInitTBID(tbid_knnk,  "KNNK");
7599 EPDTBInitTBID(tbid_kbpk,  "KBPK");
7600 EPDTBInitTBID(tbid_kbnk,  "KBNK");
7601 EPDTBInitTBID(tbid_kbbk,  "KBBK");
7602 EPDTBInitTBID(tbid_krpk,  "KRPK");
7603 EPDTBInitTBID(tbid_krnk,  "KRNK");
7604 EPDTBInitTBID(tbid_krbk,  "KRBK");
7605 EPDTBInitTBID(tbid_krrk,  "KRRK");
7606 EPDTBInitTBID(tbid_kqpk,  "KQPK");
7607 EPDTBInitTBID(tbid_kqnk,  "KQNK");
7608 EPDTBInitTBID(tbid_kqbk,  "KQBK");
7609 EPDTBInitTBID(tbid_kqrk,  "KQRK");
7610 EPDTBInitTBID(tbid_kqqk,  "KQQK");
7611 EPDTBInitTBID(tbid_kppkp, "KPPKP");
7612 EPDTBInitTBID(tbid_kppkn, "KPPKN");
7613 EPDTBInitTBID(tbid_kppkb, "KPPKB");
7614 EPDTBInitTBID(tbid_kppkr, "KPPKR");
7615 EPDTBInitTBID(tbid_kppkq, "KPPKQ");
7616 EPDTBInitTBID(tbid_knpkp, "KNPKP");
7617 EPDTBInitTBID(tbid_knpkn, "KNPKN");
7618 EPDTBInitTBID(tbid_knpkb, "KNPKB");
7619 EPDTBInitTBID(tbid_knpkr, "KNPKR");
7620 EPDTBInitTBID(tbid_knpkq, "KNPKQ");
7621 EPDTBInitTBID(tbid_knnkp, "KNNKP");
7622 EPDTBInitTBID(tbid_knnkn, "KNNKN");
7623 EPDTBInitTBID(tbid_knnkb, "KNNKB");
7624 EPDTBInitTBID(tbid_knnkr, "KNNKR");
7625 EPDTBInitTBID(tbid_knnkq, "KNNKQ");
7626 EPDTBInitTBID(tbid_kbpkp, "KBPKP");
7627 EPDTBInitTBID(tbid_kbpkn, "KBPKN");
7628 EPDTBInitTBID(tbid_kbpkb, "KBPKB");
7629 EPDTBInitTBID(tbid_kbpkr, "KBPKR");
7630 EPDTBInitTBID(tbid_kbpkq, "KBPKQ");
7631 EPDTBInitTBID(tbid_kbnkp, "KBNKP");
7632 EPDTBInitTBID(tbid_kbnkn, "KBNKN");
7633 EPDTBInitTBID(tbid_kbnkb, "KBNKB");
7634 EPDTBInitTBID(tbid_kbnkr, "KBNKR");
7635 EPDTBInitTBID(tbid_kbnkq, "KBNKQ");
7636 EPDTBInitTBID(tbid_kbbkp, "KBBKP");
7637 EPDTBInitTBID(tbid_kbbkn, "KBBKN");
7638 EPDTBInitTBID(tbid_kbbkb, "KBBKB");
7639 EPDTBInitTBID(tbid_kbbkr, "KBBKR");
7640 EPDTBInitTBID(tbid_kbbkq, "KBBKQ");
7641 EPDTBInitTBID(tbid_krpkp, "KRPKP");
7642 EPDTBInitTBID(tbid_krpkn, "KRPKN");
7643 EPDTBInitTBID(tbid_krpkb, "KRPKB");
7644 EPDTBInitTBID(tbid_krpkr, "KRPKR");
7645 EPDTBInitTBID(tbid_krpkq, "KRPKQ");
7646 EPDTBInitTBID(tbid_krnkp, "KRNKP");
7647 EPDTBInitTBID(tbid_krnkn, "KRNKN");
7648 EPDTBInitTBID(tbid_krnkb, "KRNKB");
7649 EPDTBInitTBID(tbid_krnkr, "KRNKR");
7650 EPDTBInitTBID(tbid_krnkq, "KRNKQ");
7651 EPDTBInitTBID(tbid_krbkp, "KRBKP");
7652 EPDTBInitTBID(tbid_krbkn, "KRBKN");
7653 EPDTBInitTBID(tbid_krbkb, "KRBKB");
7654 EPDTBInitTBID(tbid_krbkr, "KRBKR");
7655 EPDTBInitTBID(tbid_krbkq, "KRBKQ");
7656 EPDTBInitTBID(tbid_krrkp, "KRRKP");
7657 EPDTBInitTBID(tbid_krrkn, "KRRKN");
7658 EPDTBInitTBID(tbid_krrkb, "KRRKB");
7659 EPDTBInitTBID(tbid_krrkr, "KRRKR");
7660 EPDTBInitTBID(tbid_krrkq, "KRRKQ");
7661 EPDTBInitTBID(tbid_kqpkp, "KQPKP");
7662 EPDTBInitTBID(tbid_kqpkn, "KQPKN");
7663 EPDTBInitTBID(tbid_kqpkb, "KQPKB");
7664 EPDTBInitTBID(tbid_kqpkr, "KQPKR");
7665 EPDTBInitTBID(tbid_kqpkq, "KQPKQ");
7666 EPDTBInitTBID(tbid_kqnkp, "KQNKP");
7667 EPDTBInitTBID(tbid_kqnkn, "KQNKN");
7668 EPDTBInitTBID(tbid_kqnkb, "KQNKB");
7669 EPDTBInitTBID(tbid_kqnkr, "KQNKR");
7670 EPDTBInitTBID(tbid_kqnkq, "KQNKQ");
7671 EPDTBInitTBID(tbid_kqbkp, "KQBKP");
7672 EPDTBInitTBID(tbid_kqbkn, "KQBKN");
7673 EPDTBInitTBID(tbid_kqbkb, "KQBKB");
7674 EPDTBInitTBID(tbid_kqbkr, "KQBKR");
7675 EPDTBInitTBID(tbid_kqbkq, "KQBKQ");
7676 EPDTBInitTBID(tbid_kqrkp, "KQRKP");
7677 EPDTBInitTBID(tbid_kqrkn, "KQRKN");
7678 EPDTBInitTBID(tbid_kqrkb, "KQRKB");
7679 EPDTBInitTBID(tbid_kqrkr, "KQRKR");
7680 EPDTBInitTBID(tbid_kqrkq, "KQRKQ");
7681 EPDTBInitTBID(tbid_kqqkp, "KQQKP");
7682 EPDTBInitTBID(tbid_kqqkn, "KQQKN");
7683 EPDTBInitTBID(tbid_kqqkb, "KQQKB");
7684 EPDTBInitTBID(tbid_kqqkr, "KQQKR");
7685 EPDTBInitTBID(tbid_kqqkq, "KQQKQ");
7686 EPDTBInitTBID(tbid_kpppk, "KPPPK");
7687 EPDTBInitTBID(tbid_knppk, "KNPPK");
7688 EPDTBInitTBID(tbid_knnpk, "KNNPK");
7689 EPDTBInitTBID(tbid_knnnk, "KNNNK");
7690 EPDTBInitTBID(tbid_kbppk, "KBPPK");
7691 EPDTBInitTBID(tbid_kbnpk, "KBNPK");
7692 EPDTBInitTBID(tbid_kbnnk, "KBNNK");
7693 EPDTBInitTBID(tbid_kbbpk, "KBBPK");
7694 EPDTBInitTBID(tbid_kbbnk, "KBBNK");
7695 EPDTBInitTBID(tbid_kbbbk, "KBBBK");
7696 EPDTBInitTBID(tbid_krppk, "KRPPK");
7697 EPDTBInitTBID(tbid_krnpk, "KRNPK");
7698 EPDTBInitTBID(tbid_krnnk, "KRNNK");
7699 EPDTBInitTBID(tbid_krbpk, "KRBPK");
7700 EPDTBInitTBID(tbid_krbnk, "KRBNK");
7701 EPDTBInitTBID(tbid_krbbk, "KRBBK");
7702 EPDTBInitTBID(tbid_krrpk, "KRRPK");
7703 EPDTBInitTBID(tbid_krrnk, "KRRNK");
7704 EPDTBInitTBID(tbid_krrbk, "KRRBK");
7705 EPDTBInitTBID(tbid_krrrk, "KRRRK");
7706 EPDTBInitTBID(tbid_kqppk, "KQPPK");
7707 EPDTBInitTBID(tbid_kqnpk, "KQNPK");
7708 EPDTBInitTBID(tbid_kqnnk, "KQNNK");
7709 EPDTBInitTBID(tbid_kqbpk, "KQBPK");
7710 EPDTBInitTBID(tbid_kqbnk, "KQBNK");
7711 EPDTBInitTBID(tbid_kqbbk, "KQBBK");
7712 EPDTBInitTBID(tbid_kqrpk, "KQRPK");
7713 EPDTBInitTBID(tbid_kqrnk, "KQRNK");
7714 EPDTBInitTBID(tbid_kqrbk, "KQRBK");
7715 EPDTBInitTBID(tbid_kqrrk, "KQRRK");
7716 EPDTBInitTBID(tbid_kqqpk, "KQQPK");
7717 EPDTBInitTBID(tbid_kqqnk, "KQQNK");
7718 EPDTBInitTBID(tbid_kqqbk, "KQQBK");
7719 EPDTBInitTBID(tbid_kqqrk, "KQQRK");
7720 EPDTBInitTBID(tbid_kqqqk, "KQQQK");
7721 
7722 /* clear the file pointer cache vector */
7723 
7724 for (i = 0; i < tbcL; i++)
7725 	tbcv[i].tbc_inuse = 0;
7726 
7727 return;
7728 }
7729 
7730 /*--> EPDTBTerm: one time termination for the tablebase subsystem */
7731 static
7732 void
EPDTBTerm(void)7733 EPDTBTerm(void)
7734 {
7735 tbidT tbid;
7736 tbptrT tbptr;
7737 
7738 /* flush the file pointer cache vector */
7739 
7740 EPDTBCacheFlush();
7741 
7742 /* deallocate tablebase information vector entries */
7743 
7744 tbptr = tbbaseptr;
7745 for (tbid = 0; tbid < tbidL; tbid++)
7746 	{
7747 	EPDMemoryFree(tbptr->tb_name);
7748 	tbptr++;
7749 	};
7750 
7751 /* deallocate tablebase information vector */
7752 
7753 EPDMemoryFree(tbbaseptr);
7754 
7755 return;
7756 }
7757 
7758 /*--> EPDInit: one time initialization for EPD */
7759 nonstatic
7760 void
EPDInit(void)7761 EPDInit(void)
7762 {
7763 cpT cp;
7764 sqT sq;
7765 xsqT xsq;
7766 
7767 /* this sets up the current position */
7768 
7769 /* initialize ascii color conversion vector */
7770 
7771 asccv[c_w] = 'w';
7772 asccv[c_b] = 'b';
7773 
7774 /* initialize ascii piece conversion vector */
7775 
7776 ascpv[p_p] = 'P';
7777 ascpv[p_n] = 'N';
7778 ascpv[p_b] = 'B';
7779 ascpv[p_r] = 'R';
7780 ascpv[p_q] = 'Q';
7781 ascpv[p_k] = 'K';
7782 
7783 /* initialize ascii rank conversion vector */
7784 
7785 ascrv[rank_1] = '1';
7786 ascrv[rank_2] = '2';
7787 ascrv[rank_3] = '3';
7788 ascrv[rank_4] = '4';
7789 ascrv[rank_5] = '5';
7790 ascrv[rank_6] = '6';
7791 ascrv[rank_7] = '7';
7792 ascrv[rank_8] = '8';
7793 
7794 /* initialize ascii file conversion vector */
7795 
7796 ascfv[file_a] = 'a';
7797 ascfv[file_b] = 'b';
7798 ascfv[file_c] = 'c';
7799 ascfv[file_d] = 'd';
7800 ascfv[file_e] = 'e';
7801 ascfv[file_f] = 'f';
7802 ascfv[file_g] = 'g';
7803 ascfv[file_h] = 'h';
7804 
7805 /* initialize piece letter from special case move indicator */
7806 
7807 cv_p_scmvv[scmv_reg] = p_nil;
7808 cv_p_scmvv[scmv_epc] = p_nil;
7809 cv_p_scmvv[scmv_cks] = p_nil;
7810 cv_p_scmvv[scmv_cqs] = p_nil;
7811 cv_p_scmvv[scmv_ppn] = p_n;
7812 cv_p_scmvv[scmv_ppb] = p_b;
7813 cv_p_scmvv[scmv_ppr] = p_r;
7814 cv_p_scmvv[scmv_ppq] = p_q;
7815 
7816 /* initialize various color piece conversion arrays */
7817 
7818 for (cp = cp_wp; cp <= cp_wk; cp++)
7819 	cv_c_cpv[cp] = c_w;
7820 for (cp = cp_bp; cp <= cp_bk; cp++)
7821 	cv_c_cpv[cp] = c_b;
7822 cv_c_cpv[cp_v0] = c_v;
7823 cv_c_cpv[cp_x0] = cv_c_cpv[cp_x1] = cv_c_cpv[cp_x2] = c_x;
7824 
7825 cv_p_cpv[cp_wp] = cv_p_cpv[cp_bp] = p_p;
7826 cv_p_cpv[cp_wn] = cv_p_cpv[cp_bn] = p_n;
7827 cv_p_cpv[cp_wb] = cv_p_cpv[cp_bb] = p_b;
7828 cv_p_cpv[cp_wr] = cv_p_cpv[cp_br] = p_r;
7829 cv_p_cpv[cp_wq] = cv_p_cpv[cp_bq] = p_q;
7830 cv_p_cpv[cp_wk] = cv_p_cpv[cp_bk] = p_k;
7831 cv_p_cpv[cp_v0] = p_v;
7832 cv_p_cpv[cp_x0] = cv_p_cpv[cp_x1] = cv_p_cpv[cp_x2] = p_x;
7833 
7834 cv_cp_c_pv[c_w][p_p] = cp_wp;
7835 cv_cp_c_pv[c_w][p_n] = cp_wn;
7836 cv_cp_c_pv[c_w][p_b] = cp_wb;
7837 cv_cp_c_pv[c_w][p_r] = cp_wr;
7838 cv_cp_c_pv[c_w][p_q] = cp_wq;
7839 cv_cp_c_pv[c_w][p_k] = cp_wk;
7840 cv_cp_c_pv[c_b][p_p] = cp_bp;
7841 cv_cp_c_pv[c_b][p_n] = cp_bn;
7842 cv_cp_c_pv[c_b][p_b] = cp_bb;
7843 cv_cp_c_pv[c_b][p_r] = cp_br;
7844 cv_cp_c_pv[c_b][p_q] = cp_bq;
7845 cv_cp_c_pv[c_b][p_k] = cp_bk;
7846 
7847 inv_cv[c_w] = c_b;
7848 inv_cv[c_b] = c_w;
7849 
7850 /* initialize directional vectors */
7851 
7852 dvv[dx_0] = dv_0;
7853 dvv[dx_1] = dv_1;
7854 dvv[dx_2] = dv_2;
7855 dvv[dx_3] = dv_3;
7856 dvv[dx_4] = dv_4;
7857 dvv[dx_5] = dv_5;
7858 dvv[dx_6] = dv_6;
7859 dvv[dx_7] = dv_7;
7860 dvv[dx_8] = dv_8;
7861 dvv[dx_9] = dv_9;
7862 dvv[dx_a] = dv_a;
7863 dvv[dx_b] = dv_b;
7864 dvv[dx_c] = dv_c;
7865 dvv[dx_d] = dv_d;
7866 dvv[dx_e] = dv_e;
7867 dvv[dx_f] = dv_f;
7868 
7869 xdvv[dx_0] = xdv_0;
7870 xdvv[dx_1] = xdv_1;
7871 xdvv[dx_2] = xdv_2;
7872 xdvv[dx_3] = xdv_3;
7873 xdvv[dx_4] = xdv_4;
7874 xdvv[dx_5] = xdv_5;
7875 xdvv[dx_6] = xdv_6;
7876 xdvv[dx_7] = xdv_7;
7877 xdvv[dx_8] = xdv_8;
7878 xdvv[dx_9] = xdv_9;
7879 xdvv[dx_a] = xdv_a;
7880 xdvv[dx_b] = xdv_b;
7881 xdvv[dx_c] = xdv_c;
7882 xdvv[dx_d] = xdv_d;
7883 xdvv[dx_e] = xdv_e;
7884 xdvv[dx_f] = xdv_f;
7885 
7886 /* initialize the extended board */
7887 
7888 for (xsq = 0; xsq < xsqL; xsq++)
7889 	xb.xbv[xsq] = cp_x0;
7890 
7891 for (sq = sq_a1; sq <= sq_h8; sq++)
7892 	xb.xbv[map_xsq_sq(sq)] = cp_v0;
7893 
7894 /* initialize the standard opcode string vector */
7895 
7896 epdsostrv[epdso_acd        ] = "acd";
7897 epdsostrv[epdso_acn        ] = "acn";
7898 epdsostrv[epdso_acs        ] = "acs";
7899 epdsostrv[epdso_am         ] = "am";
7900 epdsostrv[epdso_bm         ] = "bm";
7901 epdsostrv[epdso_c0         ] = "c0";
7902 epdsostrv[epdso_c1         ] = "c1";
7903 epdsostrv[epdso_c2         ] = "c2";
7904 epdsostrv[epdso_c3         ] = "c3";
7905 epdsostrv[epdso_c4         ] = "c4";
7906 epdsostrv[epdso_c5         ] = "c5";
7907 epdsostrv[epdso_c6         ] = "c6";
7908 epdsostrv[epdso_c7         ] = "c7";
7909 epdsostrv[epdso_c8         ] = "c8";
7910 epdsostrv[epdso_c9         ] = "c9";
7911 epdsostrv[epdso_cc         ] = "cc";
7912 epdsostrv[epdso_ce         ] = "ce";
7913 epdsostrv[epdso_dm         ] = "dm";
7914 epdsostrv[epdso_draw_accept] = "draw_accept";
7915 epdsostrv[epdso_draw_claim ] = "draw_claim";
7916 epdsostrv[epdso_draw_offer ] = "draw_offer";
7917 epdsostrv[epdso_draw_reject] = "draw_reject";
7918 epdsostrv[epdso_eco        ] = "eco";
7919 epdsostrv[epdso_fmvn       ] = "fmvn";
7920 epdsostrv[epdso_hmvc       ] = "hmvc";
7921 epdsostrv[epdso_id         ] = "id";
7922 epdsostrv[epdso_nic        ] = "nic";
7923 epdsostrv[epdso_noop       ] = "noop";
7924 epdsostrv[epdso_pm         ] = "pm";
7925 epdsostrv[epdso_ptp        ] = "ptp";
7926 epdsostrv[epdso_pv         ] = "pv";
7927 epdsostrv[epdso_rc         ] = "rc";
7928 epdsostrv[epdso_refcom     ] = "refcom";
7929 epdsostrv[epdso_refreq     ] = "refreq";
7930 epdsostrv[epdso_resign     ] = "resign";
7931 epdsostrv[epdso_sm         ] = "sm";
7932 epdsostrv[epdso_sv         ] = "sv";
7933 epdsostrv[epdso_tcgs       ] = "tcgs";
7934 epdsostrv[epdso_tcri       ] = "tcri";
7935 epdsostrv[epdso_tcsi       ] = "tcsi";
7936 epdsostrv[epdso_ts         ] = "ts";
7937 epdsostrv[epdso_v0         ] = "v0";
7938 epdsostrv[epdso_v1         ] = "v1";
7939 epdsostrv[epdso_v2         ] = "v2";
7940 epdsostrv[epdso_v3         ] = "v3";
7941 epdsostrv[epdso_v4         ] = "v4";
7942 epdsostrv[epdso_v5         ] = "v5";
7943 epdsostrv[epdso_v6         ] = "v6";
7944 epdsostrv[epdso_v7         ] = "v7";
7945 epdsostrv[epdso_v8         ] = "v8";
7946 epdsostrv[epdso_v9         ] = "v9";
7947 
7948 /* set the EPD refcom operand strings */
7949 
7950 refcomstrv[refcom_conclude  ] = "conclude";
7951 refcomstrv[refcom_disconnect] = "disconnect";
7952 refcomstrv[refcom_execute   ] = "execute";
7953 refcomstrv[refcom_fault     ] = "fault";
7954 refcomstrv[refcom_inform    ] = "inform";
7955 refcomstrv[refcom_respond   ] = "respond";
7956 refcomstrv[refcom_reset     ] = "reset";
7957 
7958 /* set the EPD refreq operand strings */
7959 
7960 refreqstrv[refreq_fault   ] = "fault";
7961 refreqstrv[refreq_reply   ] = "reply";
7962 refreqstrv[refreq_sign_on ] = "sign_on";
7963 refreqstrv[refreq_sign_off] = "sign_off";
7964 
7965 /* set the PGN Seven Tag Roster names */
7966 
7967 pgnstrstrv[pgnstr_event ] = "Event";
7968 pgnstrstrv[pgnstr_site  ] = "Site";
7969 pgnstrstrv[pgnstr_date  ] = "Date";
7970 pgnstrstrv[pgnstr_round ] = "Round";
7971 pgnstrstrv[pgnstr_white ] = "White";
7972 pgnstrstrv[pgnstr_black ] = "Black";
7973 pgnstrstrv[pgnstr_result] = "Result";
7974 
7975 /* set the game termination indication marker vector */
7976 
7977 gtimstrv[gtim_w] = "1-0";
7978 gtimstrv[gtim_b] = "0-1";
7979 gtimstrv[gtim_d] = "1/2-1/2";
7980 gtimstrv[gtim_u] = "*";
7981 
7982 /* set the player name string vector */
7983 
7984 playerstrv[c_w] = "White";
7985 playerstrv[c_b] = "Black";
7986 
7987 /* clear the global game chain anchor pointers */
7988 
7989 head_gamptr = tail_gamptr = NULL;
7990 
7991 /* clear the token chain anchor pointers */
7992 
7993 head_tknptr = tail_tknptr = NULL;
7994 
7995 /* clear the current ply */
7996 
7997 ply = 0;
7998 
7999 /* allocate the move tree */
8000 
8001 treeptr = treebaseptr = (mptrT) EPDMemoryGrab(sizeof(mT) * treeL);
8002 
8003 /* allocate the tree stack entry stack */
8004 
8005 tseptr = tsebaseptr = (tseptrT) EPDMemoryGrab(sizeof(tseT) * pmhL);
8006 
8007 /* allocate the environment stack entry stack */
8008 
8009 eseptr = esebaseptr = (eseptrT) EPDMemoryGrab(sizeof(eseT) * pmhL);
8010 
8011 /* set the current position to be the initial array */
8012 
8013 EPDInitArray();
8014 
8015 /* generation */
8016 
8017 EPDGenMoves();
8018 
8019 /* initialize the tablebase subsystem */
8020 
8021 EPDTBInit();
8022 
8023 return;
8024 }
8025 
8026 /*--> EPDTerm: one time termination for EPD */
8027 nonstatic
8028 void
EPDTerm(void)8029 EPDTerm(void)
8030 {
8031 /* terminate the tablebase subsystem */
8032 
8033 EPDTBTerm();
8034 
8035 /* release any existing game chain */
8036 
8037 EPDReleaseGameChain();
8038 
8039 /* release any existing token chain */
8040 
8041 EPDReleaseTokenChain();
8042 
8043 /* deallocate various stacks */
8044 
8045 EPDMemoryFree(esebaseptr);
8046 EPDMemoryFree(tsebaseptr);
8047 EPDMemoryFree(treebaseptr);
8048 
8049 /* "Wanna see my sprocket collection?" */
8050 
8051 return;
8052 }
8053 
8054 /*<<< epd.c: EOF */
8055