/*>>> epd.c: Extended Position Description routines */ #if defined(EPD) /* 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. 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 "chess.h" # include "data.h" /* EPD definitions (host independent) */ # 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 */ /* 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 */ /* 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; /* 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; /* 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; } /*--> 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; } /*--> 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; } /*--> 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; } /*--> 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]); } /*--> 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; } /*--> 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; } /*--> 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; } /*--> 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; } /*--> 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((char) ch) || (file >= fileL)) flag = 0; else { p = EPDEvaluatePiece((char) 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((char) ch)) flag = 0; else { epdptr->epd_actc = EPDEvaluateColor((char) 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((char) ch)) flag = 0; else { file = EPDEvaluateFile((char) ch); ch = *(s + i++); if ((ch == ascii_nul) || !EPDCheckRank((char) ch)) flag = 0; else { epdptr->epd_epsq = map_sq(EPDEvaluateRank((char) 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, (char) ch); ch = *(s + i++); } else flag = 0; /* form remainder of opsym */ while (IdentChar(ch)) { eopptr->eop_opsym = EPDStringAppendChar(eopptr->eop_opsym, (char) 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, (char) 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, (char) 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; } /*--> 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; } /*--> 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 = 0; 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((siT) (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; } /*--> 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; } /*--> 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; } /*--> 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], (char) (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; } /*--> 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] = "*"; /* 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(); return; } /*--> EPDTerm: one time termination for EPD */ nonstatic void EPDTerm(void) { /* 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; } #endif /*<<< epd.c: EOF */