From 749ad0313885f3369c834c8ef88b3be8cf58762f Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Fri, 17 Aug 2018 13:29:00 +0200 Subject: [PATCH] syntetic tilings (WIP) --- bigstuff.cpp | 2 +- cell.cpp | 41 +-- classes.cpp | 3 +- classes.h | 2 +- compileunits.h | 1 + geom-exp.cpp | 1 + geometry.cpp | 2 + graph.cpp | 40 +-- heptagon.cpp | 19 +- hyper.h | 20 +- hypgraph.cpp | 12 +- monstergen.cpp | 4 +- pattern2.cpp | 14 +- shmup.cpp | 1 + syntetic.cpp | 666 +++++++++++++++++++++++++++++++++++++++++++++++++ 15 files changed, 774 insertions(+), 54 deletions(-) create mode 100644 syntetic.cpp diff --git a/bigstuff.cpp b/bigstuff.cpp index cbc64ca6..fe5ce228 100644 --- a/bigstuff.cpp +++ b/bigstuff.cpp @@ -976,7 +976,7 @@ int wallchance(cell *c, bool deepOcean) { bool horo_ok() { // do the horocycles work in the current geometry? - return hyperbolic && !binarytiling; + return hyperbolic && !binarytiling && !syntetic; } bool gp_wall_test() { diff --git a/cell.cpp b/cell.cpp index c73a737d..85f9ba7e 100644 --- a/cell.cpp +++ b/cell.cpp @@ -73,7 +73,9 @@ hrmap_hyperbolic::hrmap_hyperbolic() { h.alt = NULL; h.distance = 0; isnonbitrunc = nonbitrunc; - if(binarytiling) { + if(syntetic) + synt::initialize(&h); + else if(binarytiling) { #if DEBUG_BINARY_TILING binary::xcode.clear(); binary::rxcode.clear(); @@ -845,7 +847,7 @@ cell *createMov(cell *c, int d) { printf("ERROR createmov\n"); } - if(euclid && !c->mov[d]) { + if(masterless && !c->mov[d]) { int id = decodeId(c->master); for(int dx=-1; dx<=1; dx++) for(int dy=-1; dy<=1; dy++) @@ -864,7 +866,14 @@ cell *createMov(cell *c, int d) { exit(1); } } - else if(nonbitrunc) { + else if(nonbitrunc && syntetic) { + if(synt::id_of(c->master) <= synt::N * 2) { + heptspin hs = heptspin(c->master, d) + wstep + 2 + wstep + 1; + merge(c,d,hs.h->c7,hs.spin,false); + } + else merge(c, d, c, d, false); + } + else if(nonbitrunc || syntetic) { heptagon *h2 = createStep(c->master, d); merge(c,d,h2->c7,c->master->spin(d),false); } @@ -933,7 +942,8 @@ cell*& euclideanAtCreate(int vec) { void initcells() { DEBB(DF_INIT, (debugfile,"initcells\n")); - if(torus) currentmap = new hrmap_torus; + if(syntetic) currentmap = new hrmap_hyperbolic; + else if(torus) currentmap = new hrmap_torus; else if(euclid) currentmap = new hrmap_euclidean; else if(sphere) currentmap = new hrmap_spherical; else if(quotient) currentmap = new quotientspace::hrmap_quotient; @@ -1040,7 +1050,7 @@ void verifycell(cell *c) { for(int i=0; imov[i]; if(c2) { - if(!euclid && !nonbitrunc && c == c->master->c7) verifycell(c2); + if(!stdeuclid && !nonbitrunc && c == c->master->c7) verifycell(c2); if(c2->mov[c->spn(i)] && c2->mov[c->spn(i)] != c) { printf("cell error %p:%d [%d] %p:%d [%d]\n", c, i, c->type, c2, c->spn(i), c2->type); exit(1); @@ -1050,7 +1060,7 @@ void verifycell(cell *c) { } void verifycells(heptagon *at) { - if(gp::on || irr::on) return; + if(gp::on || irr::on || syntetic) return; for(int i=0; imove[i] && at->move[i]->move[at->spin(i)] && at->move[i]->move[at->spin(i)] != at) { printf("hexmix error %p [%d s=%d] %p %p\n", at, i, at->spin(i), at->move[i], at->move[i]->move[at->spin(i)]); } @@ -1091,14 +1101,13 @@ int compdist(int dx[]) { } int celldist(cell *c) { - if(euclid) { - if(torus) - return torusmap()->dists[decodeId(c->master)]; + if(torus) + return torusmap()->dists[decodeId(c->master)]; + if(masterless) return eudist(decodeId(c->master)); - } if(sphere) return celldistance(c, currentmap->gamestart()); if(irr::on) return irr::celldist(c, false); - if(ctof(c)) return c->master->distance; + if(binarytiling || syntetic || ctof(c)) return c->master->distance; if(gp::on) return gp::compute_dist(c, celldist); int dx[MAX_S3]; for(int u=0; umaster)); @@ -1429,7 +1438,7 @@ cdata *getEuclidCdata(int h) { } int getCdata(cell *c, int j) { - if(euclid) return getEuclidCdata(decodeId(c->master))->val[j]; + if(stdeuclid) return getEuclidCdata(decodeId(c->master))->val[j]; else if(geometry) return 0; else if(ctof(c)) return getHeptagonCdata(c->master)->val[j]*3; else { @@ -1442,7 +1451,7 @@ int getCdata(cell *c, int j) { } int getBits(cell *c) { - if(euclid) return getEuclidCdata(decodeId(c->master))->bits; + if(stdeuclid) return getEuclidCdata(decodeId(c->master))->bits; else if(geometry) return 0; else if(c->type != 6) return getHeptagonCdata(c->master)->bits; else { @@ -1486,7 +1495,7 @@ map, int> saved_distances; int celldistance(cell *c1, cell *c2) { int d = 0; - if(euclid6 || (euclid4 && nonbitrunc)) { + if((stdeuclid) && (euclid6 || (euclid4 && nonbitrunc))) { if(!torus) return eudist(decodeId(c1->master) - decodeId(c2->master)); else if(torus && torusconfig::torus_mode == 0) @@ -1511,7 +1520,7 @@ int celldistance(cell *c1, cell *c2) { return 64; } - if(gp::on || euclid || irr::on) { + if(gp::on || stdeuclid || irr::on) { if(saved_distances.count(make_pair(c1,c2))) return saved_distances[make_pair(c1,c2)]; diff --git a/classes.cpp b/classes.cpp index 8f61b3a5..6f435b6b 100644 --- a/classes.cpp +++ b/classes.cpp @@ -1680,7 +1680,8 @@ geometryinfo ginf[gGUARD] = { {"Bolza Surface", "Bolza", 8, 3, qSMALL | qDOCKS, gcHyperbolic, 0x18200, {{6, 4}}}, {"Bolza Surface x2", "Bolza2", 8, 3, qSMALL | qDOCKS, gcHyperbolic, 0x18400, {{6, 4}}}, {"minimal quotient", "minimal", 7, 3, qSMALL | qNONOR, gcHyperbolic, 0x18600, {{7, 5}}}, - {"binary tiling", "binary", 7, 3, 0, gcHyperbolic, 0, {{7, 5}}} + {"binary tiling", "binary", 7, 3, 0, gcHyperbolic, 0, {{7, 5}}}, + {"syntetic tiling", "syntetic", 7, 3, 0, gcHyperbolic, 0, {{7, 5}}} }; } diff --git a/classes.h b/classes.h index bfb7d77e..6199fa3b 100644 --- a/classes.h +++ b/classes.h @@ -198,7 +198,7 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle enum eGeometry { gNormal, gEuclid, gSphere, gElliptic, gZebraQuotient, gFieldQuotient, gTorus, gOctagon, g45, g46, g47, gSmallSphere, gTinySphere, gEuclidSquare, gSmallElliptic, - gKleinQuartic, gBolza, gBolza2, gMinimal, gBinaryTiling, + gKleinQuartic, gBolza, gBolza2, gMinimal, gBinaryTiling, gSyntetic, gGUARD}; enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere }; diff --git a/compileunits.h b/compileunits.h index 8d0a8237..644e3161 100644 --- a/compileunits.h +++ b/compileunits.h @@ -30,6 +30,7 @@ #include "fieldpattern.cpp" #include "heptagon.cpp" #include "binary-tiling.cpp" +#include "syntetic.cpp" #include "language.cpp" #include "cell.cpp" #include "goldberg.cpp" diff --git a/geom-exp.cpp b/geom-exp.cpp index a20057c1..431a4fea 100644 --- a/geom-exp.cpp +++ b/geom-exp.cpp @@ -579,6 +579,7 @@ int read_geom_args() { } TOGGLE('7', nonbitrunc, stop_game_and_switch_mode(rg::bitrunc)) else if(argis("-geo")) { + PHASEFROM(2); shift(); targetgeometry = (eGeometry) argi(); if(targetgeometry != geometry) stop_game_and_switch_mode(rg::geometry); diff --git a/geometry.cpp b/geometry.cpp index d818714b..7bccf539 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -53,6 +53,8 @@ void precalc() { int vertexdegree = S6/2; ld fmin, fmax; + if(syntetic) return; + if(euclid) { // dynamicval g(geometry, gNormal); // precalc(); } diff --git a/graph.cpp b/graph.cpp index 0ea2167b..e3100d7b 100644 --- a/graph.cpp +++ b/graph.cpp @@ -248,7 +248,7 @@ int displaydir(cell *c, int d) { int dirs[8] = {0, 11, 21, 31, 42, 53, 63, 73}; return -21-dirs[d]; } - else if(euclid) + else if(stdeuclid) return - d * S84 / c->type; else return S42 - d * S84 / c->type; @@ -286,7 +286,7 @@ void drawPlayerEffects(const transmatrix& V, cell *c, bool onplayer) { if(onplayer && (items[itOrbSword] || items[itOrbSword2])) { using namespace sword; - double esh = euclid ? M_PI - M_PI*3/S84 + 2.5 * M_PI/S42: 0; + double esh = stdeuclid ? M_PI - M_PI*3/S84 + 2.5 * M_PI/S42: 0; if(shmup::on) { #if CAP_POLY @@ -305,7 +305,7 @@ void drawPlayerEffects(const transmatrix& V, cell *c, bool onplayer) { transmatrix Vnow = gmatrix[c] * rgpushxto0(inverse(gmatrix[c]) * tC0(V)) * (irr::on ? ddspin(c,0,S42) : spin(-hexshiftat(c))); #if CAP_QUEUE - if(!euclid) for(int a=0; amaster->alt) + if(!eubinary && where && where->master->alt) col = cloakcolor(roundTableRadius(where)); else col = cloakcolor(newRoundTableRadius()); @@ -2054,7 +2054,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) { if(d>=4) cw += 2; transmatrix Vs = Vparam; bool mirr = cw.mirrored; - Vs = Vs * ddspin(c, cw.spin-cwt.spin, euclid ? 0 : S42); + Vs = Vs * ddspin(c, cw.spin-cwt.spin, stdeuclid ? 0 : S42); nospins = applyAnimation(cwt.c, Vs, footphase, LAYER_SMALL); if(!nospins) Vs = Vs * ddspin(c, cwt.spin); if(mirr) Vs = Vs * Mirror; @@ -2118,7 +2118,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) { Vb = Vb * xpush(tentacle_length - cellgfxdist(c, c->mondir)); } - // if(ctof(c) && !euclid) Vb = Vb * xpush(hexhexdist - hcrossf); + // if(ctof(c) && !stdeuclid) Vb = Vb * xpush(hexhexdist - hcrossf); // return nonbitrunc ? tessf * gp::scale : (c->type == 6 && (i&1)) ? hexhexdist : crossf; return drawMonsterTypeDH(m, c, Vb, col, darkhistory, footphase); } @@ -2406,7 +2406,7 @@ void set_towerfloor(cell *c, cellfunction *cf = coastvalEdge) { } int j = -1; - if(euclid) j = 10; + if(stdeuclid) j = 10; else if((*cf)(c) > 1) { int i = towerval(c, cf); if(i == 4) j = 0; @@ -2431,7 +2431,7 @@ void set_towerfloor(cell *c, cellfunction *cf = coastvalEdge) { void set_zebrafloor(cell *c) { - if(euclid) { set_floor(shTower[10]); return; } + if(stdeuclid) { set_floor(shTower[10]); return; } if(weirdhyperbolic) { set_floor(shFloor); return; } @@ -2520,7 +2520,7 @@ void draw_reptile(cell *c, const transmatrix &V, int col) { } void set_emeraldfloor(cell *c) { - if(!euclid && !nonbitrunc) { + if(!stdeuclid && !nonbitrunc) { auto si = patterns::getpatterninfo(c, 'f', patterns::SPF_SYM0123); int j = -1; @@ -2600,7 +2600,7 @@ bool drawstaratvec(double dx, double dy) { int reptilecolor(cell *c) { int i = zebra40(c); - if(!euclid) { + if(!stdeuclid) { if(i >= 4 && i < 16) i = 0; else if(i >= 16 && i < 28) i = 1; else if(i >= 28 && i < 40) i = 2; @@ -2642,7 +2642,7 @@ void setcolors(cell *c, int& wcol, int &fcol) { if(c->mov[i]->wall != waSea && c->mov[i]->wall != waBoat) nearshore = true; if(nearshore) mafcol += 30; */ - fcol = fcol + mafcol * (4+sin(ticks / 500. + ((euclid||c->master->alt) ? celldistAlt(c) : 0)*1.5))/5; + fcol = fcol + mafcol * (4+sin(ticks / 500. + ((eubinary||c->master->alt) ? celldistAlt(c) : 0)*1.5))/5; } else if(c->land == laDocks) { fcol = 0x0000A0; @@ -2748,7 +2748,7 @@ void setcolors(cell *c, int& wcol, int &fcol) { fcol = gradient(0x008000, 0x800000, 0, c->landparam, 10); break; case laMountain: - if(euclid || sphere || c->master->alt) + if(eubinary || sphere || c->master->alt) fcol = celldistAlt(c) & 1 ? 0x604020 : 0x302010; else fcol = 0; if(c->wall == waPlatform) wcol = 0xF0F0A0; @@ -2877,7 +2877,7 @@ void setcolors(cell *c, int& wcol, int &fcol) { break; case laCamelot: { - int d = showoff ? 0 : ((euclid||c->master->alt) ? celldistAltRelative(c) : 0); + int d = showoff ? 0 : ((eubinary||c->master->alt) ? celldistAltRelative(c) : 0); #if CAP_TOUR if(!tour::on) camelotcheat = false; if(camelotcheat) @@ -3107,7 +3107,7 @@ bool is_nice_dual(cell *c) { } bool use_swapped_duals() { - return (euclid && !a4) || gp::on; + return (stdeuclid && !a4) || gp::on; } void floorShadow(cell *c, const transmatrix& V, int col) { @@ -5218,7 +5218,7 @@ void drawthemap() { compute_graphical_distance(); centdist = 1e20; - if(!euclid) centerover.c = NULL; + if(!stdeuclid) centerover.c = NULL; for(int i=0; i 1e-9) Centered = rgpushxto0(H); @@ -5766,7 +5768,7 @@ void restartGraph() { View = Id; if(!autocheat) linepatterns::clearAll(); if(currentmap) { - if(euclid) { + if(stdeuclid) { centerover = vec_to_cellwalker(0); } else { @@ -5899,7 +5901,7 @@ void drawBug(const cellwalker& cw, int col) { } cell *viewcenter() { - if(euclid) return centerover.c; + if(stdeuclid) return centerover.c; else return viewctr.h->c7; } diff --git a/heptagon.cpp b/heptagon.cpp index 6b63e189..8ef261cf 100644 --- a/heptagon.cpp +++ b/heptagon.cpp @@ -74,7 +74,7 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0, int fix h->spintable = 0; h->move[pard] = parent; tsetspin(h->spintable, pard, d); parent->move[d] = h; tsetspin(parent->spintable, d, pard); - if(binarytiling) return h; + if(binarytiling || syntetic) return h; if(parent->c7) { if(irr::on) irr::link_next(parent, d); @@ -203,9 +203,9 @@ void connectHeptagons(heptagon *h1, int d1, heptagon *h2, int d2) { int recsteps; void addSpin(heptagon *h, int d, heptagon *from, int rot, int spin) { - rot = fixrot(rot); + rot = fixrot(h, rot); createStep(from, rot); - int fr = fixrot(from->spin(rot) + spin); + int fr = fixrot(from, from->spin(rot) + spin); connectHeptagons(h, d, from->move[rot], fr); /* h->move[d] = from->move[rot]; h->setspin(d, fr); @@ -219,8 +219,13 @@ extern int hrand(int); // a structure used to walk on the heptagonal tesselation // (remembers not only the heptagon, but also direction) +int fixrot(heptagon *h, int a) { + if(syntetic) return synt::fix(h, a); + return (a+MODFIXER) % S7; + } + heptspin& operator += (heptspin& hs, int spin) { - hs.spin = fixrot(hs.spin + (MIRR(hs)?-spin:spin)); + hs.spin = fixrot(hs.h, hs.spin + (MIRR(hs)?-spin:spin)); return hs; } @@ -238,9 +243,13 @@ heptspin operator - (heptspin h, int spin) { return h += -spin; } heptspin& operator += (heptspin& h, wstep_t) { h = h + wstep; return h; } heptagon *createStep(heptagon *h, int d) { - d = fixrot(d); + d = fixrot(h, d); if(!h->move[d] && binarytiling) return binary::createStep(h, d); + if(!h->move[d] && syntetic) { + synt::create_adjacent(h, d); + return h->move[d]; + } if(!h->move[0] && h->s != hsOrigin && !binarytiling) { // cheating: int pard=0; diff --git a/hyper.h b/hyper.h index 6f044550..94b9e020 100644 --- a/hyper.h +++ b/hyper.h @@ -88,6 +88,7 @@ void addMessage(string s, char spamtype = 0); #define stdhyperbolic (S7 == 7 && S3 == 3 && !gp::on && !irr::on && !binarytiling) #define binarytiling (geometry == gBinaryTiling) +#define syntetic (geometry == gSyntetic) #define eubinary (euclid || binarytiling) #define cgclass (ginf[geometry].cclass) @@ -102,6 +103,10 @@ void addMessage(string s, char spamtype = 0); #define smallbounded (sphere || (quotient & qSMALL) || torus) #define bounded (sphere || quotient || torus) +#define masterless among(geometry, gEuclid, gEuclidSquare) +#define stdeuclid (torus || masterless) +#define stdsphere (sphere && !syntetic) + #define a4 (S3 == 4) #define a45 (S3 == 4 && S7 == 5) #define a46 (S3 == 4 && S7 == 6) @@ -319,7 +324,8 @@ inline void tsetspin(uint32_t& t, int d, int spin) { t &= ~(15 << (d<<2)); t |= inline int tspin(uint32_t& t, int d) { return (t >> (d<<2)) & 7; } inline bool tmirror(uint32_t& t, int d) { return (t >> ((d<<2)+3)) & 1; } -inline int fixrot(int a) { return (a+MODFIXER)% S7; } +int fixrot(struct heptagon *h, int a); + inline int fix42(int a) { return (a+MODFIXER)% S42; } struct cell; @@ -357,8 +363,8 @@ struct heptagon { // associated generator of alternate structure, for Camelot and horocycles heptagon *alt; // functions - heptagon*& modmove(int i) { return move[fixrot(i)]; } - unsigned char gspin(int i) { return spin(fixrot(i)); } + heptagon*& modmove(int i) { return move[fixrot(this, i)]; } + unsigned char gspin(int i) { return spin(fixrot(this, i)); } heptagon () { heptacount++; } ~heptagon () { heptacount--; } }; @@ -3765,4 +3771,12 @@ namespace binary { heptagon *createStep(heptagon *parent, int d); } +namespace synt { + void initialize(heptagon *root); + transmatrix relative_matrix(heptagon *h1, heptagon *h2); + short& id_of(heptagon *); + void draw(); + void create_adjacent(heptagon*, int); + int fix(heptagon *h, int spin); + } } diff --git a/hypgraph.cpp b/hypgraph.cpp index 0fb13b51..bc672156 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -499,18 +499,20 @@ bool confusingGeometry() { } ld master_to_c7_angle() { - return nonbitrunc ? M_PI + gp::alpha : 0; + return (nonbitrunc && !binarytiling && !syntetic) ? M_PI + gp::alpha : 0; } transmatrix actualV(const heptspin& hs, const transmatrix& V) { if(irr::on) return V * spin(M_PI + 2 * M_PI / S7 * (hs.spin + irr::periodmap[hs.h].base.spin)); + if(syntetic) return V * spin(-synt::triangles[synt::id_of(hs.h)][hs.spin].first); if(binarytiling) return V; return (hs.spin || nonbitrunc) ? V * spin(hs.spin*2*M_PI/S7 + master_to_c7_angle()) : V; } transmatrix applyspin(const heptspin& hs, const transmatrix& V) { if(binarytiling) return V; + if(syntetic) return V * spin(synt::triangles[synt::id_of(hs.h)][hs.spin].first); return hs.spin ? V * spin(hs.spin*2*M_PI/S7) : V; } @@ -608,7 +610,7 @@ void drawrec(const heptspin& hs, hstate s, const transmatrix& V) { } if(!nonbitrunc) for(int d=0; dmov[ds] && c->spn(ds) == 0 && dodrawcell(c->mov[ds])) { transmatrix V2 = V1 * hexmove[d]; @@ -802,11 +804,11 @@ void optimizeview() { transmatrix TB = Id; - if(binarytiling) { + if(binarytiling || syntetic) { turn = -1, best = View[2][2]; for(int i=0; ic7->type; i++) { heptagon *h2 = createStep(viewctr.h, i); - transmatrix T = binary::relative_matrix(h2, viewctr.h); + transmatrix T = (binarytiling) ? binary::relative_matrix(h2, viewctr.h) : synt::relative_matrix(h2, viewctr.h); hyperpoint H = View * tC0(T); if(H[2] < best) best = H[2], turn = i, TB = T; } @@ -863,7 +865,7 @@ void resetview() { DEBB(DF_GRAPH, (debugfile,"reset view\n")); View = Id; // EUCLIDEAN - if(!euclid) + if(!stdeuclid) viewctr.h = cwt.c->master, viewctr.spin = cwt.spin; else centerover = cwt; diff --git a/monstergen.cpp b/monstergen.cpp index ea76470c..96a082b8 100644 --- a/monstergen.cpp +++ b/monstergen.cpp @@ -264,7 +264,7 @@ bool haveOrbPower() { cell *c = dcal[i]; if(itemclass(c->item) == IC_ORB) return true; } - else if(sphere) for(int i=0; ic7; if(itemclass(c->item) == IC_ORB) return true; forCellEx(c2, c) if(itemclass(c2->item) == IC_ORB) return true; @@ -446,7 +446,7 @@ void wandering() { } if(!peace::on && c->land == laKraken && ((sphere && !hrand(15)) || wchance(items[itKraken], 240)) && !kraken_pseudohept(c)) { bool b = sphere || canReachPlayer(c, moKrakenH); - if(sphere && (haveKraken() || !items[itOrbFish])) { + if(stdsphere && (haveKraken() || !items[itOrbFish])) { c->monst = moViking; c->wall = waBoat; c->item = itOrbFish; playSeenSound(c); continue; diff --git a/pattern2.cpp b/pattern2.cpp index 0c690851..4f8444e3 100644 --- a/pattern2.cpp +++ b/pattern2.cpp @@ -343,7 +343,7 @@ int fieldval_uniq(cell *c) { auto p = cell_to_pair(c); return gmod(p.first * torusconfig::dx + p.second * torusconfig::dy, torusconfig::qty); } - else if(binarytiling) return 0; + else if(binarytiling || syntetic) return 0; if(ctof(c) || gp::on || irr::on) return c->master->fieldval/S7; else { int z = 0; @@ -873,6 +873,11 @@ namespace patterns { si.dir = 0; si.reflect = false; si.id = ctof(c); si.symmetries = c->type; + if(syntetic) { + si.id = synt::id_of(c->master); + return si; + } + if(binarytiling) { if(pat == PAT_SINGLETYPE) si.id = 0; si.dir = 2; @@ -1168,6 +1173,7 @@ int pattern_threecolor(cell *c) { bool pseudohept(cell *c) { if(irr::on) return irr::pseudohept(c); if(binarytiling) return c->type & c->master->distance & 1; + if(syntetic) return synt::id_of(c->master) < 2 * isize(synt::faces); if(gp::on && gp_threecolor() == 2) return gp::pseudohept_val(c) == 0; if(gp::on && gp_threecolor() == 1 && (S7&1) && (S3 == 3)) @@ -2075,6 +2081,12 @@ namespace linepatterns { col, 1 + vid.linequality); } + else if(syntetic) { + if(!pseudohept(c)) for(int i=0; itype; i++) if(c->mov[i] && c < c->mov[i] && !pseudohept(c->mov[i]) && gmatrix.count(c->mov[i])) + queuelinef(tC0(V), gmatrix[c->mov[i]]*C0, + col, + 1 + vid.linequality); + } else { int a = emeraldval(c); if(pseudohept(c) && a/4 == 8) for(int i=0; i<7; i++) { diff --git a/shmup.cpp b/shmup.cpp index ec0952ab..ee0a2748 100644 --- a/shmup.cpp +++ b/shmup.cpp @@ -3375,6 +3375,7 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1, const hyperpoint& point_hin } if(binarytiling) return binary::relative_matrix(c2->master, c1->master); + if(syntetic) return synt::relative_matrix(c2->master, c1->master); if(torus) { transmatrix t = Id; diff --git a/syntetic.cpp b/syntetic.cpp new file mode 100644 index 00000000..c26f4547 --- /dev/null +++ b/syntetic.cpp @@ -0,0 +1,666 @@ +namespace hr { + +namespace synt { + +int indent; + +struct indenter { + indenter() { indent += 2; } + ~indenter() { indent -= 2; } + }; + +void doindent() { fflush(stdout); for(int i=0; i faces = {3, 6, 6, 6}; +vector adj = {1, 0, 2, 3}; +vector invert = {false, false, true, false}; + +/* +vector faces = {3, 6, 6, 6}; +vector adj = {1, 0, 2, 3}; +vector invert = {false, false, false, false}; +*/ + +/* +vector faces = {7, 6, 6}; +vector adj = {1, 0, 2}; +vector invert = {false, false, false}; +*/ + +/* +vector faces = {8, 8, 8}; +vector adj = {0, 1, 2}; +vector invert = {false, false, false}; +*/ + +int repetition = 1; +int N; + +vector>> adjacent; + +vector>> triangles; + +// id of vertex in the syntetic tiling +// odd numbers = reflected tiles +// 0, 2, ..., 2(N-1) = as in the symbol +// 2N = bitruncated tile + +short& id_of(heptagon *h) { + return h->zebraval; + } + +// which index in id_of's neighbor list does h->move[0] have + +short& parent_index_of(heptagon *h) { + return h->emeraldval; + } + +// total number of neighbors + +int neighbors_of(heptagon *h) { + return isize(triangles[id_of(h)]); + } + +// right_sibling_of(h) has the same distance ('right sibling'), then we have some at smaller or equal distance, +// parents_of(h) has the same distance again ('left sibling'), and then we have vertices at bigger distance, +// who are our 'children' except the rightmost one which is typically a child of the right sibling + +short& right_sibling_of(heptagon *h) { + return h->fiftyval; + } + +int parents_of(heptagon *h) { + return h->s; + } + +int children_of(heptagon *h) { + return right_sibling_of(h) - 1 - parents_of(h); + } + +ld edgelength; +vector inradius, circumradius, alphas; + +void prepare() { + + /* build the 'adjacent' table */ + + N = isize(faces); + adjacent.clear(); + adjacent.resize(2*N+2); + for(int i=0; i [%d %d]\n", at, inv); + if(faces[at] != faces[i]) printf("error!\n"); + } + } + for(int i=0; i", q.first, q.second); + if(isize(adjacent[q.first]) != isize(adjacent[i])) printf(" {error}"); + } + printf("\n"); + } + + /* verify all the triangles */ + for(int i=0; i<2*N+2; i++) { + for(int j=0; j= isize(adjacent[ai])) aj = 0; + } + printf("-> [%d %d]\n", ai, aj); + if(isize(adjacent[ai]) != isize(adjacent[i])) printf("error!\n"); + } + } + + ld sum = 0; + for(int f: faces) sum += (f-2.) / f; + if(sum < 1.999999) ginf[gSyntetic].cclass = gcSphere; + else if(sum > 2.000001) ginf[gSyntetic].cclass = gcHyperbolic; + else ginf[gSyntetic].cclass = gcEuclid; + + printf("sum = %lf\n", double(sum)); + + dynamicval dv(geometry, gSyntetic); + + /* compute the geometry */ + inradius.resize(N); + circumradius.resize(N); + alphas.resize(N); + ld elmin = 0, elmax = hyperbolic ? 10 : sphere ? M_PI : 1; + for(int p=0; p<100; p++) { + edgelength = (elmin + elmax) / 2; + + ld alpha_total = 0; + + for(int i=0; i edgelength) crmax = circumradius[i]; + else crmin = circumradius[i]; + } + hyperpoint h = xpush(edgelength/2) * spin(M_PI/2) * xpush(inradius[i]) * C0; + alphas[i] = atan2(-h[1], h[0]); + alpha_total += alphas[i]; + } + + // printf("el = %lf alpha = %lf\n", double(edgelength), double(alpha_total)); + + if(sphere ^ (alpha_total > M_PI)) elmin = edgelength; + else elmax = edgelength; + if(euclid) break; + } + + printf("computed edgelength = %lf\n", double(edgelength)); + + triangles.clear(); + triangles.resize(2*N+2); + for(int i=0; ic7 = newCell(isize(adjacent[0]), h); + + if(sphere) celllister cl(h->c7, 1000, 1000000, NULL); + + /* test */ + SDEBUG( + printf("started testing\n"); + heptagon *htest = h; + for(int i=0; i<10000; i++) + htest = createStep(htest, hrand(neighbors_of(htest))); + ) + }; + +void verify_distance_delta(heptagon *h, int d, int delta) { + if(!h->move[d]) return; + if(h->move[d]->distance != h->distance + delta) { + SDEBUG( printf("ERROR: delta %p.%d (%d/%d)\n", h, d, h->move[d]->distance, h->distance + delta); ) + // exit(1); + } + } + +void debug(heptagon *h) { + auto& p = adjacent[id_of(h)]; + if(h->s == hsOrigin) { + for(int i=0; is + 1; + verify_distance_delta(h, 0, -1); + verify_distance_delta(h, first-2, -1); + verify_distance_delta(h, first-1, 0); + verify_distance_delta(h, isize(p)-1, 0); + for(int d=first; dmove[d]) { + auto& p = adjacent[id_of(h)]; + auto uv = p[(parent_index_of(h) + d) % isize(p)]; + if(neighbors_of(h->move[d]) != isize(adjacent[uv.first])) { + SDEBUG( printf("neighbors mismatch at %p/%d->%p: is %d expected %d\n", h, d, h->move[d], neighbors_of(h->move[d]), isize(adjacent[uv.first])); ) + exit(1); + } + } + } + } + +heptagon *build_child(heptagon *parent, int d, int id, int pindex) { + indenter ind; + auto h = buildHeptagon(parent, d, hstate(1), 0); + id_of(h) = id; + parent_index_of(h) = pindex; + int nei = neighbors_of(h); + right_sibling_of(h) = nei - 1; + h->distance = parent->distance + 1; + h->c7 = newCell(nei, h); + SDEBUG( printf("%p.%d/%d ~ %p.0/%d (state=1/NEW,id=%d,pindex=%d,distance=%d)\n", parent, d, neighbors_of(parent), h, neighbors_of(h), id, pindex, h->distance); ) + debug(h); debug(parent); + return h; + } + +void connectHeptagons(heptagon *h, int i, heptspin hs) { + indenter ind; + SDEBUG( printf("%p.%d/%d ~ %p.%d/%d (state=%d,id=%d,pindex=%d,distance=%d)\n", h, i, neighbors_of(h), hs.h, hs.spin, neighbors_of(hs.h), + hs.h->s, id_of(hs.h), parent_index_of(hs.h), hs.h->distance); ) + if(h->move[i] == hs.h && h->spin(i) == hs.spin) { + SDEBUG( printf("WARNING: already connected\n"); ) + return; + } + if(h->move[i]) { + SDEBUG( printf("ERROR: already connected left to: %p not %p\n", h->move[i], hs.h); ) + exit(1); + } + if(hs.h->move[hs.spin]) { + SDEBUG( printf("ERROR: already connected right to: %p not %p\n", hs.h->move[hs.spin], h); ) + exit(1); + // exit(1); + } + hr::connectHeptagons(h, i, hs.h, hs.spin); + debug(h); + debug(hs.h); + } + +int prune(heptagon*& h) { + int result = 1; + int n = neighbors_of(h); + auto h0 = h; + SDEBUG( printf("pruning: %p\n", h0); ) + for(int i=0; imove[i]) { + if(h0->spin(i) == 0) + result += prune(h0->move[i]); + else { + h0->move[i]->move[h0->spin(i)] = NULL; + h0->move[i] = NULL; + } + } + delete h0->c7; + delete h0; + return result; + } + +void contract(heptagon *h) { + switch(children_of(h)) { + case 0: { + SDEBUG( printf("handling contraction (0) at %p\n", h); ) + heptspin right = heptspin(h, right_sibling_of(h)) + wstep + 1; + heptspin left = heptspin(h, parents_of(h)) + wstep - 1; + connectHeptagons(right.h, right.spin, left); + right.h->s++; + right_sibling_of(left.h)--; + contract(right.h); + contract(left.h); + break; + } + case -1: { + SDEBUG( printf("handling contraction (-1) at %p\n", h); ) + indenter ind2; + heptspin hs0(h, neighbors_of(h)-1); + heptspin hs = hs0; + hs = hs + 1 + wstep + 1; + while(hs.spin == neighbors_of(hs.h) - 1) { + SDEBUG( printf("hsr at %p.%d/%d (%d parents)\n", hs.h, hs.spin, neighbors_of(hs.h), parents_of(hs.h)); ) + hs = hs + wstep + 1; + } + SDEBUG( printf("hsr at %p.%d/%d (%d parents)\n", hs.h, hs.spin, neighbors_of(hs.h), parents_of(hs.h)); ) + heptspin correct = hs + wstep; + SDEBUG( printf("correct is: %p.%d/%d (%d parents)\n", correct.h, correct.spin, neighbors_of(correct.h), parents_of(correct.h)); ) + heptspin hsl = hs0; + correct = correct+1; correct.h->s++; + connectHeptagons(hsl.h, hsl.spin, correct); + hsl = hsl - 1 + wstep - 1; + while(true) { + SDEBUG( printf("hsl at %p.%d/%d (%d parents)\n", hsl.h, hsl.spin, neighbors_of(hsl.h), parents_of(hsl.h)); ) + if(hsl.spin == parents_of(hsl.h)) { + SDEBUG(printf("go left\n")) + hsl = hsl + wstep - 1; + } + else if(hsl.h->move[hsl.spin] && hsl.h->move[hsl.spin] != correct.h) { + SDEBUG(printf("prune\n");) + if(neighbors_of(hsl.h->move[hsl.spin]) != neighbors_of(correct.h)) { + SDEBUG(printf("neighbors mismatch while pruning %d -> %d\n", + neighbors_of(hsl.h->move[hsl.spin]), + neighbors_of(correct.h) + );) + exit(1); + } + prune(hsl.h->move[hsl.spin]); + } + else if(hsl.h->move[hsl.spin] == NULL) { + correct = correct+1; correct.h->s++; + SDEBUG( printf("connect\n") ) + connectHeptagons(hsl.h, hsl.spin, correct); + } + else if(hsl.spin == parents_of(hsl.h)+1) { + SDEBUG( printf("single child so go left\n") ) + hsl = hsl - 1 + wstep - 1; + } + else { SDEBUG( printf("ready\n"); ) break; } + } + contract(correct.h); + break; + } + case -2: { + SDEBUG( printf("ERROR: contraction (-2) not handled\n"); ) + exit(1); + break; + } + } + if(!sphere) for(int i=0; imove[i]) { + auto uv = adjacent[id_of(h)][(parent_index_of(h) + i) % neighbors_of(h)]; + if(isize(adjacent[uv.first]) < 6) { + SDEBUG( printf("prebuilding weak neighbor\n") ) + createStep(h, i); + } + } + } + +void build_siblings(heptagon *h, int x) { + for(int i=right_sibling_of(h); is == 0) { + auto& p = adjacent[id_of(h)]; + for(int i=0; imove[i]; + heptagon *h2 = h->move[(i+nei-1)%nei]; + connectHeptagons(h1, 1, heptspin(h2, isize(adjacent[id_of(h2)])-1)); + } + } + + else { + int first = h->s + 1; + SDEBUG( printf("h=%p dist=%d d=%d/%d s=%d id=%d pindex=%d\n", + h, h->distance, d, nei, h->s, id_of(h), parent_index_of(h)); ) + indenter ind2; + + // these vertices are not children (or possibly contractions) + if(d < first || d > right_sibling_of(h)) + connectHeptagons(h, d, heptspin(h, d-1) + wstep - 1 + wstep - 1); + else if(d == right_sibling_of(h)) { + connectHeptagons(h, d, heptspin(h, 0) + wstep + 1 + wstep + 1); + } + else { + build_siblings(h, 10); + build_siblings(h, -10); + if(h->move[d]) return; + heptspin hs(h, d); + // make sure no contractions on the left + heptspin hsl(h, d); + int steps = 0; + while(hsl.spin == parents_of(hsl.h) + 1 && steps < 100) { + hsl = hsl - 1 + wstep - 1; + steps++; + } + if(steps == 100) { + SDEBUG( printf("generating top\n"); ) + auto uv = adjacent[id_of(hs.h)][(parent_index_of(hs.h) + hs.spin) % neighbors_of(hs.h)]; + heptagon *newchild = build_child(hs.h, hs.spin, uv.first, uv.second); + hs = hs - 1 + wstep - 1; + while(hs.h != h) { + newchild->s++; + connectHeptagons(hs.h, hs.spin, heptspin(newchild, newchild->s-1)); + hs = hs - 1 + wstep - 1; + } + return; + } + // while trying to generate the last child, go right + while(true) { + if(h->move[d]) { + SDEBUG( printf("solved itself\n"); ) + return; + } + SDEBUG( printf("going right at %p.%d/%d parents = %d\n", hs.h, hs.spin, neighbors_of(hs.h), parents_of(hs.h)); ) + // rightmost child + if(hs.spin == right_sibling_of(hs.h) - 1) + hs = hs + 1 + wstep + 1; + else if(children_of(hs.h) <= 0) { + SDEBUG( printf("unexpected situation\n"); ) + return; + } + else break; + } + auto uv = adjacent[id_of(hs.h)][(parent_index_of(hs.h) + hs.spin) % neighbors_of(hs.h)]; + heptagon *newchild = build_child(hs.h, hs.spin, uv.first, uv.second); + bool add_parent = false; + while(true) { + SDEBUG( printf("going left at %p.%d/%d parents = %d\n", hs.h, hs.spin, neighbors_of(hs.h), parents_of(hs.h)); ) + // add parent + if(hs.spin > parents_of(hs.h) && add_parent) { + SDEBUG( printf("add parent\n"); ) + newchild->s++; + connectHeptagons(hs.h, hs.spin, heptspin(newchild, newchild->s-1)); + add_parent = false; + } + // childless + if(children_of(hs.h) <= 0) { + SDEBUG( printf("unexpected situation v2\n"); ) + return; + } + // lefmost child + else if(hs.spin == parents_of(hs.h)+1) { + SDEBUG( printf("(leftmost child)\n"); ) + hs = hs - 1 + wstep - 1; + add_parent = true; + } + // no more parents + else break; + } + contract(newchild); + } + } + debug(h); + } + +set visited; +queue> drawqueue; + +void enqueue(heptagon *h, const transmatrix& T) { + if(visited.count(h)) { return; } + visited.insert(h); + drawqueue.emplace(h, T); + } + +transmatrix adjcell_matrix(heptagon *h, int d) { + int S = neighbors_of(h); + int pindex = parent_index_of(h); + int id = id_of(h); + auto& t1 = triangles[id][(pindex + d)%S]; + + heptagon *h2 = h->move[d]; + + int d2 = h->spin(d); + int id2 = id_of(h2); + int pindex2 = parent_index_of(h2); + auto& t2 = triangles[id2][(pindex2 + d2) % neighbors_of(h2)]; + + // * spin(-tri[id][pi+i].first) * xpush(t.second) * pispin * spin(tri[id'][p'+d'].first) + + return spin(-t1.first) * xpush(t1.second) * spin(M_PI + t2.first); + } + +void draw() { + visited.clear(); + enqueue(viewctr.h, cview()); + int idx = 0; + + while(!drawqueue.empty()) { + auto p = drawqueue.front(); + drawqueue.pop(); + heptagon *h = p.first; + transmatrix V = p.second; + int id = id_of(h); + int S = isize(triangles[id]); + + if(!nonbitrunc || id < 2*N) { + if(!dodrawcell(h->c7)) continue; + drawcell(h->c7, V, 0, false); + } + + for(int i=0; i= 2*N && h->move[i] && id_of(h->move[i]) >= 2*N) continue; + enqueue(h->move[i], V * adjcell_matrix(h, i)); + } + idx++; + } + } + +transmatrix relative_matrix(heptagon *h2, heptagon *h1) { + if(gmatrix0.count(h2->c7) && gmatrix0.count(h1->c7)) + return inverse(gmatrix0[h1->c7]) * gmatrix0[h2->c7]; + transmatrix gm = Id, where = Id; + while(h1 != h2) { + for(int i=0; imove[i] == h2) { + return gm * adjcell_matrix(h1, i) * where; + } + else if(h1->distance > h2->distance) { + gm = gm * adjcell_matrix(h1, 0); + h1 = h1->move[0]; + } + else { + where = inverse(adjcell_matrix(h2, 0)) * where; + h2 = h2->move[0]; + } + } + return gm * where; + } + +int fix(heptagon *h, int spin) { + int type = isize(adjacent[id_of(h)]); + spin %= type; + if(spin < 0) spin += type; + return spin; + } + +void parse_symbol(string s) { + int at = 0; + + auto peek = [&] () { if(at == isize(s)) return char(0); else return s[at]; }; + auto isnumber = [&] () { char p = peek(); return p >= '0' && p <= '9'; }; + auto read_number = [&] () { int result = 0; while(isnumber()) result = 10 * result + peek() - '0', at++; return result; }; + + faces.clear(); + while(true) { + if(peek() == ')' || peek() == '^' || (peek() == '(' && isize(faces)) || peek() == 0) break; + else if(isnumber()) faces.push_back(read_number()); + else at++; + } + repetition = 1; + N = isize(faces); + invert.clear(); invert.resize(N, 0); + adj.clear(); adj.resize(N, 0); for(int i=0; i