1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2025-07-07 11:52:51 +00:00

implemented new geometries: cylinder and (only one for now) Mobius band

This commit is contained in:
Zeno Rogue 2018-11-27 02:32:11 +01:00
parent 449dd5adaf
commit 460eb19881
21 changed files with 185 additions and 83 deletions

View File

@ -729,7 +729,7 @@ void setLandSphere(cell *c) {
if(c->land == laElementalWall && (c->type != 6 || GOLDBERG)) if(c->land == laElementalWall && (c->type != 6 || GOLDBERG))
c->wall = getElementalWall(hrand(2) ? c->barleft : c->barright); c->wall = getElementalWall(hrand(2) ? c->barleft : c->barright);
} }
if(!torus) if(!euwrap)
if(specialland == laCrossroads || specialland == laCrossroads2 || specialland == laCrossroads3 || specialland == laTerracotta) { if(specialland == laCrossroads || specialland == laCrossroads2 || specialland == laCrossroads3 || specialland == laTerracotta) {
int x = getHemisphere(c, 1); int x = getHemisphere(c, 1);
if(x == 0 && specialland == laTerracotta) if(x == 0 && specialland == laTerracotta)
@ -782,6 +782,10 @@ eLand switchable(eLand nearland, eLand farland, int c) {
} }
eLand getEuclidLand(int c) { eLand getEuclidLand(int c) {
if(nonorientable) {
c = -c;
if(c < 5) return laCrossroads;
}
auto& la = get_euland(c); auto& la = get_euland(c);
if(la) return la; if(la) return la;
if(get_euland(c-2) && !get_euland(c-1)) getEuclidLand(c-1); if(get_euland(c-2) && !get_euland(c-1)) getEuclidLand(c-1);

106
cell.cpp
View File

@ -253,7 +253,11 @@ namespace torusconfig {
{"rectangle (hex)", TF_WEIRD | TF_HEX}, {"rectangle (hex)", TF_WEIRD | TF_HEX},
{"Klein bottle (squares)", TF_SIMPLE | TF_KLEIN | TF_SQUARE}, {"Klein bottle (squares)", TF_SIMPLE | TF_KLEIN | TF_SQUARE},
{"Klein bottle (hex)", TF_WEIRD | TF_KLEIN | TF_HEX}, {"Klein bottle (hex)", TF_WEIRD | TF_KLEIN | TF_HEX},
}; {"cylinder (squares)", TF_SIMPLE | TF_CYL },
{"cylinder (hex)", TF_SIMPLE | TF_CYL | TF_HEX},
{"Möbius band (squares)", TF_SIMPLE | TF_CYL | TF_KLEIN},
{"Möbius band (hex)", TF_SIMPLE | TF_CYL | TF_HEX | TF_KLEIN},
};
eTorusMode torus_mode, newmode; eTorusMode torus_mode, newmode;
flagtype tmflags() { return tmodes[torus_mode].flags; } flagtype tmflags() { return tmodes[torus_mode].flags; }
@ -342,11 +346,19 @@ namespace torusconfig {
ginf[gTorus].vertex = 3, ginf[gTorus].sides = 6; ginf[gTorus].vertex = 3, ginf[gTorus].sides = 6;
else else
ginf[gTorus].vertex = 4, ginf[gTorus].sides = 4; ginf[gTorus].vertex = 4, ginf[gTorus].sides = 4;
if(tmflags() & TF_KLEIN)
ginf[gTorus].quotientstyle |= qNONOR;
else
ginf[gTorus].quotientstyle &= ~qNONOR;
if(tmflags() & TF_CYL)
ginf[gTorus].quotientstyle &= ~qFULLTORUS;
else
ginf[gTorus].quotientstyle |= qFULLTORUS;
} }
} }
int euclid_getvec(int dx, int dy) { int euclid_getvec(int dx, int dy) {
if(torus) return torusconfig::getvec(dx, dy); if(euwrap) return torusconfig::getvec(dx, dy);
else return pair_to_vec(dx, dy); else return pair_to_vec(dx, dy);
} }
@ -438,7 +450,7 @@ hrmap_torus *torusmap() {
struct hrmap_euclidean : hrmap { struct hrmap_euclidean : hrmap {
cell *gamestart() { cell *gamestart() {
return euclideanAtCreate(0); return *(euclideanAtCreate(0).first);
} }
struct euclideanSlab { struct euclideanSlab {
@ -462,12 +474,25 @@ struct hrmap_euclidean : hrmap {
euclidean[y][x] = NULL; euclidean[y][x] = NULL;
} }
cell*& at(int vec) { euc_pointer at(int vec) {
auto p = vec_to_pair(vec); auto p = vec_to_pair(vec);
int x = p.first, y = p.second; int x = p.first, y = p.second;
bool mobius = false;
if(euwrap) {
int zx = torusconfig::sdx;
int zy = torusconfig::sdy;
int periods = gdiv(x * zx + y * zy, zx * zx + zy * zy);
if(nonorientable) mobius = (periods&1) ? S6 : 0, periods &=~ 1;
y -= zy * periods;
x -= zx * periods;
if(mobius) x -= zx, y -= zy, y = -y;
}
euclideanSlab*& slab = euclidean[(y>>8)&(slabs-1)][(x>>8)&(slabs-1)]; euclideanSlab*& slab = euclidean[(y>>8)&(slabs-1)][(x>>8)&(slabs-1)];
if(!slab) slab = new hrmap_euclidean::euclideanSlab; if(!slab) slab = new hrmap_euclidean::euclideanSlab;
return slab->a[y&255][x&255]; return make_pair(&(slab->a[y&255][x&255]), mobius);
} }
map<int, struct cdata> eucdata; map<int, struct cdata> eucdata;
@ -483,8 +508,10 @@ struct hrmap_euclidean : hrmap {
}; };
cellwalker vec_to_cellwalker(int vec) { cellwalker vec_to_cellwalker(int vec) {
if(!torus) if(!fulltorus) {
return cellwalker(euclideanAtCreate(vec), 0, false); auto p = euclideanAtCreate(vec);
return cellwalker(*p.first, 0, p.second);
}
else { else {
hrmap_torus *cur = torusmap(); hrmap_torus *cur = torusmap();
if(!cur) return cellwalker(NULL, 0); if(!cur) return cellwalker(NULL, 0);
@ -495,13 +522,23 @@ cellwalker vec_to_cellwalker(int vec) {
int cellwalker_to_vec(cellwalker cw) { int cellwalker_to_vec(cellwalker cw) {
int id = decodeId(cw.at->master); int id = decodeId(cw.at->master);
if(!torus) return id; if(!fulltorus) {
if(nonorientable) {
auto ep = euclideanAt(id);
if(ep.second != cw.mirrored) {
int x, y;
tie(x, y) = vec_to_pair(id);
return pair_to_vec(x + torusconfig::sdx, torusconfig::sdy - y);
}
}
return id;
}
return torusconfig::id_to_vec(id, cw.mirrored); return torusconfig::id_to_vec(id, cw.mirrored);
} }
int cell_to_vec(cell *c) { int cell_to_vec(cell *c) {
int id = decodeId(c->master); int id = decodeId(c->master);
if(!torus) return id; if(!fulltorus) return id;
return torusconfig::id_to_vec(id, false); return torusconfig::id_to_vec(id, false);
} }
@ -919,7 +956,10 @@ cell *createMov(cell *c, int d) {
for(int dx=-1; dx<=1; dx++) for(int dx=-1; dx<=1; dx++)
for(int dy=-1; dy<=1; dy++) for(int dy=-1; dy<=1; dy++)
euclideanAtCreate(id + pair_to_vec(dx, dy)); euclideanAtCreate(id + pair_to_vec(dx, dy));
if(!c->move(d)) { printf("fail!\n"); } if(!c->move(d)) {
println(hlog, "id = ", id, " vec_to_pair(id) = ", vec_to_pair(id), ": failed to create move ", d, " in Euclidean\n");
exit(0);
}
} }
if(c->move(d)) return c->move(d); if(c->move(d)) return c->move(d);
@ -992,28 +1032,36 @@ cell *getMovR(cell *c, int d) {
return c->move(d); return c->move(d);
} }
void eumerge(cell* c1, cell *c2, int s1, int s2) { void eumerge(cell* c1, int s1, cell *c2, int s2, bool mirror) {
if(!c2) return; if(!c2) return;
c1->move(s1) = c2; c1->c.setspin(s1, s2, false); c1->move(s1) = c2; c1->c.setspin(s1, s2, mirror);
c2->move(s2) = c1; c2->c.setspin(s2, s1, false); c2->move(s2) = c1; c2->c.setspin(s2, s1, mirror);
} }
// map<pair<eucoord, eucoord>, cell*> euclidean; // map<pair<eucoord, eucoord>, cell*> euclidean;
cell*& euclideanAt(int vec) { euc_pointer euclideanAt(int vec) {
if(torus) { printf("euclideanAt called\n"); exit(1); } if(fulltorus) { printf("euclideanAt called\n"); exit(1); }
hrmap_euclidean* euc = dynamic_cast<hrmap_euclidean*> (currentmap); hrmap_euclidean* euc = dynamic_cast<hrmap_euclidean*> (currentmap);
return euc->at(vec); return euc->at(vec);
} }
cell*& euclideanAtCreate(int vec) { euc_pointer euclideanAtCreate(int vec) {
cell*& c = euclideanAt(vec); euc_pointer ep = euclideanAt(vec);
cell*& c = *ep.first;
if(!c) { if(!c) {
c = newCell(8, encodeId(vec)); c = newCell(8, encodeId(vec));
euclideanAt(vec) = c; // euclideanAt(vec) = c;
build_euclidean_moves(c, vec, [c,vec] (int delta, int d, int d2) { eumerge(c, euclideanAt(vec + delta), d, d2); }); build_euclidean_moves(c, vec, [ep, c,vec] (int delta, int d, int d2) {
euc_pointer ep2 = euclideanAt(vec + delta);
cell* c2 = *ep2.first;
if(!c2) return;
if(ep.second) d = c->c.fix(-d);
if(ep2.second) d2 = c2->c.fix(-d2);
eumerge(c, d, c2, d2, ep.second != ep2.second);
});
} }
return c; return ep;
} }
// initializer (also inits origin from heptagon.cpp) // initializer (also inits origin from heptagon.cpp)
@ -1021,7 +1069,7 @@ void initcells() {
DEBB(DF_INIT, (debugfile,"initcells\n")); DEBB(DF_INIT, (debugfile,"initcells\n"));
if(archimedean) currentmap = arcm::new_map(); if(archimedean) currentmap = arcm::new_map();
else if(torus) currentmap = new hrmap_torus; else if(fulltorus) currentmap = new hrmap_torus;
else if(euclid) currentmap = new hrmap_euclidean; else if(euclid) currentmap = new hrmap_euclidean;
else if(sphere) currentmap = new hrmap_spherical; else if(sphere) currentmap = new hrmap_spherical;
else if(quotient) currentmap = new quotientspace::hrmap_quotient; else if(quotient) currentmap = new quotientspace::hrmap_quotient;
@ -1181,10 +1229,10 @@ int compdist(int dx[]) {
} }
int celldist(cell *c) { int celldist(cell *c) {
if(torus) if(fulltorus)
return torusmap()->dists[decodeId(c->master)]; return torusmap()->dists[decodeId(c->master)];
if(masterless) if(masterless)
return eudist(decodeId(c->master)); return eudist(decodeId(c->master)); // fix cylinder
if(sphere || binarytiling) return celldistance(c, currentmap->gamestart()); if(sphere || binarytiling) return celldistance(c, currentmap->gamestart());
if(IRREGULAR) return irr::celldist(c, false); if(IRREGULAR) return irr::celldist(c, false);
if(archimedean || ctof(c)) return c->master->distance; if(archimedean || ctof(c)) return c->master->distance;
@ -1202,7 +1250,7 @@ int celldist(cell *c) {
int celldistAlt(cell *c) { int celldistAlt(cell *c) {
if(masterless) { if(masterless) {
if(torus) return celldist(c); if(fulltorus) return celldist(c); // fix cylinder
int x, y; int x, y;
tie(x,y) = vec_to_pair(decodeId(c->master)); tie(x,y) = vec_to_pair(decodeId(c->master));
return euclidAlt(x, y); return euclidAlt(x, y);
@ -1460,7 +1508,7 @@ cdata *getHeptagonCdata(heptagon *h) {
cdata *getEuclidCdata(int h) { cdata *getEuclidCdata(int h) {
if(torus) { if(euwrap) { // fix cylinder?
static cdata xx; static cdata xx;
return &xx; return &xx;
} }
@ -1572,16 +1620,16 @@ map<pair<cell*, cell*>, int> saved_distances;
int celldistance(cell *c1, cell *c2) { int celldistance(cell *c1, cell *c2) {
if((masterless) && (euclid6 || (euclid4 && PURE))) { if((masterless) && (euclid6 || (euclid4 && PURE))) {
if(!torus) if(!euwrap)
return eudist(decodeId(c1->master) - decodeId(c2->master)); return eudist(decodeId(c1->master) - decodeId(c2->master)); // fix cylinder
else if(torus && torusconfig::torus_mode == 0) else if(euwrap && torusconfig::torus_mode == 0)
return torusmap()->dists[torusconfig::vec_to_id(decodeId(c1->master)-decodeId(c2->master))]; return torusmap()->dists[torusconfig::vec_to_id(decodeId(c1->master)-decodeId(c2->master))];
} }
if(geometry == gFieldQuotient && !GOLDBERG) if(geometry == gFieldQuotient && !GOLDBERG)
return currfp.getdist(fieldpattern::fieldval(c1), fieldpattern::fieldval(c2)); return currfp.getdist(fieldpattern::fieldval(c1), fieldpattern::fieldval(c2));
if(sphere || quotient || torus) { if(sphere || quotient || fulltorus) {
if(saved_distances.count(make_pair(c1,c2))) if(saved_distances.count(make_pair(c1,c2)))
return saved_distances[make_pair(c1,c2)]; return saved_distances[make_pair(c1,c2)];

View File

@ -1667,7 +1667,7 @@ geometryinfo ginf[gGUARD] = {
{"elliptic", "elliptic", 5, 3, qNONOR, gcSphere, 0, {{SEE_ALL, SEE_ALL}}, eVariation::bitruncated}, {"elliptic", "elliptic", 5, 3, qNONOR, gcSphere, 0, {{SEE_ALL, SEE_ALL}}, eVariation::bitruncated},
{"Zebra quotient", "Zebra", 7, 3, qSMALL | qZEBRA, gcHyperbolic, 0x00400, {{7, 5}}, eVariation::bitruncated}, {"Zebra quotient", "Zebra", 7, 3, qSMALL | qZEBRA, gcHyperbolic, 0x00400, {{7, 5}}, eVariation::bitruncated},
{"field quotient", "field", 7, 3, qFIELD, gcHyperbolic, 0x00200, {{7, 5}}, eVariation::bitruncated}, {"field quotient", "field", 7, 3, qFIELD, gcHyperbolic, 0x00200, {{7, 5}}, eVariation::bitruncated},
{"torus/Klein bottle", "torus", 6, 3, qTORUS, gcEuclid, 0x00600, {{7, 7}}, eVariation::bitruncated}, {"torus/Klein bottle", "torus", 6, 3, qEUWRAP | qFULLTORUS, gcEuclid, 0x00600, {{7, 7}}, eVariation::bitruncated},
{"octagons", "oct", 8, 3, 0, gcHyperbolic, 0x08000, {{6, 4}}, eVariation::bitruncated}, {"octagons", "oct", 8, 3, 0, gcHyperbolic, 0x08000, {{6, 4}}, eVariation::bitruncated},
{"four pentagons", "4x5", 5, 4, 0, gcHyperbolic, 0x08200, {{6, 4}}, eVariation::bitruncated}, {"four pentagons", "4x5", 5, 4, 0, gcHyperbolic, 0x08200, {{6, 4}}, eVariation::bitruncated},
{"four hexagons", "4x6", 6, 4, 0, gcHyperbolic, 0x08400, {{5, 3}}, eVariation::bitruncated}, {"four hexagons", "4x6", 6, 4, 0, gcHyperbolic, 0x08400, {{5, 3}}, eVariation::bitruncated},

View File

@ -201,7 +201,7 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle
enum eGeometry { enum eGeometry {
gNormal, gEuclid, gSphere, gElliptic, gZebraQuotient, gFieldQuotient, gTorus, gOctagon, g45, g46, g47, gSmallSphere, gTinySphere, gEuclidSquare, gSmallElliptic, gNormal, gEuclid, gSphere, gElliptic, gZebraQuotient, gFieldQuotient, gTorus, gOctagon, g45, g46, g47, gSmallSphere, gTinySphere, gEuclidSquare, gSmallElliptic,
gKleinQuartic, gBolza, gBolza2, gMinimal, gBinaryTiling, gArchimedean, gKleinQuartic, gBolza, gBolza2, gMinimal, gBinaryTiling, gArchimedean,
gMacbeath, gBring, gSchmutzM2, gSchmutzM3, gMacbeath, gBring, gSchmutzM2, gSchmutzM3,
gGUARD}; gGUARD};
enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere }; enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere };
@ -223,9 +223,10 @@ struct geometryinfo {
static const int qSMALL = 1; static const int qSMALL = 1;
static const int qFIELD = 2; static const int qFIELD = 2;
static const int qNONORIENTABLE = 4; static const int qNONORIENTABLE = 4;
static const int qTORUS = 8; static const int qEUWRAP = 8;
static const int qDOCKS = 16; static const int qDOCKS = 16;
static const int qZEBRA = 32; static const int qZEBRA = 32;
static const int qFULLTORUS = 64;
// note: dnext assumes that x&7 equals 7 // note: dnext assumes that x&7 equals 7
static const int SEE_ALL = 50; static const int SEE_ALL = 50;

View File

@ -12,7 +12,7 @@ namespace whirlwind {
int fzebra3(cell *c) { int fzebra3(cell *c) {
if(archimedean) return 0; if(archimedean) return 0;
if(euclid) { if(euclid) {
if(torus) return 0; if(fulltorus) return 0;
int x, y; int x, y;
tie(x,y) = cell_to_pair(c); tie(x,y) = cell_to_pair(c);
return 1+((((signed short)(y)+int(50000))/3)%3); return 1+((((signed short)(y)+int(50000))/3)%3);
@ -543,7 +543,7 @@ namespace princess {
int dist(cell *c) { int dist(cell *c) {
if(c->land != laPalace && c->land != laDungeon) return OUT_OF_PALACE; if(c->land != laPalace && c->land != laDungeon) return OUT_OF_PALACE;
else if(quotient || sphere || torus) return OUT_OF_PRISON; else if(quotient || sphere || fulltorus) return OUT_OF_PRISON;
else if(euclid) return celldistAlt(c); else if(euclid) return celldistAlt(c);
else if(!c->master->alt) return OUT_OF_PRISON; else if(!c->master->alt) return OUT_OF_PRISON;
else return celldistAlt(c); else return celldistAlt(c);
@ -826,7 +826,7 @@ namespace clearing {
if(quotient) return; if(quotient) return;
if(euclid) { if(euclid) {
if(torus) return; if(euwrap) return; // fix cylinder
if(pseudohept(c)) return; if(pseudohept(c)) return;
c->monst = moMutant; c->monst = moMutant;
@ -2795,7 +2795,7 @@ namespace prairie {
c->LHU.fi.walldist = 8; c->LHU.fi.walldist = 8;
c->LHU.fi.walldist2 = 8; c->LHU.fi.walldist2 = 8;
if(torus) { if(euwrap) { // fix cylinder
c->LHU.fi.rval = 0; c->LHU.fi.rval = 0;
} }
else if(euclid) { else if(euclid) {
@ -3540,7 +3540,7 @@ namespace dungeon {
*/ */
if(euclid) { if(euclid) {
if(torus) return; if(euwrap) return;
int x, y; int x, y;
tie(x, y) = cell_to_pair(c); tie(x, y) = cell_to_pair(c);
string tab6[] = { string tab6[] = {

View File

@ -596,7 +596,7 @@ namespace conformal {
vector<pair<int, int> > torus_zeros; vector<pair<int, int> > torus_zeros;
void match_torus_period() { void match_torus_period() { // fix cylinder
torus_zeros.clear(); torus_zeros.clear();
for(int y=0; y<=200; y++) for(int y=0; y<=200; y++)
for(int x=-200; x<=200; x++) { for(int x=-200; x<=200; x++) {
@ -821,7 +821,7 @@ namespace conformal {
dialog::add_action([](){ dialog::add_action([](){
dialog::editNumber(spiral_y, -20, 20, 1, 10, XLAT("spiral period: y"), ""); dialog::editNumber(spiral_y, -20, 20, 1, 10, XLAT("spiral period: y"), "");
}); });
if(torus) { if(euwrap) {
dialog::addSelItem(XLAT("match the period of the torus"), its(spiral_id), 'n'); dialog::addSelItem(XLAT("match the period of the torus"), its(spiral_id), 'n');
dialog::add_action(match_torus_period); dialog::add_action(match_torus_period);
} }

View File

@ -116,6 +116,8 @@ void showTorusConfig() {
bool single = (mode.flags & torusconfig::TF_SINGLE); bool single = (mode.flags & torusconfig::TF_SINGLE);
bool square = (mode.flags & torusconfig::TF_SQUARE); bool square = (mode.flags & torusconfig::TF_SQUARE);
bool simple = (mode.flags & torusconfig::TF_SIMPLE); bool simple = (mode.flags & torusconfig::TF_SIMPLE);
bool cyl = (mode.flags & torusconfig::TF_CYL);
bool klein = (mode.flags & torusconfig::TF_KLEIN);
if(single) { if(single) {
dialog::addSelItem(XLAT("number of cells (n)"), its(torusconfig::newqty), 'n'); dialog::addSelItem(XLAT("number of cells (n)"), its(torusconfig::newqty), 'n');
@ -124,6 +126,10 @@ void showTorusConfig() {
else else
dialog::addSelItem(XLAT("cell below 0 (d)"), its(torusconfig::newdy), 'd'); dialog::addSelItem(XLAT("cell below 0 (d)"), its(torusconfig::newdy), 'd');
} }
else if(cyl) {
dialog::addSelItem(XLAT("period (x)"), its(torusconfig::newsdx), 'x');
dialog::addSelItem(XLAT("period (y)"), its(torusconfig::newsdy), 'y');
}
else { else {
if(torusconfig::newsdx < 1) torusconfig::newsdx = 1; if(torusconfig::newsdx < 1) torusconfig::newsdx = 1;
if(torusconfig::newsdy < 1) torusconfig::newsdy = 1; if(torusconfig::newsdy < 1) torusconfig::newsdy = 1;
@ -136,6 +142,7 @@ void showTorusConfig() {
int valid = 2; int valid = 2;
int adx = torusconfig::newsdx, ady = torusconfig::newsdy;
if(single) { if(single) {
if(square) { if(square) {
dialog::addInfo("this mode has bad patterns", 0x808080), valid = 1; dialog::addInfo("this mode has bad patterns", 0x808080), valid = 1;
@ -149,6 +156,33 @@ void showTorusConfig() {
dialog::addInfo(XLAT("best if %1 is divisible by %2", "d+1", "3"), 0x808080), valid = 1; dialog::addInfo(XLAT("best if %1 is divisible by %2", "d+1", "3"), 0x808080), valid = 1;
} }
} }
else if(cyl) {
if(torusconfig::sdx == 0 && torusconfig::sdy == 0)
dialog::addInfo(XLAT("period cannot be 0"), 0x800000), valid = 0;
else if(square) {
if(torusconfig::newsdy & 1)
dialog::addInfo(XLAT("best if %1 is divisible by %2", "y", "2"), 0x808080), valid = 1;
if(torusconfig::newsdx & 1)
dialog::addInfo(XLAT("best if %1 is divisible by %2", "x", "2"), 0x808080), valid = 1;
if(!torus_bitrunc && valid == 1)
dialog::addInfo("incompatible with bitruncating", 0x808080), valid = 0;
if(klein && abs(adx) != abs(ady) && adx != 0 && ady != 0)
dialog::addInfo("Möbius band requires a symmetric period", 0x800000), valid = 0;
if(klein && ady)
dialog::addInfo("not implemented", 0x800000), valid = 0;
}
else {
if(torusconfig::newsdy % 3)
dialog::addInfo(XLAT("best if %1 is divisible by %2", "y", "3"), 0x808080), valid = 1;
if(torusconfig::newsdx % 3)
dialog::addInfo(XLAT("best if %1 is divisible by %2", "x", "3"), 0x808080), valid = 1;
if(klein && adx != 0 && ady != 0 && adx != -ady)
dialog::addInfo("Möbius band requires a symmetric period", 0x800000), valid = 0;
if(klein)
dialog::addInfo("not implemented", 0x800000), valid = 0;
}
}
else { else {
if(square) { if(square) {
if(torusconfig::newsdx & 1) if(torusconfig::newsdx & 1)
@ -286,7 +320,7 @@ void showEuclideanMenu() {
for(int i=0; i<gGUARD; i++) { for(int i=0; i<gGUARD; i++) {
bool on = geometry == i; bool on = geometry == i;
dynamicval<eGeometry> cg(geometry, eGeometry(i)); dynamicval<eGeometry> cg(geometry, eGeometry(i));
if(!!(quotient || elliptic || torus) != showquotients) continue; if(!!(quotient || elliptic || euwrap) != showquotients) continue;
dialog::addBoolItem(XLAT(ginf[i].name), on, letter++); dialog::addBoolItem(XLAT(ginf[i].name), on, letter++);
dialog::lastItem().value += validclasses[land_validity(specialland).quality_level]; dialog::lastItem().value += validclasses[land_validity(specialland).quality_level];
dialog::add_action([i] { dialog::add_action([i] {
@ -397,7 +431,9 @@ void showEuclideanMenu() {
else if((tq & qNONORIENTABLE) && sphere) qstring = "elliptic"; else if((tq & qNONORIENTABLE) && sphere) qstring = "elliptic";
else if(tq & qTORUS) qstring = "torus"; else if(tq & qFULLTORUS) qstring = "torus";
else if(tq & qEUWRAP) qstring = "cylinder";
else if(tq & qSMALL) qstring = ginf[geometry].shortname; else if(tq & qSMALL) qstring = ginf[geometry].shortname;
@ -437,7 +473,7 @@ void showEuclideanMenu() {
dialog::addBoolItem(XLAT("stereographic/orthogonal"), vid.alpha>10, '1'); dialog::addBoolItem(XLAT("stereographic/orthogonal"), vid.alpha>10, '1');
else else
dialog::addBoolItem(XLAT("Poincaré/Klein"), vid.alpha>.5, '1'); dialog::addBoolItem(XLAT("Poincaré/Klein"), vid.alpha>.5, '1');
if(torus || geometry == gFieldQuotient) if(euwrap || geometry == gFieldQuotient)
dialog::addItem(XLAT("advanced parameters"), '4'); dialog::addItem(XLAT("advanced parameters"), '4');
dialog::addHelp(); dialog::addHelp();
dialog::addBack(); dialog::addBack();
@ -482,7 +518,7 @@ void showEuclideanMenu() {
else if(uni == '5') else if(uni == '5')
ewhichscreen ^= 3; ewhichscreen ^= 3;
else if(uni == '4') { else if(uni == '4') {
if(torus) if(euwrap)
prepare_torusconfig(), prepare_torusconfig(),
pushScreen(showTorusConfig); pushScreen(showTorusConfig);
else if(geometry == gFieldQuotient) else if(geometry == gFieldQuotient)

View File

@ -81,7 +81,7 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1, const hyperpoint& point_hin
if(binarytiling) return binary::relative_matrix(c2->master, c1->master); if(binarytiling) return binary::relative_matrix(c2->master, c1->master);
if(archimedean) return arcm::relative_matrix(c2->master, c1->master); if(archimedean) return arcm::relative_matrix(c2->master, c1->master);
if(torus) { if(euwrap) {
transmatrix t = Id; transmatrix t = Id;
if(whateveri) printf("[%p,%d] ", c2, celldistance(c2, c1)); if(whateveri) printf("[%p,%d] ", c2, celldistance(c2, c1));
int mirrors = 0; int mirrors = 0;
@ -182,7 +182,7 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1, const hyperpoint& point_hin
transmatrix &ggmatrix(cell *c) { transmatrix &ggmatrix(cell *c) {
transmatrix& t = gmatrix[c]; transmatrix& t = gmatrix[c];
if(t[2][2] == 0) { if(t[2][2] == 0) {
if(torus && centerover.at) if(euwrap && centerover.at)
t = calc_relative_matrix(c, centerover.at, C0); t = calc_relative_matrix(c, centerover.at, C0);
else if(euclid) { else if(euclid) {
if(!centerover.at) centerover = cwt; if(!centerover.at) centerover = cwt;
@ -229,7 +229,7 @@ template<class T, class U>
void virtualRebase(cell*& base, T& at, bool tohex, const U& check) { void virtualRebase(cell*& base, T& at, bool tohex, const U& check) {
if(euclid || sphere) { if(euclid || sphere) {
again: again:
if(torus) for(int i=0; i<6; i++) { if(euwrap) for(int i=0; i<6; i++) {
auto newat = eumovedir(3+i) * at; auto newat = eumovedir(3+i) * at;
if(hdist0(check(newat)) < hdist0(check(at))) { if(hdist0(check(newat)) < hdist0(check(at))) {
at = newat; at = newat;

View File

@ -2156,7 +2156,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, color_t col) {
// also whatever in the lineview mode, and whatever in the quotient geometry // also whatever in the lineview mode, and whatever in the quotient geometry
else if(isFriendly(c) || isBug(c) || (c->monst && conformal::on) || c->monst == moKrakenH || (isBull(c->monst) && c->mondir != NODIR) || c->monst == moButterfly || isMagneticPole(c->monst) || else if(isFriendly(c) || isBug(c) || (c->monst && conformal::on) || c->monst == moKrakenH || (isBull(c->monst) && c->mondir != NODIR) || c->monst == moButterfly || isMagneticPole(c->monst) ||
isSwitch(c->monst) || c->monst == moPair || (c->monst && (quotient || torus || dont_face_pc))) { isSwitch(c->monst) || c->monst == moPair || (c->monst && (quotient || euwrap || dont_face_pc))) {
if(c->monst == moKrakenH) Vs = Vb, nospins = nospinb; if(c->monst == moKrakenH) Vs = Vb, nospins = nospinb;
if(!nospins) Vs = Vs * ddspin(c, c->mondir, M_PI); if(!nospins) Vs = Vs * ddspin(c, c->mondir, M_PI);
if(c->monst == moPair) Vs = Vs * xpush(-.12); if(c->monst == moPair) Vs = Vs * xpush(-.12);
@ -3577,7 +3577,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
transmatrix& gm = gmatrix[c]; transmatrix& gm = gmatrix[c];
orig = orig =
gm[2][2] == 0 ? true : gm[2][2] == 0 ? true :
torus ? hypot(gm[0][2], gm[1][2]) >= hypot(V[0][2], V[1][2]) : euwrap ? hypot(gm[0][2], gm[1][2]) >= hypot(V[0][2], V[1][2]) :
sphereflipped() ? fabs(gm[2][2]-1) <= fabs(V[2][2]-1) : sphereflipped() ? fabs(gm[2][2]-1) <= fabs(V[2][2]-1) :
fabs(gm[2][2]-1) >= fabs(V[2][2]-1) - 1e-8; fabs(gm[2][2]-1) >= fabs(V[2][2]-1) - 1e-8;

View File

@ -816,7 +816,7 @@ void describeMouseover() {
if(euclid && cheater) { if(euclid && cheater) {
out += " ("+its(cell_to_vec(c))+")"; out += " ("+its(cell_to_vec(c))+")";
if(!torus || torusconfig::torus_mode != torusconfig::tmSingle) { if(!fulltorus || torusconfig::torus_mode != torusconfig::tmSingle) {
int x, y; int x, y;
tie(x,y) = cell_to_pair(c); tie(x,y) = cell_to_pair(c);
out += " ("+its(short(x))+","+its(short(y))+")"; out += " ("+its(short(x))+","+its(short(y))+")";

20
hyper.h
View File

@ -100,10 +100,11 @@ void addMessage(string s, char spamtype = 0);
#define nonorientable (ginf[geometry].quotientstyle & qNONORIENTABLE) #define nonorientable (ginf[geometry].quotientstyle & qNONORIENTABLE)
#define elliptic (sphere && nonorientable) #define elliptic (sphere && nonorientable)
#define quotient (ginf[geometry].quotientstyle & (qSMALL | qFIELD | qDOCKS | qZEBRA)) #define quotient (ginf[geometry].quotientstyle & (qSMALL | qFIELD | qDOCKS | qZEBRA))
#define torus (ginf[geometry].quotientstyle & qTORUS) #define euwrap (ginf[geometry].quotientstyle & qEUWRAP)
#define fulltorus (ginf[geometry].quotientstyle & qFULLTORUS)
#define doall (ginf[geometry].quotientstyle) #define doall (ginf[geometry].quotientstyle)
#define smallbounded (sphere || (quotient & qSMALL) || torus) #define smallbounded (sphere || (quotient & qSMALL) || fulltorus)
#define bounded (sphere || quotient || torus) #define bounded (sphere || quotient || fulltorus)
#define masterless among(geometry, gEuclid, gEuclidSquare, gTorus) #define masterless among(geometry, gEuclid, gEuclidSquare, gTorus)
#define sphere_narcm (sphere && !archimedean) #define sphere_narcm (sphere && !archimedean)
@ -3393,7 +3394,9 @@ string llts(long long i);
void clearMemoRPM(); void clearMemoRPM();
extern int randompattern[landtypes]; extern int randompattern[landtypes];
extern int pair_to_vec(int x, int y); extern int pair_to_vec(int x, int y);
cell*& euclideanAtCreate(int vec); typedef pair<cell**, bool> euc_pointer;
euc_pointer euclideanAt(int vec);
euc_pointer euclideanAtCreate(int vec);
bool isCyclic(eLand l); bool isCyclic(eLand l);
bool generateAll(eLand l); bool generateAll(eLand l);
void extendcheck(cell *c); void extendcheck(cell *c);
@ -3791,7 +3794,11 @@ namespace torusconfig {
tmStraight, tmStraight,
tmStraightHex, tmStraightHex,
tmKlein, tmKlein,
tmKleinHex tmKleinHex,
tmCylinder,
tmCylinderHex,
tmMobius,
tmMobiusHex,
}; };
extern eTorusMode torus_mode; extern eTorusMode torus_mode;
@ -3810,7 +3817,8 @@ namespace torusconfig {
TF_WEIRD = 4, TF_WEIRD = 4,
TF_HEX = 16, TF_HEX = 16,
TF_SQUARE = 32, TF_SQUARE = 32,
TF_KLEIN = 256 TF_CYL = 64,
TF_KLEIN = 256,
}; };
flagtype tmflags(); flagtype tmflags();

View File

@ -665,7 +665,7 @@ ld spherity(const transmatrix& V) {
} }
bool confusingGeometry() { bool confusingGeometry() {
return elliptic || quotient || torus; return elliptic || quotient || euwrap;
} }
ld master_to_c7_angle() { ld master_to_c7_angle() {
@ -1476,7 +1476,7 @@ bool do_draw(cell *c, const transmatrix& T) {
if(iz < -M_PI || iz >= M_PI) return false; if(iz < -M_PI || iz >= M_PI) return false;
} }
if(cells_drawn > vid.cells_drawn_limit) return false; if(cells_drawn > vid.cells_drawn_limit) return false;
bool usr = vid.use_smart_range || quotient || torus; bool usr = vid.use_smart_range || quotient || euwrap;
if(usr && cells_drawn >= 50 && !in_smart_range(T)) return false; if(usr && cells_drawn >= 50 && !in_smart_range(T)) return false;
if(vid.use_smart_range == 2) setdist(c, 7, c); if(vid.use_smart_range == 2) setdist(c, 7, c);
return true; return true;

View File

@ -190,7 +190,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
case laPalace: // ------------------------------------------------------------- case laPalace: // -------------------------------------------------------------
if(hyperbolic_not37 || torus || S7 < 5 || archimedean) { if(hyperbolic_not37 || fulltorus || S7 < 5 || archimedean) {
if(d == 9) { if(d == 9) {
int i = hrand(100); int i = hrand(100);
if(i < 10) if(i < 10)
@ -391,7 +391,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
if(d==8) { if(d==8) {
if(randomPatternsMode) if(randomPatternsMode)
c->wall = RANDPAT3(0) ? waCavewall : waCavefloor; c->wall = RANDPAT3(0) ? waCavewall : waCavefloor;
else if(torus) { else if(fulltorus) {
c->wall = waCavefloor; c->wall = waCavefloor;
} }
else if(euclid) { else if(euclid) {
@ -482,7 +482,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
} }
else if(archimedean && arcm::current.have_line) else if(archimedean && arcm::current.have_line)
v = arcm::linespattern(c) ? 24 : 16; v = arcm::linespattern(c) ? 24 : 16;
else if(torus || hyperbolic_not37 || quotient || archimedean) { else if(fulltorus || hyperbolic_not37 || quotient || archimedean) {
v = hrand(100) < 25 ? 24 : 16; v = hrand(100) < 25 ? 24 : 16;
} }
else if(euclid) { else if(euclid) {
@ -541,7 +541,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
case laZebra: case laZebra:
if(d==8) { if(d==8) {
if(torus) ; if(fulltorus) ;
else if(archimedean && arcm::current.have_line) else if(archimedean && arcm::current.have_line)
c->wall = arcm::linespattern(c) ? waTrapdoor : waNone; c->wall = arcm::linespattern(c) ? waTrapdoor : waNone;
else if(euclid && !archimedean) { else if(euclid && !archimedean) {
@ -565,7 +565,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
case laWineyard: case laWineyard:
if(d==8) { if(d==8) {
if(torus) ; if(fulltorus) ;
else if(archimedean && arcm::current.have_line) else if(archimedean && arcm::current.have_line)
c->wall = arcm::linespattern(c) ? waVinePlant : waNone; c->wall = arcm::linespattern(c) ? waVinePlant : waNone;
else if(euclid && !archimedean) { else if(euclid && !archimedean) {
@ -1099,7 +1099,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
if(quotient && zebra40(c) == 5) { if(quotient && zebra40(c) == 5) {
c->wall = waChasm; c->wall = waChasm;
} }
if(torus) { if(fulltorus) {
int i = hrand(100); int i = hrand(100);
if(i == 0) c->item = itTreat; if(i == 0) c->item = itTreat;
else if(i < 5) c->wall = waChasm; else if(i < 5) c->wall = waChasm;
@ -1152,7 +1152,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
bool randstorm = hyperbolic_not37 || NONSTDVAR || (quotient && geometry != gZebraQuotient); bool randstorm = hyperbolic_not37 || NONSTDVAR || (quotient && geometry != gZebraQuotient);
if(d == 9) { if(d == 9) {
if(torus) { if(fulltorus) {
int pid = decodeId(c->master); int pid = decodeId(c->master);
if(pid == torusconfig::qty/3) c->wall = waCharged; if(pid == torusconfig::qty/3) c->wall = waCharged;
if(pid == torusconfig::qty*2/3) c->wall = waGrounded; if(pid == torusconfig::qty*2/3) c->wall = waGrounded;
@ -2413,7 +2413,7 @@ void setdist(cell *c, int d, cell *from) {
#else #else
if(true) { if(true) {
#endif #endif
if(sphere || torus) setLandSphere(c); if(sphere || fulltorus) setLandSphere(c);
else if(euclid) setLandEuclid(c); else if(euclid) setLandEuclid(c);
if(weirdhyperbolic) setLandWeird(c); if(weirdhyperbolic) setLandWeird(c);
if(quotient) { setland(c, specialland); setLandQuotient(c); } if(quotient) { setland(c, specialland); setLandQuotient(c); }

View File

@ -1207,7 +1207,7 @@ land_validity_t& land_validity(eLand l) {
if(archimedean && DUAL) if(archimedean && DUAL)
return not_implemented; return not_implemented;
// no equidistants supported in these geometries (big sphere is OK though) // no equidistants supported in these geometries (big sphere is OK though)
if(quotient || elliptic || smallsphere || torus) if(quotient || elliptic || smallsphere || euwrap)
return unbounded_only_except_bigsphere; return unbounded_only_except_bigsphere;
// Yendorian only implemented in standard // Yendorian only implemented in standard
if(l == laEndorian && geometry) if(l == laEndorian && geometry)
@ -1390,7 +1390,7 @@ land_validity_t& land_validity(eLand l) {
return great_walls_missing; return great_walls_missing;
// highlight Crossroads on Euclidean // highlight Crossroads on Euclidean
if(euclid && !torus && (l == laCrossroads || l == laCrossroads4)) if(euclid && !euwrap && (l == laCrossroads || l == laCrossroads4)) // fix cylinder
return full_game; return full_game;
// highlight Zebra-based lands on Zebra Quotient! // highlight Zebra-based lands on Zebra Quotient!
@ -1427,7 +1427,7 @@ land_validity_t& land_validity(eLand l) {
return pattern_not_implemented_exclude; return pattern_not_implemented_exclude;
} }
if(l == laStorms && torus) if(l == laStorms && fulltorus)
return interesting; return interesting;
if(l == laMagnetic || l == laBrownian) if(l == laMagnetic || l == laBrownian)

View File

@ -80,7 +80,7 @@ unsigned bitmajority(unsigned a, unsigned b, unsigned c) {
} }
int eufifty(cell *c) { int eufifty(cell *c) {
if(torus) { if(fulltorus) {
if(c->land == laWildWest) return cell_to_vec(c) % 37; if(c->land == laWildWest) return cell_to_vec(c) % 37;
else return cell_to_vec(c) % 27; else return cell_to_vec(c) % 27;
} }
@ -347,7 +347,7 @@ int fieldval_uniq(cell *c) {
if(ctof(c)) return c->master->fieldval; if(ctof(c)) return c->master->fieldval;
else return createMov(c, 0)->master->fieldval + 256 * createMov(c,2)->master->fieldval + (1<<16) * createMov(c,4)->master->fieldval; else return createMov(c, 0)->master->fieldval + 256 * createMov(c,2)->master->fieldval + (1<<16) * createMov(c,4)->master->fieldval;
} }
else if(torus) { else if(fulltorus) {
return decodeId(c->master); return decodeId(c->master);
} }
else if(euclid) { else if(euclid) {
@ -365,7 +365,7 @@ int fieldval_uniq(cell *c) {
} }
int fieldval_uniq_rand(cell *c, int randval) { int fieldval_uniq_rand(cell *c, int randval) {
if(sphere || torus || euclid || NONSTDVAR) if(sphere || euclid || NONSTDVAR)
// we do not care in these cases // we do not care in these cases
return fieldval_uniq(c); return fieldval_uniq(c);
if(ctof(c)) return currfp.gmul(c->master->fieldval, randval)/7; if(ctof(c)) return currfp.gmul(c->master->fieldval, randval)/7;
@ -433,7 +433,7 @@ int getHemisphere(heptagon *h, int which) {
} }
int getHemisphere(cell *c, int which) { int getHemisphere(cell *c, int which) {
if(torus) return 0; if(euwrap) return 0;
if(which == 0 && GOLDBERG && has_nice_dual()) { if(which == 0 && GOLDBERG && has_nice_dual()) {
set<cell*> visited; set<cell*> visited;
vector<cell*> q; vector<cell*> q;

View File

@ -57,7 +57,7 @@ ld widthfactor = 5;
ld label_scale = 1; ld label_scale = 1;
void fundamental_marker() { void fundamental_marker() {
if(!funmode || !(quotient || torus || elliptic)) return; if(!funmode || !(quotient || euwrap || elliptic)) return;
same.clear(); same.clear();
gm.clear(); gm.clear();

View File

@ -411,13 +411,14 @@ void buildcellcrawler(cell *c, cellcrawler& cr, int dir) {
map<int, cellcrawler> scc; map<int, cellcrawler> scc;
pair<int, int> get_cellcrawler_id(cell *c) { pair<int, int> get_cellcrawler_id(cell *c) {
if(among(geometry, gZebraQuotient, gMinimal)) { if(among(geometry, gZebraQuotient, gMinimal) || (euwrap && !fulltorus)) {
// Zebra Quotient does exhibit some symmetries, // Zebra Quotient does exhibit some symmetries,
// but these are so small anyway that it is safer to just build // but these are so small anyway that it is safer to just build
// a crawler for every neuron // a crawler for every neuron
return make_pair(neuronId(*getNeuronSlow(c)), 0); return make_pair(neuronId(*getNeuronSlow(c)), 0);
// not yet implemented for cylinder
} }
if(torus && (torusconfig::tmflags() & torusconfig::TF_KLEIN)) if(fulltorus && (torusconfig::tmflags() & torusconfig::TF_KLEIN))
return make_pair(cell_to_pair(c).second * 2 + ctof(c), 0); return make_pair(cell_to_pair(c).second * 2 + ctof(c), 0);
int id = 0, dir = 0; int id = 0, dir = 0;
if(GOLDBERG) { if(GOLDBERG) {

View File

@ -166,7 +166,7 @@ void notimpl() {
hyperpoint where(int i, cell *base) { hyperpoint where(int i, cell *base) {
auto m = vdata[i].m; auto m = vdata[i].m;
if(m->base == base) return tC0(m->at); if(m->base == base) return tC0(m->at);
else if(quotient || elliptic || torus) { else if(confusingGeometry()) {
return calc_relative_matrix(m->base, base, C0) * tC0(m->at); return calc_relative_matrix(m->base, base, C0) * tC0(m->at);
} }
else { else {
@ -177,7 +177,7 @@ hyperpoint where(int i, cell *base) {
void addedge(int i, int j, edgeinfo *ei) { void addedge(int i, int j, edgeinfo *ei) {
cell *base = cell *base =
(quotient || elliptic || torus) ? vdata[i].m->base : currentmap->gamestart(); confusingGeometry() ? vdata[i].m->base : currentmap->gamestart();
hyperpoint hi = where(i, base); hyperpoint hi = where(i, base);
hyperpoint hj = where(j, base); hyperpoint hj = where(j, base);
double d = hdist(hi, hj); double d = hdist(hi, hj);
@ -1172,7 +1172,7 @@ bool drawVertex(const transmatrix &V, cell *c, shmup::monster *m) {
if(hilite) ghilite = true; if(hilite) ghilite = true;
bool multidraw = quotient || torus; bool multidraw = quotient || euwrap;
if(ei->lastdraw < frameid || multidraw) { if(ei->lastdraw < frameid || multidraw) {
ei->lastdraw = frameid; ei->lastdraw = frameid;

View File

@ -575,7 +575,7 @@ void buildRug() {
need_mouseh = true; need_mouseh = true;
good_shape = false; good_shape = false;
if(torus) { if(euwrap) {
good_shape = true; good_shape = true;
buildTorusRug(); buildTorusRug();
return; return;
@ -812,7 +812,7 @@ int divides = 0;
bool stop = false; bool stop = false;
bool subdivide_further() { bool subdivide_further() {
if(torus) return false; if(euwrap) return false;
return isize(points) * 4 < vertex_limit; return isize(points) * 4 < vertex_limit;
} }
@ -991,7 +991,7 @@ void addNewPoints() {
if(anticusp_factor && detect_cusps()) if(anticusp_factor && detect_cusps())
return; return;
if(torus || qvalid == isize(points)) { if(euwrap || qvalid == isize(points)) {
subdivide(); subdivide();
return; return;
} }

View File

@ -172,7 +172,7 @@ void initgame() {
clear_euland(specialland); clear_euland(specialland);
if(euclid && specialland == laPrincessQuest) { if(euclid && specialland == laPrincessQuest) {
cell *c = euclideanAtCreate(pair_to_vec(EPX, EPY)); cell *c = *euclideanAtCreate(pair_to_vec(EPX, EPY)).first;
princess::generating = true; princess::generating = true;
c->land = laPalace; c->land = laPalace;
setdist(c, 7 - getDistLimit() - genrange_bonus, NULL); setdist(c, 7 - getDistLimit() - genrange_bonus, NULL);

View File

@ -82,6 +82,10 @@ int gmod(int i, int j) {
return i; return i;
} }
int gdiv(int i, int j) {
return (i - gmod(i, j)) / j;
}
ld frac(ld x) { ld frac(ld x) {
x -= int(x); x -= int(x);
if(x < 0) x++; if(x < 0) x++;