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