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