/*>>> epd.c: Extended Position Description routines */ /* Revised: 1996.06.23 */ /* Copyright (C) 1996 by Steven J. Edwards (sje@mv.mv.com) All rights reserved. This code may be freely redistibuted and used by both research and commerical applications. No warranty exists. */ /* Everything in this source file is independent of the host program, as are the prototypes in the epd.h include file. *** Not quite true---relies on tb_path from the host program Requests for changes and additions should be communicated to the author via the e-mail address given above. */ /* This file was originally prepared on an Apple Macintosh using the Metrowerks CodeWarrior 6 ANSI C compiler. Tabs are set at every four columns. Further testing and development was performed on a generic PC running Linux 1.3.20 and using the gcc 2.7.0 compiler. */ /* system includes */ #include #include #include #include #include /* EPD definitions (host independent) */ extern char *tb_path; #include "epddefs.h" /* EPD routine prototypes (host independent) */ #include "epd.h" /* ASCII character constants */ #define ascii_nul ((char) 0x00) #define ascii_sp ((char) 0x20) /* tree limit; adjust according to memory availability */ #define treeL 16384 /* tree overrun safety margin */ #define treemarginL 256 /* played moves history limit; adjust according to memory availability */ #define pmhL 512 /* data flows (input and output) */ #define flowL 2 /* character case mapping */ #define map_lower(ch) (isupper((ch)) ? tolower((ch)) : (ch)) #define map_upper(ch) (islower((ch)) ? toupper((ch)) : (ch)) /* identifier character check */ #define IdentChar(ch) (isalpha((ch)) || isdigit((ch)) || ((ch) == '_')) /* vacancy check */ #define Vacant(sq) (EPDboard.rbv[(sq)] == cp_v0) /* token record type (for token chain) */ typedef struct tknS { charptrT tkn_str; /* allocated token string value */ struct tknS *tkn_prev; /* previous record */ struct tknS *tkn_next; /* next record */ } tknT, *tknptrT; /* tree stack entry record type */ typedef struct tseS { siT tse_count; /* entry count for this level */ mptrT tse_base; /* first move in moveset */ mptrT tse_curr; /* current move of interest in moveset */ } tseT, *tseptrT; /* color to move strings */ static charptrT ctmext_strv[rcL]; /* global game chain anchors */ static gamptrT head_gamptr; static gamptrT tail_gamptr; /* EPD standard opcode mnemonics */ static charptrT epdsostrv[epdsoL]; /* EPD refcom operand strings */ static charptrT refcomstrv[refcomL]; /* EPD refreq operand strings */ static charptrT refreqstrv[refreqL]; /* PGN Seven Tag Roster names */ static charptrT pgnstrstrv[pgnstrL]; /* game termination indication marker strings */ static charptrT gtimstrv[gtimL]; /* player name strings */ static charptrT playerstrv[rcL]; /* character conversion vectors (colors and pieces) */ static char asccv[rcL]; static char ascpv[rpL]; /* character conversion vectors (ranks and files) */ static char ascrv[rankL]; static char ascfv[fileL]; /* promotion piece from special case move code coversion vector */ static pT cv_p_scmvv[scmvL]; /* various color and piece conversion vectors */ static cpT cv_cp_c_pv[rcL][rpL]; static cT cv_c_cpv[cpL]; static pT cv_p_cpv[cpL]; static cT inv_cv[rcL]; /* direction vectors */ static dvT dvv[dxL]; static xdvT xdvv[dxL]; /* extension board (border detection) */ static xbT xb; /* maps */ static siT flank_mapv[sqL]; static siT triangle_mapv[sqL]; /* token chain anchors */ static tknptrT head_tknptr; static tknptrT tail_tknptr; /* local SAN vector and its index */ static sanT lsan; static siT lsani; /* census vectors */ static siT count_cv[rcL]; static siT count_cpv[rcL][rpL]; /* the current board */ static rbT EPDboard; /* the current environment stack entry */ static eseT ese; /* the current tree stack entry */ static tseT tse; /* the master ply index */ static siT ply; /* the base of the move tree and its current pointer */ static mptrT treebaseptr; static mptrT treeptr; /* the base of the tree stack entry stack and its current pointer */ static tseptrT tsebaseptr; static tseptrT tseptr; /* base of the environment stack and its current pointer */ static eseptrT esebaseptr; static eseptrT eseptr; /* tablebase information record vector storage base */ static tbptrT tbbaseptr; /* tablebase file pointer cache vector */ static tbcT tbcv[tbcL]; /* return area for board data */ static rbT ret_rb; /* return area for move data */ static mT ret_m; /*--> EPDFatal: emit fatal diagnostic and quit */ nonstatic void EPDFatal(charptrT s) { fprintf(stderr, "EPD Fatal error: %s.\n", s); exit(1); } /*--> EPDSwitchFault: emit switch fault diagnostic and quit */ nonstatic void EPDSwitchFault(charptrT s) { fprintf(stderr, "Switch fault detected.\n"); EPDFatal(s); return; } /*--> EPDMemoryGrab: allocate memory */ nonstatic voidptrT EPDMemoryGrab(liT n) { voidptrT ptr; ptr = (voidptrT) malloc((n == 0) ? 1 : n); if (ptr == NULL) EPDFatal("EPDMemoryGrab"); return (ptr); } /*--> EPDMemoryFree: deallocate memory */ nonstatic void EPDMemoryFree(voidptrT ptr) { if (ptr != NULL) free(ptr); return; } /*--> EPDStringGrab: allocate and copy a string */ nonstatic charptrT EPDStringGrab(charptrT s) { charptrT ptr; ptr = (charptrT) EPDMemoryGrab(strlen(s) + 1); strcpy(ptr, s); return (ptr); } /*--> EPDStringFree: deallocate a string */ nonstatic void EPDStringFree(charptrT s) { EPDMemoryFree(s); return; } /*--> EPDStringAppendChar: append a character to a string */ nonstatic charptrT EPDStringAppendChar(charptrT s, char c) { charptrT ptr; liT length; /* the first argument is deallocated */ length = strlen(s); ptr = (charptrT) EPDMemoryGrab(length + 2); strcpy(ptr, s); EPDMemoryFree(s); *(ptr + length) = c; *(ptr + length + 1) = ascii_nul; return (ptr); } /*--> EPDStringAppendStr: append a string to a string */ nonstatic charptrT EPDStringAppendStr(charptrT s0, charptrT s1) { charptrT ptr; liT length; /* the first argument is deallocated */ length = strlen(s0) + strlen(s1); ptr = (charptrT) EPDMemoryGrab(length + 1); strcpy(ptr, s0); strcat(ptr, s1); EPDMemoryFree(s0); return (ptr); } /*--> EPDMapFromDuration: convert from duration to seconds */ nonstatic liT EPDMapFromDuration(charptrT s) { liT seconds; siT scs, mns, hrs, dys; sscanf(s, "%04hd:%02hd:%02hd:%02hd", &dys, &hrs, &mns, &scs); seconds = ((liT) dys * 86400) + ((liT) hrs * 3600) + ((liT) mns * 60) + (liT) scs; return (seconds); } /*--> EPDMapToDuration: convert from seconds to duration */ nonstatic charptrT EPDMapToDuration(liT seconds) { charptrT s; siT scs, mns, hrs, dys; s = (charptrT) EPDMemoryGrab(durationL); scs = seconds % 60; mns = (seconds / 60) % 60; hrs = (seconds / 3600) % 24; dys = (seconds / 86400) % 10000; sprintf(s, "%04hd:%02hd:%02hd:%02hd", dys, hrs, mns, scs); return (s); } /*--> EPDNewGPM: allocate and initialize a new GPM record */ static gpmptrT EPDNewGPM(mptrT mptr) { gpmptrT gpmptr; cT c; sqT sq; cpT cp0, cp1; gpmptr = (gpmptrT) EPDMemoryGrab(sizeof(gpmT)); gpmptr->gpm_m = *mptr; gpmptr->gpm_ese.ese_actc = ese.ese_actc; gpmptr->gpm_ese.ese_cast = ese.ese_cast; gpmptr->gpm_ese.ese_epsq = ese.ese_epsq; gpmptr->gpm_ese.ese_hmvc = ese.ese_hmvc; gpmptr->gpm_ese.ese_fmvn = ese.ese_fmvn; for (c = c_w; c <= c_b; c++) gpmptr->gpm_ese.ese_ksqv[c] = ese.ese_ksqv[c]; for (sq = sq_a1; sq <= sq_h8; sq += 2) { cp0 = EPDboard.rbv[sq + 0]; cp1 = EPDboard.rbv[sq + 1]; gpmptr->gpm_nbv[sq >> 1] = ((cp1 << nybbW) | cp0); }; gpmptr->gpm_prev = gpmptr->gpm_next = NULL; return (gpmptr); } /*--> EPDReleaseGPM: release a GPM record */ static void EPDReleaseGPM(gpmptrT gpmptr) { if (gpmptr != NULL) EPDMemoryFree(gpmptr); return; } /*--> EPDAppendGPM: append a GPM record to a game */ static void EPDAppendGPM(gamptrT gamptr, gpmptrT gpmptr) { if (gamptr->gam_tailgpm == NULL) gamptr->gam_headgpm = gpmptr; else gamptr->gam_tailgpm->gpm_next = gpmptr; gpmptr->gpm_prev = gamptr->gam_tailgpm; gpmptr->gpm_next = NULL; gamptr->gam_tailgpm = gpmptr; return; } /*--> EPDUnthreadGPM: unthread a GPM record from a game */ static void EPDUnthreadGPM(gamptrT gamptr, gpmptrT gpmptr) { if (gpmptr->gpm_prev == NULL) gamptr->gam_headgpm = gpmptr->gpm_next; else gpmptr->gpm_prev->gpm_next = gpmptr->gpm_next; if (gpmptr->gpm_next == NULL) gamptr->gam_tailgpm = gpmptr->gpm_prev; else gpmptr->gpm_next->gpm_prev = gpmptr->gpm_prev; return; } /*--> EPDReleaseGPMoveChain: release the game played moves chain */ static void EPDReleaseGPMoveChain(gamptrT gamptr) { gpmptrT gpmptr; while (gamptr->gam_headgpm != NULL) { gpmptr = gamptr->gam_tailgpm; EPDUnthreadGPM(gamptr, gpmptr); EPDReleaseGPM(gpmptr); }; return; } /*--> EPDNewGAM: allocate and initialize a new GAM record */ static gamptrT EPDNewGAM(void) { gamptrT gamptr; pgnstrT pgnstr; gamptr = (gamptrT) EPDMemoryGrab(sizeof(gamT)); for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++) gamptr->gam_strv[pgnstr] = EPDStringGrab(""); gamptr->gam_gtim = gtim_u; gamptr->gam_headgpm = gamptr->gam_tailgpm = NULL; gamptr->gam_prev = gamptr->gam_next = NULL; return (gamptr); } /*--> EPDReleaseGAM: release a GAM record */ static void EPDReleaseGAM(gamptrT gamptr) { pgnstrT pgnstr; if (gamptr != NULL) { for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++) if (gamptr->gam_strv[pgnstr] != NULL) EPDMemoryFree(gamptr->gam_strv[pgnstr]); EPDReleaseGPMoveChain(gamptr); EPDMemoryFree(gamptr); }; return; } /*--> EPDAppendGAM: append a GAM record to the game chain */ static void EPDAppendGAM(gamptrT gamptr) { if (tail_gamptr == NULL) head_gamptr = gamptr; else tail_gamptr->gam_next = gamptr; gamptr->gam_prev = tail_gamptr; gamptr->gam_next = NULL; tail_gamptr = gamptr; return; } /*--> EPDUnthreadGAM: unthread a GAM record from the game chain */ static void EPDUnthreadGAM(gamptrT gamptr) { if (gamptr->gam_prev == NULL) head_gamptr = gamptr->gam_next; else gamptr->gam_prev->gam_next = gamptr->gam_next; if (gamptr->gam_next == NULL) tail_gamptr = gamptr->gam_prev; else gamptr->gam_next->gam_prev = gamptr->gam_prev; return; } /*--> EPDReleaseGameChain: release the game chain */ static void EPDReleaseGameChain(void) { gamptrT gamptr; while (head_gamptr != NULL) { gamptr = tail_gamptr; EPDUnthreadGAM(gamptr); EPDReleaseGAM(gamptr); }; return; } /*--> EPDGamePlyCount: return ply count of a game */ static siT EPDGamePlyCount(gamptrT gamptr) { siT count; gpmptrT gpmptr; count = 0; gpmptr = gamptr->gam_headgpm; while (gpmptr != NULL) { count++; gpmptr = gpmptr->gpm_next; }; return (count); } /*--> EPDGameOpen: create/open a new game structure */ nonstatic gamptrT EPDGameOpen(void) { gamptrT gamptr; gamptr = EPDNewGAM(); EPDAppendGAM(gamptr); return (gamptr); } /*--> EPDGameClose: close/destroy a game structure */ nonstatic void EPDGameClose(gamptrT gamptr) { if (gamptr != NULL) { EPDUnthreadGAM(gamptr); EPDReleaseGAM(gamptr); }; return; } /*--> EPDGameAppendMove: append a move to a game structure */ nonstatic void EPDGameAppendMove(gamptrT gamptr, mptrT mptr) { gpmptrT gpmptr; gpmptr = EPDNewGPM(mptr); EPDAppendGPM(gamptr, gpmptr); return; } /*--> EPDNewTKN: allocate and initialize a new TKN record */ static tknptrT EPDNewTKN(charptrT s) { tknptrT tknptr; tknptr = (tknptrT) EPDMemoryGrab(sizeof(tknT)); tknptr->tkn_str = EPDStringGrab(s); tknptr->tkn_prev = tknptr->tkn_next = NULL; return (tknptr); } /*--> EPDReleaseTKN: release a TKN record */ static void EPDReleaseTKN(tknptrT tknptr) { if (tknptr != NULL) { if (tknptr->tkn_str != NULL) EPDMemoryFree(tknptr->tkn_str); EPDMemoryFree(tknptr); }; return; } /*--> EPDAppendTKN: append a TKN record to the token chain */ static void EPDAppendTKN(tknptrT tknptr) { if (tail_tknptr == NULL) head_tknptr = tknptr; else tail_tknptr->tkn_next = tknptr; tknptr->tkn_prev = tail_tknptr; tknptr->tkn_next = NULL; tail_tknptr = tknptr; return; } /*--> EPDUnthreadTKN: unthread a TKN record from the token chain */ static void EPDUnthreadTKN(tknptrT tknptr) { if (tknptr->tkn_prev == NULL) head_tknptr = tknptr->tkn_next; else tknptr->tkn_prev->tkn_next = tknptr->tkn_next; if (tknptr->tkn_next == NULL) tail_tknptr = tknptr->tkn_prev; else tknptr->tkn_next->tkn_prev = tknptr->tkn_prev; return; } /*--> EPDReleaseTokenChain: release the token chain */ static void EPDReleaseTokenChain(void) { tknptrT tknptr; while (head_tknptr != NULL) { tknptr = tail_tknptr; EPDUnthreadTKN(tknptr); EPDReleaseTKN(tknptr); }; return; } /*--> EPDTokenize: create the token chain */ nonstatic void EPDTokenize(charptrT s) { siT i; char c; tknptrT tknptr; charptrT str; /* first, release any existing chain */ EPDReleaseTokenChain(); /* scan the input until end of string */ i = 0; c = *(s + i++); while (c != ascii_nul) { /* skip leading whitespace */ while ((c != ascii_nul) && isspace(c)) c = *(s + i++); /* if not at end of string, then a token has started */ if (c != ascii_nul) { str = EPDStringGrab(""); while ((c != ascii_nul) && !isspace(c)) { str = EPDStringAppendChar(str, c); c = *(s + i++); }; tknptr = EPDNewTKN(str); EPDAppendTKN(tknptr); EPDMemoryFree(str); }; }; return; } /*--> EPDTokenCount: count the tokens in the token chain */ nonstatic siT EPDTokenCount(void) { siT n; tknptrT tknptr; n = 0; tknptr = head_tknptr; while (tknptr != NULL) { n++; tknptr = tknptr->tkn_next; }; return (n); } /*--> EPDTokenFetch: fetch n-th (zero origin) token from the token chain */ nonstatic charptrT EPDTokenFetch(siT n) { charptrT s; siT i; tknptrT tknptr; i = 0; tknptr = head_tknptr; while ((tknptr != NULL) && (i < n)) { i++; tknptr = tknptr->tkn_next; }; if (tknptr == NULL) s = NULL; else s = tknptr->tkn_str; return (s); } /*--> EPDCICharEqual: test for case independent character equality */ nonstatic siT EPDCICharEqual(char ch0, char ch1) { siT flag; if (map_lower(ch0) == map_lower(ch1)) flag = 1; else flag = 0; return (flag); } /*--> EPDPieceFromCP: fetch piece from color-piece */ nonstatic pT EPDPieceFromCP(cpT cp) { pT p; p = cv_p_cpv[cp]; return (p); } /*--> EPDCheckPiece: test if a character is a piece letter */ nonstatic siT EPDCheckPiece(char ch) { siT flag; pT p; flag = 0; p = p_p; while (!flag && (p <= p_k)) if (EPDCICharEqual(ch, ascpv[p])) flag = 1; else p++; return (flag); } /*--> EPDEvaluatePiece: evaluate a piece letter character */ nonstatic pT EPDEvaluatePiece(char ch) { pT p; siT flag; flag = 0; p = p_p; while (!flag && (p <= p_k)) if (EPDCICharEqual(ch, ascpv[p])) flag = 1; else p++; if (!flag) p = p_nil; return (p); } /*--> EPDCheckColor: test if a character is a color letter */ nonstatic siT EPDCheckColor(char ch) { siT flag; cT c; flag = 0; c = c_w; while (!flag && (c <= c_b)) if (EPDCICharEqual(ch, asccv[c])) flag = 1; else c++; return (flag); } /*--> EPDEvaluateColor: evaluate a color letter character */ nonstatic cT EPDEvaluateColor(char ch) { cT c; siT flag; flag = 0; c = c_w; while (!flag && (c <= c_b)) if (EPDCICharEqual(ch, asccv[c])) flag = 1; else c++; if (!flag) c = c_nil; return (c); } /*--> EPDCheckRank: test if a character is a rank character */ nonstatic siT EPDCheckRank(char ch) { siT flag; rankT rank; flag = 0; rank = rank_1; while (!flag && (rank <= rank_8)) if (EPDCICharEqual(ch, ascrv[rank])) flag = 1; else rank++; return (flag); } /*--> EPDEvaluateRank: evaluate a color rank character */ nonstatic rankT EPDEvaluateRank(char ch) { rankT rank; siT flag; flag = 0; rank = rank_1; while (!flag && (rank <= rank_8)) if (EPDCICharEqual(ch, ascrv[rank])) flag = 1; else rank++; if (!flag) rank = rank_nil; return (rank); } /*--> EPDCheckFile: test if a character is a file character */ nonstatic siT EPDCheckFile(char ch) { siT flag; fileT file; flag = 0; file = file_a; while (!flag && (file <= file_h)) if (EPDCICharEqual(ch, ascfv[file])) flag = 1; else file++; return (flag); } /*--> EPDEvaluateFile: evaluate a color file character */ nonstatic rankT EPDEvaluateFile(char ch) { fileT file; siT flag; flag = 0; file = file_a; while (!flag && (file <= file_h)) if (EPDCICharEqual(ch, ascfv[file])) flag = 1; else file++; if (!flag) file = file_nil; return (file); } /*--> EPDNewEOV: allocate a new EOV record */ nonstatic eovptrT EPDNewEOV(void) { eovptrT eovptr; eovptr = (eovptrT) EPDMemoryGrab(sizeof(eovT)); eovptr->eov_eob = eob_nil; eovptr->eov_str = NULL; eovptr->eov_prev = eovptr->eov_next = NULL; return (eovptr); } /*--> EPDReleaseEOV: release an EOV record */ nonstatic void EPDReleaseEOV(eovptrT eovptr) { if (eovptr != NULL) { if (eovptr->eov_str != NULL) EPDMemoryFree(eovptr->eov_str); EPDMemoryFree(eovptr); }; return; } /*--> EPDAppendEOV: append an EOV record */ nonstatic void EPDAppendEOV(eopptrT eopptr, eovptrT eovptr) { if (eopptr->eop_taileov == NULL) eopptr->eop_headeov = eovptr; else eopptr->eop_taileov->eov_next = eovptr; eovptr->eov_prev = eopptr->eop_taileov; eovptr->eov_next = NULL; eopptr->eop_taileov = eovptr; return; } /*--> EPDUnthreadEOV: unthread an EOV record */ static void EPDUnthreadEOV(eopptrT eopptr, eovptrT eovptr) { if (eovptr->eov_prev == NULL) eopptr->eop_headeov = eovptr->eov_next; else eovptr->eov_prev->eov_next = eovptr->eov_next; if (eovptr->eov_next == NULL) eopptr->eop_taileov = eovptr->eov_prev; else eovptr->eov_next->eov_prev = eovptr->eov_prev; return; } /*--> EPDCreateEOVStr: create a new EOV record with a string value */ nonstatic eovptrT EPDCreateEOVStr(charptrT str) { eovptrT eovptr; eovptr = EPDNewEOV(); eovptr->eov_eob = eob_string; eovptr->eov_str = EPDStringGrab(str); return (eovptr); } /*--> EPDCreateEOVSym: create a new EOV record with a symbol value */ nonstatic eovptrT EPDCreateEOVSym(charptrT sym) { eovptrT eovptr; eovptr = EPDNewEOV(); eovptr->eov_eob = eob_symbol; eovptr->eov_str = EPDStringGrab(sym); return (eovptr); } /*--> EPDCreateEOVInt: create a new EOV record with an integer value */ nonstatic eovptrT EPDCreateEOVInt(liT lval) { eovptrT eovptr; char tv[tL]; sprintf(tv, "%ld", lval); eovptr = EPDNewEOV(); eovptr->eov_eob = eob_symbol; eovptr->eov_str = EPDStringGrab(tv); return (eovptr); } /*--> EPDLocateEOV: try to locate 1st EOV record with given string value */ nonstatic eovptrT EPDLocateEOV(eopptrT eopptr, charptrT strval) { eovptrT eovptr; siT flag; flag = 0; eovptr = eopptr->eop_headeov; while (!flag && (eovptr != NULL)) if (strcmp(strval, eovptr->eov_str) == 0) flag = 1; else eovptr = eovptr->eov_next; if (!flag) eovptr = NULL; return (eovptr); } /*--> EPDCountEOV: count EOV entries in EOP */ nonstatic siT EPDCountEOV(eopptrT eopptr) { eovptrT eovptr; siT count; count = 0; eovptr = eopptr->eop_headeov; while (eovptr != NULL) { count++; eovptr = eovptr->eov_next; }; return (count); } /*--> EPDReplaceEOVStr: replace EOV string value with given string value */ nonstatic void EPDReplaceEOVStr(eovptrT eovptr, charptrT str) { if (eovptr->eov_str != NULL) { EPDMemoryFree(eovptr->eov_str); eovptr->eov_str = NULL; }; if (str != NULL) eovptr->eov_str = EPDStringGrab(str); return; } /*--> EPDNewEOP: allocate a new EOP record */ nonstatic eopptrT EPDNewEOP(void) { eopptrT eopptr; eopptr = (eopptrT) EPDMemoryGrab(sizeof(eopT)); eopptr->eop_opsym = NULL; eopptr->eop_headeov = eopptr->eop_taileov = NULL; eopptr->eop_prev = eopptr->eop_next = NULL; return (eopptr); } /*--> EPDReleaseEOP: release an EOP record */ nonstatic void EPDReleaseEOP(eopptrT eopptr) { eovptrT eovptr0, eovptr1; if (eopptr != NULL) { if (eopptr->eop_opsym != NULL) EPDMemoryFree(eopptr->eop_opsym); eovptr0 = eopptr->eop_headeov; while (eovptr0 != NULL) { eovptr1 = eovptr0->eov_next; EPDUnthreadEOV(eopptr, eovptr0); EPDReleaseEOV(eovptr0); eovptr0 = eovptr1; }; EPDMemoryFree(eopptr); }; return; } /*--> EPDAppendEOP: append an EOP record */ nonstatic void EPDAppendEOP(epdptrT epdptr, eopptrT eopptr) { if (epdptr->epd_taileop == NULL) epdptr->epd_headeop = eopptr; else epdptr->epd_taileop->eop_next = eopptr; eopptr->eop_prev = epdptr->epd_taileop; eopptr->eop_next = NULL; epdptr->epd_taileop = eopptr; return; } /*--> EPDUnthreadEOP: unthread an EOP record */ static void EPDUnthreadEOP(epdptrT epdptr, eopptrT eopptr) { if (eopptr->eop_prev == NULL) epdptr->epd_headeop = eopptr->eop_next; else eopptr->eop_prev->eop_next = eopptr->eop_next; if (eopptr->eop_next == NULL) epdptr->epd_taileop = eopptr->eop_prev; else eopptr->eop_next->eop_prev = eopptr->eop_prev; return; } /*--> EPDCreateEOP: create a new EOP record with opsym */ nonstatic eopptrT EPDCreateEOP(charptrT opsym) { eopptrT eopptr; eopptr = EPDNewEOP(); eopptr->eop_opsym = EPDStringGrab(opsym); return (eopptr); } /*--> EPDCreateEOPCode: create a new EOP record using opsym index */ nonstatic eopptrT EPDCreateEOPCode(epdsoT epdso) { eopptrT eopptr; eopptr = EPDCreateEOP(EPDFetchOpsym(epdso)); return (eopptr); } /*--> EPDLocateEOP: attempt to locate EOP record with given opsym */ nonstatic eopptrT EPDLocateEOP(epdptrT epdptr, charptrT opsym) { eopptrT eopptr; siT flag; flag = 0; eopptr = epdptr->epd_headeop; while (!flag && (eopptr != NULL)) if (strcmp(opsym, eopptr->eop_opsym) == 0) flag = 1; else eopptr = eopptr->eop_next; if (!flag) eopptr = NULL; return (eopptr); } /*--> EPDLocateEOPCode: attempt to locate EOP record with given code */ nonstatic eopptrT EPDLocateEOPCode(epdptrT epdptr, epdsoT epdso) { return (EPDLocateEOP(epdptr, epdsostrv[epdso])); } /*--> EPDCountEOP: count EOP entries in EPD */ nonstatic siT EPDCountEOP(epdptrT epdptr) { eopptrT eopptr; siT count; count = 0; eopptr = epdptr->epd_headeop; while (eopptr != NULL) { count++; eopptr = eopptr->eop_next; }; return (count); } /*--> EPDDropIfLocEOP: try to locate/drop EOP record with given opsym */ nonstatic void EPDDropIfLocEOP(epdptrT epdptr, charptrT opsym) { eopptrT eopptr; eopptr = EPDLocateEOP(epdptr, opsym); if (eopptr != NULL) { EPDUnthreadEOP(epdptr, eopptr); EPDReleaseEOP(eopptr); }; return; } /*--> EPDDropIfLocEOPCode: try to locate/drop EOP record with given code */ nonstatic void EPDDropIfLocEOPCode(epdptrT epdptr, epdsoT epdso) { eopptrT eopptr; eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso]); if (eopptr != NULL) { EPDUnthreadEOP(epdptr, eopptr); EPDReleaseEOP(eopptr); }; return; } /*--> EPDAddOpInt: add a single integer operand operation */ nonstatic void EPDAddOpInt(epdptrT epdptr, epdsoT epdso, liT val) { eopptrT eopptr; eovptrT eovptr; eovptr = EPDCreateEOVInt(val); eopptr = EPDCreateEOPCode(epdso); EPDAppendEOV(eopptr, eovptr); EPDDropIfLocEOPCode(epdptr, epdso); EPDAppendEOP(epdptr, eopptr); return; } /*--> EPDAddOpStr: add a single string operand operation */ nonstatic void EPDAddOpStr(epdptrT epdptr, epdsoT epdso, charptrT s) { eopptrT eopptr; eovptrT eovptr; eovptr = EPDCreateEOVStr(s); eopptr = EPDCreateEOPCode(epdso); EPDAppendEOV(eopptr, eovptr); EPDDropIfLocEOPCode(epdptr, epdso); EPDAppendEOP(epdptr, eopptr); return; } /*--> EPDAddOpSym: add a single symbol operand operation */ nonstatic void EPDAddOpSym(epdptrT epdptr, epdsoT epdso, charptrT s) { eopptrT eopptr; eovptrT eovptr; eovptr = EPDCreateEOVSym(s); eopptr = EPDCreateEOPCode(epdso); EPDAppendEOV(eopptr, eovptr); EPDDropIfLocEOPCode(epdptr, epdso); EPDAppendEOP(epdptr, eopptr); return; } /*--> EPDNewEPD: allocate a new EPD record */ nonstatic epdptrT EPDNewEPD(void) { epdptrT epdptr; siT i; epdptr = (epdptrT) EPDMemoryGrab(sizeof(epdT)); for (i = 0; i < nbL; i++) epdptr->epd_nbv[i] = ((cp_v0 << nybbW) | cp_v0); epdptr->epd_actc = c_v; epdptr->epd_cast = 0; epdptr->epd_epsq = sq_nil; epdptr->epd_headeop = epdptr->epd_taileop = NULL; return (epdptr); } /*--> EPDReleaseOperations: release EPD operation list */ nonstatic void EPDReleaseOperations(epdptrT epdptr) { eopptrT eopptr0, eopptr1; if (epdptr != NULL) { eopptr0 = epdptr->epd_headeop; while (eopptr0 != NULL) { eopptr1 = eopptr0->eop_next; EPDUnthreadEOP(epdptr, eopptr0); EPDReleaseEOP(eopptr0); eopptr0 = eopptr1; }; epdptr->epd_headeop = NULL; epdptr->epd_taileop = NULL; }; return; } /*--> EPDReleaseEPD: release an EPD record */ nonstatic void EPDReleaseEPD(epdptrT epdptr) { if (epdptr != NULL) { EPDReleaseOperations(epdptr); EPDMemoryFree(epdptr); }; return; } /*--> EPDFetchOpsym: return a pointer to the indicated mnemonic */ nonstatic charptrT EPDFetchOpsym(epdsoT epdso) { return (epdsostrv[epdso]); } /*--> EPDCountOperands: count operands */ static siT EPDCountOperands(eopptrT eopptr) { siT count; eovptrT eovptr; count = 0; eovptr = eopptr->eop_headeov; while (eovptr != NULL) { count++; eovptr = eovptr->eov_next; }; return (count); } /*--> EPDCountOperations: count operations */ static siT EPDCountOperations(epdptrT epdptr) { siT count; eopptrT eopptr; count = 0; eopptr = epdptr->epd_headeop; while (eopptr != NULL) { count++; eopptr = eopptr->eop_next; }; return (count); } /*--> EPDSortOperands: sort operands according to string value */ static void EPDSortOperands(eopptrT eopptr) { siT count; siT pass, flag; eovptrT ptr0, ptr1, ptr2, ptr3; count = EPDCountOperands(eopptr); if (count > 1) { flag = 1; pass = 0; while (flag && (pass < (count - 1))) { flag = 0; ptr0 = eopptr->eop_headeov; ptr1 = ptr0->eov_next; while (ptr1 != NULL) { if (strcmp(ptr0->eov_str, ptr1->eov_str) > 0) { flag = 1; ptr2 = ptr0->eov_prev; ptr3 = ptr1->eov_next; ptr0->eov_prev = ptr1; ptr0->eov_next = ptr3; ptr1->eov_prev = ptr2; ptr1->eov_next = ptr0; if (ptr2 == NULL) eopptr->eop_headeov = ptr1; else ptr2->eov_next = ptr1; if (ptr3 == NULL) eopptr->eop_taileov = ptr0; else ptr3->eov_prev = ptr0; } else ptr0 = ptr1; ptr1 = ptr0->eov_next; }; pass++; }; }; return; } /*--> EPDSortOperations: sort operations according to opcode */ static void EPDSortOperations(epdptrT epdptr) { siT count; siT pass, flag; eopptrT ptr0, ptr1, ptr2, ptr3; count = EPDCountOperations(epdptr); if (count > 1) { flag = 1; pass = 0; while (flag && (pass < (count - 1))) { flag = 0; ptr0 = epdptr->epd_headeop; ptr1 = ptr0->eop_next; while (ptr1 != NULL) { if (strcmp(ptr0->eop_opsym, ptr1->eop_opsym) > 0) { flag = 1; ptr2 = ptr0->eop_prev; ptr3 = ptr1->eop_next; ptr0->eop_prev = ptr1; ptr0->eop_next = ptr3; ptr1->eop_prev = ptr2; ptr1->eop_next = ptr0; if (ptr2 == NULL) epdptr->epd_headeop = ptr1; else ptr2->eop_next = ptr1; if (ptr3 == NULL) epdptr->epd_taileop = ptr0; else ptr3->eop_prev = ptr0; } else ptr0 = ptr1; ptr1 = ptr0->eop_next; }; pass++; }; }; return; } /*--> EPDNormalize: apply normalizing sorts */ static void EPDNormalize(epdptrT epdptr) { eopptrT eopptr; charptrT opsym; siT flag; /* sort all operations */ EPDSortOperations(epdptr); /* sort operands for selected standard operations */ eopptr = epdptr->epd_headeop; while (eopptr != NULL) { flag = 0; opsym = eopptr->eop_opsym; if (!flag && (strcmp(opsym, epdsostrv[epdso_am]) == 0)) { EPDSortOperands(eopptr); flag = 1; }; if (!flag && (strcmp(opsym, epdsostrv[epdso_bm]) == 0)) { EPDSortOperands(eopptr); flag = 1; }; eopptr = eopptr->eop_next; }; return; } /*--> EPDCloneEPDBase: clone an EPD structure, base items only */ nonstatic epdptrT EPDCloneEPDBase(epdptrT epdptr) { epdptrT nptr; siT index; nptr = EPDNewEPD(); for (index = 0; index < nbL; index++) nptr->epd_nbv[index] = epdptr->epd_nbv[index]; nptr->epd_actc = epdptr->epd_actc; nptr->epd_cast = epdptr->epd_cast; nptr->epd_epsq = epdptr->epd_epsq; return (nptr); } /*--> EPDCloneEOV: clone an EOV structure */ nonstatic eovptrT EPDCloneEOV(eovptrT eovptr) { eovptrT nptr; nptr = EPDNewEOV(); nptr->eov_eob = eovptr->eov_eob; if (eovptr->eov_str != NULL) nptr->eov_str = EPDStringGrab(eovptr->eov_str); return (nptr); } /*--> EPDCloneEOP: clone an EOP structure */ nonstatic eopptrT EPDCloneEOP(eopptrT eopptr) { eopptrT nptr; eovptrT eovptr, rptr; nptr = EPDNewEOP(); if (eopptr->eop_opsym != NULL) nptr->eop_opsym = EPDStringGrab(eopptr->eop_opsym); rptr = eopptr->eop_headeov; while (rptr != NULL) { eovptr = EPDCloneEOV(rptr); EPDAppendEOV(nptr, eovptr); rptr = rptr->eov_next; }; return (nptr); } /*--> EPDCloneEPD: clone an EPD structure */ nonstatic epdptrT EPDCloneEPD(epdptrT epdptr) { epdptrT nptr; eopptrT eopptr, rptr; nptr = EPDCloneEPDBase(epdptr); rptr = epdptr->epd_headeop; while (rptr != NULL) { eopptr = EPDCloneEOP(rptr); EPDAppendEOP(nptr, eopptr); rptr = rptr->eop_next; }; return (nptr); } /*--> EPDSetKings: set the king location vector */ static void EPDSetKings(void) { sqT sq; /* this operates only on the local environment */ ese.ese_ksqv[c_w] = ese.ese_ksqv[c_b] = sq_nil; for (sq = sq_a1; sq <= sq_h8; sq++) switch (EPDboard.rbv[sq]) { case cp_wk: ese.ese_ksqv[c_w] = sq; break; case cp_bk: ese.ese_ksqv[c_b] = sq; break; default: break; }; return; } /*--> EPDSet: set up an EPD structure for the given position */ nonstatic epdptrT EPDSet(rbptrT rbptr, cT actc, castT cast, sqT epsq) { epdptrT epdptr; sqT sq; cpT cp0, cp1; /* this does not reference the current position */ epdptr = EPDNewEPD(); for (sq = sq_a1; sq <= sq_h8; sq += 2) { cp0 = rbptr->rbv[sq + 0]; cp1 = rbptr->rbv[sq + 1]; epdptr->epd_nbv[sq >> 1] = ((cp1 << nybbW) | cp0); }; epdptr->epd_actc = actc; epdptr->epd_cast = cast; epdptr->epd_epsq = epsq; return (epdptr); } /*--> EPDSetCurrentPosition: set current position */ nonstatic void EPDSetCurrentPosition(rbptrT rbptr, cT actc, castT cast, sqT epsq, siT hmvc, siT fmvn) { sqT sq; /* this changes the current position */ for (sq = sq_a1; sq <= sq_h8; sq++) EPDboard.rbv[sq] = rbptr->rbv[sq]; ese.ese_actc = actc; ese.ese_cast = cast; ese.ese_epsq = epsq; ese.ese_hmvc = hmvc; ese.ese_fmvn = fmvn; EPDSetKings(); return; } /*--> EPDGetCurrentPosition: return EPD structure for current position */ nonstatic epdptrT EPDGetCurrentPosition(void) { epdptrT epdptr; sqT sq; cpT cp0, cp1; epdptr = EPDNewEPD(); for (sq = sq_a1; sq <= sq_h8; sq += 2) { cp0 = EPDboard.rbv[sq + 0]; cp1 = EPDboard.rbv[sq + 1]; epdptr->epd_nbv[sq >> 1] = ((cp1 << nybbW) | cp0); }; epdptr->epd_actc = ese.ese_actc; epdptr->epd_cast = ese.ese_cast; epdptr->epd_epsq = ese.ese_epsq; return (epdptr); } /*--> EPDFetchACTC: fetch current active color */ nonstatic cT EPDFetchACTC(void) { /* return the value of the current active color */ return (ese.ese_actc); } /*--> EPDFetchCAST: fetch current castling availability */ nonstatic castT EPDFetchCAST(void) { /* return the value of the current castling availability */ return (ese.ese_cast); } /*--> EPDFetchEPSQ: fetch current en passant target square */ nonstatic sqT EPDFetchEPSQ(void) { /* return the value of the current en passant target square */ return (ese.ese_epsq); } /*--> EPDFetchHMVC: fetch current halfmove clock */ nonstatic siT EPDFetchHMVC(void) { /* return the value of the current halfmove clock */ return (ese.ese_hmvc); } /*--> EPDFetchFMVN: fetch current fullmove number */ nonstatic siT EPDFetchFMVN(void) { /* return the value of the current fullmove number */ return (ese.ese_fmvn); } /*--> EPDFetchBoard: fetch current board */ nonstatic rbptrT EPDFetchBoard(void) { /* copy from the local board into the designated static return area */ ret_rb = EPDboard; return (&ret_rb); } /*--> EPDFetchCP: fetch color-piece */ nonstatic cpT EPDFetchCP(sqT sq) { cpT cp; /* fetch from the local board */ cp = EPDboard.rbv[sq]; return (cp); } /*--> EPDFetchBoardString: create and return a board diagram */ nonstatic charptrT EPDFetchBoardString(void) { charptrT s; charptrT r; rankT rank; fileT file; cpT cp; /* allocate */ s = (charptrT) EPDMemoryGrab((rankL * ((fileL * 2) + 1)) + 1); /* fill */ r = s; for (rank = rank_8; rank >= rank_1; rank--) { for (file = file_a; file <= file_h; file++) { cp = EPDboard.rbm[rank][file]; if (cp == cp_v0) if ((rank % 2) == (file % 2)) { *r++ = ':'; *r++ = ':'; } else { *r++ = ascii_sp; *r++ = ascii_sp; } else { *r++ = asccv[cv_c_cpv[cp]]; *r++ = ascpv[cv_p_cpv[cp]]; }; }; *r++ = '\n'; }; /* terminating NUL */ *r = ascii_nul; return (s); } /*--> EPDGetGTIM: get game termination marker indicator */ nonstatic gtimT EPDGetGTIM(gamptrT gamptr) { return (gamptr->gam_gtim); } /*--> EPDPutGTIM: put game termination marker indicator */ nonstatic void EPDPutGTIM(gamptrT gamptr, gtimT gtim) { gamptr->gam_gtim = gtim; return; } /*--> EPDGenBasic: generate basic EPD notation for a given position */ nonstatic charptrT EPDGenBasic(rbptrT rbptr, cT actc, castT cast, sqT epsq) { charptrT ptr; epdptrT epdptr; /* this does not reference the current position */ epdptr = EPDSet(rbptr, actc, cast, epsq); ptr = EPDEncode(epdptr); EPDReleaseEPD(epdptr); return (ptr); } /*--> EPDGenBasicCurrent: generate basic EPD for current position */ nonstatic charptrT EPDGenBasicCurrent(void) { charptrT ptr; /* this references but does not change the current position */ ptr = EPDGenBasic(&EPDboard, ese.ese_actc, ese.ese_cast, ese.ese_epsq); return (ptr); } /*--> EPDDecodeFEN: read a FEN string to make an EPD structure */ nonstatic epdptrT EPDDecodeFEN(charptrT s) { epdptrT epdptr; siT flag; tknptrT save_head_tknptr, save_tail_tknptr; charptrT tptr; /* this does not reference the current position */ flag = 1; epdptr = NULL; tptr = NULL; /* save the initial token chain pointers */ save_head_tknptr = head_tknptr; save_tail_tknptr = tail_tknptr; /* clear the token chain pointers */ head_tknptr = NULL; tail_tknptr = NULL; /* tokenize the input */ EPDTokenize(s); /* check for six tokens */ if (flag) if (EPDTokenCount() != 6) flag = 0; /* construct an input string from the tokens */ if (flag) { /* handle the first four common fields */ tptr = EPDStringGrab(""); tptr = EPDStringAppendStr(tptr, EPDTokenFetch(0)); tptr = EPDStringAppendChar(tptr, ascii_sp); tptr = EPDStringAppendStr(tptr, EPDTokenFetch(1)); tptr = EPDStringAppendChar(tptr, ascii_sp); tptr = EPDStringAppendStr(tptr, EPDTokenFetch(2)); tptr = EPDStringAppendChar(tptr, ascii_sp); tptr = EPDStringAppendStr(tptr, EPDTokenFetch(3)); tptr = EPDStringAppendChar(tptr, ascii_sp); /* append the halfmove clock operation */ tptr = EPDStringAppendStr(tptr, epdsostrv[epdso_hmvc]); tptr = EPDStringAppendChar(tptr, ascii_sp); tptr = EPDStringAppendStr(tptr, EPDTokenFetch(4)); tptr = EPDStringAppendChar(tptr, ';'); tptr = EPDStringAppendChar(tptr, ascii_sp); /* append the fullmove number operation */ tptr = EPDStringAppendStr(tptr, epdsostrv[epdso_fmvn]); tptr = EPDStringAppendChar(tptr, ascii_sp); tptr = EPDStringAppendStr(tptr, EPDTokenFetch(5)); tptr = EPDStringAppendChar(tptr, ';'); }; /* release the temporary token chain */ EPDReleaseTokenChain(); /* restore the initial token chain pointers */ head_tknptr = save_head_tknptr; tail_tknptr = save_tail_tknptr; /* read the resulting EPD input string */ if (flag) { epdptr = EPDDecode(tptr); if (epdptr == NULL) flag = 0; }; /* cancellations if a problem occurred */ if (!flag) { if (tptr != NULL) EPDMemoryFree(tptr); if (epdptr != NULL) { EPDReleaseEPD(epdptr); epdptr = NULL; }; }; return (epdptr); } /*--> EPDEncodeFEN: make a FEN string from an EPD structure */ nonstatic charptrT EPDEncodeFEN(epdptrT epdptr) { charptrT s; char ch; siT bi; siT ps; sqT sq; cpT cp; rankT rank; fileT file; eopptrT eopptr; char nv[tL]; char bv[tL]; /* this does not reference the current position */ bi = 0; /* output board */ for (rank = rank_8; rank >= rank_1; rank--) { ps = 0; for (file = file_a; file <= file_h; file++) { sq = map_sq(rank, file); if ((sq % 2) == 0) cp = (epdptr->epd_nbv[sq >> 1] & nybbM); else cp = ((epdptr->epd_nbv[sq >> 1] >> nybbW) & nybbM); if (cp == cp_v0) ps++; else { if (ps != 0) { bv[bi++] = '0' + ps; ps = 0; }; ch = ascpv[cv_p_cpv[cp]]; if (cv_c_cpv[cp] == c_w) ch = map_upper(ch); else ch = map_lower(ch); bv[bi++] = ch; }; }; if (ps != 0) { bv[bi++] = '0' + ps; ps = 0; }; if (rank != rank_1) bv[bi++] = '/'; }; bv[bi++] = ascii_sp; /* output active color (lower case) */ bv[bi++] = map_lower(asccv[epdptr->epd_actc]); bv[bi++] = ascii_sp; /* output castling availablility */ if (epdptr->epd_cast == 0) bv[bi++] = '-'; else { if (epdptr->epd_cast & cf_wk) bv[bi++] = map_upper(ascpv[p_k]); if (epdptr->epd_cast & cf_wq) bv[bi++] = map_upper(ascpv[p_q]); if (epdptr->epd_cast & cf_bk) bv[bi++] = map_lower(ascpv[p_k]); if (epdptr->epd_cast & cf_bq) bv[bi++] = map_lower(ascpv[p_q]); }; bv[bi++] = ascii_sp; /* output ep capture square */ if (epdptr->epd_epsq == sq_nil) bv[bi++] = '-'; else { bv[bi++] = ascfv[map_file(epdptr->epd_epsq)]; bv[bi++] = ascrv[map_rank(epdptr->epd_epsq)]; }; bv[bi++] = ascii_sp; /* output halfmove clock */ eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_hmvc]); if ((eopptr != NULL) && (eopptr->eop_headeov != NULL) && (eopptr->eop_headeov->eov_str != NULL)) sprintf(nv, "%ld", atol(eopptr->eop_headeov->eov_str)); else sprintf(nv, "0"); strcpy(&bv[bi], nv); bi += strlen(nv); bv[bi++] = ascii_sp; /* output fullmove number */ eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_fmvn]); if ((eopptr != NULL) && (eopptr->eop_headeov != NULL) && (eopptr->eop_headeov->eov_str != NULL)) sprintf(nv, "%ld", atol(eopptr->eop_headeov->eov_str)); else sprintf(nv, "1"); strcpy(&bv[bi], nv); bi += strlen(nv); /* NUL termination */ bv[bi++] = ascii_nul; /* allocate result */ s = EPDStringGrab(bv); return (s); } /*--> EPDDecode: read an EPD structure from a string */ nonstatic epdptrT EPDDecode(charptrT s) { epdptrT epdptr; eopptrT eopptr; eovptrT eovptr; siT flag, quoteflag; siT ch; liT i; siT j, d; byteptrT bptr; fileT file; rankT rank; sqT sq; cT c; pT p; cpT cp; /* this does not reference the current position */ /* set up */ flag = 1; i = 0; ch = *(s + i++); /* initialize the return structure */ epdptr = EPDNewEPD(); /* skip whitespace */ if (flag) { while (flag && (ch != ascii_nul) && isspace(ch)) ch = *(s + i++); if (ch == ascii_nul) flag = 0; }; /* process piece placement data */ if (flag) { rank = rank_8; file = file_a; while (flag && (ch != ascii_nul) && !isspace(ch)) { switch (ch) { case '/': if ((file != fileL) || (rank == rank_1)) flag = 0; else { rank--; file = file_a; }; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': d = ch - '0'; if ((file + d) > fileL) flag = 0; else for (j = 0; j < d; j++) { sq = map_sq(rank, file); bptr = &epdptr->epd_nbv[sq >> 1]; if ((sq % 2) == 0) { *bptr &= ~nybbM; *bptr |= cp_v0; } else { *bptr &= ~(nybbM << nybbW); *bptr |= (cp_v0 << nybbW); }; file++; }; break; default: if (!EPDCheckPiece(ch) || (file >= fileL)) flag = 0; else { p = EPDEvaluatePiece(ch); if (isupper(ch)) c = c_w; else c = c_b; sq = map_sq(rank, file); bptr = &epdptr->epd_nbv[sq >> 1]; cp = cv_cp_c_pv[c][p]; if ((sq % 2) == 0) { *bptr &= ~nybbM; *bptr |= cp; } else { *bptr &= ~(nybbM << nybbW); *bptr |= (cp << nybbW); }; file++; }; break; }; ch = *(s + i++); }; if (flag) if ((file != fileL) || (rank != rank_1)) flag = 0; }; /* need at least one whitespace character */ if (flag) if ((ch == ascii_nul) || !isspace(ch)) flag = 0; /* skip whitespace */ if (flag) { while (flag && (ch != ascii_nul) && isspace(ch)) ch = *(s + i++); if (ch == ascii_nul) flag = 0; }; /* process active color */ if (flag) { if (!EPDCheckColor(ch)) flag = 0; else { epdptr->epd_actc = EPDEvaluateColor(ch); ch = *(s + i++); }; }; /* need at least one whitespace character */ if (flag) if ((ch == ascii_nul) || !isspace(ch)) flag = 0; /* skip whitespace */ if (flag) { while (flag && (ch != ascii_nul) && isspace(ch)) ch = *(s + i++); if (ch == ascii_nul) flag = 0; }; /* process castling availability */ if (flag) { epdptr->epd_cast = 0; if (ch == '-') ch = *(s + i++); else { /* white kingside castling availability */ if (flag && (ch == map_upper(ascpv[p_k]))) { epdptr->epd_cast |= cf_wk; ch = *(s + i++); if (ch == ascii_nul) flag = 0; }; /* white queenside castling availability */ if (flag && (ch == map_upper(ascpv[p_q]))) { epdptr->epd_cast |= cf_wq; ch = *(s + i++); if (ch == ascii_nul) flag = 0; }; /* black kingside castling availability */ if (flag && (ch == map_lower(ascpv[p_k]))) { epdptr->epd_cast |= cf_bk; ch = *(s + i++); if (ch == ascii_nul) flag = 0; }; /* black queenside castling availability */ if (flag && (ch == map_lower(ascpv[p_q]))) { epdptr->epd_cast |= cf_bq; ch = *(s + i++); if (ch == ascii_nul) flag = 0; }; }; }; /* need at least one whitespace character */ if (flag) if ((ch == ascii_nul) || !isspace(ch)) flag = 0; /* skip whitespace */ if (flag) { while (flag && (ch != ascii_nul) && isspace(ch)) ch = *(s + i++); if (ch == ascii_nul) flag = 0; }; /* process en passant target */ if (flag) if (ch == '-') { epdptr->epd_epsq = sq_nil; ch = *(s + i++); if ((ch != ascii_nul) && !isspace(ch)) flag = 0; } else if (!EPDCheckFile(ch)) flag = 0; else { file = EPDEvaluateFile(ch); ch = *(s + i++); if ((ch == ascii_nul) || !EPDCheckRank(ch)) flag = 0; else { epdptr->epd_epsq = map_sq(EPDEvaluateRank(ch), file); ch = *(s + i++); if ((ch != ascii_nul) && !isspace(ch)) flag = 0; }; }; /* skip whitespace (end-of-line is not an error) */ if (flag) while ((ch != ascii_nul) && isspace(ch)) ch = *(s + i++); /* process operation sequence (if any) */ if (flag) { while (flag && (ch != ascii_nul)) { /* allocate a new operation */ eopptr = EPDNewEOP(); /* form opsym (first character) */ if (IdentChar(ch)) { eopptr->eop_opsym = EPDStringGrab(""); eopptr->eop_opsym = EPDStringAppendChar(eopptr->eop_opsym, ch); ch = *(s + i++); } else flag = 0; /* form remainder of opsym */ while (IdentChar(ch)) { eopptr->eop_opsym = EPDStringAppendChar(eopptr->eop_opsym, ch); ch = *(s + i++); }; /* skip whitespace */ if (flag) { while (flag && (ch != ascii_nul) && isspace(ch)) ch = *(s + i++); if (ch == ascii_nul) flag = 0; }; /* process operand list */ while (flag && (ch != ';')) { /* allocate operand value */ eovptr = EPDNewEOV(); /* set quoted string as appropriate */ if (ch == '"') { quoteflag = 1; eovptr->eov_eob = eob_string; ch = *(s + i++); } else { quoteflag = 0; eovptr->eov_eob = eob_symbol; }; eovptr->eov_str = EPDStringGrab(""); if (quoteflag) { while (flag && (ch != '"')) { if (ch == ascii_nul) flag = 0; else { eovptr->eov_str = EPDStringAppendChar(eovptr->eov_str, ch); ch = *(s + i++); }; }; if (ch == '"') ch = *(s + i++); } else { while (flag && !isspace(ch) && (ch != ';')) { if (ch == ascii_nul) flag = 0; else { eovptr->eov_str = EPDStringAppendChar(eovptr->eov_str, ch); ch = *(s + i++); }; }; }; /* append operand onto operation */ if (flag) EPDAppendEOV(eopptr, eovptr); else EPDReleaseEOV(eovptr); /* skip whitespace */ while (flag && (ch != ascii_nul) && isspace(ch)) ch = *(s + i++); }; /* process semicolon */ if (flag) if (ch == ';') ch = *(s + i++); else flag = 0; /* append operation */ if (flag) EPDAppendEOP(epdptr, eopptr); else EPDReleaseEOP(eopptr); /* skip whitespace (end-of-line is not an error) */ if (flag) while (flag && (ch != ascii_nul) && isspace(ch)) ch = *(s + i++); }; }; /* check for fault */ if (!flag) { EPDReleaseEPD(epdptr); epdptr = NULL; }; /* normalize */ if (epdptr != NULL) EPDNormalize(epdptr); return (epdptr); } /*--> EPDEncode: write an EPD structure to a string */ nonstatic charptrT EPDEncode(epdptrT epdptr) { charptrT ptr; sqT sq; cpT cp; rankT rank; fileT file; siT bi, ps, ch; char bv[tL]; eopptrT eopptr; eovptrT eovptr; charptrT s0, s1; /* this does not reference the current position */ bi = 0; /* normalize */ EPDNormalize(epdptr); /* output board */ for (rank = rank_8; rank >= rank_1; rank--) { ps = 0; for (file = file_a; file <= file_h; file++) { sq = map_sq(rank, file); if ((sq % 2) == 0) cp = (epdptr->epd_nbv[sq >> 1] & nybbM); else cp = ((epdptr->epd_nbv[sq >> 1] >> nybbW) & nybbM); if (cp == cp_v0) ps++; else { if (ps != 0) { bv[bi++] = '0' + ps; ps = 0; }; ch = ascpv[cv_p_cpv[cp]]; if (cv_c_cpv[cp] == c_w) ch = map_upper(ch); else ch = map_lower(ch); bv[bi++] = ch; }; }; if (ps != 0) { bv[bi++] = '0' + ps; ps = 0; }; if (rank != rank_1) bv[bi++] = '/'; }; bv[bi++] = ascii_sp; /* output active color (lower case) */ bv[bi++] = map_lower(asccv[epdptr->epd_actc]); bv[bi++] = ascii_sp; /* output castling availablility */ if (epdptr->epd_cast == 0) bv[bi++] = '-'; else { if (epdptr->epd_cast & cf_wk) bv[bi++] = map_upper(ascpv[p_k]); if (epdptr->epd_cast & cf_wq) bv[bi++] = map_upper(ascpv[p_q]); if (epdptr->epd_cast & cf_bk) bv[bi++] = map_lower(ascpv[p_k]); if (epdptr->epd_cast & cf_bq) bv[bi++] = map_lower(ascpv[p_q]); }; bv[bi++] = ascii_sp; /* output ep capture square */ if (epdptr->epd_epsq == sq_nil) bv[bi++] = '-'; else { bv[bi++] = ascfv[map_file(epdptr->epd_epsq)]; bv[bi++] = ascrv[map_rank(epdptr->epd_epsq)]; }; /* NUL termination */ bv[bi++] = ascii_nul; /* allocate and copy basic result */ ptr = EPDStringGrab(bv); /* construct and append operations */ eopptr = epdptr->epd_headeop; while (eopptr != NULL) { /* leading space */ s0 = EPDStringGrab(" "); /* opcode */ s0 = EPDStringAppendStr(s0, eopptr->eop_opsym); /* construct and append operands */ eovptr = eopptr->eop_headeov; while (eovptr != NULL) { /* leading space */ s1 = EPDStringGrab(" "); /* conjure operand value */ switch (eovptr->eov_eob) { case eob_string: s1 = EPDStringAppendChar(s1, '"'); s1 = EPDStringAppendStr(s1, eovptr->eov_str); s1 = EPDStringAppendChar(s1, '"'); break; case eob_symbol: s1 = EPDStringAppendStr(s1, eovptr->eov_str); break; default: EPDSwitchFault("EPDEncode"); break; }; /* append */ s0 = EPDStringAppendStr(s0, s1); EPDMemoryFree(s1); /* next operand */ eovptr = eovptr->eov_next; }; /* trailing semicolon */ s0 = EPDStringAppendChar(s0, ';'); /* append operation */ ptr = EPDStringAppendStr(ptr, s0); EPDMemoryFree(s0); /* advance */ eopptr = eopptr->eop_next; }; return (ptr); } /*--> EPDRealize: set the current position according to EPD */ nonstatic void EPDRealize(epdptrT epdptr) { sqT sq; cpT cp; eopptrT eopptr; eovptrT eovptr; /* this changes the current position */ for (sq = sq_a1; sq <= sq_h8; sq++) { if ((sq % 2) == 0) cp = (epdptr->epd_nbv[sq >> 1] & nybbM); else cp = ((epdptr->epd_nbv[sq >> 1] >> nybbW) & nybbM); EPDboard.rbv[sq] = cp; }; ese.ese_actc = epdptr->epd_actc; ese.ese_cast = epdptr->epd_cast; ese.ese_epsq = epdptr->epd_epsq; eopptr = EPDLocateEOPCode(epdptr, epdso_hmvc); if ((eopptr != NULL) && ((eovptr = eopptr->eop_headeov) != NULL)) ese.ese_hmvc = atoi(eovptr->eov_str); else ese.ese_hmvc = 0; eopptr = EPDLocateEOPCode(epdptr, epdso_fmvn); if ((eopptr != NULL) && ((eovptr = eopptr->eop_headeov) != NULL)) ese.ese_fmvn = atoi(eovptr->eov_str); else ese.ese_fmvn = 1; EPDSetKings(); return; } /*--> EPDInitArray: set the current position to the initial array */ nonstatic void EPDInitArray(void) { sqT sq; /* this changes the current position */ for (sq = sq_a1; sq <= sq_h8; sq++) EPDboard.rbv[sq] = cp_v0; EPDboard.rbv[sq_a1] = EPDboard.rbv[sq_h1] = cp_wr; EPDboard.rbv[sq_b1] = EPDboard.rbv[sq_g1] = cp_wn; EPDboard.rbv[sq_c1] = EPDboard.rbv[sq_f1] = cp_wb; EPDboard.rbv[sq_d1] = cp_wq; EPDboard.rbv[sq_e1] = cp_wk; for (sq = sq_a2; sq <= sq_h2; sq++) EPDboard.rbv[sq] = cp_wp; EPDboard.rbv[sq_a8] = EPDboard.rbv[sq_h8] = cp_br; EPDboard.rbv[sq_b8] = EPDboard.rbv[sq_g8] = cp_bn; EPDboard.rbv[sq_c8] = EPDboard.rbv[sq_f8] = cp_bb; EPDboard.rbv[sq_d8] = cp_bq; EPDboard.rbv[sq_e8] = cp_bk; for (sq = sq_a7; sq <= sq_h7; sq++) EPDboard.rbv[sq] = cp_bp; ese.ese_actc = c_w; ese.ese_cast = cf_wk | cf_wq | cf_bk | cf_bq; ese.ese_epsq = sq_nil; ese.ese_hmvc = 0; ese.ese_fmvn = 1; EPDSetKings(); return; } /*--> EPDPlayerString: return a pointer to the player name string */ nonstatic charptrT EPDPlayerString(cT c) { return (playerstrv[c]); } /*--> EPDSANEncodeChar: encode SAN character */ static void EPDSANEncodeChar(char ch) { if ((lsani < (sanL - 1)) || ((ch == '\0') && (lsani < sanL))) lsan[lsani++] = ch; else EPDFatal("EPDSANEncodeChar: overflow"); return; } /*--> EPDSANEncodeStr: encode a SAN string */ static void EPDSANEncodeStr(charptrT s) { charptrT p; p = s; while (*p) EPDSANEncodeChar(*p++); return; } /*--> EPDSANEncodeFile: encode SAN file from square */ static void EPDSANEncodeFile(sqT sq) { EPDSANEncodeChar(ascfv[map_file(sq)]); return; } /*--> EPDSANEncodeRank: encode SAN rank from square */ static void EPDSANEncodeRank(sqT sq) { EPDSANEncodeChar(ascrv[map_rank(sq)]); return; } /*--> EPDSANEncodeSq: encode SAN square */ static void EPDSANEncodeSq(sqT sq) { EPDSANEncodeFile(sq); EPDSANEncodeRank(sq); return; } /*--> EPDSANEncodeCI: encode an appropriate capture indicator */ static void EPDSANEncodeCI(siT index) { switch (index) { case 0: EPDSANEncodeChar('x'); break; case 1: break; case 2: EPDSANEncodeChar(':'); break; case 3: EPDSANEncodeChar('*'); break; case 4: EPDSANEncodeChar('-'); break; }; return; } /*--> EPDSANEncodeAux: encode SAN format move with variants */ static void EPDSANEncodeAux(mptrT mptr, sanT san, ssavT ssav) { siT i; /* reset local index */ lsani = 0; /* busted? */ if (mptr->m_flag & mf_bust) EPDSANEncodeChar('*'); /* process according to moving piece */ switch (cv_p_cpv[mptr->m_frcp]) { case p_p: switch (mptr->m_scmv) { case scmv_reg: if (mptr->m_tocp != cp_v0) { EPDSANEncodeFile(mptr->m_frsq); if (ssav[ssa_edcr] == 1) EPDSANEncodeRank(mptr->m_frsq); EPDSANEncodeCI(ssav[ssa_capt]); if (ssav[ssa_ptar] == 0) EPDSANEncodeSq(mptr->m_tosq); else EPDSANEncodeFile(mptr->m_tosq); } else { EPDSANEncodeFile(mptr->m_frsq); if (ssav[ssa_edcr] == 1) EPDSANEncodeRank(mptr->m_frsq); if (ssav[ssa_move] == 1) EPDSANEncodeChar('-'); if (ssav[ssa_edcf] == 1) EPDSANEncodeFile(mptr->m_tosq); EPDSANEncodeRank(mptr->m_tosq); }; break; case scmv_epc: EPDSANEncodeFile(mptr->m_frsq); if (ssav[ssa_edcr] == 1) EPDSANEncodeRank(mptr->m_frsq); EPDSANEncodeCI(ssav[ssa_capt]); if (ssav[ssa_ptar] == 0) EPDSANEncodeSq(mptr->m_tosq); else EPDSANEncodeFile(mptr->m_tosq); if (ssav[ssa_epct] == 1) EPDSANEncodeStr("ep"); break; case scmv_ppn: case scmv_ppb: case scmv_ppr: case scmv_ppq: if (mptr->m_tocp != cp_v0) { EPDSANEncodeFile(mptr->m_frsq); if (ssav[ssa_edcr] == 1) EPDSANEncodeRank(mptr->m_frsq); EPDSANEncodeCI(ssav[ssa_capt]); if (ssav[ssa_ptar] == 0) EPDSANEncodeSq(mptr->m_tosq); else EPDSANEncodeFile(mptr->m_tosq); } else { EPDSANEncodeFile(mptr->m_frsq); if (ssav[ssa_edcr] == 1) EPDSANEncodeRank(mptr->m_frsq); if (ssav[ssa_move] == 1) EPDSANEncodeChar('-'); if (ssav[ssa_edcf] == 1) EPDSANEncodeFile(mptr->m_tosq); EPDSANEncodeRank(mptr->m_tosq); }; switch (ssav[ssa_prom]) { case 0: EPDSANEncodeChar('='); EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]); break; case 1: EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]); break; case 2: EPDSANEncodeChar('/'); EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]); break; case 3: EPDSANEncodeChar('('); EPDSANEncodeChar(ascpv[cv_p_scmvv[mptr->m_scmv]]); EPDSANEncodeChar(')'); break; }; break; }; break; case p_n: case p_b: case p_r: case p_q: EPDSANEncodeChar(ascpv[cv_p_cpv[mptr->m_frcp]]); if (((mptr->m_flag & mf_sanf) || (ssav[ssa_edcf] == 1)) || ((mptr->m_flag & mf_sanr) && (ssav[ssa_edcf] == 2))) EPDSANEncodeFile(mptr->m_frsq); if (((mptr->m_flag & mf_sanr) || (ssav[ssa_edcr] == 1)) || ((mptr->m_flag & mf_sanf) && (ssav[ssa_edcr] == 2))) EPDSANEncodeRank(mptr->m_frsq); if (mptr->m_tocp != cp_v0) EPDSANEncodeCI(ssav[ssa_capt]); else if (ssav[ssa_move] == 1) EPDSANEncodeChar('-'); EPDSANEncodeSq(mptr->m_tosq); break; case p_k: switch (mptr->m_scmv) { case scmv_reg: EPDSANEncodeChar(ascpv[p_k]); if (ssav[ssa_edcf] == 1) EPDSANEncodeFile(mptr->m_frsq); if (ssav[ssa_edcr] == 1) EPDSANEncodeRank(mptr->m_frsq); if (mptr->m_tocp != cp_v0) EPDSANEncodeCI(ssav[ssa_capt]); else if (ssav[ssa_move] == 1) EPDSANEncodeChar('-'); EPDSANEncodeSq(mptr->m_tosq); break; case scmv_cks: switch (ssav[ssa_cast]) { case 0: EPDSANEncodeStr("O-O"); break; case 1: EPDSANEncodeStr("0-0"); break; case 2: EPDSANEncodeStr("OO"); break; case 3: EPDSANEncodeStr("00"); break; case 4: EPDSANEncodeChar(ascpv[p_k]); if (ssav[ssa_edcf] == 1) EPDSANEncodeFile(mptr->m_frsq); if (ssav[ssa_edcr] == 1) EPDSANEncodeRank(mptr->m_frsq); if (ssav[ssa_move] == 1) EPDSANEncodeChar('-'); EPDSANEncodeSq(mptr->m_tosq); break; }; break; case scmv_cqs: switch (ssav[ssa_cast]) { case 0: EPDSANEncodeStr("O-O-O"); break; case 1: EPDSANEncodeStr("0-0-0"); break; case 2: EPDSANEncodeStr("OOO"); break; case 3: EPDSANEncodeStr("000"); break; case 4: EPDSANEncodeChar(ascpv[p_k]); if (ssav[ssa_edcf] == 1) EPDSANEncodeFile(mptr->m_frsq); if (ssav[ssa_edcr] == 1) EPDSANEncodeRank(mptr->m_frsq); if (ssav[ssa_move] == 1) EPDSANEncodeChar('-'); EPDSANEncodeSq(mptr->m_tosq); break; }; break; }; break; }; /* insert markers */ if ((mptr->m_flag & mf_chec) && !(mptr->m_flag & mf_chmt)) switch (ssav[ssa_chec]) { case 0: EPDSANEncodeChar('+'); break; case 1: break; case 2: EPDSANEncodeStr("ch"); break; }; if (mptr->m_flag & mf_chmt) switch (ssav[ssa_chmt]) { case 0: EPDSANEncodeChar('#'); break; case 1: break; case 2: EPDSANEncodeChar('+'); break; case 3: EPDSANEncodeStr("++"); break; }; if (mptr->m_flag & mf_draw) if (ssav[ssa_draw] == 1) EPDSANEncodeChar('='); /* map to lower case if indicated */ if (ssav[ssa_case] == 1) for (i = 0; i < lsani; i++) lsan[i] = map_lower(lsan[i]); /* pad and copy */ while (lsani < sanL) EPDSANEncodeChar('\0'); for (i = 0; i < sanL; i++) san[i] = lsan[i]; return; } /*--> EPDSANEncode: encode a move into a SAN string */ nonstatic void EPDSANEncode(mptrT mptr, sanT san) { ssaT ssa; ssavT ssav; /* select canonical encoding (zero point in variant space) */ for (ssa = 0; ssa < ssaL; ssa++) ssav[ssa] = 0; EPDSANEncodeAux(mptr, san, ssav); return; } /*--> EPDSANDecodeBump: increment a style vector and return overflow */ static siT EPDSANDecodeBump(ssavT ssav, ssavT bssav) { siT flag; ssaT ssa; flag = 1; ssa = 0; while (flag && (ssa < ssaL)) { flag = 0; ssav[ssa]++; if (ssav[ssa] == bssav[ssa]) { flag = 1; ssav[ssa] = 0; }; ssa++; }; return (flag); } /*--> EPDSANDecodeFlex: locate a move from SAN (flexible interpretation) */ static mptrT EPDSANDecodeFlex(sanT san) { mptrT mptr; ssavT ssav, bssav; siT i, flag; mptrT rmptr; sanT lcsan, rsan; /* set default return value */ mptr = NULL; /* set minimal upper bounds */ for (i = 0; i < ssaL; i++) bssav[i] = 1; /* scan for upper bound conditions */ rmptr = tse.tse_base; for (i = 0; i < tse.tse_count; i++) { /* letter case */ bssav[ssa_case] = 2; /* capturing */ if ((rmptr->m_tocp != cp_v0) || (rmptr->m_scmv == scmv_epc)) bssav[ssa_capt] = 5; /* checking */ if (rmptr->m_flag & mf_chec) bssav[ssa_chec] = 3; /* castling */ if ((rmptr->m_scmv == scmv_cks) || (rmptr->m_scmv == scmv_cqs)) bssav[ssa_cast] = 5; /* promoting */ if ((rmptr->m_scmv == scmv_ppn) || (rmptr->m_scmv == scmv_ppb) || (rmptr->m_scmv == scmv_ppr) || (rmptr->m_scmv == scmv_ppq)) bssav[ssa_prom] = 4; /* pawn destination target */ if (cv_p_cpv[rmptr->m_frcp] == p_p) bssav[ssa_ptar] = 2; /* checkmating */ if (rmptr->m_flag & mf_chmt) bssav[ssa_chmt] = 4; /* en passant capturing */ if (rmptr->m_scmv == scmv_epc) bssav[ssa_epct] = 2; /* drawing */ if (rmptr->m_flag & mf_draw) bssav[ssa_draw] = 2; /* moving (non-capturing) */ if ((rmptr->m_tocp == cp_v0) && (rmptr->m_scmv != scmv_epc)) bssav[ssa_move] = 2; /* extra disambiguation: file */ if (!(rmptr->m_flag & mf_sanf)) bssav[ssa_edcf] = 3; /* extra disambiguation: rank */ if (!(rmptr->m_flag & mf_sanr)) bssav[ssa_edcr] = 3; rmptr++; }; /* make a lower case copy of the input */ for (i = 0; i < sanL; i++) lcsan[i] = map_lower(san[i]); /* initialize the index style vector */ for (i = 0; i < ssaL; i++) ssav[i] = 0; /* search */ flag = 0; while (!flag && (mptr == NULL)) { rmptr = tse.tse_base; i = 0; /* scan candidate moves */ while ((mptr == NULL) && (i < tse.tse_count)) { /* encode the current style version of a candidate */ EPDSANEncodeAux(rmptr, rsan, ssav); /* select either original or lower case comparison */ if (ssav[ssa_case] == 0) { if (strcmp(san, rsan) == 0) mptr = rmptr; } else { if (strcmp(lcsan, rsan) == 0) mptr = rmptr; }; /* next candidate */ rmptr++; i++; }; /* update the overflow termination flag */ flag = EPDSANDecodeBump(ssav, bssav); }; return (mptr); } /*--> EPDSANDecode: locate a move from SAN (strict interpretation) */ static mptrT EPDSANDecode(sanT san) { mptrT mptr; mptrT rmptr; sanT rsan; siT i; /* set default return value */ mptr = NULL; /* assume current moveset properly generated */ rmptr = tse.tse_base; i = 0; /* search */ while ((mptr == NULL) && (i < tse.tse_count)) { EPDSANEncode(rmptr, rsan); if (strcmp(san, rsan) == 0) mptr = rmptr; else { rmptr++; i++; }; }; return (mptr); } /*--> EPDSANDecodeAux: locate a move from SAN */ nonstatic mptrT EPDSANDecodeAux(sanT san, siT strict) { mptrT mptr; if (strict) mptr = EPDSANDecode(san); else mptr = EPDSANDecodeFlex(san); return (mptr); } /*--> EPDAttack: determine if a color attacks a square */ static siT EPDAttack(cT c, sqT sq) { siT flag; dxT dx; dvT dv; xdvT xdv; sqptrT sqptr0, sqptr1; xsqptrT xsqptr0, xsqptr1; /* clear result */ flag = 0; /* set origin square pointers */ sqptr0 = &EPDboard.rbv[sq]; xsqptr0 = &xb.xbv[map_xsq_sq(sq)]; /* process according to specified color */ if (c == c_w) { /* pawn attacks */ if ((*(xsqptr0 + xdv_7) == cp_v0) && (*(sqptr0 + dv_7) == cp_wp)) flag = 1; else if ((*(xsqptr0 + xdv_6) == cp_v0) && (*(sqptr0 + dv_6) == cp_wp)) flag = 1; /* knight attacks */ if (!flag) { dx = dx_8; while (!flag && (dx <= dx_f)) if ((*(xsqptr0 + xdvv[dx]) == cp_v0) && (*(sqptr0 + dvv[dx]) == cp_wn)) flag = 1; else dx++; }; /* orthogonal sweeps */ if (!flag) { dx = dx_0; while (!flag && (dx <= dx_3)) { dv = dvv[dx]; xdv = xdvv[dx]; sqptr1 = sqptr0; xsqptr1 = xsqptr0; while ((*(xsqptr1 += xdv) == cp_v0) && (*(sqptr1 += dv) == cp_v0)) ; if ((*xsqptr1 == cp_v0) && ((*sqptr1 == cp_wq) || (*sqptr1 == cp_wr))) flag = 1; else dx++; }; }; /* diagonal sweeps */ if (!flag) { dx = dx_4; while (!flag && (dx <= dx_7)) { dv = dvv[dx]; xdv = xdvv[dx]; sqptr1 = sqptr0; xsqptr1 = xsqptr0; while ((*(xsqptr1 += xdv) == cp_v0) && (*(sqptr1 += dv) == cp_v0)) ; if ((*xsqptr1 == cp_v0) && ((*sqptr1 == cp_wq) || (*sqptr1 == cp_wb))) flag = 1; else dx++; }; }; /* king attacks */ if (!flag) { dx = dx_0; while (!flag && (dx <= dx_7)) if ((*(xsqptr0 + xdvv[dx]) == cp_v0) && (*(sqptr0 + dvv[dx]) == cp_wk)) flag = 1; else dx++; }; } else { /* pawn attacks */ if ((*(xsqptr0 + xdv_4) == cp_v0) && (*(sqptr0 + dv_4) == cp_bp)) flag = 1; else if ((*(xsqptr0 + xdv_5) == cp_v0) && (*(sqptr0 + dv_5) == cp_bp)) flag = 1; /* knight attacks */ if (!flag) { dx = dx_8; while (!flag && (dx <= dx_f)) if ((*(xsqptr0 + xdvv[dx]) == cp_v0) && (*(sqptr0 + dvv[dx]) == cp_bn)) flag = 1; else dx++; }; /* orthogonal sweeps */ if (!flag) { dx = dx_0; while (!flag && (dx <= dx_3)) { dv = dvv[dx]; xdv = xdvv[dx]; sqptr1 = sqptr0; xsqptr1 = xsqptr0; while ((*(xsqptr1 += xdv) == cp_v0) && (*(sqptr1 += dv) == cp_v0)) ; if ((*xsqptr1 == cp_v0) && ((*sqptr1 == cp_bq) || (*sqptr1 == cp_br))) flag = 1; else dx++; }; }; /* diagonal sweeps */ if (!flag) { dx = dx_4; while (!flag && (dx <= dx_7)) { dv = dvv[dx]; xdv = xdvv[dx]; sqptr1 = sqptr0; xsqptr1 = xsqptr0; while ((*(xsqptr1 += xdv) == cp_v0) && (*(sqptr1 += dv) == cp_v0)) ; if ((*xsqptr1 == cp_v0) && ((*sqptr1 == cp_bq) || (*sqptr1 == cp_bb))) flag = 1; else dx++; }; }; /* king attacks */ if (!flag) { dx = dx_0; while (!flag && (dx <= dx_7)) if ((*(xsqptr0 + xdvv[dx]) == cp_v0) && (*(sqptr0 + dvv[dx]) == cp_bk)) flag = 1; else dx++; }; }; return (flag); } /*--> EPDWhiteAttacks: check if White attacks a square */ static siT EPDWhiteAttacks(sqT sq) { return (EPDAttack(c_w, sq)); } /*--> EPDBlackAttacks: check if White attacks a square */ static siT EPDBlackAttacks(sqT sq) { return (EPDAttack(c_b, sq)); } /*--> EPDTestAKIC: test for active king in check */ static siT EPDTestAKIC(void) { siT flag; if (ese.ese_actc == c_w) flag = EPDBlackAttacks(ese.ese_ksqv[c_w]); else flag = EPDWhiteAttacks(ese.ese_ksqv[c_b]); return (flag); } /*--> EPDTestPKIC: test for passive king in check */ static siT EPDTestPKIC(void) { siT flag; if (ese.ese_actc == c_b) flag = EPDBlackAttacks(ese.ese_ksqv[c_w]); else flag = EPDWhiteAttacks(ese.ese_ksqv[c_b]); return (flag); } /*--> EPDCensus: calculate local census vectors */ static void EPDCensus(void) { cT c; pT p; sqT sq; cpT cp; /* clear census vectors */ for (c = c_w; c <= c_b; c++) { count_cv[c] = 0; for (p = p_p; p <= p_k; p++) count_cpv[c][p] = 0; }; /* calculate census vectors */ for (sq = sq_a1; sq <= sq_h8; sq++) { cp = EPDboard.rbv[sq]; if (cp != cp_v0) { c = cv_c_cpv[cp]; count_cv[c]++; count_cpv[c][cv_p_cpv[cp]]++; }; }; return; } /*--> EPDIsLegal: determine if current position is legal */ nonstatic siT EPDIsLegal(void) { siT flag; cT c; fileT file; siT apv[rcL]; /* set default return value: legal position */ flag = 1; /* calculate the local census vectors */ EPDCensus(); /* calculate available promoted pawns */ for (c = c_w; c <= c_b; c++) apv[c] = fileL - count_cpv[c][p_p]; /* check white pawn count */ if (flag && (count_cpv[c_w][p_p] > fileL)) flag = 0; /* check black pawn count */ if (flag && (count_cpv[c_b][p_p] > fileL)) flag = 0; /* check white knight count */ if (flag && (count_cpv[c_w][p_n] > 2)) { apv[c_w] -= (count_cpv[c_w][p_n] - 2); if (apv[c_w] < 0) flag = 0; }; /* check black knight count */ if (flag && (count_cpv[c_b][p_n] > 2)) { apv[c_b] -= (count_cpv[c_b][p_n] - 2); if (apv[c_b] < 0) flag = 0; }; /* check white bishop count */ if (flag && (count_cpv[c_w][p_b] > 2)) { apv[c_w] -= (count_cpv[c_w][p_b] - 2); if (apv[c_w] < 0) flag = 0; }; /* check black bishop count */ if (flag && (count_cpv[c_b][p_b] > 2)) { apv[c_b] -= (count_cpv[c_b][p_b] - 2); if (apv[c_b] < 0) flag = 0; }; /* check white rook count */ if (flag && (count_cpv[c_w][p_r] > 2)) { apv[c_w] -= (count_cpv[c_w][p_r] - 2); if (apv[c_w] < 0) flag = 0; }; /* check black rook count */ if (flag && (count_cpv[c_b][p_r] > 2)) { apv[c_b] -= (count_cpv[c_b][p_r] - 2); if (apv[c_b] < 0) flag = 0; }; /* check white queen count */ if (flag && (count_cpv[c_w][p_q] > 1)) { apv[c_w] -= (count_cpv[c_w][p_q] - 1); if (apv[c_w] < 0) flag = 0; }; /* check black queen count */ if (flag && (count_cpv[c_b][p_q] > 1)) { apv[c_b] -= (count_cpv[c_b][p_q] - 1); if (apv[c_b] < 0) flag = 0; }; /* check white king count */ if (flag && (count_cpv[c_w][p_k] != 1)) flag = 0; /* check black king count */ if (flag && (count_cpv[c_b][p_k] != 1)) flag = 0; /* check pawn placement */ if (flag) { file = file_a; while (flag && (file <= file_h)) if ((EPDboard.rbm[rank_1][file] == cp_wp) || (EPDboard.rbm[rank_1][file] == cp_bp) || (EPDboard.rbm[rank_8][file] == cp_wp) || (EPDboard.rbm[rank_8][file] == cp_bp)) flag = 0; else file++; }; /* check white kingside castling availability */ if (flag && (ese.ese_cast & cf_wk)) if ((EPDboard.rbv[sq_e1] != cp_wk) || (EPDboard.rbv[sq_h1] != cp_wr)) flag = 0; /* check white queenside castling availability */ if (flag && (ese.ese_cast & cf_wq)) if ((EPDboard.rbv[sq_e1] != cp_wk) || (EPDboard.rbv[sq_a1] != cp_wr)) flag = 0; /* check black kingside castling availability */ if (flag && (ese.ese_cast & cf_bk)) if ((EPDboard.rbv[sq_e8] != cp_bk) || (EPDboard.rbv[sq_h8] != cp_br)) flag = 0; /* check black queenside castling availability */ if (flag && (ese.ese_cast & cf_bq)) if ((EPDboard.rbv[sq_e8] != cp_bk) || (EPDboard.rbv[sq_a8] != cp_br)) flag = 0; /* check en passant target square */ if (flag && (ese.ese_epsq != sq_nil)) if (ese.ese_actc == c_w) { if (map_rank(ese.ese_epsq) != rank_6) flag = 0; else if (EPDboard.rbv[ese.ese_epsq + dv_3] != cp_bp) flag = 0; else if (EPDboard.rbv[ese.ese_epsq] != cp_v0) flag = 0; else if (EPDboard.rbv[ese.ese_epsq + dv_1] != cp_v0) flag = 0; } else { if (map_rank(ese.ese_epsq) != rank_3) flag = 0; else if (EPDboard.rbv[ese.ese_epsq + dv_1] != cp_wp) flag = 0; else if (EPDboard.rbv[ese.ese_epsq] != cp_v0) flag = 0; else if (EPDboard.rbv[ese.ese_epsq + dv_3] != cp_v0) flag = 0; }; /* check for passive king in check */ if (flag && EPDTestPKIC()) flag = 0; return (flag); } /*--> EPDIsCheckmate: test for checkmate status */ nonstatic siT EPDIsCheckmate(void) { siT flag; /* set default return value: no checkmate */ flag = 0; /* generate legal moves (assume legal position) */ EPDGenMoves(); /* no legal moves and in check? */ if ((tse.tse_count == 0) && EPDTestAKIC()) flag = 1; return (flag); } /*--> EPDIsStalemate: test for stalemate status */ nonstatic siT EPDIsStalemate(void) { siT flag; /* set default return value: no stalemate */ flag = 0; /* generate legal moves (assume legal position) */ EPDGenMoves(); /* no legal moves and not in check? */ if ((tse.tse_count == 0) && !EPDTestAKIC()) flag = 1; return (flag); } /*--> EPDIsInsufficientMaterial: test for insufficient material */ nonstatic siT EPDIsInsufficientMaterial(void) { siT flag; /* set default return value: no draw by insufficient material */ flag = 0; /* calculate local census (assume legal position) */ EPDCensus(); /* only K vs K, K+N vs K, and K+B vs K are considered draws here */ if ((count_cv[c_w] == 1) && (count_cv[c_b] == 1)) flag = 1; else if ((count_cv[c_w] == 2) && (count_cv[c_b] == 1) && ((count_cpv[c_w][p_n] == 1) || (count_cpv[c_w][p_b] == 1))) flag = 1; else if ((count_cv[c_b] == 2) && (count_cv[c_w] == 1) && ((count_cpv[c_b][p_n] == 1) || (count_cpv[c_b][p_b] == 1))) flag = 1; return (flag); } /*--> EPDIsFiftyMoveDraw: test for 50 move draw */ nonstatic siT EPDIsFiftyMoveDraw(void) { siT flag; if (ese.ese_hmvc >= 100) flag = 1; else flag = 0; return (flag); } /*--> EPDIsThirdRepetition: test for third repetition */ nonstatic siT EPDIsThirdRepetition(gamptrT gamptr) { siT flag; gpmptrT gpmptr; siT count, limit, index, match; sqT sq; cpT cp0, cp1; nbvT nbv; /* point to the last game played move record */ gpmptr = gamptr->gam_tailgpm; /* set the repetion count (current position counts as one) */ count = 1; /* set the limit on the number of records to check */ limit = ese.ese_hmvc; /* construct the nybble board for the current position */ for (sq = sq_a1; sq <= sq_h8; sq += 2) { cp0 = EPDboard.rbv[sq + 0]; cp1 = EPDboard.rbv[sq + 1]; nbv[sq >> 1] = ((cp1 << nybbW) | cp0); }; /* loop backwards */ while ((gpmptr != NULL) && (limit > 0) && (count < 3)) { /* check for match against current position */ if ((ese.ese_actc == gpmptr->gpm_ese.ese_actc) && (ese.ese_cast == gpmptr->gpm_ese.ese_cast) && (ese.ese_epsq == gpmptr->gpm_ese.ese_epsq)) { /* scalars matched, check for board match */ match = 1; index = 0; while (match && (index < nbL)) { if (nbv[index] == gpmptr->gpm_nbv[index]) index++; else match = 0; }; /* complete match? */ if (match) count++; }; /* retreat to previous played move record */ gpmptr = gpmptr->gpm_prev; /* one less to go */ limit--; }; /* set return value */ if (count == 3) flag = 1; else flag = 0; return (flag); } /*--> EPDIsDraw: determine if the current position is a draw */ nonstatic siT EPDIsDraw(gamptrT gamptr) { siT flag; if (EPDIsFiftyMoveDraw() || EPDIsInsufficientMaterial() || EPDIsStalemate() || EPDIsThirdRepetition(gamptr)) flag = 1; else flag = 0; return (flag); } /*--> EPDMateInOne: return a mating move if one exists */ nonstatic mptrT EPDMateInOne(void) { mptrT mptr; mptrT rmptr; siT index; /* set default return value (no mate in one) */ mptr = NULL; /* generate legal moves (assume legal position) */ EPDGenMoves(); /* try to locate a mating move */ rmptr = tse.tse_base; index = 0; while ((mptr == NULL) && (index < tse.tse_count)) if (rmptr->m_flag & mf_chmt) { ret_m = *rmptr; mptr = &ret_m; } else { rmptr++; index++; }; return (mptr); } /*--> EPDGeneratePL: generate psuedolegal moves */ static void EPDGeneratePL(void) { dxT dx; dvT dv; xdvT xdv; xsqptrT xsqptr0, xsqptr1; fileT frfile; rankT frrank; mT gen_m; /* set up the generation base */ if (ply == 0) treeptr = tse.tse_base = treebaseptr; else treeptr = tse.tse_base = (tseptr - 1)->tse_base + (tseptr - 1)->tse_count; /* test against safety margin */ if ((treeptr - treebaseptr) >= (treeL - treemarginL)) EPDFatal("EPDGeneratePL: move tree size safety limit exceeded"); /* set up current generation items */ tse.tse_curr = treeptr; tse.tse_count = 0; /* set the psuedoinvariant generated move template components */ gen_m.m_scmv = scmv_reg; gen_m.m_flag = 0; /* look at each origin square of the active color */ for (gen_m.m_frsq = sq_a1; gen_m.m_frsq <= sq_h8; gen_m.m_frsq++) { /* get origin square and moving piece */ gen_m.m_frcp = EPDboard.rbv[gen_m.m_frsq]; /* continue if it is an active piece */ if (cv_c_cpv[gen_m.m_frcp] == ese.ese_actc) { /* generate moves for active color piece */ xsqptr0 = &xb.xbv[map_xsq_sq(gen_m.m_frsq)]; switch (cv_p_cpv[gen_m.m_frcp]) { case p_p: /* pawn moves: a bit tricky; colors done separately */ frfile = map_file(gen_m.m_frsq); frrank = map_rank(gen_m.m_frsq); if (ese.ese_actc == c_w) { /* one square non-capture */ gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq = gen_m.m_frsq + dv_1]; if (gen_m.m_tocp == cp_v0) if (frrank != rank_7) { /* non-promotion */ *treeptr++ = gen_m; tse.tse_count++; } else { /* promotion */ for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++) { *treeptr++ = gen_m; tse.tse_count++; } gen_m.m_scmv = scmv_reg; }; /* two squares forward */ if ((frrank == rank_2) && Vacant(gen_m.m_frsq + dv_1) && Vacant(gen_m.m_frsq + (2 * dv_1))) { gen_m.m_tosq = gen_m.m_frsq + (2 * dv_1); gen_m.m_tocp = cp_v0; *treeptr++ = gen_m; tse.tse_count++; }; /* capture to left */ if (frfile != file_a) { gen_m.m_tosq = gen_m.m_frsq + dv_5; gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq]; if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]) if (frrank != rank_7) { /* non-promote */ *treeptr++ = gen_m; tse.tse_count++; } else { /* promote */ for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++) { *treeptr++ = gen_m; tse.tse_count++; }; gen_m.m_scmv = scmv_reg; }; }; /* capture to right */ if (frfile != file_h) { gen_m.m_tosq = gen_m.m_frsq + dv_4; gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq]; if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]) if (frrank != rank_7) { /* non-promote */ *treeptr++ = gen_m; tse.tse_count++; } else { /* promote */ for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++) { *treeptr++ = gen_m; tse.tse_count++; }; gen_m.m_scmv = scmv_reg; }; }; /* en passant */ if ((frrank == rank_5) && (ese.ese_epsq != sq_nil)) { /* capture to left */ if ((frfile != file_a) && ((gen_m.m_tosq = gen_m.m_frsq + dv_5) == ese.ese_epsq)) { gen_m.m_tocp = cp_v0; gen_m.m_scmv = scmv_epc; *treeptr++ = gen_m; tse.tse_count++; gen_m.m_scmv = scmv_reg; }; /* capture to right */ if ((frfile != file_h) && ((gen_m.m_tosq = gen_m.m_frsq + dv_4) == ese.ese_epsq)) { gen_m.m_tocp = cp_v0; gen_m.m_scmv = scmv_epc; *treeptr++ = gen_m; tse.tse_count++; gen_m.m_scmv = scmv_reg; }; }; } else { /* one square non-capture */ gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq = gen_m.m_frsq + dv_3]; if (gen_m.m_tocp == cp_v0) if (frrank != rank_2) { /* non-promotion */ *treeptr++ = gen_m; tse.tse_count++; } else { /* promotion */ for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++) { *treeptr++ = gen_m; tse.tse_count++; } gen_m.m_scmv = scmv_reg; }; /* two squares forward */ if ((frrank == rank_7) && Vacant(gen_m.m_frsq + dv_3) && Vacant(gen_m.m_frsq + (2 * dv_3))) { gen_m.m_tosq = gen_m.m_frsq + (2 * dv_3); gen_m.m_tocp = cp_v0; *treeptr++ = gen_m; tse.tse_count++; }; /* capture to left */ if (frfile != file_a) { gen_m.m_tosq = gen_m.m_frsq + dv_6; gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq]; if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]) if (frrank != rank_2) { /* non-promote */ *treeptr++ = gen_m; tse.tse_count++; } else { /* promote */ for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++) { *treeptr++ = gen_m; tse.tse_count++; }; gen_m.m_scmv = scmv_reg; }; }; /* capture to right */ if (frfile != file_h) { gen_m.m_tosq = gen_m.m_frsq + dv_7; gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq]; if (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc]) if (frrank != rank_2) { /* non-promote */ *treeptr++ = gen_m; tse.tse_count++; } else { /* promote */ for (gen_m.m_scmv = scmv_ppn; gen_m.m_scmv <= scmv_ppq; gen_m.m_scmv++) { *treeptr++ = gen_m; tse.tse_count++; }; gen_m.m_scmv = scmv_reg; }; }; /* en passant */ if ((frrank == rank_4) && (ese.ese_epsq != sq_nil)) { /* capture to left */ if ((frfile != file_a) && ((gen_m.m_tosq = gen_m.m_frsq + dv_6) == ese.ese_epsq)) { gen_m.m_tocp = cp_v0; gen_m.m_scmv = scmv_epc; *treeptr++ = gen_m; tse.tse_count++; gen_m.m_scmv = scmv_reg; }; /* capture to right */ if ((frfile != file_h) && ((gen_m.m_tosq = gen_m.m_frsq + dv_7) == ese.ese_epsq)) { gen_m.m_tocp = cp_v0; gen_m.m_scmv = scmv_epc; *treeptr++ = gen_m; tse.tse_count++; gen_m.m_scmv = scmv_reg; }; }; }; break; case p_n: /* knight moves: very simple */ for (dx = dx_8; dx <= dx_f; dx++) if (*(xsqptr0 + xdvv[dx]) == cp_v0) { gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq = gen_m.m_frsq + dvv[dx]]; if (cv_c_cpv[gen_m.m_tocp] != ese.ese_actc) { *treeptr++ = gen_m; tse.tse_count++; }; }; break; case p_b: /* bishop moves: diagonal sweeper */ for (dx = dx_4; dx <= dx_7; dx++) { dv = dvv[dx]; xdv = xdvv[dx]; gen_m.m_tosq = gen_m.m_frsq; xsqptr1 = xsqptr0; while ((*(xsqptr1 += xdv) == cp_v0) && ((gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq += dv]) == cp_v0)) { *treeptr++ = gen_m; tse.tse_count++; }; if ((*xsqptr1 == cp_v0) && (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc])) { *treeptr++ = gen_m; tse.tse_count++; }; }; break; case p_r: /* rook moves: orthogonal sweeper */ for (dx = dx_0; dx <= dx_3; dx++) { dv = dvv[dx]; xdv = xdvv[dx]; gen_m.m_tosq = gen_m.m_frsq; xsqptr1 = xsqptr0; while ((*(xsqptr1 += xdv) == cp_v0) && ((gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq += dv]) == cp_v0)) { *treeptr++ = gen_m; tse.tse_count++; }; if ((*xsqptr1 == cp_v0) && (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc])) { *treeptr++ = gen_m; tse.tse_count++; }; }; break; case p_q: /* queen moves: orthogonal and diagonal sweeper */ for (dx = dx_0; dx <= dx_7; dx++) { dv = dvv[dx]; xdv = xdvv[dx]; gen_m.m_tosq = gen_m.m_frsq; xsqptr1 = xsqptr0; while ((*(xsqptr1 += xdv) == cp_v0) && ((gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq += dv]) == cp_v0)) { *treeptr++ = gen_m; tse.tse_count++; }; if ((*xsqptr1 == cp_v0) && (cv_c_cpv[gen_m.m_tocp] == inv_cv[ese.ese_actc])) { *treeptr++ = gen_m; tse.tse_count++; }; }; break; case p_k: /* king moves: one square adjacent regular */ for (dx = dx_0; dx <= dx_7; dx++) if (*(xsqptr0 + xdvv[dx]) == cp_v0) { gen_m.m_tocp = EPDboard.rbv[gen_m.m_tosq = gen_m.m_frsq + dvv[dx]]; if (cv_c_cpv[gen_m.m_tocp] != ese.ese_actc) { *treeptr++ = gen_m; tse.tse_count++; }; }; /* castling; process according to active color */ if (ese.ese_actc == c_w) { if ((ese.ese_cast & cf_wk) && !EPDBlackAttacks(sq_e1) && Vacant(sq_f1) && !EPDBlackAttacks(sq_f1) && Vacant(sq_g1) && !EPDBlackAttacks(sq_g1)) { gen_m.m_tosq = sq_g1; gen_m.m_tocp = cp_v0; gen_m.m_scmv = scmv_cks; *treeptr++ = gen_m; tse.tse_count++; gen_m.m_scmv = scmv_reg; }; if ((ese.ese_cast & cf_wq) && !EPDBlackAttacks(sq_e1) && Vacant(sq_d1) && !EPDBlackAttacks(sq_d1) && Vacant(sq_c1) && !EPDBlackAttacks(sq_c1) && Vacant(sq_b1)) { gen_m.m_tosq = sq_c1; gen_m.m_tocp = cp_v0; gen_m.m_scmv = scmv_cqs; *treeptr++ = gen_m; tse.tse_count++; gen_m.m_scmv = scmv_reg; }; } else { if ((ese.ese_cast & cf_bk) && !EPDWhiteAttacks(sq_e8) && Vacant(sq_f8) && !EPDWhiteAttacks(sq_f8) && Vacant(sq_g8) && !EPDWhiteAttacks(sq_g8)) { gen_m.m_tosq = sq_g8; gen_m.m_tocp = cp_v0; gen_m.m_scmv = scmv_cks; *treeptr++ = gen_m; tse.tse_count++; gen_m.m_scmv = scmv_reg; }; if ((ese.ese_cast & cf_bq) && !EPDWhiteAttacks(sq_e8) && Vacant(sq_d8) && !EPDWhiteAttacks(sq_d8) && Vacant(sq_c8) && !EPDWhiteAttacks(sq_c8) && Vacant(sq_b8)) { gen_m.m_tosq = sq_c8; gen_m.m_tocp = cp_v0; gen_m.m_scmv = scmv_cqs; *treeptr++ = gen_m; tse.tse_count++; gen_m.m_scmv = scmv_reg; }; }; break; }; }; }; return; } /*--> EPDSameMoveRef: check if two move references are the same move */ static siT EPDSameMoveRef(mptrT mptr0, mptrT mptr1) { siT flag; if ((mptr0->m_tosq == mptr1->m_tosq) && (mptr0->m_frsq == mptr1->m_frsq) && (mptr0->m_frcp == mptr1->m_frcp) && (mptr0->m_tocp == mptr1->m_tocp) && (mptr0->m_scmv == mptr1->m_scmv)) flag = 1; else flag = 0; return (flag); } /*--> EPDFindMove: locate the move in the current generation set */ static mptrT EPDFindMove(mptrT mptr) { mptrT rmptr; siT flag; siT index; rmptr = tse.tse_base; flag = 0; index = 0; while (!flag && (index < tse.tse_count)) if (EPDSameMoveRef(mptr, rmptr)) flag = 1; else { rmptr++; index++; }; if (!flag) rmptr = NULL; return (rmptr); } /*--> EPDExecute: execute the supplied move */ static void EPDExecute(mptrT mptr) { sqT pcsq; cpT ppcp; /* test for overflow */ if (ply == (pmhL - 1)) EPDFatal("EPDExecute: played move history overflow"); /* save old environment and generation records */ *eseptr++ = ese; *tseptr++ = tse; /* set the legality tested flag */ mptr->m_flag |= mf_exec; /* process according to move case */ switch (mptr->m_scmv) { case scmv_reg: EPDboard.rbv[mptr->m_frsq] = cp_v0; EPDboard.rbv[mptr->m_tosq] = mptr->m_frcp; break; case scmv_epc: if (ese.ese_actc == c_w) pcsq = mptr->m_tosq + dv_3; else pcsq = mptr->m_tosq + dv_1; EPDboard.rbv[mptr->m_frsq] = cp_v0; EPDboard.rbv[mptr->m_tosq] = mptr->m_frcp; EPDboard.rbv[pcsq] = cp_v0; break; case scmv_cks: if (ese.ese_actc == c_w) { EPDboard.rbv[sq_e1] = cp_v0; EPDboard.rbv[sq_g1] = cp_wk; EPDboard.rbv[sq_h1] = cp_v0; EPDboard.rbv[sq_f1] = cp_wr; } else { EPDboard.rbv[sq_e8] = cp_v0; EPDboard.rbv[sq_g8] = cp_bk; EPDboard.rbv[sq_h8] = cp_v0; EPDboard.rbv[sq_f8] = cp_br; }; break; case scmv_cqs: if (ese.ese_actc == c_w) { EPDboard.rbv[sq_e1] = cp_v0; EPDboard.rbv[sq_c1] = cp_wk; EPDboard.rbv[sq_a1] = cp_v0; EPDboard.rbv[sq_d1] = cp_wr; } else { EPDboard.rbv[sq_e8] = cp_v0; EPDboard.rbv[sq_c8] = cp_bk; EPDboard.rbv[sq_a8] = cp_v0; EPDboard.rbv[sq_d8] = cp_br; }; break; case scmv_ppn: if (ese.ese_actc == c_w) ppcp = cp_wn; else ppcp = cp_bn; EPDboard.rbv[mptr->m_frsq] = cp_v0; EPDboard.rbv[mptr->m_tosq] = ppcp; break; case scmv_ppb: if (ese.ese_actc == c_w) ppcp = cp_wb; else ppcp = cp_bb; EPDboard.rbv[mptr->m_frsq] = cp_v0; EPDboard.rbv[mptr->m_tosq] = ppcp; break; case scmv_ppr: if (ese.ese_actc == c_w) ppcp = cp_wr; else ppcp = cp_br; EPDboard.rbv[mptr->m_frsq] = cp_v0; EPDboard.rbv[mptr->m_tosq] = ppcp; break; case scmv_ppq: if (ese.ese_actc == c_w) ppcp = cp_wq; else ppcp = cp_bq; EPDboard.rbv[mptr->m_frsq] = cp_v0; EPDboard.rbv[mptr->m_tosq] = ppcp; break; }; /* set values for updated environment record: active color */ ese.ese_actc = inv_cv[ese.ese_actc]; /* set values for updated environment record: castling availablity */ if (ese.ese_cast != 0) { if (ese.ese_cast & cf_wk) if ((mptr->m_frsq == sq_e1) || (mptr->m_frsq == sq_h1) || (mptr->m_tosq == sq_h1)) ese.ese_cast &= ~cf_wk; if (ese.ese_cast & cf_wq) if ((mptr->m_frsq == sq_e1) || (mptr->m_frsq == sq_a1) || (mptr->m_tosq == sq_a1)) ese.ese_cast &= ~cf_wq; if (ese.ese_cast & cf_bk) if ((mptr->m_frsq == sq_e8) || (mptr->m_frsq == sq_h8) || (mptr->m_tosq == sq_h8)) ese.ese_cast &= ~cf_bk; if (ese.ese_cast & cf_bq) if ((mptr->m_frsq == sq_e8) || (mptr->m_frsq == sq_a8) || (mptr->m_tosq == sq_a8)) ese.ese_cast &= ~cf_bq; }; /* set values for updated environment record: en passant */ if (ese.ese_actc == c_b) if ((mptr->m_frcp == cp_wp) && (map_rank(mptr->m_frsq) == rank_2) && (map_rank(mptr->m_tosq) == rank_4)) ese.ese_epsq = mptr->m_frsq + dv_1; else ese.ese_epsq = sq_nil; else if ((mptr->m_frcp == cp_bp) && (map_rank(mptr->m_frsq) == rank_7) && (map_rank(mptr->m_tosq) == rank_5)) ese.ese_epsq = mptr->m_frsq + dv_3; else ese.ese_epsq = sq_nil; /* set values for updated environment record: halfmove clock */ if ((mptr->m_tocp != cp_v0) || (cv_p_cpv[mptr->m_frcp] == p_p)) ese.ese_hmvc = 0; else ese.ese_hmvc++; /* set values for updated environment record: fullmove number */ if (ese.ese_actc == c_w) ese.ese_fmvn++; /* set values for updated environment record: king locations */ switch (mptr->m_frcp) { case cp_wk: ese.ese_ksqv[c_w] = mptr->m_tosq; break; case cp_bk: ese.ese_ksqv[c_b] = mptr->m_tosq; break; default: break; }; /* check/bust flags */ if (EPDTestAKIC()) mptr->m_flag |= mf_chec; if (EPDTestPKIC()) mptr->m_flag |= mf_bust; /* increment ply index */ ply++; return; } /*--> EPDExecuteUpdate: update the current move pointer, then execute */ nonstatic void EPDExecuteUpdate(mptrT mptr) { tse.tse_curr = EPDFindMove(mptr); if (tse.tse_curr == NULL) EPDFatal("EPDExecuteUpdate: can't find move"); EPDExecute(tse.tse_curr); return; } /*--> EPDRetract: retract the supplied move */ static void EPDRetract(mptrT mptr) { /* decrement ply */ ply--; /* restore the current environment and generation */ ese = *--eseptr; tse = *--tseptr; /* process by move case */ switch (mptr->m_scmv) { case scmv_reg: EPDboard.rbv[mptr->m_tosq] = mptr->m_tocp; EPDboard.rbv[mptr->m_frsq] = mptr->m_frcp; break; case scmv_epc: EPDboard.rbv[mptr->m_tosq] = cp_v0; EPDboard.rbv[mptr->m_frsq] = mptr->m_frcp; if (ese.ese_actc == c_w) EPDboard.rbv[mptr->m_tosq + dv_3] = cp_bp; else EPDboard.rbv[mptr->m_tosq + dv_1] = cp_wp; break; case scmv_cks: if (ese.ese_actc == c_w) { EPDboard.rbv[sq_g1] = cp_v0; EPDboard.rbv[sq_e1] = cp_wk; EPDboard.rbv[sq_f1] = cp_v0; EPDboard.rbv[sq_h1] = cp_wr; } else { EPDboard.rbv[sq_g8] = cp_v0; EPDboard.rbv[sq_e8] = cp_bk; EPDboard.rbv[sq_f8] = cp_v0; EPDboard.rbv[sq_h8] = cp_br; } break; case scmv_cqs: if (ese.ese_actc == c_w) { EPDboard.rbv[sq_c1] = cp_v0; EPDboard.rbv[sq_e1] = cp_wk; EPDboard.rbv[sq_d1] = cp_v0; EPDboard.rbv[sq_a1] = cp_wr; } else { EPDboard.rbv[sq_c8] = cp_v0; EPDboard.rbv[sq_e8] = cp_bk; EPDboard.rbv[sq_d8] = cp_v0; EPDboard.rbv[sq_a8] = cp_br; }; break; case scmv_ppn: case scmv_ppb: case scmv_ppr: case scmv_ppq: EPDboard.rbv[mptr->m_tosq] = mptr->m_tocp; EPDboard.rbv[mptr->m_frsq] = mptr->m_frcp; break; }; return; } /*--> EPDRetractUpdate: retract last executed move */ nonstatic void EPDRetractUpdate(void) { mptrT mptr; mptr = (tseptr - 1)->tse_curr; EPDRetract(mptr); return; } /*--> EPDRetractAll: retract all moves in current variation */ nonstatic void EPDRetractAll(void) { while (ply > 0) EPDRetractUpdate(); return; } /*--> EPDCollapse: collapse the played move stack */ nonstatic void EPDCollapse(void) { /* process for nonzero ply */ if (ply > 0) { /* reset the stack pointers */ treeptr = treebaseptr; eseptr = esebaseptr; tseptr = tsebaseptr; /* reset the ply */ ply = 0; }; return; } /*--> EPDReset: collapse, then reset starting position */ nonstatic void EPDReset(void) { EPDCollapse(); EPDInitArray(); return; } /*--> EPDMLExec: execute the current move list */ static void EPDMLExec(void) { siT i; mptrT mptr; /* test and mark each move for legality and checking status */ mptr = tse.tse_base; for (i = 0; i < tse.tse_count; i++) { tse.tse_curr = mptr; EPDExecute(mptr); EPDRetract(mptr); mptr++; }; return; } /*--> EPDMLPolice: remove illegal moves the current move list */ static void EPDMLPolice(void) { mptrT tptr, mptr; siT i, bust; mT t_m; /* move illegal moves to end of list */ mptr = tse.tse_base; bust = 0; i = 0; while (i < (tse.tse_count - bust)) if (mptr->m_flag & mf_bust) { tptr = (tse.tse_base + (tse.tse_count - 1)) - bust; t_m = *mptr; *mptr = *tptr; *tptr = t_m; bust++; } else { mptr++; i++; }; /* shrink */ tse.tse_count -= bust; return; } /*--> EPDMLDisambiguate: insert disambiguation flags in move list */ static void EPDMLDisambiguate(void) { siT i, j, tmc, rmc, fmc; mptrT mptr0, mptr1; pT p; rankT rank; fileT file; /* it's magic */ mptr0 = tse.tse_base; for (i = 0; i < tse.tse_count; i++) { /* the outer loop disambiguates a single move per cycle */ p = cv_p_cpv[mptr0->m_frcp]; if ((p != p_p) && (p != p_k)) { rank = map_rank(mptr0->m_frsq); file = map_file(mptr0->m_frsq); tmc = rmc = fmc = 0; mptr1 = tse.tse_base; for (j = 0; j < tse.tse_count; j++) { /* the inner loop examines all possible sibling puns */ if ((i != j) && (mptr0->m_frcp == mptr1->m_frcp) && (mptr0->m_tosq == mptr1->m_tosq)) { tmc++; if (map_rank(mptr1->m_frsq) == rank) rmc++; if (map_file(mptr1->m_frsq) == file) fmc++; }; mptr1++; }; /* check pun count for outer loop move */ if (tmc > 0) { /* file disambiguation has priority */ if ((rmc > 0) || ((rmc == 0) && (fmc == 0))) mptr0->m_flag |= mf_sanf; /* rank disambiguation may be needed */ if (fmc > 0) mptr0->m_flag |= mf_sanr; }; }; mptr0++; }; return; } /*--> EPDMLScanMate: scan current move list for mating moves */ static void EPDMLScanMate(void) { siT i, j, mateflag, drawflag, moveflag; mptrT mptr0, mptr1; /* scan */ mptr0 = tse.tse_base; for (i = 0; i < tse.tse_count; i++) { tse.tse_curr = mptr0; EPDExecute(mptr0); /* now at next higher ply, generate psuedolegal set */ EPDGeneratePL(); /* try to find at least one legal move */ mptr1 = tse.tse_base; moveflag = 0; j = 0; while (!moveflag && (j < tse.tse_count)) { tse.tse_curr = mptr1; EPDExecute(mptr1); EPDRetract(mptr1); if (!(mptr1->m_flag & mf_bust)) moveflag = 1; else { mptr1++; j++; }; }; /* any second level moves detected? */ if (moveflag != 0) { /* not a mate */ mateflag = drawflag = 0; } else { /* a mating move is detected */ if (EPDTestAKIC()) { mateflag = 1; drawflag = 0; } else { drawflag = 1; mateflag = 0; }; }; /* undo execution */ EPDRetract(mptr0); /* now back at lower ply */ if (mateflag) mptr0->m_flag |= mf_chmt; else if (drawflag) mptr0->m_flag |= (mf_draw | mf_stmt); /* next move */ mptr0++; }; return; } /*--> EPDGenClean: generate move list with first level processing */ static void EPDGenClean(void) { /* basic psuedolegal generation */ EPDGeneratePL(); /* set legality flags, remove illegal moves, and disambiguate */ EPDMLExec(); EPDMLPolice(); EPDMLDisambiguate(); return; } /*--> EPDGenMoves: generate legal moves and set mate flags */ nonstatic void EPDGenMoves(void) { /* perform basic first level generation */ EPDGenClean(); /* handle two ply draw and checkmate detection */ EPDMLScanMate(); return; } /*--> EPDFetchMoveCount: fetch the move count */ nonstatic siT EPDFetchMoveCount(void) { return (tse.tse_count); } /*--> EPDFetchMove: fetch the nth move */ nonstatic mptrT EPDFetchMove(siT index) { ret_m = *(tse.tse_base + index); return (&ret_m); } /*--> EPDSetMoveFlags: set move flags from current generation set */ nonstatic void EPDSetMoveFlags(mptrT mptr) { mptrT rmptr; rmptr = EPDFindMove(mptr); if (rmptr != NULL) mptr->m_flag = rmptr->m_flag; return; } /*--> EPDSortSAN: ASCII SAN sort move list */ nonstatic void EPDSortSAN(void) { mptrT mptr, mptr0, mptr1; siT i, j, pair, pass, flag; sanptrT sanptr, sptr0, sptr1; char t_ch; mT t_m; /* allocate the SAN string vector */ sanptr = (sanptrT) EPDMemoryGrab(sizeof(sanT) * tse.tse_count); /* construct the SAN string entries */ mptr = tse.tse_base; for (i = 0; i < tse.tse_count; i++) EPDSANEncode(mptr++, *(sanptr + i)); /* a low tech bubble sort */ flag = 1; pass = 0; while (flag && (pass < (tse.tse_count - 1))) { sptr0 = sanptr; sptr1 = sanptr + 1; mptr0 = tse.tse_base; mptr1 = tse.tse_base + 1; flag = 0; pair = 0; while (pair < (tse.tse_count - pass - 1)) { /* case sensitive ascending order */ if (strcmp((charptrT) sptr0, (charptrT) sptr1) > 0) { flag = 1; for (j = 0; j < sanL; j++) { t_ch = (*sptr0)[j]; (*sptr0)[j] = (*sptr1)[j]; (*sptr1)[j] = t_ch; }; t_m = *mptr0; *mptr0 = *mptr1; *mptr1 = t_m; }; sptr0++; sptr1++; mptr0++; mptr1++; pair++; }; pass++; }; EPDMemoryFree(sanptr); return; } /*--> EPDRepairMove: repair a move operation */ static void EPDRepairMove(eopptrT eopptr) { eovptrT eovptr; mptrT mptr; mT m; sanT san; /* repair a single move from the current position */ eovptr = eopptr->eop_headeov; if (eovptr != NULL) { mptr = EPDSANDecodeAux(eovptr->eov_str, 0); if (mptr != NULL) { m = *mptr; EPDSANEncode(&m, san); if (strcmp(eovptr->eov_str, san) != 0) EPDReplaceEOVStr(eovptr, san); }; }; return; } /*--> EPDRepairMoveset: repair a moveset operation */ static void EPDRepairMoveset(eopptrT eopptr) { eovptrT eovptr; mptrT mptr; mT m; sanT san; /* check each move from the current position */ eovptr = eopptr->eop_headeov; while (eovptr != NULL) { mptr = EPDSANDecodeAux(eovptr->eov_str, 0); if (mptr != NULL) { m = *mptr; EPDSANEncode(&m, san); if (strcmp(eovptr->eov_str, san) != 0) EPDReplaceEOVStr(eovptr, san); }; eovptr = eovptr->eov_next; }; return; } /*--> EPDRepairVariation: repair a variation operation */ static void EPDRepairVariation(eopptrT eopptr) { eovptrT eovptr; mptrT mptr; mT m; sanT san; /* play move sequence from the current position */ eovptr = eopptr->eop_headeov; while (eovptr != NULL) { mptr = EPDSANDecodeAux(eovptr->eov_str, 0); if (mptr == NULL) eovptr = NULL; else { m = *mptr; EPDSANEncode(&m, san); if (strcmp(eovptr->eov_str, san) != 0) EPDReplaceEOVStr(eovptr, san); tse.tse_curr = EPDFindMove(mptr); if (tse.tse_curr == NULL) EPDFatal("EPDRepairVariation: can't find move"); EPDExecute(mptr); EPDGenMoves(); eovptr = eovptr->eov_next; } }; /* retract any executed moves */ EPDRetractAll(); return; } /*--> EPDPurgeOpFile: purge operation from input file to output file */ nonstatic siT EPDPurgeOpFile(charptrT opsym, charptrT fn0, charptrT fn1) { siT flag; fptrT fptr0, fptr1; epdptrT epdptr; eopptrT eopptr; charptrT eptr; char ev[epdL]; /* set default return value (success) */ flag = 1; /* clear the input and output file pointers */ fptr0 = fptr1 = NULL; /* open the input file for reading */ if (flag) { fptr0 = fopen(fn0, "r"); if (fptr0 == NULL) flag = 0; }; /* open the output file for writing */ if (flag) { fptr1 = fopen(fn1, "w"); if (fptr1 == NULL) flag = 0; }; /* scan entire file */ while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL)) { /* decode a record */ epdptr = EPDDecode(ev); /* check record decode validity */ if (epdptr == NULL) flag = 0; else { /* locate the operation to be purged */ eopptr = EPDLocateEOP(epdptr, opsym); if (eopptr != NULL) { EPDUnthreadEOP(epdptr, eopptr); EPDReleaseEOP(eopptr); }; /* encode the record (includes normalization) */ eptr = EPDEncode(epdptr); /* release EPD structure */ EPDReleaseEPD(epdptr); /* check result */ if (eptr == NULL) flag = 0; else { fprintf(fptr1, "%s\n", eptr); EPDMemoryFree(eptr); }; }; }; /* close input and output files */ if (fptr0 != NULL) fclose(fptr0); if (fptr1 != NULL) fclose(fptr1); return (flag); } /*--> EPDRepairEPD: repair an EPD structure */ nonstatic siT EPDRepairEPD(epdptrT epdptr) { siT flag; eopptrT eopptr; /* set default return value: repair successful */ flag = 1; /* set up the position as the current position */ EPDRealize(epdptr); /* check legality */ if (!EPDIsLegal()) flag = 0; else { /* generate moves and notation */ EPDGenMoves(); /* repair moveset "am" */ eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_am]); if (eopptr != NULL) EPDRepairMoveset(eopptr); /* repair moveset "bm" */ eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_bm]); if (eopptr != NULL) EPDRepairMoveset(eopptr); /* repair move "pm" */ eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_pm]); if (eopptr != NULL) EPDRepairMove(eopptr); /* repair variation "pv" */ eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_pv]); if (eopptr != NULL) EPDRepairVariation(eopptr); /* repair move "sm" */ eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_sm]); if (eopptr != NULL) EPDRepairMove(eopptr); /* repair variation "sv" */ eopptr = EPDLocateEOP(epdptr, epdsostrv[epdso_sv]); if (eopptr != NULL) EPDRepairVariation(eopptr); }; return (flag); } /*--> EPDRepairFile: repair input file to output file */ nonstatic siT EPDRepairFile(charptrT fn0, charptrT fn1) { siT flag; fptrT fptr0, fptr1; epdptrT epdptr; charptrT eptr; char ev[epdL]; /* set default return value (success) */ flag = 1; /* clear the input and output file pointers */ fptr0 = fptr1 = NULL; /* open the input file for reading */ if (flag) { fptr0 = fopen(fn0, "r"); if (fptr0 == NULL) flag = 0; }; /* open the output file for writing */ if (flag) { fptr1 = fopen(fn1, "w"); if (fptr1 == NULL) flag = 0; }; /* scan entire file */ while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL)) { /* decode a record */ epdptr = EPDDecode(ev); /* check record decode validity */ if (epdptr == NULL) flag = 0; else { /* make repairs */ flag = EPDRepairEPD(epdptr); /* continue if repair okay */ if (flag) { /* encode the normalized record */ eptr = EPDEncode(epdptr); /* check result */ if (eptr == NULL) flag = 0; else { fprintf(fptr1, "%s\n", eptr); EPDMemoryFree(eptr); }; }; /* release EPD structure */ EPDReleaseEPD(epdptr); }; }; /* close input and output files */ if (fptr0 != NULL) fclose(fptr0); if (fptr1 != NULL) fclose(fptr1); return (flag); } /*--> EPDNormalizeFile: normalize input file to output file */ nonstatic siT EPDNormalizeFile(charptrT fn0, charptrT fn1) { siT flag; fptrT fptr0, fptr1; epdptrT epdptr; charptrT eptr; char ev[epdL]; /* set default return value (success) */ flag = 1; /* clear the input and output file pointers */ fptr0 = fptr1 = NULL; /* open the input file for reading */ if (flag) { fptr0 = fopen(fn0, "r"); if (fptr0 == NULL) flag = 0; }; /* open the output file for writing */ if (flag) { fptr1 = fopen(fn1, "w"); if (fptr1 == NULL) flag = 0; }; /* scan entire file */ while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL)) { /* decode a record */ epdptr = EPDDecode(ev); /* check record decode validity */ if (epdptr == NULL) flag = 0; else { /* encode the record (this includes normalization) */ eptr = EPDEncode(epdptr); /* release EPD structure */ EPDReleaseEPD(epdptr); /* check result */ if (eptr == NULL) flag = 0; else { fprintf(fptr1, "%s\n", eptr); EPDMemoryFree(eptr); }; }; }; /* close input and output files */ if (fptr0 != NULL) fclose(fptr0); if (fptr1 != NULL) fclose(fptr1); return (flag); } /*--> EPDScoreFile: score a benchmark file */ nonstatic siT EPDScoreFile(charptrT fn, bmsptrT bmsptr) { siT flag; siT skipflag; siT am_flag, bm_flag; siT solved; fptrT fptr; epdptrT epdptr; eopptrT am_eopptr, bm_eopptr, acd_eopptr, acn_eopptr, acs_eopptr; eopptrT sm_eopptr, sv_eopptr, pm_eopptr, pv_eopptr; charptrT result; char ev[epdL]; /* set default return value (success) */ flag = 1; /* clear the input file pointer */ fptr = NULL; /* preset the summary structure */ bmsptr->bms_acdflag = bmsptr->bms_acnflag = bmsptr->bms_acsflag = 1; bmsptr->bms_total = bmsptr->bms_solve = bmsptr->bms_unsol = 0; bmsptr->bms_total_acd = bmsptr->bms_solve_acd = bmsptr->bms_unsol_acd = 0; bmsptr->bms_total_acn = bmsptr->bms_solve_acn = bmsptr->bms_unsol_acn = 0; bmsptr->bms_total_acs = bmsptr->bms_solve_acs = bmsptr->bms_unsol_acs = 0; /* open the input file for reading */ if (flag) { fptr = fopen(fn, "r"); if (fptr == NULL) flag = 0; }; /* scan entire file */ while (flag && (fgets(ev, (epdL - 1), fptr) != NULL)) { /* decode a record */ epdptr = EPDDecode(ev); /* check record decode validity */ if (epdptr == NULL) flag = 0; else { /* clear the move result pointer */ result = NULL; /* initialize various operation pointers */ am_eopptr = EPDLocateEOPCode(epdptr, epdso_am); bm_eopptr = EPDLocateEOPCode(epdptr, epdso_bm); acd_eopptr = EPDLocateEOPCode(epdptr, epdso_acd); acn_eopptr = EPDLocateEOPCode(epdptr, epdso_acn); acs_eopptr = EPDLocateEOPCode(epdptr, epdso_acs); sm_eopptr = EPDLocateEOPCode(epdptr, epdso_sm); sv_eopptr = EPDLocateEOPCode(epdptr, epdso_sv); pm_eopptr = EPDLocateEOPCode(epdptr, epdso_pm); pv_eopptr = EPDLocateEOPCode(epdptr, epdso_pv); /* test for am/bm existence */ if ((am_eopptr == NULL) && (bm_eopptr == NULL)) skipflag = 1; else skipflag = 0; /* try to locate a result move (note priority) */ if (!skipflag) { if (result == NULL) if ((pv_eopptr != NULL) && (pv_eopptr->eop_headeov != NULL)) result = pv_eopptr->eop_headeov->eov_str; if (result == NULL) if ((pm_eopptr != NULL) && (pm_eopptr->eop_headeov != NULL)) result = pm_eopptr->eop_headeov->eov_str; if (result == NULL) if ((sv_eopptr != NULL) && (sv_eopptr->eop_headeov != NULL)) result = sv_eopptr->eop_headeov->eov_str; if (result == NULL) if ((sm_eopptr != NULL) && (sm_eopptr->eop_headeov != NULL)) result = sm_eopptr->eop_headeov->eov_str; if (result == NULL) skipflag = 1; }; /* determine solve status */ if (!skipflag) { /* check for clearance with the am set */ if ((am_eopptr == NULL) || (EPDLocateEOV(am_eopptr, result) == NULL)) am_flag = 1; else am_flag = 0; /* check for clearance with the bm set */ if ((bm_eopptr == NULL) || (EPDLocateEOV(bm_eopptr, result) != NULL)) bm_flag = 1; else bm_flag = 0; /* set solution flag */ solved = am_flag && bm_flag; }; /* update statistics block */ if (!skipflag) { /* clear acd flag if acd is missing */ if ((acd_eopptr == NULL) || (acd_eopptr->eop_headeov == NULL)) bmsptr->bms_acdflag = 0; /* clear acn flag if acn is missing */ if ((acn_eopptr == NULL) || (acn_eopptr->eop_headeov == NULL)) bmsptr->bms_acnflag = 0; /* clear acs flag if acs is missing */ if ((acs_eopptr == NULL) || (acs_eopptr->eop_headeov == NULL)) bmsptr->bms_acsflag = 0; /* increment record count */ bmsptr->bms_total++; /* fold in acd value */ if (bmsptr->bms_acdflag) { bmsptr->bms_total_acd += atoi(acd_eopptr->eop_headeov->eov_str); if (solved) bmsptr->bms_solve_acd += atoi(acd_eopptr->eop_headeov->eov_str); else bmsptr->bms_unsol_acd += atoi(acd_eopptr->eop_headeov->eov_str); }; /* fold in acn value */ if (bmsptr->bms_acnflag) { bmsptr->bms_total_acn += atoi(acn_eopptr->eop_headeov->eov_str); if (solved) bmsptr->bms_solve_acn += atoi(acn_eopptr->eop_headeov->eov_str); else bmsptr->bms_unsol_acn += atoi(acn_eopptr->eop_headeov->eov_str); }; /* fold in acs value */ if (bmsptr->bms_acsflag) { bmsptr->bms_total_acs += atoi(acs_eopptr->eop_headeov->eov_str); if (solved) bmsptr->bms_solve_acs += atoi(acs_eopptr->eop_headeov->eov_str); else bmsptr->bms_unsol_acs += atoi(acs_eopptr->eop_headeov->eov_str); }; /* update remaining items according to solved status */ if (solved) bmsptr->bms_solve++; else bmsptr->bms_unsol++; }; /* release EPD structure */ EPDReleaseEPD(epdptr); }; }; /* close input file */ if (fptr != NULL) fclose(fptr); return (flag); } /*--> EPDEnumerate: enumeration of current position */ static liT EPDEnumerate(siT depth) { liT total; mptrT mptr; siT i; /* enumerate current position to the indicated depth */ if (depth == 0) total = 1; else { total = 0; EPDGeneratePL(); mptr = tse.tse_base; for (i = 0; i < tse.tse_count; i++) { tse.tse_curr = mptr; EPDExecute(mptr); if (!(mptr->m_flag & mf_bust)) total += EPDEnumerate(depth - 1); EPDRetract(mptr); mptr++; }; }; return (total); } /*--> EPDEnumerateFile: enumerate input file to output file */ nonstatic siT EPDEnumerateFile(siT depth, charptrT fn0, charptrT fn1, liptrT totalptr) { siT flag; fptrT fptr0, fptr1; time_t start_time; liT acn, acs; epdptrT epdptr; charptrT eptr; char ev[epdL]; /* set default return value (success) */ flag = 1; /* clear the grand total */ *totalptr = 0; /* clear the input and output file pointers */ fptr0 = fptr1 = NULL; /* open the input file for reading */ if (flag) { fptr0 = fopen(fn0, "r"); if (fptr0 == NULL) flag = 0; }; /* open the output file for writing */ if (flag) { fptr1 = fopen(fn1, "w"); if (fptr1 == NULL) flag = 0; }; /* scan entire file */ while (flag && (fgets(ev, (epdL - 1), fptr0) != NULL)) { /* decode a record */ epdptr = EPDDecode(ev); /* check record decode validity */ if (epdptr == NULL) flag = 0; else { /* set up the current position */ EPDRealize(epdptr); /* check legality */ if (!EPDIsLegal()) flag = 0; else { /* perform enumeration */ start_time = time(NULL); acn = EPDEnumerate(depth); acs = time(NULL) - start_time; /* update the grand total */ *totalptr += acn; /* record the updated field: acd */ EPDAddOpInt(epdptr, epdso_acd, depth); /* record the updated field: acn */ EPDAddOpInt(epdptr, epdso_acn, acn); /* record the updated field: acs */ EPDAddOpInt(epdptr, epdso_acs, acs); /* encode the record */ EPDNormalize(epdptr); eptr = EPDEncode(epdptr); /* check result */ if (eptr == NULL) flag = 0; else { fprintf(fptr1, "%s\n", eptr); EPDMemoryFree(eptr); }; }; /* release EPD structure */ EPDReleaseEPD(epdptr); }; }; /* close input and output files */ if (fptr0 != NULL) fclose(fptr0); if (fptr1 != NULL) fclose(fptr1); return (flag); } /*--> EPDMoveList: generate a string representation of a move list */ nonstatic charptrT EPDMoveList(gamptrT gamptr) { charptrT s; charptrT b; siT count; gpmptrT gpmptr; mT m; siT sn; cT sc, c; siT pi, index, limit, length, n, column; sanT san; char tv[tL]; /* calculate upper bound on storage requirement */ count = EPDGamePlyCount(gamptr); limit = (((count + 1) / 2) * 5) + 4 + (count * 8) + 8 + 1; b = (charptrT) EPDMemoryGrab(limit); /* set the inital played move pointer */ gpmptr = gamptr->gam_headgpm; /* set up starting color and starting move number */ if (count == 0) sc = c_w; else sc = gpmptr->gpm_ese.ese_actc; if (count == 0) sn = 1; else sn = gpmptr->gpm_ese.ese_fmvn; /* more set up */ pi = 0; index = 0; c = sc; n = sn; column = 0; /* loop through moves */ for (pi = 0; pi < count; pi++) { /* handle move number indication */ if ((c == c_w) || ((pi == 0) && (sc == c_b))) { sprintf(tv, "%hd.", n); length = strlen(tv); if ((column + 1 + length) >= columnL) { strcpy((b + index), "\n"); index++; column = 0; }; if (column != 0) { strcpy((b + index), " "); index++; column++; }; strcpy((b + index), tv); index += length; column += length; n++; }; /* handle ellipsis */ if ((pi == 0) && (sc == c_b)) { sprintf(tv, "..."); length = strlen(tv); if ((column + 1 + length) >= columnL) { strcpy((b + index), "\n"); index++; column = 0; }; if (column != 0) { strcpy((b + index), " "); index++; column++; }; strcpy((b + index), tv); index += length; column += length; }; /* handle move */ m = gpmptr->gpm_m; EPDSANEncode(&m, san); length = strlen(san); if ((column + 1 + length) >= columnL) { strcpy((b + index), "\n"); index++; column = 0; }; if (column != 0) { strcpy((b + index), " "); index++; column++; }; strcpy((b + index), san); index += length; column += length; gpmptr = gpmptr->gpm_next; c = inv_cv[c]; }; /* append game termination marker */ sprintf(tv, "%s", gtimstrv[gamptr->gam_gtim]); length = strlen(tv); if ((column + 1 + length) >= columnL) { strcpy((b + index), "\n"); index++; column = 0; }; if (column != 0) { strcpy((b + index), " "); index++; column++; }; strcpy((b + index), tv); index += length; column += length; /* closing newline */ if (column != 0) strcpy((b + index), "\n"); /* allocate and copy to result */ s = EPDStringGrab(b); EPDMemoryFree(b); return (s); } /*--> EPDPGNFetchTagIndex: return a PGN Seven Tag Roster tag index */ nonstatic pgnstrT EPDPGNFetchTagIndex(charptrT s) { pgnstrT pgnstr; pgnstrT rstr; pgnstr = pgnstr_nil; rstr = 0; while ((pgnstr == pgnstr_nil) && (rstr < pgnstrL)) if (strcmp(s, EPDPGNFetchTagName(rstr)) == 0) pgnstr = rstr; else rstr++; return (pgnstr); } /*--> EPDPGNFetchTagName: return a PGN Seven Tag Roster tag name */ nonstatic charptrT EPDPGNFetchTagName(pgnstrT pgnstr) { return (pgnstrstrv[pgnstr]); } /*--> EPDPGNGetSTR: return a string from the Seven Tag Roster */ nonstatic charptrT EPDPGNGetSTR(gamptrT gamptr, pgnstrT pgnstr) { return (gamptr->gam_strv[pgnstr]); } /*--> EPDPGNPutSTR: enter a string into the Seven Tag Roster */ nonstatic void EPDPGNPutSTR(gamptrT gamptr, pgnstrT pgnstr, charptrT s) { if (gamptr->gam_strv[pgnstr] != NULL) EPDMemoryFree(gamptr->gam_strv[pgnstr]); gamptr->gam_strv[pgnstr] = EPDStringGrab(s); return; } /*--> EPDPGNGenSTR: return a string with the entire STR */ nonstatic charptrT EPDPGNGenSTR(gamptrT gamptr) { charptrT s; pgnstrT pgnstr; char tv[tL]; s = EPDStringGrab(""); for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++) { sprintf(tv, "[%s \"%s\"]\n", pgnstrstrv[pgnstr], gamptr->gam_strv[pgnstr]); s = EPDStringAppendStr(s, tv); }; return (s); } /*--> EPDPGNHistory: generate a string for PGN version of history */ nonstatic charptrT EPDPGNHistory(gamptrT gamptr) { charptrT s; charptrT ms; s = EPDPGNGenSTR(gamptr); s = EPDStringAppendChar(s, '\n'); ms = EPDMoveList(gamptr); s = EPDStringAppendStr(s, ms); EPDMemoryFree(ms); s = EPDStringAppendChar(s, '\n'); return (s); } /*--> EPDCopyInPTP: copy STR into an EDP structure (ptp operation) */ nonstatic void EPDCopyInPTP(gamptrT gamptr, epdptrT epdptr) { eopptrT eopptr; pgnstrT pgnstr; if (epdptr != NULL) { EPDDropIfLocEOPCode(epdptr, epdso_ptp); eopptr = EPDCreateEOPCode(epdso_ptp); for (pgnstr = 0; pgnstr < pgnstrL; pgnstr++) { EPDAppendEOV(eopptr, EPDCreateEOVSym(EPDPGNFetchTagName(pgnstr))); EPDAppendEOV(eopptr, EPDCreateEOVStr(EPDPGNGetSTR(gamptr, pgnstr))); }; EPDAppendEOP(epdptr, eopptr); }; return; } /*--> EPDCopyOutPTP: copy STR from an EDP structure (ptp operation) */ nonstatic void EPDCopyOutPTP(gamptrT gamptr, epdptrT epdptr) { eopptrT eopptr; eovptrT eovptr; pgnstrT pgnstr; if (epdptr != NULL) { eopptr = EPDLocateEOPCode(epdptr, epdso_ptp); eovptr = eopptr->eop_headeov; while ((eovptr != NULL) && (eovptr->eov_next != NULL)) { pgnstr = EPDPGNFetchTagIndex(eovptr->eov_str); if (pgnstr != pgnstr_nil) EPDPGNPutSTR(gamptr, pgnstr, eovptr->eov_next->eov_str); eovptr = eovptr->eov_next->eov_next; }; }; return; } /*--> EPDFetchRefcomStr: return pointer of indicated refcom string */ nonstatic charptrT EPDFetchRefcomStr(refcomT refcom) { return (refcomstrv[refcom]); } /*--> EPDFetchRefreqStr: return pointer of indicated refreq string */ nonstatic charptrT EPDFetchRefreqStr(refreqT refreq) { return (refreqstrv[refreq]); } /*--> EPDFetchRefcomIndex: return a referee command index */ nonstatic refcomT EPDFetchRefcomIndex(charptrT s) { refcomT refcom; refcomT rcom; refcom = refcom_nil; rcom = 0; while ((refcom == refcom_nil) && (rcom < refcomL)) if (strcmp(s, EPDFetchRefcomStr(rcom)) == 0) refcom = rcom; else rcom++; return (refcom); } /*--> EPDFetchRefreqIndex: return a referee request index */ nonstatic refreqT EPDFetchRefreqIndex(charptrT s) { refreqT refreq; refreqT rreq; refreq = refreq_nil; rreq = 0; while ((refreq == refreq_nil) && (rreq < refreqL)) if (strcmp(s, EPDFetchRefreqStr(rreq)) == 0) refreq = rreq; else rreq++; return (refreq); } /*--> EPDExtractRefcomIndex: extract a referee command index */ nonstatic refreqT EPDExtractRefcomIndex(epdptrT epdptr) { refcomT refcom; eopptrT eopptr; eovptrT eovptr; /* set default return value */ refcom = refreq_nil; if (epdptr != NULL) if ((eopptr = EPDLocateEOPCode(epdptr, epdso_refcom)) != NULL) if ((eovptr = eopptr->eop_headeov) != NULL) refcom = EPDFetchRefcomIndex(eovptr->eov_str); return (refcom); } /*--> EPDExtractRefreqIndex: extract a referee request index */ nonstatic refreqT EPDExtractRefreqIndex(epdptrT epdptr) { refreqT refreq; eopptrT eopptr; eovptrT eovptr; /* set default return value */ refreq = refreq_nil; if (epdptr != NULL) if ((eopptr = EPDLocateEOPCode(epdptr, epdso_refreq)) != NULL) if ((eovptr = eopptr->eop_headeov) != NULL) refreq = EPDFetchRefreqIndex(eovptr->eov_str); return (refreq); } /*--> EPDComm: slave to Duplex autoplay program */ nonstatic siT EPDComm(refintptrT refintptr, charptrT pipebase) { siT flag; siT done; siT flow; refcomT refcom; charptrT pfnv[flowL]; fptrT pfptrv[flowL]; epdptrT epdptr0, epdptr1; charptrT eptr; char ev[epdL]; /* set default result: success */ flag = 1; /* set up the EPD Kit for a new game */ EPDInitArray(); /* generate pipe file names and clear their pointers */ for (flow = 0; flow < flowL; flow++) { pfnv[flow] = EPDStringGrab(pipebase); pfnv[flow] = EPDStringAppendStr(pfnv[flow], ".pc"); pfnv[flow] = EPDStringAppendChar(pfnv[flow], (flow + '0')); pfptrv[flow] = NULL; }; /* pipe files already created by Duplex, attempt open */ flow = 0; while (flag && (flow < flowL)) { pfptrv[flow] = fopen(pfnv[flow], "a+"); if (pfptrv[flow] == NULL) flag = 0; else flow++; }; /* sign on to Duplex */ if (flag) { epdptr0 = EPDGetCurrentPosition(); EPDAddOpSym(epdptr0, epdso_refreq, refreqstrv[refreq_sign_on]); eptr = EPDEncode(epdptr0); EPDReleaseEPD(epdptr0); fprintf(pfptrv[0], "%s\n", eptr); fflush(pfptrv[0]); EPDMemoryFree(eptr); }; /* run event cycle loop */ done = 0; while (flag && !done) { /* read an incoming EPD message */ if (fgets(ev, (epdL - 1), pfptrv[1]) == NULL) flag = 0; else { /* decode the message */ epdptr1 = EPDDecode(ev); if ((epdptr1 == NULL) || ((refcom = EPDExtractRefcomIndex(epdptr1)) == refcom_nil)) flag = 0; else { /* send the message to the callback routine */ epdptr0 = (*refintptr)(epdptr1, &flag); /* release input storage */ EPDReleaseEPD(epdptr1); /* construct and transmit output string */ if (flag && (epdptr0 != NULL)) { eptr = EPDEncode(epdptr0); fprintf(pfptrv[0], "%s\n", eptr); fflush(pfptrv[0]); EPDMemoryFree(eptr); }; /* release output storage */ if (epdptr0 != NULL) EPDReleaseEPD(epdptr0); /* set the completion flag on disconnect */ if (flag && !done && (refcom == refcom_disconnect)) done = 1; }; }; }; /* close pipes and release pipe file names */ for (flow = 0; flow < flowL; flow++) { if (pfptrv[flow] != NULL) fclose(pfptrv[flow]); EPDMemoryFree(pfnv[flow]); }; return (flag); } /*--> EPDTBClassFileName: return an allocated class name */ static charptrT EPDTBClassFileName(charptrT dirstr, tbidT tbid, cT c) { charptrT name; #if (!defined(__MWERKS__)) if (dirstr == NULL) name = EPDStringGrab(""); else { name = EPDStringGrab(dirstr); name = EPDStringAppendChar(name, '/'); }; #else if (dirstr == NULL) name = EPDStringGrab(""); else { name = EPDStringGrab(":"); name = EPDStringAppendStr(name, dirstr); name = EPDStringAppendChar(name, ':'); }; #endif name = EPDStringAppendStr(name, (tbbaseptr + tbid)->tb_name); name = EPDStringAppendStr(name, ctmext_strv[c]); return (name); } /*--> EPDTBGetSignature: get the signature for a distribution */ static liT EPDTBGetSignature(distvT distv) { liT sig; cT c; pT p; sig = 0; for (c = c_w; c <= c_b; c++) for (p = p_p; p <= p_q; p++) sig = (sig << 3) | distv[c][p]; return (sig); } /*--> EPDTBGetInvertedSignature: get the inverted signature for a distribution */ static liT EPDTBGetInvertedSignature(distvT distv) { liT sig; cT c; pT p; sig = 0; for (c = c_w; c <= c_b; c++) for (p = p_p; p <= p_q; p++) sig = (sig << 3) | distv[inv_cv[c]][p]; return (sig); } /*--> EPDTBLocateClass: locate a class for a piece distribution */ static tbidT EPDTBLocateClass(distvT distv, siptrT invertptr) { tbidT tbid; siT flag; tbptrT classptr; liT sig; /* set "not found" */ flag = 0; /* get the piece distribution signature */ sig = EPDTBGetSignature(distv); /* search for signature match */ classptr = tbbaseptr; tbid = 0; while (!flag && (tbid < tbidL)) if (sig == classptr->tb_sig0) { flag = 1; *invertptr = 0; } else if (sig == classptr->tb_sig1) { flag = 1; *invertptr = 1; } else { classptr++; tbid++; }; /* if not found, set return to nil */ if (!flag) tbid = tbid_nil; return (tbid); } /*--> EPDTBCopyPosition: copy a position vector */ static void EPDTBCopyPosition(posvT posv0, posvT posv1) { cT c; siT i; for (c = c_w; c <= c_b; c++) for (i = 0; i < tbmecL; i++) posv1[c][i] = posv0[c][i]; return; } /*--> EPDTBReflectX: reflect a position along the X axis */ static void EPDTBReflectX(tbptrT classptr, posvT posv) { cT c; siT i; for (c = c_w; c <= c_b; c++) for (i = 0; i < classptr->tb_mcv[c]; i++) posv[c][i] ^= 0x38; return; } /*--> EPDTBReflectY: reflect a position along the Y axis */ static void EPDTBReflectY(tbptrT classptr, posvT posv) { cT c; siT i; for (c = c_w; c <= c_b; c++) for (i = 0; i < classptr->tb_mcv[c]; i++) posv[c][i] ^= 0x07; return; } /*--> EPDTBReflectXY: reflect a position along the X=Y axis */ static void EPDTBReflectXY(tbptrT classptr, posvT posv) { cT c; siT i; rankT rank; fileT file; for (c = c_w; c <= c_b; c++) for (i = 0; i < classptr->tb_mcv[c]; i++) { rank = map_rank(posv[c][i]); file = map_file(posv[c][i]); posv[c][i] = map_sq(file, rank); }; return; } /*--> EPDTBNormalize: normalize a position */ static void EPDTBNormalize(tbptrT classptr, posvT posv) { sqT sq; cT pivot_c; siT pivot_slot; /* get pivot color and slot */ pivot_c = classptr->tb_pivot_c; pivot_slot = classptr->tb_pivot_slot; /* determine normalization mode */ if (classptr->tb_fold == fold_flank) { /* class has at least one pawn */ sq = posv[pivot_c][pivot_slot]; if (map_file(sq) > file_d) EPDTBReflectY(classptr, posv); } else { /* class has no pawns */ sq = posv[pivot_c][pivot_slot]; if (map_rank(sq) > rank_4) EPDTBReflectX(classptr, posv); sq = posv[pivot_c][pivot_slot]; if (map_file(sq) > file_d) EPDTBReflectY(classptr, posv); sq = posv[pivot_c][pivot_slot]; if (map_rank(sq) > map_file(sq)) EPDTBReflectXY(classptr, posv); }; return; } /*--> EPDTBGenIndex: generate a file index for a class and position */ static indexT EPDTBGenIndex(tbptrT classptr, posvT posv) { indexT index; liT factor=0; posvT nposv; cT c; siT i; EPDTBCopyPosition(posv, nposv); EPDTBNormalize(classptr, nposv); index = 0; for (c = c_w; c <= c_b; c++) for (i = 0; i < classptr->tb_mcv[c]; i++) { switch (classptr->tb_scalev[c][i]) { case sqL: factor = nposv[c][i]; break; case ff_flankL: factor = flank_mapv[nposv[c][i]]; break; case ff_triangleL: factor = triangle_mapv[nposv[c][i]]; break; default: EPDSwitchFault("EPDTBGenIndex"); break; }; index += factor * classptr->tb_multv[c][i]; }; return (index); } /*--> EPDTBGenInvertIndex: generate a file index for a class and position (inverted) */ static indexT EPDTBGenInvertIndex(tbptrT classptr, posvT posv) { indexT index; liT factor=0; posvT nposv; cT c, invc; siT i; for (c = c_w; c <= c_b; c++) { invc = inv_cv[c]; for (i = 0; i < classptr->tb_mcv[invc]; i++) nposv[invc][i] = posv[c][i]; }; if (classptr->tb_flags & tbf_has_pawns) EPDTBReflectX(classptr, nposv); EPDTBNormalize(classptr, nposv); index = 0; for (c = c_w; c <= c_b; c++) { for (i = 0; i < classptr->tb_mcv[c]; i++) { switch (classptr->tb_scalev[c][i]) { case sqL: factor = nposv[c][i]; break; case ff_flankL: factor = flank_mapv[nposv[c][i]]; break; case ff_triangleL: factor = triangle_mapv[nposv[c][i]]; break; default: EPDSwitchFault("EPDTBGenInvertIndex"); break; }; index += factor * classptr->tb_multv[c][i]; }; }; return (index); } /*--> EPDTBMapFromBEV: convert to centipawns from byte evaluation */ static cpevT EPDTBMapFromBEV(bevT bev) { cpevT cpev; siT distance; switch (bev) { case bev_broken: case bev_reserved: case bev_unknown: cpev = cpev_wrck; break; case bev_draw: cpev = cpev_draw; break; default: if (tbe_mating(bev)) { distance = ((bev_mi1 - bev) * 2) + 1; cpev = cpev_best - distance; } else { distance = -((bev_li0 - bev) * 2); cpev = cpev_bust + distance; }; break; }; return (cpev); } /*--> EPDTBProbeFile: return a centipawn value from a probe */ static cpevT EPDTBProbeFile(tbidT tbid, cT c, liT index) { cpevT cpev; siT i, slot; bevT bev; tbcT tbc; charptrT fnptr; /* set default return value: no evaluation found */ cpev = cpev_wrck; /* search cache for a slot with currently open file */ slot = -1; i = 0; while ((slot == -1) && (i < tbcL)) if (tbcv[i].tbc_inuse && (tbcv[i].tbc_tbid == tbid) && (tbcv[i].tbc_c == c)) slot = i; else i++; /* if no slot was found, try to find an empty one */ if (slot == -1) { /* look for a free slot */ i = 0; while ((slot == -1) && (i < tbcL)) if (!tbcv[i].tbc_inuse) slot = i; else i++; /* if no empty slot, drop the bottom (LRU) entry */ if (slot == -1) { slot = tbcL - 1; if (tbcv[slot].tbc_fptr != NULL) fclose(tbcv[slot].tbc_fptr); }; /* initialize the slot */ tbcv[slot].tbc_inuse = 1; tbcv[slot].tbc_tbid = tbid; tbcv[slot].tbc_c = c; fnptr = EPDTBClassFileName(tb_path, tbid, c); tbcv[slot].tbc_fptr = fopen(fnptr, "rb"); EPDStringFree(fnptr); }; /* move slot entry to top */ if (slot != 0) { tbc = tbcv[slot]; for (i = slot; i > 0; i--) tbcv[i] = tbcv[i - 1]; slot = 0; tbcv[slot] = tbc; }; /* file probe */ if (tbcv[slot].tbc_fptr != NULL) if (fseek(tbcv[slot].tbc_fptr, index, SEEK_SET) == 0) if (fread(&bev, sizeof(bevT), 1, tbcv[slot].tbc_fptr) == sizeof(bevT)) cpev = EPDTBMapFromBEV(bev); return (cpev); } /*--> EPDTBIsFilePresent: test if the given TB file is readable */ nonstatic siT EPDTBIsFilePresent(tbidT tbid, cT c) { siT flag; fptrT fptr; charptrT fnptr; fnptr = EPDTBClassFileName(tb_path, tbid, c); fptr = fopen(fnptr, "rb"); EPDStringFree(fnptr); if (fptr == NULL) flag = 0; else { fclose(fptr); flag = 1; }; return (flag); } /*--> EPDTBScore: return tablebase certain score (if possible) */ nonstatic cpevT EPDTBScore(void) { cpevT cpev; tbidT tbid; siT invert; cT probe_c; liT index; distvT distv; cT c; pT p; sqT sq; cpT cp; cT invc; siT flag; siT i; tbptrT classptr; posvT posv, nposv; rbT rb; /* set default return value: score unfound */ cpev = cpev_wrck; /* clear the distribution */ for (c = c_w; c <= c_b; c++) for (p = p_p; p <= p_k; p++) distv[c][p] = 0; /* calculate the distribution */ for (sq = sq_a1; sq <= sq_h8; sq++) if ((cp = EPDboard.rbv[sq]) != cp_v0) distv[cv_c_cpv[cp]][cv_p_cpv[cp]]++; /* locate the class */ tbid = EPDTBLocateClass(distv, &invert); /* was a class identified? */ if (tbid != tbid_nil) { /* get the class pointer */ classptr = tbbaseptr + tbid; /* calculate probe color */ if (!invert) probe_c = ese.ese_actc; else probe_c = inv_cv[ese.ese_actc]; /* set up the position vector */ for (sq = sq_a1; sq <= sq_h8; sq++) { cp = EPDboard.rbv[sq]; if ((cp != cp_v0) && invert) cp = cv_cp_c_pv[inv_cv[cv_c_cpv[cp]]][cv_p_cpv[cp]]; rb.rbv[sq] = cp; }; for (c = c_w; c <= c_b; c++) for (i = 0; i < classptr->tb_mcv[c]; i++) { /* which color-piece to match? */ cp = classptr->tb_cpv[c][i]; /* find it */ flag = 0; sq = sq_a1; while (!flag) if (rb.rbv[sq] == cp) { posv[c][i] = sq; rb.rbv[sq] = cp_v0; flag = 1; } else sq++; }; /* calculate index */ if (!invert) index = EPDTBGenIndex(classptr, posv); else { for (c = c_w; c <= c_b; c++) { invc = inv_cv[c]; for (i = 0; i < classptr->tb_mcv[c]; i++) nposv[invc][i] = posv[c][i]; }; index = EPDTBGenInvertIndex(classptr, nposv); }; /* probe */ cpev = EPDTBProbeFile(tbid, probe_c, index); }; return (cpev); } /*--> EPDTBInitTBID: initialize an entry in the tablebase vector */ static void EPDTBInitTBID(tbidT tbid, charptrT name) { cT c; pT p; siT i, slot; liT mult; char ch; tbptrT classptr; classptr = tbbaseptr + tbid; /* clear flags and set name items */ classptr->tb_flags = 0; classptr->tb_name = EPDStringGrab(name); classptr->tb_count = strlen(name); /* clear various vectors */ for (c = c_w; c <= c_b; c++) { classptr->tb_mcv[c] = 0; for (p = p_p; p <= p_k; p++) classptr->tb_distv[c][p] = 0; }; /* scan through pieces in class names */ c = c_b; for (i = 0; i < classptr->tb_count; i++) { /* identify current piece */ ch = *(name + i); switch (ch) { case 'P': p = p_p; break; case 'N': p = p_n; break; case 'B': p = p_b; break; case 'R': p = p_r; break; case 'Q': p = p_q; break; case 'K': p = p_k; break; default: EPDSwitchFault("EPDTBInitTBID"); break; }; /* swap color if current piece is a king */ if (p == p_k) c = inv_cv[c]; /* set various flags if current piece is a pawn */ if (p == p_p) { classptr->tb_flags |= tbf_has_pawns; if (c == c_w) { classptr->tb_flags |= tbf_has_white_pawn; if (classptr->tb_flags & tbf_has_black_pawn) classptr->tb_flags |= tbf_ep_captures; } else { classptr->tb_flags |= tbf_has_black_pawn; if (classptr->tb_flags & tbf_has_white_pawn) classptr->tb_flags |= tbf_ep_captures; }; }; /* adjust count and distribution for this color */ classptr->tb_mcv[c]++; classptr->tb_distv[c][p]++; /* set piece and color-piece vector for this color */ if (c == c_w) slot = i; else slot = i - classptr->tb_mcv[c_w]; classptr->tb_pv[c][slot] = p; classptr->tb_cpv[c][slot] = cv_cp_c_pv[c][p]; }; /* set the distribution signatures */ classptr->tb_sig0 = EPDTBGetSignature(classptr->tb_distv); classptr->tb_sig1 = EPDTBGetInvertedSignature(classptr->tb_distv); /* set fold mode information */ if (classptr->tb_flags & tbf_has_pawns) { classptr->tb_flags |= tbf_fold_flank; classptr->tb_fold = fold_flank; } else { classptr->tb_flags |= tbf_fold_triangle; classptr->tb_fold = fold_triangle; }; /* calculate file length */ classptr->tb_length = 1; for (i = 1; i < classptr->tb_count; i++) classptr->tb_length *= sqL; if (classptr->tb_fold == fold_flank) classptr->tb_length *= ff_flankL; else classptr->tb_length *= ff_triangleL; /* calculate pivot color and slot */ if (classptr->tb_fold == fold_triangle) { classptr->tb_pivot_c = c_b; classptr->tb_pivot_slot = classptr->tb_mcv[c_b] - 1; } else { if (classptr->tb_flags & tbf_has_black_pawn) { classptr->tb_pivot_c = c_b; i = classptr->tb_count - 1; while (*(name + i) != ascpv[p_p]) i--; classptr->tb_pivot_slot = i - classptr->tb_mcv[c_w]; } else { classptr->tb_pivot_c = c_w; i = classptr->tb_mcv[c_w] - 1; while (*(name + i) != ascpv[p_p]) i--; classptr->tb_pivot_slot = i; }; }; /* calculate scale factors */ for (c = c_w; c <= c_b; c++) for (i = 0; i < classptr->tb_mcv[c]; i++) if ((c != classptr->tb_pivot_c) || (i != classptr->tb_pivot_slot)) classptr->tb_scalev[c][i] = sqL; else if (classptr->tb_fold == fold_triangle) classptr->tb_scalev[c][i] = ff_triangleL; else classptr->tb_scalev[c][i] = ff_flankL; /* calculate multipliers */ mult = 1; for (c = c_w; c <= c_b; c++) for (i = 0; i < classptr->tb_mcv[c]; i++) { classptr->tb_multv[c][i] = mult; mult *= classptr->tb_scalev[c][i]; }; return; } /*--> EPDTBCacheFlush: flush the tablebase file pointer cache */ nonstatic void EPDTBCacheFlush(void) { siT i; for (i = 0; i < tbcL; i++) if (tbcv[i].tbc_inuse) { if (tbcv[i].tbc_fptr != NULL) fclose(tbcv[i].tbc_fptr); tbcv[i].tbc_inuse = 0; }; return; } /*--> EPDTBInit: one time initialization for the tablebase subsystem */ static void EPDTBInit(void) { siT i; sqT sq; /* initialize the flank map */ for (sq = sq_a1; sq <= sq_h8; sq++) flank_mapv[sq] = -1; flank_mapv[sq_a1] = 0; flank_mapv[sq_b1] = 1; flank_mapv[sq_c1] = 2; flank_mapv[sq_d1] = 3; flank_mapv[sq_a2] = 4; flank_mapv[sq_b2] = 5; flank_mapv[sq_c2] = 6; flank_mapv[sq_d2] = 7; flank_mapv[sq_a3] = 8; flank_mapv[sq_b3] = 9; flank_mapv[sq_c3] = 10; flank_mapv[sq_d3] = 11; flank_mapv[sq_a4] = 12; flank_mapv[sq_b4] = 13; flank_mapv[sq_c4] = 14; flank_mapv[sq_d4] = 15; flank_mapv[sq_a5] = 16; flank_mapv[sq_b5] = 17; flank_mapv[sq_c5] = 18; flank_mapv[sq_d5] = 19; flank_mapv[sq_a6] = 20; flank_mapv[sq_b6] = 21; flank_mapv[sq_c6] = 22; flank_mapv[sq_d6] = 23; flank_mapv[sq_a7] = 24; flank_mapv[sq_b7] = 25; flank_mapv[sq_c7] = 26; flank_mapv[sq_d7] = 27; flank_mapv[sq_a8] = 28; flank_mapv[sq_b8] = 29; flank_mapv[sq_c8] = 30; flank_mapv[sq_d8] = 31; /* initialize the triangle map */ for (sq = sq_a1; sq <= sq_h8; sq++) triangle_mapv[sq] = -1; triangle_mapv[sq_a1] = 0; triangle_mapv[sq_b1] = 1; triangle_mapv[sq_c1] = 2; triangle_mapv[sq_d1] = 3; triangle_mapv[sq_b2] = 4; triangle_mapv[sq_c2] = 5; triangle_mapv[sq_d2] = 6; triangle_mapv[sq_c3] = 7; triangle_mapv[sq_d3] = 8; triangle_mapv[sq_d4] = 9; /* set the color to move tablebase file name suffixes */ ctmext_strv[c_w] = ".tbw"; ctmext_strv[c_b] = ".tbb"; /* allocate tablebase information vector */ tbbaseptr = (tbptrT) EPDMemoryGrab(sizeof(tbT) * tbidL); /* initialize the tablebase vector */ EPDTBInitTBID(tbid_kk, "KK"); EPDTBInitTBID(tbid_kpk, "KPK"); EPDTBInitTBID(tbid_knk, "KNK"); EPDTBInitTBID(tbid_kbk, "KBK"); EPDTBInitTBID(tbid_krk, "KRK"); EPDTBInitTBID(tbid_kqk, "KQK"); EPDTBInitTBID(tbid_kpkp, "KPKP"); EPDTBInitTBID(tbid_knkp, "KNKP"); EPDTBInitTBID(tbid_knkn, "KNKN"); EPDTBInitTBID(tbid_kbkp, "KBKP"); EPDTBInitTBID(tbid_kbkn, "KBKN"); EPDTBInitTBID(tbid_kbkb, "KBKB"); EPDTBInitTBID(tbid_krkp, "KRKP"); EPDTBInitTBID(tbid_krkn, "KRKN"); EPDTBInitTBID(tbid_krkb, "KRKB"); EPDTBInitTBID(tbid_krkr, "KRKR"); EPDTBInitTBID(tbid_kqkp, "KQKP"); EPDTBInitTBID(tbid_kqkn, "KQKN"); EPDTBInitTBID(tbid_kqkb, "KQKB"); EPDTBInitTBID(tbid_kqkr, "KQKR"); EPDTBInitTBID(tbid_kqkq, "KQKQ"); EPDTBInitTBID(tbid_kppk, "KPPK"); EPDTBInitTBID(tbid_knpk, "KNPK"); EPDTBInitTBID(tbid_knnk, "KNNK"); EPDTBInitTBID(tbid_kbpk, "KBPK"); EPDTBInitTBID(tbid_kbnk, "KBNK"); EPDTBInitTBID(tbid_kbbk, "KBBK"); EPDTBInitTBID(tbid_krpk, "KRPK"); EPDTBInitTBID(tbid_krnk, "KRNK"); EPDTBInitTBID(tbid_krbk, "KRBK"); EPDTBInitTBID(tbid_krrk, "KRRK"); EPDTBInitTBID(tbid_kqpk, "KQPK"); EPDTBInitTBID(tbid_kqnk, "KQNK"); EPDTBInitTBID(tbid_kqbk, "KQBK"); EPDTBInitTBID(tbid_kqrk, "KQRK"); EPDTBInitTBID(tbid_kqqk, "KQQK"); EPDTBInitTBID(tbid_kppkp, "KPPKP"); EPDTBInitTBID(tbid_kppkn, "KPPKN"); EPDTBInitTBID(tbid_kppkb, "KPPKB"); EPDTBInitTBID(tbid_kppkr, "KPPKR"); EPDTBInitTBID(tbid_kppkq, "KPPKQ"); EPDTBInitTBID(tbid_knpkp, "KNPKP"); EPDTBInitTBID(tbid_knpkn, "KNPKN"); EPDTBInitTBID(tbid_knpkb, "KNPKB"); EPDTBInitTBID(tbid_knpkr, "KNPKR"); EPDTBInitTBID(tbid_knpkq, "KNPKQ"); EPDTBInitTBID(tbid_knnkp, "KNNKP"); EPDTBInitTBID(tbid_knnkn, "KNNKN"); EPDTBInitTBID(tbid_knnkb, "KNNKB"); EPDTBInitTBID(tbid_knnkr, "KNNKR"); EPDTBInitTBID(tbid_knnkq, "KNNKQ"); EPDTBInitTBID(tbid_kbpkp, "KBPKP"); EPDTBInitTBID(tbid_kbpkn, "KBPKN"); EPDTBInitTBID(tbid_kbpkb, "KBPKB"); EPDTBInitTBID(tbid_kbpkr, "KBPKR"); EPDTBInitTBID(tbid_kbpkq, "KBPKQ"); EPDTBInitTBID(tbid_kbnkp, "KBNKP"); EPDTBInitTBID(tbid_kbnkn, "KBNKN"); EPDTBInitTBID(tbid_kbnkb, "KBNKB"); EPDTBInitTBID(tbid_kbnkr, "KBNKR"); EPDTBInitTBID(tbid_kbnkq, "KBNKQ"); EPDTBInitTBID(tbid_kbbkp, "KBBKP"); EPDTBInitTBID(tbid_kbbkn, "KBBKN"); EPDTBInitTBID(tbid_kbbkb, "KBBKB"); EPDTBInitTBID(tbid_kbbkr, "KBBKR"); EPDTBInitTBID(tbid_kbbkq, "KBBKQ"); EPDTBInitTBID(tbid_krpkp, "KRPKP"); EPDTBInitTBID(tbid_krpkn, "KRPKN"); EPDTBInitTBID(tbid_krpkb, "KRPKB"); EPDTBInitTBID(tbid_krpkr, "KRPKR"); EPDTBInitTBID(tbid_krpkq, "KRPKQ"); EPDTBInitTBID(tbid_krnkp, "KRNKP"); EPDTBInitTBID(tbid_krnkn, "KRNKN"); EPDTBInitTBID(tbid_krnkb, "KRNKB"); EPDTBInitTBID(tbid_krnkr, "KRNKR"); EPDTBInitTBID(tbid_krnkq, "KRNKQ"); EPDTBInitTBID(tbid_krbkp, "KRBKP"); EPDTBInitTBID(tbid_krbkn, "KRBKN"); EPDTBInitTBID(tbid_krbkb, "KRBKB"); EPDTBInitTBID(tbid_krbkr, "KRBKR"); EPDTBInitTBID(tbid_krbkq, "KRBKQ"); EPDTBInitTBID(tbid_krrkp, "KRRKP"); EPDTBInitTBID(tbid_krrkn, "KRRKN"); EPDTBInitTBID(tbid_krrkb, "KRRKB"); EPDTBInitTBID(tbid_krrkr, "KRRKR"); EPDTBInitTBID(tbid_krrkq, "KRRKQ"); EPDTBInitTBID(tbid_kqpkp, "KQPKP"); EPDTBInitTBID(tbid_kqpkn, "KQPKN"); EPDTBInitTBID(tbid_kqpkb, "KQPKB"); EPDTBInitTBID(tbid_kqpkr, "KQPKR"); EPDTBInitTBID(tbid_kqpkq, "KQPKQ"); EPDTBInitTBID(tbid_kqnkp, "KQNKP"); EPDTBInitTBID(tbid_kqnkn, "KQNKN"); EPDTBInitTBID(tbid_kqnkb, "KQNKB"); EPDTBInitTBID(tbid_kqnkr, "KQNKR"); EPDTBInitTBID(tbid_kqnkq, "KQNKQ"); EPDTBInitTBID(tbid_kqbkp, "KQBKP"); EPDTBInitTBID(tbid_kqbkn, "KQBKN"); EPDTBInitTBID(tbid_kqbkb, "KQBKB"); EPDTBInitTBID(tbid_kqbkr, "KQBKR"); EPDTBInitTBID(tbid_kqbkq, "KQBKQ"); EPDTBInitTBID(tbid_kqrkp, "KQRKP"); EPDTBInitTBID(tbid_kqrkn, "KQRKN"); EPDTBInitTBID(tbid_kqrkb, "KQRKB"); EPDTBInitTBID(tbid_kqrkr, "KQRKR"); EPDTBInitTBID(tbid_kqrkq, "KQRKQ"); EPDTBInitTBID(tbid_kqqkp, "KQQKP"); EPDTBInitTBID(tbid_kqqkn, "KQQKN"); EPDTBInitTBID(tbid_kqqkb, "KQQKB"); EPDTBInitTBID(tbid_kqqkr, "KQQKR"); EPDTBInitTBID(tbid_kqqkq, "KQQKQ"); EPDTBInitTBID(tbid_kpppk, "KPPPK"); EPDTBInitTBID(tbid_knppk, "KNPPK"); EPDTBInitTBID(tbid_knnpk, "KNNPK"); EPDTBInitTBID(tbid_knnnk, "KNNNK"); EPDTBInitTBID(tbid_kbppk, "KBPPK"); EPDTBInitTBID(tbid_kbnpk, "KBNPK"); EPDTBInitTBID(tbid_kbnnk, "KBNNK"); EPDTBInitTBID(tbid_kbbpk, "KBBPK"); EPDTBInitTBID(tbid_kbbnk, "KBBNK"); EPDTBInitTBID(tbid_kbbbk, "KBBBK"); EPDTBInitTBID(tbid_krppk, "KRPPK"); EPDTBInitTBID(tbid_krnpk, "KRNPK"); EPDTBInitTBID(tbid_krnnk, "KRNNK"); EPDTBInitTBID(tbid_krbpk, "KRBPK"); EPDTBInitTBID(tbid_krbnk, "KRBNK"); EPDTBInitTBID(tbid_krbbk, "KRBBK"); EPDTBInitTBID(tbid_krrpk, "KRRPK"); EPDTBInitTBID(tbid_krrnk, "KRRNK"); EPDTBInitTBID(tbid_krrbk, "KRRBK"); EPDTBInitTBID(tbid_krrrk, "KRRRK"); EPDTBInitTBID(tbid_kqppk, "KQPPK"); EPDTBInitTBID(tbid_kqnpk, "KQNPK"); EPDTBInitTBID(tbid_kqnnk, "KQNNK"); EPDTBInitTBID(tbid_kqbpk, "KQBPK"); EPDTBInitTBID(tbid_kqbnk, "KQBNK"); EPDTBInitTBID(tbid_kqbbk, "KQBBK"); EPDTBInitTBID(tbid_kqrpk, "KQRPK"); EPDTBInitTBID(tbid_kqrnk, "KQRNK"); EPDTBInitTBID(tbid_kqrbk, "KQRBK"); EPDTBInitTBID(tbid_kqrrk, "KQRRK"); EPDTBInitTBID(tbid_kqqpk, "KQQPK"); EPDTBInitTBID(tbid_kqqnk, "KQQNK"); EPDTBInitTBID(tbid_kqqbk, "KQQBK"); EPDTBInitTBID(tbid_kqqrk, "KQQRK"); EPDTBInitTBID(tbid_kqqqk, "KQQQK"); /* clear the file pointer cache vector */ for (i = 0; i < tbcL; i++) tbcv[i].tbc_inuse = 0; return; } /*--> EPDTBTerm: one time termination for the tablebase subsystem */ static void EPDTBTerm(void) { tbidT tbid; tbptrT tbptr; /* flush the file pointer cache vector */ EPDTBCacheFlush(); /* deallocate tablebase information vector entries */ tbptr = tbbaseptr; for (tbid = 0; tbid < tbidL; tbid++) { EPDMemoryFree(tbptr->tb_name); tbptr++; }; /* deallocate tablebase information vector */ EPDMemoryFree(tbbaseptr); return; } /*--> EPDInit: one time initialization for EPD */ nonstatic void EPDInit(void) { cpT cp; sqT sq; xsqT xsq; /* this sets up the current position */ /* initialize ascii color conversion vector */ asccv[c_w] = 'w'; asccv[c_b] = 'b'; /* initialize ascii piece conversion vector */ ascpv[p_p] = 'P'; ascpv[p_n] = 'N'; ascpv[p_b] = 'B'; ascpv[p_r] = 'R'; ascpv[p_q] = 'Q'; ascpv[p_k] = 'K'; /* initialize ascii rank conversion vector */ ascrv[rank_1] = '1'; ascrv[rank_2] = '2'; ascrv[rank_3] = '3'; ascrv[rank_4] = '4'; ascrv[rank_5] = '5'; ascrv[rank_6] = '6'; ascrv[rank_7] = '7'; ascrv[rank_8] = '8'; /* initialize ascii file conversion vector */ ascfv[file_a] = 'a'; ascfv[file_b] = 'b'; ascfv[file_c] = 'c'; ascfv[file_d] = 'd'; ascfv[file_e] = 'e'; ascfv[file_f] = 'f'; ascfv[file_g] = 'g'; ascfv[file_h] = 'h'; /* initialize piece letter from special case move indicator */ cv_p_scmvv[scmv_reg] = p_nil; cv_p_scmvv[scmv_epc] = p_nil; cv_p_scmvv[scmv_cks] = p_nil; cv_p_scmvv[scmv_cqs] = p_nil; cv_p_scmvv[scmv_ppn] = p_n; cv_p_scmvv[scmv_ppb] = p_b; cv_p_scmvv[scmv_ppr] = p_r; cv_p_scmvv[scmv_ppq] = p_q; /* initialize various color piece conversion arrays */ for (cp = cp_wp; cp <= cp_wk; cp++) cv_c_cpv[cp] = c_w; for (cp = cp_bp; cp <= cp_bk; cp++) cv_c_cpv[cp] = c_b; cv_c_cpv[cp_v0] = c_v; cv_c_cpv[cp_x0] = cv_c_cpv[cp_x1] = cv_c_cpv[cp_x2] = c_x; cv_p_cpv[cp_wp] = cv_p_cpv[cp_bp] = p_p; cv_p_cpv[cp_wn] = cv_p_cpv[cp_bn] = p_n; cv_p_cpv[cp_wb] = cv_p_cpv[cp_bb] = p_b; cv_p_cpv[cp_wr] = cv_p_cpv[cp_br] = p_r; cv_p_cpv[cp_wq] = cv_p_cpv[cp_bq] = p_q; cv_p_cpv[cp_wk] = cv_p_cpv[cp_bk] = p_k; cv_p_cpv[cp_v0] = p_v; cv_p_cpv[cp_x0] = cv_p_cpv[cp_x1] = cv_p_cpv[cp_x2] = p_x; cv_cp_c_pv[c_w][p_p] = cp_wp; cv_cp_c_pv[c_w][p_n] = cp_wn; cv_cp_c_pv[c_w][p_b] = cp_wb; cv_cp_c_pv[c_w][p_r] = cp_wr; cv_cp_c_pv[c_w][p_q] = cp_wq; cv_cp_c_pv[c_w][p_k] = cp_wk; cv_cp_c_pv[c_b][p_p] = cp_bp; cv_cp_c_pv[c_b][p_n] = cp_bn; cv_cp_c_pv[c_b][p_b] = cp_bb; cv_cp_c_pv[c_b][p_r] = cp_br; cv_cp_c_pv[c_b][p_q] = cp_bq; cv_cp_c_pv[c_b][p_k] = cp_bk; inv_cv[c_w] = c_b; inv_cv[c_b] = c_w; /* initialize directional vectors */ dvv[dx_0] = dv_0; dvv[dx_1] = dv_1; dvv[dx_2] = dv_2; dvv[dx_3] = dv_3; dvv[dx_4] = dv_4; dvv[dx_5] = dv_5; dvv[dx_6] = dv_6; dvv[dx_7] = dv_7; dvv[dx_8] = dv_8; dvv[dx_9] = dv_9; dvv[dx_a] = dv_a; dvv[dx_b] = dv_b; dvv[dx_c] = dv_c; dvv[dx_d] = dv_d; dvv[dx_e] = dv_e; dvv[dx_f] = dv_f; xdvv[dx_0] = xdv_0; xdvv[dx_1] = xdv_1; xdvv[dx_2] = xdv_2; xdvv[dx_3] = xdv_3; xdvv[dx_4] = xdv_4; xdvv[dx_5] = xdv_5; xdvv[dx_6] = xdv_6; xdvv[dx_7] = xdv_7; xdvv[dx_8] = xdv_8; xdvv[dx_9] = xdv_9; xdvv[dx_a] = xdv_a; xdvv[dx_b] = xdv_b; xdvv[dx_c] = xdv_c; xdvv[dx_d] = xdv_d; xdvv[dx_e] = xdv_e; xdvv[dx_f] = xdv_f; /* initialize the extended board */ for (xsq = 0; xsq < xsqL; xsq++) xb.xbv[xsq] = cp_x0; for (sq = sq_a1; sq <= sq_h8; sq++) xb.xbv[map_xsq_sq(sq)] = cp_v0; /* initialize the standard opcode string vector */ epdsostrv[epdso_acd ] = "acd"; epdsostrv[epdso_acn ] = "acn"; epdsostrv[epdso_acs ] = "acs"; epdsostrv[epdso_am ] = "am"; epdsostrv[epdso_bm ] = "bm"; epdsostrv[epdso_c0 ] = "c0"; epdsostrv[epdso_c1 ] = "c1"; epdsostrv[epdso_c2 ] = "c2"; epdsostrv[epdso_c3 ] = "c3"; epdsostrv[epdso_c4 ] = "c4"; epdsostrv[epdso_c5 ] = "c5"; epdsostrv[epdso_c6 ] = "c6"; epdsostrv[epdso_c7 ] = "c7"; epdsostrv[epdso_c8 ] = "c8"; epdsostrv[epdso_c9 ] = "c9"; epdsostrv[epdso_cc ] = "cc"; epdsostrv[epdso_ce ] = "ce"; epdsostrv[epdso_dm ] = "dm"; epdsostrv[epdso_draw_accept] = "draw_accept"; epdsostrv[epdso_draw_claim ] = "draw_claim"; epdsostrv[epdso_draw_offer ] = "draw_offer"; epdsostrv[epdso_draw_reject] = "draw_reject"; epdsostrv[epdso_eco ] = "eco"; epdsostrv[epdso_fmvn ] = "fmvn"; epdsostrv[epdso_hmvc ] = "hmvc"; epdsostrv[epdso_id ] = "id"; epdsostrv[epdso_nic ] = "nic"; epdsostrv[epdso_noop ] = "noop"; epdsostrv[epdso_pm ] = "pm"; epdsostrv[epdso_ptp ] = "ptp"; epdsostrv[epdso_pv ] = "pv"; epdsostrv[epdso_rc ] = "rc"; epdsostrv[epdso_refcom ] = "refcom"; epdsostrv[epdso_refreq ] = "refreq"; epdsostrv[epdso_resign ] = "resign"; epdsostrv[epdso_sm ] = "sm"; epdsostrv[epdso_sv ] = "sv"; epdsostrv[epdso_tcgs ] = "tcgs"; epdsostrv[epdso_tcri ] = "tcri"; epdsostrv[epdso_tcsi ] = "tcsi"; epdsostrv[epdso_ts ] = "ts"; epdsostrv[epdso_v0 ] = "v0"; epdsostrv[epdso_v1 ] = "v1"; epdsostrv[epdso_v2 ] = "v2"; epdsostrv[epdso_v3 ] = "v3"; epdsostrv[epdso_v4 ] = "v4"; epdsostrv[epdso_v5 ] = "v5"; epdsostrv[epdso_v6 ] = "v6"; epdsostrv[epdso_v7 ] = "v7"; epdsostrv[epdso_v8 ] = "v8"; epdsostrv[epdso_v9 ] = "v9"; /* set the EPD refcom operand strings */ refcomstrv[refcom_conclude ] = "conclude"; refcomstrv[refcom_disconnect] = "disconnect"; refcomstrv[refcom_execute ] = "execute"; refcomstrv[refcom_fault ] = "fault"; refcomstrv[refcom_inform ] = "inform"; refcomstrv[refcom_respond ] = "respond"; refcomstrv[refcom_reset ] = "reset"; /* set the EPD refreq operand strings */ refreqstrv[refreq_fault ] = "fault"; refreqstrv[refreq_reply ] = "reply"; refreqstrv[refreq_sign_on ] = "sign_on"; refreqstrv[refreq_sign_off] = "sign_off"; /* set the PGN Seven Tag Roster names */ pgnstrstrv[pgnstr_event ] = "Event"; pgnstrstrv[pgnstr_site ] = "Site"; pgnstrstrv[pgnstr_date ] = "Date"; pgnstrstrv[pgnstr_round ] = "Round"; pgnstrstrv[pgnstr_white ] = "White"; pgnstrstrv[pgnstr_black ] = "Black"; pgnstrstrv[pgnstr_result] = "Result"; /* set the game termination indication marker vector */ gtimstrv[gtim_w] = "1-0"; gtimstrv[gtim_b] = "0-1"; gtimstrv[gtim_d] = "1/2-1/2"; gtimstrv[gtim_u] = "*"; /* set the player name string vector */ playerstrv[c_w] = "White"; playerstrv[c_b] = "Black"; /* clear the global game chain anchor pointers */ head_gamptr = tail_gamptr = NULL; /* clear the token chain anchor pointers */ head_tknptr = tail_tknptr = NULL; /* clear the current ply */ ply = 0; /* allocate the move tree */ treeptr = treebaseptr = (mptrT) EPDMemoryGrab(sizeof(mT) * treeL); /* allocate the tree stack entry stack */ tseptr = tsebaseptr = (tseptrT) EPDMemoryGrab(sizeof(tseT) * pmhL); /* allocate the environment stack entry stack */ eseptr = esebaseptr = (eseptrT) EPDMemoryGrab(sizeof(eseT) * pmhL); /* set the current position to be the initial array */ EPDInitArray(); /* generation */ EPDGenMoves(); /* initialize the tablebase subsystem */ EPDTBInit(); return; } /*--> EPDTerm: one time termination for EPD */ nonstatic void EPDTerm(void) { /* terminate the tablebase subsystem */ EPDTBTerm(); /* release any existing game chain */ EPDReleaseGameChain(); /* release any existing token chain */ EPDReleaseTokenChain(); /* deallocate various stacks */ EPDMemoryFree(esebaseptr); EPDMemoryFree(tsebaseptr); EPDMemoryFree(treebaseptr); /* "Wanna see my sprocket collection?" */ return; } /*<<< epd.c: EOF */