diff --git a/archimedean.cpp b/archimedean.cpp index bec90c91..f075e923 100644 --- a/archimedean.cpp +++ b/archimedean.cpp @@ -51,9 +51,11 @@ struct archimedean_tiling { vector inradius, circumradius, alphas; - int matches[30][30]; - int periods[30]; - int tilegroup[30], groupoffset[30], tilegroups; + vector> matches; + vector periods; + vector tilegroup; + vector groupoffset; + int tilegroups; int errors; string errormsg; @@ -130,18 +132,21 @@ void archimedean_tiling::make_match(int a, int i, int b, int j) { periods[a] = periods[b] = gcd(matches[a][b] - (j-i), periods[a]); } +/** mostly to protect the user from entering too large numbers */ +const int MAX_EDGE_ARCM = FULL_EDGE; + void archimedean_tiling::prepare() { euclidean_angle_sum = 0; for(int f: faces) euclidean_angle_sum += (f-2.) / f; - for(int i: faces) if(i > MAX_EDGE) { - errormsg = XLAT("currently no more than %1 edges", its(MAX_EDGE)); + for(int i: faces) if(i > MAX_EDGE_ARCM) { + errormsg = XLAT("currently no more than %1 edges", its(MAX_EDGE_ARCM)); errors++; return; } - if(isize(faces) > MAX_EDGE/2) { - errormsg = XLAT("currently no more than %1 faces in vertex", its(MAX_EDGE/2)); + if(isize(faces) > MAX_EDGE_ARCM/2) { + errormsg = XLAT("currently no more than %1 faces in vertex", its(MAX_EDGE_ARCM/2)); errors++; return; } @@ -192,8 +197,13 @@ void archimedean_tiling::prepare() { have_symmetry = false; for(int i=0; i dv(geometry, gArchimedean); /* compute the geometry */ - inradius.resize(N); + inradius.resize(N+1); inradius[N] = 0; circumradius.resize(N); alphas.resize(N); ld elmin = 0, elmax = hyperbolic ? 10 : sphere ? M_PI : 1; + /* inradius[N] is used in farcorner and nearcorner. Probably a bug */ + if(real_faces == 2) { /* standard methods fail for dihedra, but the answer is easy */ edgelength = 2 * M_PI / faces[0]; @@ -777,19 +791,19 @@ void fixup_matrix(transmatrix& T, const transmatrix& X, ld step) { } pair& archimedean_tiling::get_triangle(heptagon *h, int cid) { - return triangles[id_of(h)][(parent_index_of(h) + cid + MODFIXER) % neighbors_of(h)]; + return triangles[id_of(h)][gmod(parent_index_of(h) + cid, neighbors_of(h))]; } pair& archimedean_tiling::get_adj(heptagon *h, int cid) { - return adjacent[id_of(h)][(parent_index_of(h) + cid + MODFIXER) % neighbors_of(h)]; + return adjacent[id_of(h)][gmod(parent_index_of(h) + cid, neighbors_of(h))]; } pair& archimedean_tiling::get_adj(const pair& p, int delta) { - return adjacent[p.first][(p.second + delta + MODFIXER) % isize(adjacent[p.first])]; + return adjacent[p.first][gmod(p.second + delta, isize(adjacent[p.first]))]; } pair& archimedean_tiling::get_triangle(const pair& p, int delta) { - return triangles[p.first][(p.second + delta + MODFIXER) % isize(adjacent[p.first])]; + return triangles[p.first][gmod(p.second + delta, isize(adjacent[p.first]))]; } transmatrix adjcell_matrix(heptagon *h, int d) { diff --git a/barriers.cpp b/barriers.cpp index e2e87a60..357fb60d 100644 --- a/barriers.cpp +++ b/barriers.cpp @@ -841,9 +841,7 @@ EX bool buildBarrierNowall(cell *c, eLand l2, int forced_dir IS(NODIR)) { bool warpv = warped_version(c->land, l2); if(warpv && !arcm::in() && !pseudohept(c)) return false; - int ds[MAX_EDGE]; - for(int i=0; itype; i++) ds[i] = i; - for(int j=0; jtype; j++) swap(ds[j], ds[hrand(j+1)]); + vector ds = hrandom_permutation(c->type); for(int i=0; itype; i++) { int d = forced_dir != NODIR ? forced_dir : (valence()>3) ? (2+(i&1)) : ds[i]; diff --git a/bigstuff.cpp b/bigstuff.cpp index 544a2f5a..19ffca58 100644 --- a/bigstuff.cpp +++ b/bigstuff.cpp @@ -298,32 +298,32 @@ EX void generateTreasureIsland(cell *c) { beCIsland(c); if(c->wall == waCTree) return; } - cell* ctab[MAX_EDGE]; - int qc = 0, qlo, qhi; + vector ctab; + int qlo, qhi; for(int i=0; itype; i++) { cell *c2 = createMov(c, i); if(!eubinary) currentmap->generateAlts(c2->master); if((eubinary || (c->master->alt && c2->master->alt)) && celldistAlt(c2) < celldistAlt(c)) { - ctab[qc++] = c2; + ctab.push_back(c2); qlo = i; qhi = i; - while(true && qc < MAX_EDGE) { + while(true && isize(ctab) < c->type) { qlo--; c2 = c->cmodmove(qlo); if(!eubinary && !c2->master->alt) break; if(celldistAlt(c2) >= celldistAlt(c)) break; - ctab[qc++] = c2; + ctab.push_back(c2); } - while(true && qc < MAX_EDGE) { + while(true && isize(ctab) < c->type) { qhi++; c2 = c->cmodmove(qhi); if(!eubinary && !c2->master->alt) break; if(celldistAlt(c2) >= celldistAlt(c)) break; - ctab[qc++] = c2; + ctab.push_back(c2); } break; } } - if(!qc) { + if(ctab.empty()) { printf("NO QC\n"); c->wall = waSea; for(int i=0; itype; i++) printf("%d ", celldistAlt(c->move(i))); printf("vs %d\n", celldistAlt(c)); @@ -338,9 +338,9 @@ EX void generateTreasureIsland(cell *c) { } if(src && c2->wall == waCTree && (eubinary||c->master->alt) && celldistAlt(c) <= -10 && geometry != gRhombic3) { bool end = true; - for(int i=0; iwall != waCTree) + for(cell *cc: ctab) { + generateTreasureIsland(cc); + if(cc->wall != waCTree) end = false; } // printf("%p: end=%d, qc=%d, dist=%d\n", c, end, qc, celldistAlt(c)); @@ -571,8 +571,8 @@ EX void buildEquidistant(cell *c) { // if(qcv != 1) { printf("qcv = %d\n", qcv); exit(1); } cell *c2 = c->move(sid); int bsid = c->c.spin(sid); - for(int j=0; j<7; j++) { - int q = (bsid+j+42) % c2->type; + for(int j=0; jtype; j++) { + int q = gmod(bsid+j, c2->type); cell *c3 = c2->move(q); if(coastval(c3, b) < mcv) { cell *c4 = c2->cmodmove(bsid+1); @@ -581,7 +581,7 @@ EX void buildEquidistant(cell *c) { mcv2 = coastval(c4, b); break; } - q = (bsid-j+MODFIXER) % c2->type; + q = gmod(bsid-j, c2->type); c3 = c2->move(q); if(coastval(c3, b) < mcv) { cell *c4 = c2->cmodmove(bsid-1); @@ -774,14 +774,12 @@ EX void buildEquidistant(cell *c) { } EX cell *randomDown(cell *c) { - cell *tab[MAX_EDGE]; - int q=0; + vector tab; for(int i=0; itype; i++) if(c->move(i) && coastval(c->move(i), laIvoryTower) < coastval(c, laIvoryTower)) - tab[q++] = c->move(i); - if(!q) return NULL; - if(q==1) return tab[0]; - return tab[hrand(q)]; + tab.push_back(c->move(i)); + if(isize(tab)==1) return tab[0]; + return hrand_elt(tab, (cell*)nullptr); } EX int edgeDepth(cell *c) { diff --git a/blizzard.cpp b/blizzard.cpp index b20c651a..0826e212 100644 --- a/blizzard.cpp +++ b/blizzard.cpp @@ -28,7 +28,7 @@ struct blizzardcell { transmatrix *gm; char wmap; int inward, outward, ward; - int qty[MAX_EDGE]; + vector qty; vector inorder, outorder; int inid, outid; ~blizzardcell() { for(auto i: inorder) delete i; } @@ -77,6 +77,7 @@ EX void drawBlizzards() { auto& bc = *bcells[i]; cell *c = bc.c; bc.inward = bc.outward = 0; + bc.qty.resize(c->type); for(int i=0; itype; i++) { int& qty = bc.qty[i]; qty = 0; diff --git a/celldrawer.cpp b/celldrawer.cpp index f29801f1..28fe4266 100644 --- a/celldrawer.cpp +++ b/celldrawer.cpp @@ -858,7 +858,10 @@ void celldrawer::draw_halfvine() { queuepolyat(GDIM == 2 ? Vdepth : V2, cgi.shSemiFloor[0], darkena(vcol, fd, 0xFF), PPR::WALL3A); {dynamicval p(poly_outline, OUTLINE_TRANS); queuepolyat(V2 * spin(M_PI*2/3), cgi.shSemiFloorShadow, SHADOW_WALL, GDIM == 2 ? PPR::WALLSHADOW : PPR::TRANSPARENT_SHADOW); } auto& side = queuepolyat(V2, cgi.shSemiFloorSide[SIDE_WALL], darkena(vcol, fd, 0xFF), PPR::WALL3A-2+away(V2)); - if(GDIM == 3 && qfi.fshape) side.tinf = &floor_texture_vertices[shar.id]; + if(GDIM == 3 && qfi.fshape) { + side.tinf = &floor_texture_vertices[shar.id]; + ensure_vertex_number(*side.tinf, side.cnt); + } if(cgi.validsidepar[SIDE_WALL]) forCellIdEx(c2, j, c) { int dis = i-j; @@ -1570,6 +1573,7 @@ void celldrawer::draw_features_and_walls_3d() { #endif { poly.tinf = &floor_texture_vertices[qfi.fshape->id]; + ensure_vertex_number(*poly.tinf, poly.cnt); poly.offset_texture = 0; } } @@ -1813,7 +1817,7 @@ void celldrawer::draw_cellstat() { auto si = patterns::getpatterninfo0(c); - for(int i=(si.dir + MODFIXER) % si.symmetries; itype; i += si.symmetries) { + for(int i= gmod(si.dir, si.symmetries); itype; i += si.symmetries) { queuepoly(V * ddspin(c, i) * (si.reflect?Mirror:Id), cgi.shAsymmetric, darkena(0x000000, 0, 0xC0)); si.dir += si.symmetries; } diff --git a/checkmove.cpp b/checkmove.cpp index a541f019..7ff92231 100644 --- a/checkmove.cpp +++ b/checkmove.cpp @@ -28,7 +28,7 @@ EX eMonster who_kills_me; EX int lastkills; -EX bool legalmoves[MAX_EDGE+1]; +EX vector legalmoves; EX bool hasSafeOrb(cell *c) { return @@ -402,11 +402,11 @@ EX void checkmove() { // do not activate orbs! for(int i=0; itype+1, false); canmove = haveRangedTarget(); items[itWarning]+=2; - if(movepcto(-1, 0, true)) canmove = legalmoves[MAX_EDGE] = true; + if(movepcto(-1, 0, true)) canmove = legalmoves[cwt.at->type] = true; if(vid.mobilecompasssize || !canmove) for(int i=0; itype; i++) diff --git a/complex.cpp b/complex.cpp index eea97b46..c3be7512 100644 --- a/complex.cpp +++ b/complex.cpp @@ -64,7 +64,7 @@ EX namespace whirlwind { qdirs = 0; if(d == 0) return; int qdf = 0, qdt = 0; - int cats[MAX_EDGE]; + vector cats(c->type); for(int i=0; itype; i++) cats[i] = cat(createMov(c,i)); for(int i=0; itype; i++) @@ -2923,11 +2923,10 @@ EX namespace kraken { for(int i=0; imonst == moKrakenH && !c->stuntime && !isWateryOrBoat(c)) { - int qdir = 0; - cell *ctab[MAX_EDGE]; - forCellEx(c2, c) if(isWatery(c2)) ctab[qdir++] = c2; - hrandom_shuffle(ctab, qdir); - while(qdir--) trymove(ctab[qdir]); + vector ctab; + forCellEx(c2, c) if(isWatery(c2)) ctab.push_back(c2); + hrandom_shuffle(ctab); + for(auto& cc: ctab) trymove(cc); } } } @@ -4052,14 +4051,6 @@ EX namespace dungeon { } if(c->wparam) { - /* int q = 0; - cell* downs[MAX_EDGE]; - forCellEx(c2, c) { - buildEquidistant(c2); - if(coastvalEdge(c2) > coastvalEdge(c)) downs[q++] = c2; - } - if(q) downs[hrand(q)]->wall = waLadder; - */ cell *c2 = WDIM == 3 ? random_child(c, coastvalEdge) : c->wparam == 1 ? ts::add(c, 1, 2, coastvalEdge) : diff --git a/control.cpp b/control.cpp index 8cc4aa17..3165b5f6 100644 --- a/control.cpp +++ b/control.cpp @@ -83,7 +83,7 @@ EX movedir vectodir(hyperpoint P) { ld binv = 99; - ld dirdist[MAX_EDGE]; + vector dirdist(cwt.at->type); for(int i=0; itype; i++) { transmatrix T = currentmap->adj(cwt.at, (cwt + i).spin); @@ -139,7 +139,7 @@ EX void calcMousedest() { cellwalker bcwt = cwt; - ld dists[MAX_EDGE]; + vector dists(cwt.at->type); transmatrix U = ggmatrix(cwt.at); diff --git a/crystal.cpp b/crystal.cpp index e445ee0b..da2f5e2f 100644 --- a/crystal.cpp +++ b/crystal.cpp @@ -13,6 +13,7 @@ EX namespace crystal { #if HDR static const int MAXDIM = 7; +static const int MAX_EDGE_CRYSTAL = 2 * MAXDIM; struct coord : public array { coord operator + (coord b) { for(int i=0; i MAX_EDGE || dim > MAXDIM) { + if(dir > MAX_EDGE_CRYSTAL || dim > MAXDIM) { printf("Dimension or directions exceeded -- I have generated it, but won't play"); exit(0); } @@ -722,7 +723,7 @@ bool is_bi(crystal_structure& cs, coord co) { return false; } -array, MAX_EDGE> distlimit_table = {{ +array, MAX_EDGE_CRYSTAL> distlimit_table = {{ {{SEE_ALL,SEE_ALL}}, {{SEE_ALL,SEE_ALL}}, {{SEE_ALL,SEE_ALL}}, {{SEE_ALL,SEE_ALL}}, {{15, 10}}, {{6, 4}}, {{5, 3}}, {{4, 3}}, {{4, 3}}, {{3, 2}}, {{3, 2}}, {{3, 2}}, {{3, 2}}, {{3, 2}} }}; @@ -1257,7 +1258,7 @@ EX void build_rugdata() { const transmatrix& V = gp.second; auto co = m->get_coord(c); - ldcoord vcoord[MAX_EDGE]; + vector vcoord(c->type); for(int i=0; itype; i++) if(valence() == 4) @@ -1270,7 +1271,7 @@ EX void build_rugdata() { v->flat = coord_to_flat(co); v->valid = true; - rugpoint *p[MAX_EDGE]; + rugpoint *p[MAX_EDGE_CRYSTAL]; for(int i=0; itype; i++) { p[i] = addRugpoint(V * get_corner_position(c, i), 0); @@ -1284,7 +1285,7 @@ EX void build_rugdata() { else { hyperpoint hco = coord_to_flat(co, 4); hco[3] -= cut_level * rug::modelscale; - hyperpoint vco[MAX_EDGE]; + vector vco(c->type); for(int i=0; itype; i++) { vco[i] = coord_to_flat(vcoord[i], 4); vco[i][3] -= cut_level * rug::modelscale; @@ -1325,8 +1326,7 @@ EX void set_crystal(int sides) { static char buf[20]; sprintf(buf, "{%d,4}", sides); ginf[gCrystal].tiling_name = buf; - if(sides < MAX_EDGE) - ginf[gCrystal].distlimit = distlimit_table[sides]; + ginf[gCrystal].distlimit = distlimit_table[min(sides, MAX_EDGE_CRYSTAL-1)]; } void test_crt() { diff --git a/environment.cpp b/environment.cpp index dfa35106..981e429b 100644 --- a/environment.cpp +++ b/environment.cpp @@ -557,7 +557,7 @@ EX void moverefresh(bool turn IS(true)) { c->monst = moReptile; c->hitpoints = 3; c->stuntime = 0; - int gooddirs[MAX_EDGE], qdirs = 0; + vector gooddirs; // in the peace mode, a reptile will // prefer to walk on the ground, rather than the chasm for(int i=0; itype; i++) { @@ -565,9 +565,9 @@ EX void moverefresh(bool turn IS(true)) { int i1 = (i+c->type-3) % c->type; if(c->move(i0) && passable(c->move(i0), c, 0)) if(c->move(i1) && passable(c->move(i1), c, 0)) - gooddirs[qdirs++] = i; + gooddirs.push_back(i); } - if(qdirs) c->mondir = gooddirs[hrand(qdirs)]; + c->mondir = hrand_elt(gooddirs, c->mondir); playSound(c, "click"); } } diff --git a/floorshapes.cpp b/floorshapes.cpp index 3660bdf2..b2881323 100644 --- a/floorshapes.cpp +++ b/floorshapes.cpp @@ -79,7 +79,7 @@ void geometry_information::init_floorshapes() { for(auto sh: all_escher_floorshapes) sh->id = ids++; } -typedef pair> matrixitem; +typedef pair> matrixitem; struct mesher { eGeometry g; @@ -119,6 +119,7 @@ struct matrixlist { matrixitem genitem(const transmatrix& m1, const transmatrix& m2, int nsym) { matrixitem mi; mi.first = m1; + mi.second.resize(nsym); for(int i=0; itype); for(int i=0; itype; i++) { sizeto(fsh.gpside[k][i], id); bshape(fsh.gpside[k][i][id], PPR::LAKEWALL); @@ -435,7 +437,8 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i for(int i=0; i<=cor; i++) hpcpush(mid_at(hpxy(0,0), cornerlist[i%cor], SHADMUL)); - for(int k=0; ktype); + for(int e=0; etype; e++) { fsh.gpside[l][e] = shFullFloor.gpside[l][e]; for(auto& li: fsh.gpside[l][e]) li.tinf = &floor_texture_vertices[fsh.id]; } @@ -1016,16 +1034,28 @@ void draw_shape_for_texture(floorshape* sh) { } // SL2 needs 6 times more - for(int a=0; a T pick(T x, U... u) { std::initializer_list i = {x,u...}; return *(i.begin() + hrand(1+sizeof...(u))); } template void hrandom_shuffle(T* x, int n) { for(int k=1; k void hrandom_shuffle(T& container) { hrandom_shuffle(&container[0], isize(container)); } +template auto hrand_elt(U& container) -> decltype(container[0]) { return container[hrand(isize(container))]; } +template T hrand_elt(U& container, T default_value) { + if(container.empty()) return default_value; + return container[hrand(isize(container))]; + } #endif +EX vector hrandom_permutation(int qty) { + vector res(qty); + for(int i=0; i b, shadow, side[SIDEPARS], gpside[SIDEPARS][MAX_EDGE], levels[SIDEPARS], cone[2]; + vector b, shadow, side[SIDEPARS], levels[SIDEPARS], cone[2]; + vector> gpside[SIDEPARS]; floorshape() { prio = PPR::FLOOR; pstrength = fstrength = 10; } }; @@ -112,8 +113,7 @@ struct geometry_information { /** distance from heptagon center to heptagon vertex (either hexf or hcrossf) */ ld rhexf; - transmatrix heptmove[MAX_EDGE], hexmove[MAX_EDGE]; - transmatrix invhexmove[MAX_EDGE]; + vector heptmove, hexmove, invhexmove; int base_distlimit; @@ -381,7 +381,7 @@ hpcshape /* Goldberg parameters */ #if CAP_GP struct gpdata_t { - transmatrix Tf[MAX_EDGE][32][32][6]; + vector, 32>, 32>> Tf; transmatrix corners; ld alpha; int area; @@ -478,6 +478,10 @@ void geometry_information::prepare_basics() { finish: + heptmove.resize(S7); + hexmove.resize(S7); + invhexmove.resize(S7); + for(int d=0; dTf.resize(S7); for(int i=0; imaster)/DUALMUL + MODFIXER) % c->type; + i = gmod(i + arcm::parent_index_of(c->master)/DUALMUL, c->type); #endif draw_shapevec(c, V2, qfi.fshape->gpside[sidepar][i], col, prio); return false; diff --git a/hud.cpp b/hud.cpp index 0ae19507..185b97ea 100644 --- a/hud.cpp +++ b/hud.cpp @@ -437,7 +437,7 @@ EX void drawStats() { #if CAP_QUEUE queuecircle(xmove, yb, rad, 0xFF0000FF); queuecircle(xmove, yb, rad*SKIPFAC, - legalmoves[MAX_EDGE] ? 0xFF0000FF : 0xFF000080 + legalmoves[cwt.at->type] ? 0xFF0000FF : 0xFF000080 ); #endif #if CAP_SHAPES diff --git a/locations.cpp b/locations.cpp index 876ea502..977be055 100644 --- a/locations.cpp +++ b/locations.cpp @@ -110,7 +110,7 @@ struct gcell { #define landparam_color LHU.landpar_color #define fval LHU.fi.fieldval -#define MAX_EDGE 18 +#define FULL_EDGE 120 template struct walker; @@ -125,10 +125,12 @@ template struct walker; * and freed with tailored_free. */ +int gmod(int i, int j); + template struct connection_table { /** Table of moves. This is the maximum size, but tailored_alloc allocates less. */ - T* move_table[MAX_EDGE + (MAX_EDGE + sizeof(char*) - 1) / sizeof(char*)]; + T* move_table[FULL_EDGE + (FULL_EDGE + sizeof(char*) - 1) / sizeof(char*)]; unsigned char *spintable() { return (unsigned char*) (&move_table[full()->degree()]); } @@ -145,7 +147,7 @@ template struct connection_table { /** on non-orientable surfaces, the d-th edge may be mirrored */ bool mirror(int d) { return spintable() [d] & 128; } /** 'fix' the edge number d to get the actual index in [0, degree()) */ - int fix(int d) { return (d + MODFIXER) % full()->degree(); } + int fix(int d) { return gmod(d, full()->degree()); } /** T in the direction i */ T*& move(int i) { return move_table[i]; } /** T in the direction i, modulo degree() */ diff --git a/mapeditor.cpp b/mapeditor.cpp index e86b0423..b9152962 100644 --- a/mapeditor.cpp +++ b/mapeditor.cpp @@ -86,7 +86,7 @@ EX namespace mapeditor { c->hitpoints = c2->hitpoints; if(c2->mondir != NODIR) { auto si2 = patterns::getpatterninfo0(c2); - c->mondir = (c2->mondir - si2.dir + si.dir + MODFIXER) % c->type; + c->mondir = gmod(c2->mondir - si2.dir + si.dir, c->type); // todo reflect } } @@ -434,7 +434,7 @@ namespace mapstream { // printf("%p:%d,%d -> %p\n", c2, relspin[parent], dir, c); // spinval becomes xspinval - rspin = (c2->c.spin(dir) - f.read_char() + MODFIXER) % (c->type - sub); + rspin = gmod(c2->c.spin(dir) - f.read_char(), c->type - sub); if(GDIM == 3 && rspin && !hybri) { println(hlog, "rspin in 3D"); throw hstream_exception(); @@ -898,7 +898,7 @@ namespace mapeditor { c->hitpoints = copywhat->hitpoints; c->stuntime = copywhat->stuntime; if(copywhat->mondir == NODIR) c->mondir = NODIR; - else c->mondir = ((where.first.mirrored == where.second.mirrored ? 1 : -1) * (copywhat->mondir - where.second.spin) + cdir + MODFIXER) % c->type; + else c->mondir = gmod((where.first.mirrored == where.second.mirrored ? 1 : -1) * (copywhat->mondir - where.second.spin) + cdir, c->type); break; } checkUndo(); diff --git a/monstermove.cpp b/monstermove.cpp index 49a25206..90165b78 100644 --- a/monstermove.cpp +++ b/monstermove.cpp @@ -19,7 +19,7 @@ EX int sagephase = 0; EX vector targets; /** monsters to move, ordered by the number of possible good moves */ -vector movesofgood[MAX_EDGE+1]; +grow_vector> movesofgood; EX vector > butterflies; @@ -538,11 +538,12 @@ EX int totalbulldistance(cell *c, int k) { return tbd; } -EX void determinizeBull(cell *c, int *posdir, int& nc) { +EX void determinizeBull(cell *c, vector& posdir) { // determinize the Angry Beast movement: // use the previous PC's positions as the tiebreaker + int nc = isize(posdir); for(int k=0; k1; k++) { - int pts[MAX_EDGE]; + vector pts(nc); for(int d=0; dcmove(posdir[d]), k); int bestpts = 1000; @@ -551,46 +552,46 @@ EX void determinizeBull(cell *c, int *posdir, int& nc) { for(int d=0; d dirs(2); + int positive; bull += wstep; cell *c2 = bull.at; if(!(c2->type & 1)) return 1; // irrelevant int d = c2->type / 2; bull += d; dirs[0] = positive = bull.spin; bull -= 2*d; dirs[1] = bull.spin; - determinizeBull(c2, dirs, nc); + determinizeBull(c2, dirs); if(dirs[0] == positive) return -1; return 1; } -int posdir[MAX_EDGE], nc; +vector global_posdir; EX int pickMoveDirection(cell *c, flagtype mf) { int bestval = stayval(c, mf); - nc = 1; posdir[0] = -1; + global_posdir = {-1}; // printf("stayval [%p, %s]: %d\n", c, dnameof(c->monst), bestval); for(int d=0; dtype; d++) { cell *c2 = c->move(d); int val = moveval(c, c2, d, mf); // printf("[%d] %p: val=%5d pass=%d\n", d, c2, val, passable(c2,c,0)); - if(val > bestval) nc = 0, bestval = val; - if(val == bestval) posdir[nc++] = d; + if(val > bestval) global_posdir.clear(), bestval = val; + if(val == bestval) global_posdir.push_back(d); } if(c->monst == moRagingBull) - determinizeBull(c, posdir, nc); + determinizeBull(c, global_posdir); - if(!nc) return -1; - return posdir[hrand(nc)]; + return hrand_elt(global_posdir, -1); } EX int pickDownDirection(cell *c, flagtype mf) { - int downs[MAX_EDGE], qdowns = 0; + vector downs; int bestdif = -100; forCellIdEx(c2, i, c) { if(gravityLevelDiff(c2, c) < 0 && passable_for(c->monst, c2, c, P_MIRROR) && @@ -602,12 +603,11 @@ EX int pickDownDirection(cell *c, flagtype mf) { // printf("i=%d md=%d dif=%d\n", i, c->mondir, cdif); if(c2->wall == waClosePlate || c->wall == waClosePlate) cdif += 20; - if(cdif > bestdif) bestdif = cdif, qdowns = 0; - if(cdif == bestdif) downs[qdowns++] = i; + if(cdif > bestdif) bestdif = cdif, downs.clear(); + if(cdif == bestdif) downs.push_back(i); } } - if(!qdowns) return -1; - return downs[hrand(qdowns)]; + return hrand_elt(downs, -1); } // Angry Beast attack @@ -657,7 +657,7 @@ EX cell *moveNormal(cell *c, flagtype mf) { int d; if(c->stuntime) { - if(cellEdgeUnstable(c, MF_STUNNED)) d = pickDownDirection(c, mf), nc = 1, posdir[0] = d; + if(cellEdgeUnstable(c, MF_STUNNED)) d = pickDownDirection(c, mf), global_posdir = {d}; else return NULL; } else { @@ -706,8 +706,8 @@ EX cell *moveNormal(cell *c, flagtype mf) { } else { bool attacking = false; - for(int i=0; imove(posdir[i]); + for(int dir: global_posdir) { + cell *c2 = c->move(dir); if(isPlayerOn(c2)) { killThePlayerAt(m, c2, 0); @@ -725,8 +725,8 @@ EX cell *moveNormal(cell *c, flagtype mf) { } } - if(!attacking) for(int i=0; imonst) c->monst = m; moveMonster(mi); if(m == moRagingBull) beastAttack(mi.t, false, false); @@ -1152,13 +1152,12 @@ EX void groupmove(eMonster movtype, flagtype mf) { for(int i=0; i dirtable; - forCellIdAll(c2,t,c) dirtable[qdirtable++] = t; - hrandom_shuffle(dirtable, qdirtable); + forCellIdAll(c2,t,c) dirtable.push_back(t); + hrandom_shuffle(dirtable); - while(qdirtable--) { - int t = dirtable[qdirtable]; + for(auto& t: dirtable) { groupmove2(movei(c, t).rev(),movtype,mf); } @@ -1287,13 +1286,12 @@ EX void movehex(bool mounted, int colorpair) { for(int i=0; i dirtable; for(int t=0; ttype; t++) if(c->move(t) && inpair(c->move(t), colorpair)) - dirtable[qdirtable++] = t; + dirtable.push_back(t); - hrandom_shuffle(dirtable, qdirtable); - while(qdirtable--) { - int t = dirtable[qdirtable]; + hrandom_shuffle(dirtable); + for(auto& t: dirtable) { hexvisit(c->move(t), c, t, mounted, colorpair); } } @@ -1306,13 +1304,11 @@ EX void movehex_rest(bool mounted) { if(c->monst == moHexSnake) { colorpair = snake_pair(c); if(!goodmount(c, mounted)) continue; - int t[MAX_EDGE]; - for(int i=0; itype; i++) t[i] = i; - for(int j=1; jtype; j++) swap(t[j], t[hrand(j+1)]); + vector dirtable = hrandom_permutation(c->type); for(int u=0; utype; u++) { - createMov(c, t[u]); - if(inpair(c->move(t[u]), colorpair)) - hexvisit(c, c->move(t[u]), c->c.spin(t[u]), mounted, colorpair); + createMov(c, dirtable[u]); + if(inpair(c->move(dirtable[u]), colorpair)) + hexvisit(c, c->move(dirtable[u]), c->c.spin(dirtable[u]), mounted, colorpair); } } if(c->monst == moHexSnake) { @@ -1429,7 +1425,7 @@ EX void moveshadow() { EX void moveghosts() { if(invismove) return; - for(int d=0; d<=MAX_EDGE; d++) movesofgood[d].clear(); + movesofgood.clear(); for(int i=0; imonst, c->move(k), c) && !isPlayerOn(c->move(k))) goodmoves++; - movesofgood[goodmoves].push_back(c); + movesofgood.grow(goodmoves).push_back(c); } } - for(int d=0; d<=MAX_EDGE; d++) for(int i=0; istuntime) continue; if(isPowerMonster(c) && !playerInPower()) continue; if(isGhostMover(c->monst) && c->cpdist >= 1) { - int mdir[MAX_EDGE]; + vector mdir; for(int j=0; jtype; j++) if(c->move(j) && canAttack(c, c->monst, c->move(j), c->move(j)->monst, AF_GETPLAYER | AF_ONLY_FBUG)) { @@ -1466,12 +1461,11 @@ EX void moveghosts() { goto nextghost; } - int qmpos = 0; for(int k=0; ktype; k++) if(c->move(k) && c->move(k)->cpdist < c->cpdist) if(ghostmove(c->monst, c->move(k), c)) - mdir[qmpos++] = k; - if(!qmpos) continue; - int d = mdir[hrand(qmpos)]; + mdir.push_back(k); + if(mdir.empty()) continue; + int d = hrand_elt(mdir); cell *c2 = c->move(d); if(c2->monst == moTortoise && c2->stuntime > 1) { addMessage(XLAT("%The1 scares %the2 a bit!", c->monst, c2->monst)); @@ -1606,15 +1600,16 @@ EX void movegolems(flagtype flags) { for(int i=0; i bdirs; DEBB(DF_TURN, ("moveval")); for(int k=0; ktype; k++) if(c->move(k)) { cell *c2 = c->move(k); int val = movevalue(m, c, c2, flags); - if(val > bestv) bestv = val, bq = 0; - if(val == bestv) bdirs[bq++] = k; + if(val > bestv) bestv = val, bdirs.clear(); + if(val == bestv) bdirs.push_back(k); } if(m == moTameBomberbird) { @@ -1622,8 +1617,8 @@ EX void movegolems(flagtype flags) { if(c2 && !c2->monst) { int val = movevalue(m, c, c2, flags); // printf("val = %d bestv = %d\n", - if(val > bestv) bestv = val, bq = 0; - if(val == bestv) bdirs[bq++] = STRONGWIND; + if(val > bestv) bestv = val, bdirs.clear(); + if(val == bestv) bdirs.push_back(STRONGWIND); } } @@ -1631,8 +1626,8 @@ EX void movegolems(flagtype flags) { // printf("stayvalue = %d, result = %d, bq = %d\n", stayvalue(m,c), bestv, bq); - if(bq == 0) continue; - int dir = bdirs[hrand(bq)]; + if(bdirs.empty()) continue; + int dir = hrand_elt(bdirs); auto mi = movei(c, dir); auto& c2 = mi.t; if(c2->monst) { @@ -1882,16 +1877,16 @@ EX void consMove(cell *c, eMonster param) { if(c2 && c2->pathdist < c->pathdist) goodmoves++; } - movesofgood[goodmoves].push_back(c); + movesofgood.grow(goodmoves).push_back(c); } else - movesofgood[0].push_back(c); + movesofgood.grow(0).push_back(c); } EX void moveNormals(eMonster param) { pathdata pd(param); - - for(int d=0; d<=MAX_EDGE; d++) movesofgood[d].clear(); + + movesofgood.clear(); for(int i=0; ipathdist == PINFD) consMove(c, param); } - for(int d=0; d<=MAX_EDGE; d++) for(int i=0; imonst].mgroup == moYeti) { moveNormal(c, MF_PATHDIST); } diff --git a/netgen.cpp b/netgen.cpp index e3bab5fd..e49203a6 100644 --- a/netgen.cpp +++ b/netgen.cpp @@ -57,15 +57,15 @@ EX namespace netgen { vec center[MAXCELLS]; double rot[MAXCELLS]; int glued[MAXCELLS]; - int nei[MAXCELLS][MAX_EDGE]; + vector nei[MAXCELLS]; // auxiliary data double raylen[MAXCELLS]; double edgist[MAXCELLS]; - char patek[MAXCELLS][MAX_EDGE]; + vector patek[MAXCELLS]; // data generated by HyperRogue - hyperpoint hcenter[MAXCELLS][MAX_EDGE+1]; + vector hcenter[MAXCELLS]; // Functions handling the data. //============================== @@ -79,7 +79,8 @@ EX namespace netgen { if(mode == 1) for(int ii=0; iitype+1); + hcenter[ii][c->type] = V * C0; if(c->type == S7) { for(int i=0; itype; i++) { @@ -110,11 +111,12 @@ EX namespace netgen { for(int i=0; itype; - for(int k=0; k<8; k++) + for(int k=0; k<=ct[i]; k++) vx[i][2*k] = hcenter[i][k][0], vx[i][2*k+1] = hcenter[i][k][1]; - for(int k=0; k= 3) return true; if(d <= -3) return true; - d = c.spin + d + MODFIXER; - d%=c.at->type; + d = gmod(c.spin + d, c.at->type); if(!c.at->move(d)) return true; return reflectingBarrierAt(c.at->move(d)); @@ -1104,8 +1103,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) { // nature if(items[itOrbNature] && numplayers() == 1 && c->monst != moFriendlyIvy) { - int dirs[MAX_EDGE]; - int qsides = 0; + vector dirs; forCellIdCM(cf, d, c) if(cf->monst == moFriendlyIvy) { @@ -1118,11 +1116,11 @@ EX eItem targetRangedOrb(cell *c, orbAction a) { if(strictlyAgainstGravity(c, cf, false, MF_IVY)) continue; if(monstersnear(cwt.at, NULL, moPlayer, c, cwt.at)) continue; } - dirs[qsides++] = d; + dirs.push_back(d); } - if(qsides > 0) { - int di = dirs[hrand(qsides)]; + int di = hrand_elt(dirs, -1); + if(di != -1) { if(!isCheck(a)) growIvyTo(movei(c, di).rev()); return itOrbNature; } diff --git a/pattern2.cpp b/pattern2.cpp index 21326b2b..e2482e6d 100644 --- a/pattern2.cpp +++ b/pattern2.cpp @@ -1278,8 +1278,8 @@ EX int pattern_threecolor(cell *c) { #if CAP_GP if(S3 == 3 && !(S7&1) && gp_threecolor() == 1 && c->master->c7 != c) { auto li = gp::get_local_info(c); - int rel = (li.relative.first - li.relative.second + MODFIXER) % 3; - int par = (gp::param.first - gp::param.second + MODFIXER) % 3; + int rel = gmod(li.relative.first - li.relative.second, 3); + int par = gmod(gp::param.first - gp::param.second, 3); if(rel == 0) return pattern_threecolor(c->master->c7); else if(rel == par) @@ -1335,7 +1335,7 @@ EX int pattern_threecolor(cell *c) { #if CAP_GP if(gp_threecolor() == 2) { auto li = gp::get_local_info(c); - int sp = (MODFIXER + li.relative.first + 2 * li.relative.second) % 3; + int sp = gmod(li.relative.first + 2 * li.relative.second, 3); if(sp != 0) { if(li.last_dir & 1) sp = 3 - sp; diff --git a/quotient.cpp b/quotient.cpp index e2a47d7c..f2b174ae 100644 --- a/quotient.cpp +++ b/quotient.cpp @@ -12,25 +12,16 @@ namespace hr { EX namespace quotientspace { - bool operator == (const code& c1, const code &c2) { - for(int i=0; i<=S7; i++) if(c1.c[i] != c2.c[i]) return false; - return true; - } - - bool operator < (const code& c1, const code &c2) { - for(int i=0; i<=S7; i++) if(c1.c[i] != c2.c[i]) return c1.c[i] < c2.c[i]; - return false; - } - int cod(heptagon *h) { return zebra40(h->c7); } code get(heptspin hs) { code res; - res.c[0] = cod(hs.at); + res.connections.resize(S7); + res.connections[0] = cod(hs.at); for(int i=1; i<=S7; i++) { - res.c[i] = cod((hs + wstep).at); + res.connections[i] = cod((hs + wstep).at); hs += 1; } return res; @@ -45,7 +36,11 @@ EX namespace quotientspace { #if HDR struct code { - int c[MAX_EDGE+1]; + vector connections; + + bool operator == (const code &c2) const { return connections == c2.connections; } + bool operator < (const code &c2) const { return connections < c2.connections; } + }; struct hrmap_quotient : hrmap_standard { diff --git a/rug.cpp b/rug.cpp index 5ef88983..12ddf533 100644 --- a/rug.cpp +++ b/rug.cpp @@ -609,7 +609,7 @@ EX void buildRug() { rugpoint *v = p.second; if(arcm::in() || (euclid && quotient)) { - rugpoint *p[MAX_EDGE+1]; + vector p(c->type+1); for(int j=0; jtype; j++) p[j] = findOrAddRugpoint(ggmatrix(c) * get_corner_position(c, j), v->dist); for(int j=0; jtype; j++) addTriangle(v, p[j], p[(j+1) % c->type]);