diff --git a/binary-tiling.cpp b/binary-tiling.cpp index 9a050ba5..8663d35b 100644 --- a/binary-tiling.cpp +++ b/binary-tiling.cpp @@ -385,6 +385,49 @@ namespace binary { } return gm * where; } + + vector get_vertices(cell* c) override { + vector res; + ld yy = log(2) / 2; + using namespace hyperpoint_vec; + auto add = [&] (hyperpoint h) { + res.push_back(binary::parabolic3(h[0], h[1]) * xpush0(yy*h[2])); + }; + switch(geometry) { + case gBinary3: + for(int x=-1; x<2; x++) for(int y=-1; y<2; y++) for(int z=-1; z<=1; z+=2) + if(z == -1 || x != 0 || y != 0) + add(point3(x,y,z)); + break; + case gHoroTris: { + ld r = sqrt(3)/6; + ld r2 = r * 2; + + hyperpoint shift3 = point3(0,0,-3); + hyperpoint shift1 = point3(0,0,-1); + + for(int i=0; i<3; i++) { + hyperpoint t0 = spin(120 * degree * i) * point3(0,-r2,-1); + add(t0); + add(-2 * t0 + shift3); + add(-2 * t0 + shift1); + } + } + case gHoroRec: { + ld r2 = sqrt(2); + for(int y=-1; y<=1; y++) for(int x=-1; x<=1; x+=2) for(int z=-1; z<=1; z++) + if(z == -1 || y != 0) + add(point3(-r2*x*hororec_scale, -2*y*hororec_scale, z*.5)); + break; + } + case gHoroHex: { + // complicated and unused for now -- todo + break; + } + default: ; + } + return res; + } }; hrmap *new_map() { return new hrmap_binary; } diff --git a/euclid.cpp b/euclid.cpp index 23225301..e7a550fd 100644 --- a/euclid.cpp +++ b/euclid.cpp @@ -620,6 +620,29 @@ namespace euclid3 { return eupush3(v[0], v[1], v[2]); } + vector get_vertices(cell* c) override { + vector res; + if(S7 < 14) + for(ld a: {-.5,.5}) for(ld b: {-.5,.5}) for(ld c: {-.5, .5}) res.push_back(hpxy3(a,b,c)); + if(S7 == 12) { + res.push_back(hpxy3(1,0,0)); + res.push_back(hpxy3(-1,0,0)); + res.push_back(hpxy3(0,1,0)); + res.push_back(hpxy3(0,-1,0)); + res.push_back(hpxy3(0,0,1)); + res.push_back(hpxy3(0,0,-1)); + } + if(S7 == 14) { + for(ld a: {-1.,-.5,0.,.5,1.}) + for(ld b: {-1.,-.5,0.,.5,1.}) + for(ld c: {-1.,-.5,0.,.5,1.}) + if(a == 0 || b == 0 || c == 0) + if(a == .5 || a == -.5 || b == .5 || b == -.5 || c == .5 || c == -.5) + if(a == 1 || a == -1 || b == 1 || b == -1 || c == 1 || c == -1) + res.push_back(hpxy3(a,b,c)); + } + return res; + } }; hrmap_euclid3* cubemap() { diff --git a/game.cpp b/game.cpp index d0ecbe42..9a5de2e8 100644 --- a/game.cpp +++ b/game.cpp @@ -7354,9 +7354,17 @@ void knightFlavorMessage(cell *c2) { int mine_adjacency_rule = 0; +map> adj_memo; + +bool geometry_has_alt_mine_rule() { + if(DIM == 2) return VALENCE > 3; + if(DIM == 3) return !among(geometry, gHoroHex, gCell5, gBitrunc3, gCell8, gECell8, gCell120, gECell120); + return true; + } + vector adj_minefield_cells(cell *c) { vector res; - if(mine_adjacency_rule == 0 || (VALENCE == 3 && DIM == 2)) + if(mine_adjacency_rule == 0 || !geometry_has_alt_mine_rule()) forCellCM(c2, c) res.push_back(c2); else if(DIM == 2) { cellwalker cw(c, 0); @@ -7371,6 +7379,25 @@ vector adj_minefield_cells(cell *c) { } while(cw != cw1); } + else if(adj_memo.count(c)) return adj_memo[c]; + else { + const vector vertices = currentmap->get_vertices(c); + manual_celllister cl; + cl.add(c); + for(int i=0; irelative_matrix(c1->master, c->master); + for(hyperpoint h: vertices) for(hyperpoint h2: vertices) + if(hdist(h, T * h2) < 1e-6) shares = true; + if(shares) res.push_back(c1); + } + if(shares || c == c1) forCellEx(c2, c1) cl.add(c2); + } + println(hlog, "adjacent to ", c, " = ", isize(res)); + adj_memo[c] = res; + } return res; } diff --git a/geom-exp.cpp b/geom-exp.cpp index 3990aa47..e2ffe07a 100644 --- a/geom-exp.cpp +++ b/geom-exp.cpp @@ -696,7 +696,7 @@ void showEuclideanMenu() { }); } - if(specialland == laMinefield && (DIM == 3 || VALENCE != 3)) { + if(specialland == laMinefield && geometry_has_alt_mine_rule()) { dialog::addSelItem(XLAT("mine adjacency rule"), XLAT(mine_adjacency_rule ? "vertex" : DIM == 3 ? "face" : "edge"), 'M'); dialog::add_action([] { stop_game(); diff --git a/geometry2.cpp b/geometry2.cpp index ef6da6bd..53624b17 100644 --- a/geometry2.cpp +++ b/geometry2.cpp @@ -598,5 +598,11 @@ hyperpoint get_warp_corner(cell *c, int cid) { #endif return ddspin(c,cid,M_PI/S7) * xpush0(tessf/2); } - + +vector hrmap::get_vertices(cell* c) { + vector res; + for(int i=0; itype; i++) res.push_back(get_corner_position(c, i, 3)); + return res; + } + } diff --git a/hyper.h b/hyper.h index 7659c134..22162542 100644 --- a/hyper.h +++ b/hyper.h @@ -3103,6 +3103,7 @@ struct hrmap { virtual void draw() { printf("undrawable\n"); } + virtual vector get_vertices(cell*); }; // hrmaps which are based on regular non-Euclidean 2D tilings, possibly quotient diff --git a/reg3.cpp b/reg3.cpp index cdef6bd9..3032aff9 100644 --- a/reg3.cpp +++ b/reg3.cpp @@ -31,6 +31,7 @@ namespace reg3 { int loop, face; vector cellshape; + vector vertices_only; transmatrix spins[12], adjmoves[12]; @@ -169,6 +170,13 @@ namespace reg3 { if(loop == 4) strafedist = adjcheck; else strafedist = hdist(adjmoves[0] * C0, adjmoves[1] * C0); + + vertices_only.clear(); + for(hyperpoint h: cellshape) { + bool found = false; + for(hyperpoint h2: vertices_only) if(hdist(h, h2) < 1e-6) found = true; + if(!found) vertices_only.push_back(h); + } } void binary_rebase(heptagon *h, const transmatrix& V) { @@ -505,6 +513,10 @@ namespace reg3 { heptagon *getOrigin() override { return allh[0]; } vector& allcells() override { return acells; } + + vector get_vertices(cell* c) override { + return vertices_only; + } }; struct hrmap_reg3 : hrmap { @@ -787,6 +799,9 @@ namespace reg3 { return inverse(p1.second) * T * p2.second; } + vector get_vertices(cell* c) override { + return vertices_only; + } }; hrmap* new_map() { diff --git a/system.cpp b/system.cpp index 24714c61..0c7173f4 100644 --- a/system.cpp +++ b/system.cpp @@ -1412,6 +1412,7 @@ auto cgm = addHook(clearmemory, 40, [] () { crush_next.clear(); crush_now.clear(); rosemap.clear(); + adj_memo.clear(); }) + addHook(hooks_removecells, 0, [] () { eliminate_if(crush_next, is_cell_removed);