/* * CHEST, chess analyst. For Copyright notice read file "COPYRIGHT". * * $Source: /home/heiner/ca/chest/RCS/extern.c,v $ * $Id: extern.c,v 3.30 1999/09/12 21:06:47 heiner Exp $ * * defines global arrays */ #if INIT_PUT # undef INIT_GET #endif #ifndef INIT_HERE # define INIT_HERE() /* empty */ #endif #include "bsd.h" #include "types.h" #include "board.h" #include "sysdep.h" #include #include #if INIT_GET # include "inited.h" #endif Eximpl int f_stats; /* statistics level */ Eximpl Flag f_danswer; /* whether to sort defender's answers */ Eximpl int f_mvtrace; /* how deep to trace executed moves */ Eximpl Flag f_fac; /* whether to do fac heuristic */ Eximpl Flag f_mate2; /* whether to do #2 heuristic */ #if ! PROD_LEV Eximpl int o_hops = 0; Eximpl int o_heiner = 0; Eximpl int o_thorak = 0; #endif /* * D-directions: * 7 2 4 * 1 8 0 * 5 3 6 */ #define DAM_MOV__ITOR(f,mkd) \ (f) * mkd( 1, 0), (f) * mkd(-1, 0), \ (f) * mkd( 0, 1), (f) * mkd( 0, -1), \ (f) * mkd( 1, 1), (f) * mkd(-1, -1), \ (f) * mkd( 1, -1), (f) * mkd(-1, 1), \ (f) * mkd( 0, 0) /* ZERO_DIR */ #define DAM_MOV_ITOR(f) DAM_MOV__ITOR(f, MK_DELTA) #define DAM_MOV64_ITOR(f) DAM_MOV__ITOR(f, MK_DELTA64) /* * S-directions: * - 2 - 4 - * 0 - - - 6 * - - S - - * 1 - - - 7 * - 3 - 5 - */ Eximpl const StepDelta spr_mov[] = {MK_DELTA(-2, 1), MK_DELTA(-2, -1), MK_DELTA(-1, 2), MK_DELTA(-1, -2), MK_DELTA(1, 2), MK_DELTA(1, -2), MK_DELTA(2, 1), MK_DELTA(2, -1)}; Eximpl const StepDelta dam_mov[] = {DAM_MOV_ITOR(1)}; Eximpl const StepDelta bau_mov[] = {MK_DELTA(0, 1), MK_DELTA(0, -1)}; Eximpl const StepDelta bau_left[] = {MK_DELTA(-1, 1), MK_DELTA(-1, -1)}; Eximpl const StepDelta bau_right[] = {MK_DELTA(1, 1), MK_DELTA(1, -1)}; Eximpl const Position trm_00[] = {MK_POS(7, 0), MK_POS(7, 7)}; Eximpl const Position trm_000[] = {MK_POS(0, 0), MK_POS(0, 7)}; Eximpl const AddrDelta dam_fmov[] = {DAM_MOV_ITOR((int) sizeof(Field))}; Eximpl const StepDelta dam_mov64[] = {DAM_MOV64_ITOR(1)}; #if ! INITED_att_table Eximpl int8 att_table[2 * ATT_TAB_MID + 1]; #endif #if ! INITED_pos64_pos Eximpl Position pos64_pos[64]; #endif #if ! INITED_pos64_dark Eximpl int8 pos64_dark[64]; /* whether dark field (as e.g. a1) */ #endif #if ! INITED_pos64_borders Eximpl int8 pos64_borders[64]; /* how many border fields around */ #endif #if ! INITED_pos64_nb_ddirs Eximpl DirSet pos64_nb_ddirs[64]; /* [Pos64]: {non-border rel D-dirs} */ #endif #if ! INITED_pos64_nb_sdirs Eximpl DirSet pos64_nb_sdirs[64]; /* [Pos64]: {non-border rel S-dirs} */ #endif #if ! INITED_pos64_nb_steps Eximpl uint8 pos64_nb_steps[64][8]; /* [Pos64][D-dir] #steps non-border */ #endif #if ! INITED_min_0low Eximpl ShiftCnt min_0low[1 << LOW_SEARCH_BITS]; #endif #if ! INITED_bitsum Eximpl int8 bitsum[1 << SUM_BITS]; /* map SUM_BIT bit vals to bitcount */ #endif #if WITH_ZHASH Eximpl const Zhash zh_tab[2 * MAX_FIGURES][64] = { # include "zhi.h" }; #endif #if ! INITED_cov_esc Eximpl EscInfo *cov_esc[ESCSETS]; /* how to cover escapes */ Eximpl EscSet *fig_cov[MAX_FIGURES]; /* maximal covering */ #endif # if ! INITED_fig_attdirset_tab Eximpl AttDirSet fig_attdirset_tab[fig_attdirset_idx(MAX_FIGURES)]; # endif # if ! INITED_fig_fardirset_tab Eximpl AttDirSet fig_fardirset_tab[fig_attdirset_idx(MAX_FIGURES)]; # endif # if ! INITED_bau_attdirset_tab Eximpl AttDirSet bau_attdirset_tab[NELEMS(bau_mov)]; # endif # if ! INITED_attdirset_tab Eximpl AttDirSet attdirset_tab[LEGAL_DELTA_RANGE]; # endif #if WITH_SET5 # if ! INITED_set5_subsets Eximpl uint32 set5_subsets[1 << 5]; /* [set5] all subsets (incl) */ # endif # if ! INITED_set5_supsets Eximpl uint32 set5_supsets[1 << 5]; /* [set5] all supersets (incl) */ # endif #endif #if ! INITED_ebc_tab Eximpl uint16 ebc_inx[64][64];/* [e][b], []ebc_tab */ Eximpl FieldSet ebc_tab[64 * 64]; /* [ebc_inx] */ static int ebc_tab_full = 0; #endif #if ! INITED_ldf_acov_dirs Eximpl DirSet ldf_acov_dirs[MAX_FIGURES][LEGAL_DELTA_RANGE]; #endif #if ! INITED_cov_esc # define MAX_DELTA_EXPLICIT 8 /* guarantees S to be complete */ static LegalDelta lds[1 + (MAX_DELTA_EXPLICIT + 1) * MAX_FIGURES * ESCSETS]; static EscInfo ces[ESCSETS]; static EscSet fig__cov[MAX_FIGURES * LEGAL_DELTA_RANGE]; static void into_legdelset( register LegalDelta ld, register LegDelSet * ldsp) { register LegalDelta *p; if (ldsp->count <= MAX_DELTA_EXPLICIT) { for (p = ldsp->deltas; *p; ++p) { if (*p == ld) { return; } } if (ldsp->count < MAX_DELTA_EXPLICIT) { *p = ld; } ++(ldsp->count); } } static void ice_note( register rFigure fig, EscSet dirs, LegalDelta ld) { register rEscSet mask; register rEscSet subs; fig_cov[fig][ld] |= dirs; /* If a set is covered, all subsets of it are covered also. Therefore * enumerate all subsets of "dirs": */ subs = mask = dirs; do { subs &= mask; /* fast decrement */ cov_esc[subs]->figcan |= (1 << fig); into_legdelset(ld, &(cov_esc[subs]->fighow[fig])); } while (subs--); } static void ice_ini_board(register Colour * bp) { register int i; register int j; for (i = 0; i < B_SIZE; ++i) { bp[i] = border; } for (i = 0; i < 8; ++i) { for (j = 0; j < 8; ++j) { bp[MK_POS(i, j)] = empty; } } } static void ice_ini_arrs(void) { register int i; register rFigure f; static EscInfo ei; /* statically zeroed */ register EscSet *p; for (i = 0; i < ESCSETS; ++i) { ces[i] = ei; cov_esc[i] = &(ces[i]); } p = &(fig__cov[0 - MIN_LEGAL_DELTA]); for (f = 0; f < MAX_FIGURES; ++f) { fig_cov[f] = p; p += LEGAL_DELTA_RANGE; } for (f = 0; f < MAX_FIGURES; ++f) { p = fig_cov[f]; for (i = MIN_LEGAL_DELTA; i <= MAX_LEGAL_DELTA; ++i) { p[i] = 0; } } } static void ice_assign_lds(void) { register LegalDelta *p; register int f; register int i; p = lds; ++p; /* reserve first element for 0 */ for (i = 0; i < ESCSETS; ++i) { for (f = 0; f < MAX_FIGURES; ++f) { cov_esc[i]->fighow[f].deltas = p; p += MAX_DELTA_EXPLICIT + 1; } } } static void ice_cut_lds(void) { register int f; register int i; register LegDelSet *p; for (i = 0; i < ESCSETS; ++i) { for (f = 0; f < MAX_FIGURES; ++f) { p = &(cov_esc[i]->fighow[f]); if (p->count > MAX_DELTA_EXPLICIT) { p->count = -1; } } } } static void ice_enumerate(register const Colour * board) { register int dir; register int edir; register rPosition epos; register rPosition fpos; register rPosition kpos; register int i; register int fkdir; register Bool klegal; register rLegalDelta ld; EscSet fcan[MAX_FIGURES]; EscSet bcan[2]; for (kpos = 0; kpos < B_SIZE; ++kpos) { if (board[kpos] != empty) { continue; } for (fpos = 0; fpos < B_SIZE; ++fpos) { if ((board[fpos] != empty) || (fpos == kpos)) { continue; } ld = fpos - kpos; /* as seen from K */ fkdir = att_dir(fpos, kpos); /* F -> K */ for (i = 0; i < MAX_FIGURES; ++i) { fcan[i] = 0; } bcan[white] = 0; bcan[black] = 0; klegal = TRUE; if (dam_dir(fkdir) && ((fpos + dam_mov[fkdir]) == kpos)) { klegal = FALSE; } for (dir = MIN_E_DIR; dir < MAX_E_DIR; ++dir) { epos = kpos + dam_mov[dir]; if (board[epos] != empty) { continue; } edir = att_dir(fpos, epos); if (dam_dir(edir)) { fcan[dame] |= (1 << dir); if (lfr_dir(edir)) { fcan[laeufer] |= (1 << dir); /* Do the baroque B separately for both colours: */ for (i = 0; i < 2; ++i) { if (((fpos + bau_left[i]) == epos) || ((fpos + bau_right[i]) == epos)) { bcan[i] |= (1 << dir); } } } else { /* trm_dir(edir) */ fcan[turm] |= (1 << dir); } /* As Ks are never legally adjacent, restrict fpos: */ if (klegal && ((fpos + dam_mov[edir]) == epos)) { fcan[koenig] |= (1 << dir); } } else if (spr_dir(edir)) { fcan[springer] |= (1 << dir); } } /* for dir */ /* That these figures do this delta is known, now. Put it into * our data structures. */ ice_note(bauer, bcan[white], ld); ice_note(bauer, bcan[black], ld); ice_note(springer, fcan[springer], ld); ice_note(laeufer, fcan[laeufer], ld); #if 0 if (1 || (ld == MIN_LEGAL_DELTA) && fcan[turm]) { printf("turm[%2x->%2x (%d)] -> %03x\n", fpos, kpos, ld, fcan[turm]); } #endif ice_note(turm, fcan[turm], ld); ice_note(dame, fcan[dame], ld); ice_note(koenig, fcan[koenig], ld); } /* for fpos */ } /* for kpos */ } static void ini_cov_esc(void) { Colour board[B_SIZE]; ice_ini_board(board); /* Initialize "board[]": */ ice_ini_arrs(); /* Initialize escape info arrays */ ice_assign_lds(); /* Assign the space for LegalDelta's: */ ice_enumerate(board); /* Enumerate all combinations (Figure, King): */ ice_cut_lds(); /* Cut out the too-large delta sets: */ } #endif /* ! INITED_cov_esc */ #if ! INITED_ebc_tab /* * An 3x3 environment (around a K) is described by an EscSet. * EscSets can be covered by certain pieces from certain distances. * Here we compute potential to block such coverings. * * "ebc" == EscSet blocked completely. */ # define EBC_VERBOSE 0 # define EBC_DEBUG 0 static void fs_clear(FieldSet * p) { p->fs_long[0] = 0; p->fs_long[1] = 0; } static void fs_setbit(FieldSet * p, register rPos64 pos64) { p->fs_line[LIN64(pos64)] |= (1 << COL64(pos64)); } static Bool fs_equal(const FieldSet * p1, const FieldSet * p2) { return (p1->fs_long[0] == p2->fs_long[0]) && (p1->fs_long[1] == p2->fs_long[1]); } # if EBC_VERBOSE static Bool fs_empty(const FieldSet * p) { return (p->fs_long[0] == 0) && (p->fs_long[1] == 0); } # endif /* EBC_VERBOSE */ static Bool legal_pos(Position pos) { return !(LIN(pos) & ~07) && !(COL(pos) & ~07); } static EscSet eset_redu_border(register EscSet eset, register Position epos) { register int dir; if (!legal_pos(epos)) { eset &= ~(1 << ZERO_DIR); } for (dir = 0; dir < 8; ++dir) { if ((eset & (1 << dir)) && !legal_pos(epos + dam_mov[dir])) { eset &= ~(1 << dir); } } return eset; } static int /* NO_DIR | unique dir from fpos to eset around epos */ eset_uniq_dir(Position fpos, EscSet eset, Position epos) { int udir; int cdir; int dir; udir = NO_DIR; if (eset & (1 << ZERO_DIR)) { cdir = att_dir(fpos, epos); if (!dam_dir(cdir)) { return NO_DIR; } udir = cdir; } for (dir = 0; dir < 8; ++dir) { if (eset & (1 << dir)) { cdir = att_dir(fpos, epos + dam_mov[dir]); if (!dam_dir(cdir) || (dam_dir(udir) && (cdir != udir))) { return NO_DIR; } udir = cdir; } } return udir; } static Bool /* whether "pos" is in "eset" araound "epos" */ eset_has_pos(EscSet eset, Position epos, Position pos) { int dir; if (pos == epos) { return !!(eset & (1 << ZERO_DIR)); } return dam_dir(dir = att_dir(epos, pos)) && (eset & (1 << dir)) && ((epos + dam_mov[dir]) == pos); } static void ebctab_ini(register FieldSet tab[64][64]) { register rPos64 e; register rPos64 b; for (e = 0; e < 64; ++e) { for (b = 0; b < 64; ++b) { fs_clear(&(tab[e][b])); } } } # if EBC_VERBOSE static void ebctab_show(register FieldSet tab[64][64]) { /* [e][b] -> {f} */ register rPos64 e; register rPos64 b; register int lin; register const FieldSet *p; printf("/* without empty sets:\n"); for (e = 0; e < 64; ++e) { for (b = 0; b < 64; ++b) { p = &(tab[e][b]); if (fs_empty(p)) continue; printf("[%02o][%02o] =", e, b); for (lin = 0; lin < 8; ++lin) { printf(" %02x", p->fs_line[lin]); } printf("\n"); } } printf(" */\n"); } # endif /* EBC_VERBOSE */ static void ebctab_fill(register /* const */ FieldSet tab[64][64]) { /* [e][b] -> {f} */ register rPos64 e; register rPos64 b; register rPos64 f; register rPosition epos; register rPosition bpos; register rPosition fpos; register int step; register rEscSet covd; register int udir; for (e = 0; e < 64; ++e) { epos = MK_POS(COL64(e), LIN64(e)); for (f = 0; f < 64; ++f) { if (f == e) continue; fpos = MK_POS(COL64(f), LIN64(f)); covd = fig_cov[dame][fpos - epos]; if (!covd) continue; covd = eset_redu_border(covd, epos); if (!covd) continue; udir = eset_uniq_dir(fpos, covd, epos); # if EBC_DEBUG printf("f=%02o, e=%02o, covd=%03x, udir=%d\n", f, e, covd, udir); # endif if (!dam_dir(udir)) continue; /* Ok, there is a unique direction "udir" from "f" to the * nonempty environment "covd" around "e". We scan this * direction from "f", constructing "b", until we hit one of the * blocked fields in "covd". */ step = dam_mov[udir]; for (bpos = fpos + step;; bpos += step) { if (!legal_pos(bpos)) { printf("f=%02o, e=%02o, step=%d, [ebf]pos=%d/%d/%d\n", f, e, step, epos, bpos, fpos); sys_exit(1); } if (eset_has_pos(covd, epos, bpos)) { break; } b = MK_POS64(COL(bpos), LIN(bpos)); fs_setbit(&(tab[e][b]), f); # if EBC_DEBUG printf("|= f=%02o, e=%02o, b=%02o\n", f, e, b); # endif } } } } static int /* -1 | index into arena */ ebctab_xfind( register const FieldSet * p, /* candidate */ register const FieldSet * arr, /* search arena */ register int full) { register int i; for (i = 0; i < full; ++i) { if (fs_equal(p, arr + i)) { return i; } } return -1; } static int /* full (arr) */ ebctab_crunch( /* const */ FieldSet tab[64][64], /* IN [e][b] */ uint16 inx[64][64], /* OUT [e][b] */ FieldSet arr[]) { /* OUT [inx] */ /* Crunching is performed to achieve better locality. First, many sets * are equal: we store them once. Then, some sets are more frequent than * others: the more frequent ones should stick together. */ uint16 tmpinx[64][64]; /* [e][b] */ FieldSet tmparr[64 * 64]; uint16 usecnt[64 * 64]; uint16 cntocc[64 * 64]; uint16 curinx[64 * 64]; /* [occ] -> []arr */ uint16 inxmap[64 * 64]; /* []tmparr -> []arr */ register int full; register rPos64 e; register rPos64 b; register int x; register int f; register int xallo; /* []tab */ fs_clear(&(tmparr[0])); full = 1; for (e = 0; e < 64; ++e) { for (b = 0; b < 64; ++b) { x = ebctab_xfind(&(tab[e][b]), tmparr, full); if (x < 0) { x = full; full += 1; tmparr[x] = tab[e][b]; usecnt[x] = 0; } tmpinx[e][b] = x; usecnt[x] += 1; } } /* "usecnt[x]" tells the frequency of reference of tmparr[x]. Except for * the first fixed entry, we put the most frequent ones first. We count * the number of usecnt-entries with the same frequency. */ for (f = 0; f < (64 * 64); ++f) { cntocc[f] = 0; } for (x = 1; x < full; ++x) { cntocc[usecnt[x]] += 1; } /* Now we compute allocation points for the most frequent ones, first. */ # if EBC_VERBOSE printf("/* freq %4d for empty */\n", usecnt[0]); # endif xallo = 1; /* first is reserved */ for (f = (64 * 64); --f > 0;) { /* decreasing frequency */ curinx[f] = xallo; xallo += cntocc[f]; # if EBC_VERBOSE if (cntocc[f]) { printf("/* freq %4d: %3d times */\n", f, cntocc[f]); } # endif } # if EBC_VERBOSE printf("/* full %3d, xallo %3d */\n", full, xallo); # endif /* Place tmparr[x] into the final arr[]. usecnt[x] often this set * occured: its frequency. curinx[f] is out allocation point, which we * advance. */ fs_clear(&(arr[0])); inxmap[0] = 0; for (x = 1; x < full; ++x) { f = usecnt[x]; xallo = curinx[f]++; arr[xallo] = tmparr[x]; inxmap[x] = xallo; } for (e = 0; e < 64; ++e) { for (b = 0; b < 64; ++b) { inx[e][b] = inxmap[tmpinx[e][b]]; } } return full; } static void ini_ebc(void) { /* First, fill a direct table, locally. Then, crunch out duplicates, and * build an index table. * * Environment e is completely blocked by b towards an f, if the covering * f->e is all the same D-direction, and b is outside e, but on the path * f->b->e. */ FieldSet tab[64][64];/* [e][b] -> {f} */ ebctab_ini(tab); /* clear big table */ ebctab_fill(tab); /* fill big table */ # if EBC_VERBOSE >= 2 ebctab_show(tab); # endif ebc_tab_full = ebctab_crunch(tab, ebc_inx, ebc_tab); } #endif /* ! INITED_ebc_tab */ /* * ini_extern() * Initialize external tables. */ Eximpl void ini_extern(void) { /* Initialize attack directions: */ #if ! INITED_att_table { register int i; register int j; register Position pos; register Position mov; for (i = 0; i < NELEMS(att_table); ++i) { att_table[i] = NO_DIR; } /* Define the 8 S attacks: */ for (i = 0; i < 8; ++i) { att_dir(0, spr_mov[i]) = MIN_S_DIR + i; } /* For all D directions do 7 steps: */ for (i = 0; i < 8; ++i) { mov = dam_mov[i]; pos = 0; for (j = 0; j < 7; ++j) { pos += mov; att_dir(0, pos) = MIN_D_DIR + i; } } } #endif /* ! INITED_att_dir */ /* Initialize translation of Pos64 into Position: */ #if ! INITED_pos64_pos { register int i; register int j; for (i = 0; i < 8; ++i) { for (j = 0; j < 8; ++j) { pos64_pos[MK_POS64(i, j)] = MK_POS(i, j); } } } #endif /* ! INITED_pos64_pos */ /* Initialize mapping of Pos64 into darkness: */ #if ! INITED_pos64_dark { register int i; register int j; for (i = 0; i < 8; ++i) { for (j = 0; j < 8; ++j) { pos64_dark[MK_POS64(i, j)] = (i + j + 1) & 01; } } } #endif /* ! INITED_pos64_dark */ /* Initialize mapping of Pos64 into border count: */ #if ! INITED_pos64_borders { register int i; register int j; register int c; for (i = 0; i < 8; ++i) { c = (((i == 0) || (i == 7)) ? 3 : 0); for (j = 0; j < 8; ++j) { pos64_borders[MK_POS64(i, j)] = (((j == 0) || (j == 7)) ? (c ? c + 2 : 3) : c ); } } } #endif /* ! INITED_pos64_borders */ #if ! INITED_pos64_nb_ddirs { register int t; register int dir; register int f; register int f64; for (f64 = 0; f64 < 64; ++f64) { f = pos64_pos[f64]; pos64_nb_ddirs[f64] = 0; for (dir = 0; dir < 8; ++dir) { t = f + dam_mov[dir]; if (!((LIN(t) & ~07) || (COL(t) & ~07))) { pos64_nb_ddirs[f64] |= (1 << dir); } } } } #endif /* ! INITED_pos64_nb_ddirs */ #if ! INITED_pos64_nb_sdirs { register int t; register int dir; register int f; register int f64; for (f64 = 0; f64 < 64; ++f64) { f = pos64_pos[f64]; pos64_nb_sdirs[f64] = 0; for (dir = 0; dir < 8; ++dir) { t = f + spr_mov[dir]; if (!((LIN(t) & ~07) || (COL(t) & ~07))) { pos64_nb_sdirs[f64] |= (1 << dir); } } } } #endif /* ! INITED_pos64_nb_sdirs */ #if ! INITED_pos64_nb_steps { register int t; register int dir; register int f; register int f64; register int steps; for (f64 = 0; f64 < 64; ++f64) { f = pos64_pos[f64]; for (dir = 0; dir < 8; ++dir) { for (steps = 0, t = f;; ++steps) { t += dam_mov[dir]; if ((LIN(t) & ~07) || (COL(t) & ~07)) { break; } } pos64_nb_steps[f64][dir] = steps; } } } #endif /* Fill table for fast skip of low zeroes in sets: */ #if ! INITED_min_0low { register int i; register int j; register int set; min_0low[0] = LOW_SEARCH_BITS; for (set = 1; set < (1 << LOW_SEARCH_BITS); ++set) { j = 0; i = set; while (!(i & 01)) { ++j; i >>= 1; } min_0low[set] = j; } } #endif /* ! INITED_min_0low */ /* Initialize mapping of certain value range into bit count: */ #if ! INITED_bitsum { register int i; register int s; register int t; for (i = 0; i < (1 << SUM_BITS); ++i) { s = 0; for (t = i; t; t >>= 1) { s += (t & 01); } bitsum[i] = s; } } #endif /* ! INITED_bitsum */ /* Initialize support for "move1gen()": */ #if ! INITED_cov_esc ini_cov_esc(); #endif /* ! INITED_cov_esc */ # if ! INITED_fig_attdirset_tab /* The following construction seems to be stupid, but reflects changes of * configuration. */ { register int dir1; register int dir2; register rAttDirSet set; register int i; if (NELEMS(fig_attdirset_tab) < fig_attdirset_idx(MAX_FIGURES)) { printf("fig_attdirset_tab[] (init): panic\n"); sys_exit(1); } for (i = 0; i < NELEMS(fig_attdirset_tab); ++i) { fig_attdirset_tab[i] = 0; } for (i = 0; i < MAX_FIGURES; ++i) { switch (i) { case springer: dir1 = MIN_S_DIR; dir2 = MAX_S_DIR; break; case bauer: /* ! *//* both colours */ continue; /* ! EXCLUDED ! */ case laeufer: dir1 = MIN_L_DIR; dir2 = MAX_L_DIR; break; case turm: dir1 = MIN_T_DIR; dir2 = MAX_T_DIR; break; case dame: case koenig: dir1 = MIN_D_DIR; dir2 = MAX_D_DIR; break; default: assert(FALSE); /* ! */ continue; /* for */ } for (set = 0; dir1 < dir2; ++dir1) { set |= ATTDIRSET1(dir1); } fig_attdirset(i) = set; } } # endif /* ! INITED_fig_attdirset_tab */ # if ! INITED_fig_fardirset_tab { register int i; if (NELEMS(fig_fardirset_tab) != NELEMS(fig_attdirset_tab)) { printf("fig_fardirset_tab[] (init): panic\n"); sys_exit(1); } for (i = 0; i < NELEMS(fig_fardirset_tab); ++i) { fig_fardirset_tab[i] = fig_attdirset_tab[i]; /* ! */ } for (i = 0; i < MAX_FIGURES; ++i) { switch (i) { case bauer: case springer: case koenig: fig_fardirset(i) = 0; break; default:; } } } # endif /* ! INITED_fig_fardirset_tab */ # if ! INITED_bau_attdirset_tab { register int dir; register rAttDirSet set; register int colour; if (NELEMS(bau_attdirset_tab) != NELEMS(bau_mov)) { printf("bau_attdirset_tab[] (init): panic\n"); sys_exit(1); } for (colour = 0; colour < NELEMS(bau_attdirset_tab); ++colour) { bau_attdirset_tab[colour] = 0; } for (colour = 0; colour < NELEMS(bau_attdirset_tab); ++colour) { set = 0; dir = att_dir(MK_DELTA(0, 0), bau_left[colour]); set |= ATTDIRSET1(dir); dir = att_dir(MK_DELTA(0, 0), bau_right[colour]); set |= ATTDIRSET1(dir); bau_attdirset_tab[colour] = set; } } # endif /* ! INITED_bau_attdirset_tab */ # if ! INITED_attdirset_tab { register int i; register rAttDirSet set; register Position pos; register Position mov; for (i = 0; i < NELEMS(attdirset_tab); ++i) { attdirset_tab[i] = 0; } /* For all S directions */ for (i = MIN_S_DIR; i < MAX_S_DIR; ++i) { register int idx = attdirset_idx(0, spr_mov[i - MIN_S_DIR]); if ((idx < 0) || (idx >= NELEMS(attdirset_tab))) { printf("attdirset_tab[] (init): panic (S)\n"); sys_exit(1); } attdirset_tab[idx] |= ATTDIRSET1(i); } /* For all D directions including LT(K) */ for (i = MIN_D_DIR; i < MAX_D_DIR; ++i) { mov = dam_mov[i - MIN_D_DIR]; set = ATTDIRSET1(i); for (pos = mov; dam_dir(att_dir(0, pos)); pos += mov) { register int idx = attdirset_idx(0, pos); if ((idx < 0) || (idx >= NELEMS(attdirset_tab))) { printf("attdirset_tab[] (init): panic (LTD)\n"); sys_exit(1); } attdirset_tab[idx] |= set; } } } # endif /* ! INITED_attdirset_tab */ /* Initialize support for Set-of(Set): */ #if WITH_SET5 # if ! INITED_set5_subsets { register int set; /* signed ! */ register uint32 sets; register unsigned elem; for (set = 0; set < (1 << 5); ++set) { sets = ((uint32) 1) << set; for (elem = 0; elem < 5; ++elem) { if (set & (1 << elem)) { sets |= set5_subsets[set & ~(1 << elem)]; } } set5_subsets[set] = sets; } } # endif /* ! INITED_set5_subsets */ # if ! INITED_set5_supsets { register int set; /* signed ! */ register uint32 sets; register unsigned elem; for (set = (1 << 5); --set >= 0;) { sets = ((uint32) 1) << set; for (elem = 0; elem < 5; ++elem) { if (!(set & (1 << elem))) { sets |= set5_supsets[set | (1 << elem)]; } } set5_supsets[set] = sets; } } # endif /* ! INITED_set5_supsets */ #endif #if ! INITED_ebc_tab ini_ebc(); #endif #if ! INITED_ldf_acov_dirs { register rFigure fig; register int ld; for (fig = 0; fig < MAX_FIGURES; ++fig) { for (ld = MIN_LEGAL_DELTA; ld <= MAX_LEGAL_DELTA; ++ld) { LDF_ACOV_TAB(fig)[ld] = 0; } } } { register int t; register int dir; register int f; register int f64; register int e; register int e64; for (e64 = 0; e64 < 64; ++e64) { e = pos64_pos[e64]; for (f64 = 0; f64 < 64; ++f64) { f = pos64_pos[f64]; /* LDF_ACOV_TAB(F)[f-e] shall contain the set of rel. dirs, * moving into which an F@f may at some target t cover some * part of the environment around e. FFS: B contains * promotions. */ for (dir = 0; dir < 8; ++dir) { t = f + spr_mov[dir]; if ((LIN(t) & ~07) || (COL(t) & ~07)) { continue; } if (fig_cov[springer][t - e]) { LDF_ACOV_TAB(springer)[f - e] |= (1 << dir); } } for (dir = 0; dir < 8; ++dir) { t = f + dam_mov[dir]; if ((LIN(t) & ~07) || (COL(t) & ~07)) { continue; } if (fig_cov[koenig][t - e]) { LDF_ACOV_TAB(koenig)[f - e] |= (1 << dir); } } for (dir = 0; dir < 8; ++dir) { t = f; for (;;) { t += dam_mov[dir]; if ((LIN(t) & ~07) || (COL(t) & ~07)) { break; } if (fig_cov[dame][t - e]) { LDF_ACOV_TAB(dame)[f - e] |= (1 << dir); } if (lfr_dir(dir)) { if (fig_cov[laeufer][t - e]) { LDF_ACOV_TAB(laeufer)[f - e] |= (1 << dir); } } else { if (fig_cov[turm][t - e]) { LDF_ACOV_TAB(turm)[f - e] |= (1 << dir); } } } } #if 1 /* FFS: prom should be extra table */ if ((LIN64(f64) != PROM_LIN(white)) && (LIN64(f64) != PROM_LIN(black))) { register rColour c; register Bool prom; register Bool dopp; register int i; register DirSet dirset; for (c = 0; c < 2; ++c) { prom = (LIN64(f64) == BAS_LIN(opp_colour(c))); dopp = (LIN64(f64) == BAS_LIN(c)); for (i = 0; i < 4; ++i) { switch (i) { default: /* make lint happy */ case 0: t = f + bau_left[c]; break; case 1: t = f + bau_right[c]; break; case 2: t = f + bau_mov[c]; break; case 3: if (!dopp) continue; t = f + 2 * bau_mov[c]; break; } dirset = (1 << att_dir(f, t)); if (prom) { if (fig_cov[dame][t - e] || fig_cov[springer][t - e]) { LDF_ACOV_TAB(bauer)[f - e] |= dirset; } } else { if (fig_cov[bauer][t - e]) { LDF_ACOV_TAB(bauer)[f - e] |= dirset; } } } } } #endif } } } #endif /* ! INITED_ldf_acov_dirs */ } #if INIT_PUT || INIDEFS_PUT /* * get_attdirset_fmt() */ static void get_attdirset_fmt(char **fmt_p, int *pl_p, int do_cast) { static char fmt_buf[32]; char *fmt; int len; int cnt; switch (sizeof(AttDirSet)) { case sizeof(char): fmt = "0x%02.2X"; len = 4; break; case sizeof(short): fmt = "0x%04.4X"; len = 6; break; default: fmt = ((sizeof(AttDirSet) == sizeof(long)) ? "0x%08.8lX" : "0x%08.8X"); len = 10; } if (do_cast) { sprintf(fmt_buf, "((AttDirSet)%s)", fmt); *fmt_p = &fmt_buf[0]; len += 13; assert(strlen(fmt_buf) < NELEMS(fmt_buf)); } else { *fmt_p = fmt; } cnt = (80 - 16) / (len + 2); if (cnt <= 0) cnt = 1; *pl_p = cnt; } #endif /* INIT_PUT || INIDEFS_PUT */ #if INIT_PUT #include "sysdep.c" /* !! */ static char curly[2] = {'{', '}'}; static char smooth[2] = {'(', ')'}; static void wrt_open(void) { printf("%c\n", curly[0]); } static void wrt_close(void) { printf("%c\n", curly[1]); } static void wrt_fieldset(const FieldSet * p) { /* The first and portable component is the "fs_line[8]". */ register int i; printf("%c", curly[0]); for (i = 0; i < 8; ++i) { printf(" 0x%02x,", p->fs_line[i]); } printf("%c", curly[1]); } /* * wrt_arr() * Print the contents of an array suitable as C initializer. */ static void wrt_arr( register char *arrp, /* array address */ register int nelem, /* number of elements */ register int width, /* size of each element */ register Bool isu, /* whether values are * unsigned */ register char *fmt, /* format of each * element value */ register int perline) { /* so many per line */ register int i; register int j; wrt_open(); j = 0; for (i = 0; i < nelem; arrp += width, ++i) { if (j == 0) { printf(" /*%5d */ ", i); } if (width == sizeof(char)) { if (isu) { printf(fmt, *(unsigned char *) arrp); } else { printf(fmt, *(signed char *) arrp); } } else if (width == sizeof(short)) { if (isu) { printf(fmt, *((unsigned short *) arrp)); } else { printf(fmt, *((signed short *) arrp)); } } else if (width == sizeof(long)) { printf(fmt, *((long *) arrp)); } else { printf(">>>>illegal width %d<<<<\n", width); } printf(","); if (++j >= perline) { printf("\n"); j = 0; } } wrt_close(); } /* * nonspace() * Return the first non-blank/tab character location of a string. */ static char * nonspace(register char *str) { while (*str && ((*str == ' ') || (*str == '\t'))) { ++str; } return str; } #if defined(__STDC__) # define STRING(arr) #arr #else # define STRING(arr) "arr" #endif #define wrtINITED(arr) printf("#define INITED_%s\t1\n", nonspace(STRING(arr))) #define wrt1arr(ty,arr,isu,fmt,pl) \ { printf("\nEximpl const %s %s[] =", ty, STRING(arr)); \ wrt_arr((char*)(arr), \ NELEMS(arr), \ sizeof((arr)[0]), \ isu, \ fmt, pl); \ printf(";\n\n"); \ wrtINITED(arr); \ } /* * cmp_legdel() * Compare function to sort an array of "LegalDelta" via "qsort()". * Note: legal deltas never cover a significant part of the value * range of "int" (thus returning difference is ok). */ static int cmp_legdel(const void *p1, const void *p2) { return (*((LegalDelta *) p1) - *((LegalDelta *) p2)); } /* * equal_ld_vector() * Compare two (0-terminated) vectors of legal deltas, * and return whether they are equal. */ static int equal_ld_vector( register const LegalDelta * p1, register const LegalDelta * p2) { register rLegalDelta d; while ((d = *p1) == *p2) { if (d == 0) { return (TRUE); } ++p1; ++p2; } return (FALSE); } static int equal_escinfo( EscInfo * p1, EscInfo * p2) { return mem_eq(p1, p2, sizeof(*p1)); } static void wrt_cov_esc(void) { int ldsfull; char *ldsname; int cesfull; char *cesname; int fcvfull; char *fcvname; printf("\n/* sizeof(EscInfo) = %d */\n\n", (int) sizeof(EscInfo)); /* Crunch together the "lds[]" array. Zero length lists still get an * explicit terminator. */ { register LegalDelta *xp; register rLegalDelta d; register LegalDelta *inp; register LegalDelta *outp; register LegDelSet *p; register int c; register int f; register int i; outp = lds; ++outp; /* skip reserved zero */ for (i = 0; i < ESCSETS; ++i) { for (f = 0; f < MAX_FIGURES; ++f) { p = &(cov_esc[i]->fighow[f]); c = p->count; if (c < 0) { p->deltas = 0; } else if (c == 0) { p->deltas = lds; } else { /* c > 0 */ inp = p->deltas; if (inp < outp) { printf("wrt_cov_esc panic 1\n"); sys_exit(1); } /* sort set for better searching: */ arr_Q_sort(inp, c, cmp_legdel); /* search whether vector already there: */ d = *inp; /* fast check of first elem */ for (xp = lds; xp < outp; ++xp) { if ((*xp == d) && equal_ld_vector(xp, inp)) { break; /* found same (old) vector */ } } if (xp < outp) { p->deltas = xp; /* use old vector */ } else { /* copy vector into newly allocated space */ p->deltas = outp; for (; c > 0; --c) { *outp++ = *inp++; } *outp++ = 0; } } } } ldsfull = outp - lds; } /* Put the used part of the crunched array out: */ ldsname = "ld_"; { printf("static LegalDelta %s[] =", ldsname); wrt_arr((char *) lds, ldsfull, sizeof(lds[0]), 0, "%5d", 8); printf(";\n\n"); } /* Crunch together the "ces[]" array. */ { register int j; register int i; register int outx; /* For speed and readability we want to handle specially the empty * entry (which is the most frequent). The last entry (maximal * escape) is expected to be such a. Hence, we first crunch into the * upper part of the array. */ outx = ESCSETS - 1; /* last entry */ if (ces[outx].figcan) { printf("wrt_cov_esc panic 2\n"); } for (i = outx; --i >= 0;) { /* Try to locate this ces entry somewhere in the already * collected ones. */ for (j = ESCSETS; --j >= outx;) { if (equal_escinfo(ces + i, ces + j)) { break; } } if (j >= outx) { /* found old at j */ cov_esc[i] = &(ces[j]); } else { /* want new at j (== outx-1) */ if (--outx != i) { ces[outx] = ces[i]; cov_esc[i] = &(ces[j]); } } } cesfull = ESCSETS - outx; /* Now swap them to the first part of the array. */ for (i = 0, j = ESCSETS - 1; i < j; ++i, --j) { EscInfo ei; ei = ces[i]; ces[i] = ces[j]; ces[j] = ei; } for (i = 0; i < ESCSETS; ++i) { j = cov_esc[i] - &(ces[0]); cov_esc[i] = &(ces[ESCSETS - 1 - j]); } } /* Put the used part of the crunched array out: */ cesname = "ce_"; { register int f; register int i; register const LegDelSet *p; register const EscInfo *ep; printf("static EscInfo %s[] =", cesname); wrt_open(); for (i = 0; i < cesfull; ++i) { printf("%c /* %3d */", curly[0], i); ep = &(ces[i]); printf(" 0x%02x,\n", ep->figcan); printf("%c", curly[0]); for (f = 0; f < MAX_FIGURES; ++f) { p = &(ep->fighow[f]); printf("%c %2d, ", curly[0], p->count); if (!p->deltas) { printf("0"); } else if (p->deltas == lds) { printf("%s", ldsname); } else { printf("%s+%d", ldsname, p->deltas - lds); } printf("%c,", curly[1]); } printf("%c,", curly[1]); printf("\n%c,", curly[1]); } wrt_close(); printf(";\n\n"); } /* Put the EscInfo array: */ { register int i; register int j; printf("Eximpl const EscInfo *cov_esc[%d] =", ESCSETS); wrt_open(); for (i = 0; i < ESCSETS; ++i) { printf(" /* 0x%03x */ %s", i, cesname); j = cov_esc[i] - &(ces[0]); if (j) { printf("+%3d", j); } printf(",\n"); } wrt_close(); printf(";\n\n"); } /* Put the direct coverings of the figures: Crunch array (FFS, not yet * done). Put the crunched array */ fcvname = "fig_cov_"; fcvfull = MAX_FIGURES * LEGAL_DELTA_RANGE; { printf("static EscSet %s[%d] =", fcvname, fcvfull); wrt_arr((char *) fig__cov, fcvfull, sizeof(fig__cov[0]), 1, "0x%03x", 10 ); printf(";\n\n"); } /* Put extern array: references into crunched array. */ { register rFigure f; register int inx; printf("Eximpl const EscSet* fig_cov[%d] =", MAX_FIGURES); wrt_open(); for (f = 0; f < MAX_FIGURES; ++f) { printf(" /* %d */ %s", (int) f, fcvname); inx = fig_cov[f] - &(fig__cov[0]); if (inx) { printf("+%4d", inx); } printf(",\n"); } wrt_close(); printf(";\n\n"); } wrtINITED(cov_esc); } static void wrt_ebc(void) { register int x; register rPos64 e; printf("\n"); printf("Eximpl const FieldSet ebc_tab[] ="); wrt_open(); for (x = 0; x < ebc_tab_full; ++x) { printf(" /* %3d */ ", x); wrt_fieldset(&(ebc_tab[x])); printf(",\n"); } wrt_close(); printf(";\n\n"); printf("Eximpl const uint16 ebc_inx[64][64] ="); wrt_open(); for (e = 0; e < 64; ++e) { printf("/* e = %02o */", e); wrt_arr((char *) ebc_inx[e], 64, sizeof(ebc_inx[0][0]), 1, "%3u", 8 ); printf(","); } wrt_close(); printf(";\n\n"); wrtINITED(ebc_tab); } static void wrt_pos64_nb_steps(void) { register rPos64 pos64; register int dir; printf("\n"); printf("Eximpl const uint8 pos64_nb_steps[64][8] ="); wrt_open(); for (pos64 = 0; pos64 < 64; ++pos64) { printf("/* pos64 = %02o */ %c", pos64, curly[0]); for (dir = 0; dir < 8; ++dir) { printf("%2u,", (unsigned) pos64_nb_steps[pos64][dir]); } printf("%c,\n", curly[1]); } wrt_close(); printf(";\n\n"); wrtINITED(pos64_nb_steps); } static void wrt_ldf_acov_dirs(void) { register rFigure f; printf("\n"); printf("Eximpl const DirSet ldf_acov_dirs[%d][%d] =", MAX_FIGURES, LEGAL_DELTA_RANGE); wrt_open(); for (f = 0; f < MAX_FIGURES; ++f) { printf("/* fig = %d */", f); wrt_arr((char *) ldf_acov_dirs[f], LEGAL_DELTA_RANGE, sizeof(ldf_acov_dirs[0][0]), 1, "0x%02x", 8 ); printf(","); } wrt_close(); printf(";\n\n"); wrtINITED(ldf_acov_dirs); } /* * wrt_extern() * Write the initialized external tables. */ static void wrt_extern(void) { char *u32fmt; char *fmt; int pl; u32fmt = ((sizeof(uint32) == sizeof(long)) ? "0x%08lx" : "0x%08x"); wrt1arr("int8", att_table, 0, "%3d", 16); wrt1arr("Position", pos64_pos, 0, "%4d", 8); wrt1arr("int8", pos64_dark, 0, "%1d", 16); wrt1arr("int8", pos64_borders, 0, "%1d", 8); wrt1arr("DirSet", pos64_nb_ddirs, 1, "0x%02x", 8); wrt1arr("DirSet", pos64_nb_sdirs, 1, "0x%02x", 8); wrt_pos64_nb_steps(); wrt1arr("ShiftCnt", min_0low, 1, "%2u", 16); wrt1arr("int8", bitsum, 0, "%1d", 16); #if WITH_SET5 wrt1arr("uint32", set5_subsets, 1, u32fmt, 1); wrt1arr("uint32", set5_supsets, 1, u32fmt, 1); #endif wrt_cov_esc(); wrt_ebc(); wrt_ldf_acov_dirs(); get_attdirset_fmt(&fmt, &pl, FALSE); wrt1arr("AttDirSet", fig_attdirset_tab, TRUE, fmt, pl); wrt1arr("AttDirSet", fig_fardirset_tab, TRUE, fmt, pl); wrt1arr("AttDirSet", bau_attdirset_tab, TRUE, fmt, pl); wrt1arr("AttDirSet", attdirset_tab, TRUE, fmt, pl); } #endif /* INIT_PUT */