Subversion Repositories Games.Chess Giants

Rev

Rev 154 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
33 pmbaty 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
 
108 pmbaty 122
/* the current environment stack entry */
33 pmbaty 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 */
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 */
156
nonstatic void EPDSwitchFault(charptrT s) {
157
  fprintf(stderr, "Switch fault detected.\n");
158
  EPDFatal(s);
159
  return;
160
}
161
 
162
/*--> EPDMemoryGrab: allocate memory */
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 */
173
nonstatic void EPDMemoryFree(voidptrT ptr) {
174
  if (ptr != NULL)
175
    free(ptr);
176
  return;
177
}
178
 
179
/*--> EPDStringGrab: allocate and copy a string */
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 */
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 */
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 */
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
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
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
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
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 */
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
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
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
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
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 */
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 */
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 */
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 */
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 */
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
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
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
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
945
nonstatic charptrT EPDFetchOpsym(epdsoT epdso) {
946
  return epdsostrv[epdso];
947
}
948
 
949
/*--> EPDCountOperands: count operands */
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 */
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
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
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
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 */
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 */
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
1252
nonstatic gtimT EPDGetGTIM(gamptrT gamptr) {
1253
  return gamptr->gam_gtim;
1254
}
1255
 
1256
/*--> EPDPutGTIM: put game termination marker indicator */
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 */
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 */
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 */
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 */
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);
156 pmbaty 1625
        bv[bi++] = (char) ch; // Pierre-Marie Baty -- added type cast
33 pmbaty 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 */
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 */
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
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
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
1792
void EPDSANEncodeFile(sqT sq) {
1793
  EPDSANEncodeChar(ascfv[map_file(sq)]);
1794
  return;
1795
}
1796
 
1797
/*--> EPDSANEncodeRank: encode SAN rank from square */
1798
static
1799
void EPDSANEncodeRank(sqT sq) {
1800
  EPDSANEncodeChar(ascrv[map_rank(sq)]);
1801
  return;
1802
}
1803
 
1804
/*--> EPDSANEncodeSq: encode SAN square */
1805
static
1806
void EPDSANEncodeSq(sqT sq) {
1807
  EPDSANEncodeFile(sq);
1808
  EPDSANEncodeRank(sq);
1809
  return;
1810
}
1811
 
1812
/*--> EPDSANEncodeCI: encode an appropriate capture indicator */
1813
static
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
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 */
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 */
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) */
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) */
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 */
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 */
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 */
2338
static siT EPDWhiteAttacks(sqT sq) {
2339
  return EPDAttack(c_w, sq);
2340
}
2341
 
2342
/*--> EPDBlackAttacks: check if White attacks a square */
2343
static siT EPDBlackAttacks(sqT sq) {
2344
  return EPDAttack(c_b, sq);
2345
}
2346
 
2347
/*--> EPDTestAKIC: test for active king in check */
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 */
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
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 */
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
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 */
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 */
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
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 */
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
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 */
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 */
3141
nonstatic void EPDRetractAll(void) {
3142
  while (ply > 0)
3143
    EPDRetractUpdate();
3144
  return;
3145
}
3146
 
3147
/*--> EPDCollapse: collapse the played move stack */
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 */
3162
nonstatic void EPDReset(void) {
3163
  EPDCollapse();
3164
  EPDInitArray();
3165
  return;
3166
}
3167
 
3168
/*--> EPDMLExec: execute the current move list */
3169
static
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
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
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
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
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 */
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 */
3335
nonstatic siT EPDFetchMoveCount(void) {
3336
  return tse.tse_count;
3337
}
3338
 
3339
/*--> EPDFetchMove: fetch the nth move */
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 */
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 */
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
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
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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);
156 pmbaty 3905
        acs = (liT) (time(NULL) - start_time); // Pierre-Marie Baty -- added type cast
33 pmbaty 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 */
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);
156 pmbaty 3976
      length = (siT) strlen(tv); // Pierre-Marie Baty -- added type cast
33 pmbaty 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, "...");
156 pmbaty 3995
      length = (siT) strlen(tv); // Pierre-Marie Baty -- added type cast
33 pmbaty 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);
156 pmbaty 4013
    length = (siT) strlen(san); // Pierre-Marie Baty -- added type cast
33 pmbaty 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]);
156 pmbaty 4032
  length = (siT) strlen(tv); // Pierre-Marie Baty -- added type cast
33 pmbaty 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 */
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 */
4071
nonstatic charptrT EPDPGNFetchTagName(pgnstrT pgnstr) {
4072
  return pgnstrstrv[pgnstr];
4073
}
4074
 
4075
/*--> EPDPGNGetSTR: return a string from the Seven Tag Roster */
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 */
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 */
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 */
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) */
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 */
4137
nonstatic charptrT EPDFetchRefcomStr(refcomT refcom) {
4138
  return refcomstrv[refcom];
4139
}
4140
 
4141
/*--> EPDFetchRefreqStr: return  pointer of indicated refreq string */
4142
nonstatic charptrT EPDFetchRefreqStr(refreqT refreq) {
4143
  return refreqstrv[refreq];
4144
}
4145
 
4146
/*--> EPDFetchRefcomIndex: return a referee command index */
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 */
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 */
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 */
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 */
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 */