diff --git a/cell.cpp b/cell.cpp index cb92ff1c..94bf0868 100644 --- a/cell.cpp +++ b/cell.cpp @@ -713,49 +713,6 @@ void verifycells(heptagon *at) { verifycell(at->c7); } -int eupattern(cell *c) { - if(torus) return (decodeId(c->master)*2) % 3; - eucoord x, y; - decodeMaster(c->master, x, y); - short z = (short(y+2*x))%3; - z %= 3; - if(z<0) z += 3; - return z; - } - - -bool ishept(cell *c) { - // EUCLIDEAN - if(euclid) return eupattern(c) == 0; - else return c->type != S6; - } - -bool ishex1(cell *c) { - // EUCLIDEAN - if(euclid) return eupattern(c) == 1; - else return c->type != S6; - } - -int val46(cell *c) { - return ctof(c) ? c->master->emeraldval : - ((c->master->emeraldval & 1) ^ ((c->master->emeraldval & 2)>>1) ^ (c->spin(0)&1)) ? 8 : 4; - } - -int emeraldval(cell *c) { - if(euclid) return eupattern(c); - if(a46) return val46(c); - if(sphere) return 0; - if(ctof(c)) - return c->master->emeraldval >> 3; - else { - return emerald_hexagon( - emeraldval(createMov(c,0)), - emeraldval(createMov(c,2)), - emeraldval(createMov(c,4)) - ); - } - } - int eudist(short sx, short sy) { int z0 = abs(sx); int z1 = abs(sy); @@ -836,202 +793,6 @@ int dirfromto(cell *cfrom, cell *cto) { return -1; } -// === FIFTYVALS === - -unsigned bitmajority(unsigned a, unsigned b, unsigned c) { - return (a&b) | ((a^b)&c); - } - -int eufifty(cell *c) { - eucoord x, y; - if(torus) { - if(c->land == laWildWest) return decodeId(c->master) % 37; - else return decodeId(c->master) % 27; - } - decodeMaster(c->master, x, y); - int ix = short(x) + 99999 + short(y); - int iy = short(y) + 99999; - if(c->land == laWildWest) - return (ix + iy * 26 + 28) % 37; - else { - ix += (iy/3) * 3; - iy %= 3; ix %= 9; - return iy * 9 + ix; - } - } - -int val38(cell *c) { - if(ctof(c)) return c->master->fiftyval; - else return 4 ^ c->master->fiftyval ^ (c->spin(0) & 1); - } - -int fiftyval(cell *c) { - if(a38) return val38(c); - if(euclid) return eufifty(c) * 32; - if(sphere || S7>7 || S6>6) return 0; - if(ctof(c)) - return c->master->fiftyval; - else { - return bitmajority( - fiftyval(createMov(c,0)), - fiftyval(createMov(c,2)), - fiftyval(createMov(c,4))) + 512; - } - } - -int cdist50(cell *c) { - if(sphere || S7>7 || S6>6) return 0; - if(euclid) { - if(c->land == laWildWest) - return "0123333332112332223322233211233333322"[eufifty(c)] - '0'; - else return "012333321112322232222321123"[eufifty(c)] - '0'; - } - if(c->type != 6) return cdist50(fiftyval(c)); - int a0 = cdist50(createMov(c,0)); - int a1 = cdist50(createMov(c,2)); - int a2 = cdist50(createMov(c,4)); - if(a0 == 0 || a1 == 0 || a2 == 0) return 1; - return a0+a1+a2-5; - } - -int land50(cell *c) { - if(c->type != 6) return land50(fiftyval(c)); - else if(sphere || euclid) return 0; - else { - if(cdist50(createMov(c,0)) < 3) return land50(createMov(c,0)); - if(cdist50(createMov(c,2)) < 3) return land50(createMov(c,2)); - if(cdist50(createMov(c,4)) < 3) return land50(createMov(c,4)); - return 0; - } - } - -int polara50(cell *c) { - if(c->type != 6) return polara50(fiftyval(c)); - else if(sphere || euclid || S7>7 || S6>6) return 0; - else { - if(cdist50(createMov(c,0)) < 3) return polara50(createMov(c,0)); - if(cdist50(createMov(c,2)) < 3) return polara50(createMov(c,2)); - if(cdist50(createMov(c,4)) < 3) return polara50(createMov(c,4)); - return 0; - } - } - -int polarb50(cell *c) { - if(euclid) return true; - if(c->type != 6) return polarb50(fiftyval(c)); - else if(sphere || euclid || S7>7 || S6>6) return true; - else { - if(cdist50(createMov(c,0)) < 3) return polarb50(createMov(c,0)); - if(cdist50(createMov(c,2)) < 3) return polarb50(createMov(c,2)); - if(cdist50(createMov(c,4)) < 3) return polarb50(createMov(c,4)); - return 0; - } - } - -int elhextable[28][3] = { - {0,1,2}, {1,2,9}, {1,9,-1}, {1,8,-1}, {1,-1,-1} - }; - -int fiftyval049(cell *c) { - if(c->type != 6 || euclid) return fiftyval(c) / 32; - else if(sphere) return 0; - else { - int a[3], qa=0; - int pa = polara50(c), pb = polarb50(c); - for(int i=0; i<6; i+=2) { - cell *c2 = c->mov[i]; - if(polara50(c2) == pa && polarb50(c2) == pb) - a[qa++] = fiftyval049(c2); - } - // 0-1-2 - sort(a, a+qa); - if(qa == 1) return 43+a[0]-1; - if(qa == 2 && a[1] == a[0]+7) return 36+a[0]-1; - if(qa == 2 && a[1] != a[0]+7) return 29+a[0]-1; - if(a[1] == 1 && a[2] == 7) - return 15 + 6; - if(a[2] >= 1 && a[2] <= 7) - return 15 + a[1]-1; - if(a[0] == 1 && a[1] == 7 && a[2] == 8) - return 22; - if(a[1] <= 7 && a[2] >= 8) - return 22 + a[1]-1; - return 0; - } - } - -/* -{0,1,2} 15+0..15+6 -{1,2,9},22+0..22+6 -{1,9} 29+0..29+6 -{1,8} 36+0..36+6 -{1} 43+0..43+6 -*/ - -// zebraval - -int dir_truncated457(cell *c) { - int wset = 0; - for(int i=0; i<4; i++) - if(zebra40(createMov(c, i*2))&2) wset |= (1<master->zebraval/10); - else if(a4) { - int ws = dir_truncated457(c); - if(ws < 0) return -ws; - return 16 + (ws/2); - } - else if(sphere) return 0; - else if(euclid) return eupattern(c); - else if(S3 == 4 && S7 == 6) { - return 8 + ((c->master->zebraval / 10 + c->spin(0))%2) * 2; - } - else { - int ii[3], z; - ii[0] = (c->mov[0]->master->zebraval/10); - ii[1] = (c->mov[2]->master->zebraval/10); - ii[2] = (c->mov[4]->master->zebraval/10); - for(int r=0; r<2; r++) - if(ii[1] < ii[0] || ii[2] < ii[0]) - z = ii[0], ii[0] = ii[1], ii[1] = ii[2], ii[2] = z; - for(int i=0; i<28; i++) - if(zebratable6[i][0] == ii[0] && zebratable6[i][1] == ii[1] && - zebratable6[i][2] == ii[2]) { - int ans = 16+i; - // if(ans >= 40) ans ^= 2; - // if(ans >= 4 && ans < 16) ans ^= 2; - return ans; - } - return 0; - } - } - -int zebra3(cell *c) { - if(c->type != 6) return (c->master->zebraval/10)/4; - else if(sphere || S7>7 || S6>6) return 0; - else { - int ii[3]; - ii[0] = (c->mov[0]->master->zebraval/10)/4; - ii[1] = (c->mov[2]->master->zebraval/10)/4; - ii[2] = (c->mov[4]->master->zebraval/10)/4; - if(ii[0] == ii[1]) return ii[0]; - if(ii[1] == ii[2]) return ii[1]; - if(ii[2] == ii[0]) return ii[2]; - return 0; - } - } - #define RPV_MODULO 5 #define RPV_RAND 0 @@ -1345,76 +1106,6 @@ cell *heptatdir(cell *c, int d) { else return createMov(c, d); } -namespace fieldpattern { - -pair fieldval(cell *c) { - if(ctof(c)) return make_pair(c->master->fieldval, false); - else return make_pair(btspin(c->master->fieldval, c->spin(0)), true); - } - -int fieldval_uniq(cell *c) { - if(sphere) { - 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 if(torus) { - return decodeId(c->master); - } - else if(euclid) { - eucoord x, y; - decodeMaster(c->master, x, y); - int i = (short int)(x) * torusconfig::dx + (short int)(y) * torusconfig::dy; - i %= torusconfig::qty; - if(i<0) i += torusconfig::qty; - return i; - } - if(ctof(c)) return c->master->fieldval/S7; - else { - int z = 0; - for(int u=0; umaster->fieldval, c->spin(u))); - return -1-z; - } - } - -int fieldval_uniq_rand(cell *c, int randval) { - if(sphere || torus || euclid) - // we do not care in these cases - return fieldval_uniq(c); - if(ctof(c)) return currfp.gmul(c->master->fieldval, randval)/7; - else { - int z = 0; - for(int u=0; u<6; u+=2) - z = max(z, btspin(currfp.gmul(createMov(c, u)->master->fieldval, randval), c->spin(u))); - return -1-z; - } - } - -int subpathid = currfp.matcode[currfp.strtomatrix("RRRPRRRRRPRRRP")]; -int subpathorder = currfp.order(currfp.matrices[subpathid]); - -pair subval(cell *c, int _subpathid = subpathid, int _subpathorder = subpathorder) { - if(!ctof(c)) { - auto m = subval(createMov(c, 0)); - for(int u=2; u pbest, pcur; - pcur.first = c->master->fieldval; - pcur.second = 0; - pbest = pcur; - for(int i=0; i<_subpathorder; i++) { - pcur.first = currfp.gmul(pcur.first, _subpathid); - pcur.second++; - if(pcur < pbest) pbest = pcur; - } - return pbest; - } - } - -} int celldistance(cell *c1, cell *c2) { int d = 0; @@ -1509,89 +1200,3 @@ void clearCellMemory() { auto cellhooks = addHook(clearmemory, 500, clearCellMemory); -int getHemisphere(cell *c, int which) { - if(torus) return 0; - if(ctof(c)) { - int id = c->master->fiftyval; - if(S7 == 5) { - int hemitable[3][12] = { - { 6, 3, 3, 3, 3, 3,-6,-3,-3,-3,-3,-3}, - { 6, 3, 6, 3, 0, 0,-6,-3,-6,-3, 0, 0}, - {-3, 0, 3, 0,-6,-6, 3, 0,-3, 0, 6, 6} - }; - return hemitable[which][id]; - } - else if(S7 == 4) { - int hemitable[3][6] = { - { 2, 2, 2,-1,-1,-1}, - { 2,-1, 2, 2,-1,-1}, - { 2,-1,-1, 2, 2,-1}, - }; - return hemitable[which][id]; - } - else if(S7 == 3) { - int hemitable[3][4] = { - { 2, 2,-1,-1}, - { 2,-1, 2,-1}, - { 2,-1,-1, 2}, - }; - return hemitable[which][id]; - } - else return 0; - } - else { - int score = 0; - for(int i=0; i<6; i+=2) - score += getHemisphere(c->mov[i], which) * (c->mirror(i) ? -1 : 1); - return score/3; - } - } - -struct sphereinfo { - int id; - int dir; - bool reflect; - }; - -sphereinfo valsphere(cell *c) { - sphereinfo si; - if(ctof(c)) { - int d = c->master->fieldval; - si.id = (d < siblings[d]) ? 0 : 1; - for(int i=0; imaster->move[i]->fieldval; - if(di == siblings[d]) si.dir = i; - } - si.reflect = false; - } - else { - int ids = 0, tids = 0, td = 0; - for(int i=0; imov[i*2]->master->fieldval; - ids |= (1<mov[i*2]->master->fieldval; - if(ids & (1<mov[i*2]->master->fieldval; - if(!(ids & (1<mov[0]); - int di = si2.dir - c->spin(0); - di %= S7; - if(di<0) di += S7; - si.reflect = di > S7/2; - } - } - return si; - } - diff --git a/compileunits.h b/compileunits.h index 076cf57b..4adfa012 100644 --- a/compileunits.h +++ b/compileunits.h @@ -29,6 +29,7 @@ #include "heptagon.cpp" #include "language.cpp" #include "cell.cpp" +#include "pattern2.cpp" #include "flags.cpp" #include "yendor.cpp" #include "complex.cpp" diff --git a/game.cpp b/game.cpp index b6fa5e64..ec381b1d 100644 --- a/game.cpp +++ b/game.cpp @@ -357,24 +357,6 @@ bool isWarped(cell *c) { return isWarped(c->land) || (!inmirrororwall(c->land) && (items[itOrb37] && c->cpdist <= 4)); } -// returns ishept in the normal tiling; -// in the 'pure heptagonal' tiling, returns true for a set of cells -// which roughly corresponds to the heptagons in the normal tiling -bool pseudohept(cell *c) { - if(nontruncated) { - if(sphere) - return - c->master == getDodecahedron(3) || - c->master == getDodecahedron(5) || - c->master == getDodecahedron(6); - if(S3 > 3) - return c->master->distance & 1; - int z = zebra40(c); - return z == 5 || z == 8 || z == 15; - } - else return ishept(c); - } - bool nonAdjacent(cell *c, cell *c2) { if(isWarped(c) && isWarped(c2) && !pseudohept(c) && !pseudohept(c2)) { /* int i = neighborId(c, c2); diff --git a/heptagon.cpp b/heptagon.cpp index 384641b5..9f4c16f9 100644 --- a/heptagon.cpp +++ b/heptagon.cpp @@ -79,8 +79,8 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0, int fix h->emeraldval = emerald_heptagon(parent->emeraldval, d); h->zebraval = zebra_heptagon(parent->zebraval, d); h->fieldval = currfp.connections[fieldpattern::btspin(parent->fieldval, d)]; - if(a38) - h->fiftyval = (parent->fiftyval ^ d ^ 1) & 1; + if(a38) + h->fiftyval = fifty_38(parent->fiftyval, d); else if(parent->s == hsOrigin) h->fiftyval = firstfiftyval(d); else diff --git a/hyper.h b/hyper.h index bd687a83..b95cd028 100644 --- a/hyper.h +++ b/hyper.h @@ -660,9 +660,12 @@ namespace mapeditor { extern int displaycodes; int generateCanvas(cell *c); void applyModelcell(cell *c); - int realpattern(cell *c); + + int realpattern(cell *c, char w = whichPattern); int patterndir(cell *c, char w = whichPattern); - int subpattern(cell *c); + bool reflectPatternAt(cell *c, char p = whichPattern); + int subpattern(cell *c, char w = whichPattern); + extern cell *drawcell; void initdraw(cell *c); void showMapEditor(); @@ -1823,6 +1826,7 @@ namespace windmap { static const int NOWINDBELOW = 8; static const int NOWINDFROM = 120; + int getId(cell *c); int at(cell *c); } @@ -2100,6 +2104,7 @@ int polarb50(cell *c); bool isGravityLand(eLand l); bool isWarped(eLand l); +bool isWarped(cell *c); struct hrmap { virtual heptagon *getOrigin() { return NULL; } @@ -2280,3 +2285,13 @@ void sdltogl(SDL_Surface *txt, struct glfont_t& f, int ch); void glcolor2(int color); void showStartMenu(); + +bool polara50(int x); +int polara50(cell *c); +int fiftyval049(cell *c); + +namespace fieldpattern { + pair fieldval(cell *c); + } + +int emeraldval(cell *c); diff --git a/landlock.cpp b/landlock.cpp index 886a3b07..f0e4c8ea 100644 --- a/landlock.cpp +++ b/landlock.cpp @@ -1110,8 +1110,8 @@ int isLandValid(eLand l) { return 0; // Graveyard pattern does not work on non-truncated weird geometries - if(l == laGraveyard && weirdhyperbolic && nontruncated) - return 0; + if(l == laGraveyard) + return geosupport_graveyard(); // Warped Coast does not work on non-truncated S3s (except standard heptagonal where we have to keep it) if(l == laWarpCoast && (S3==3) && nontruncated) { diff --git a/mapeditor.cpp b/mapeditor.cpp index ef08bba7..40ac472f 100644 --- a/mapeditor.cpp +++ b/mapeditor.cpp @@ -315,190 +315,51 @@ namespace mapeditor { char whichShape = 0; char whichCanvas = 0; - int nopattern(cell *c) { - if(isWarped(c) && !euclid) { - int u = ishept(c)?1:0; - int qhex = 0; - for(int v=0; vtype; v++) if(c->mov[v] && !isWarped(c->mov[v])) { - u += 2; - if(!ishept(c->mov[v])) qhex++; - } - if(u == 8 && qhex == 2) return 12; - if(u == 2 && qhex == 1) return 8; - if(u == 6 && qhex == 2) return 10; - return u; - } - return ishept(c) ? 1 : ishex1(c) ? 2 : 0; // 0 to 1 - } - - bool reflectPatternAt(cell *c, char p = whichPattern) { - if(p == 'p' && sphere) return valsphere(c).reflect; - if(p == 'p' && polarb50(c)) return true; - if(p == 0) { - int np = nopattern(c); - if(np == 4) { - int d = patterndir(c); - return !isWarped(createMov(c, (d+1)%6)); - } - if(np == 12) { - int d = patterndir(c); - return !isWarped(createMov(c, (d+1)%6)); - } - } - return false; - } - - int downdir(cell *c, cellfunction *cf = coastvalEdge) { - cell *c2 = chosenDown(c, 1, 1, cf); - if(!c2) return 0; - return neighborId(c, c2); - } - - int patterndir46(cell *c, int bits) { - if(ctof(c)) { - int b = c->master->emeraldval & bits; - return (b&1) ^ (b & 2 ? 1 : 0); - } - else - return ((c->mov[0]->master->emeraldval + c->spin(0)) & 1) ? 2 : 0; + bool symRotation, sym01, sym02, sym03; + + int subpattern(int i, char w) { + if(euclid) { + if(w == 'p') + return i; + if(w == 'z' || w == 'f') + return (symRotation && (i<3)) ? 0 : i; } - int patterndir38(cell *c) { - if(ctof(c)) return c->master->fiftyval; - return 0; - } - - int patterndir457(cell *c) { - if(!ctof(c)) { - int d = dir_truncated457(c); - if(d >= 0) return d; - return 0; - } - for(int i=0; itype; i++) - if((zebra40(createStep(c->master, i + S7/2)->c7)&2) == (zebra40(createStep(c->master, i + 1 + S7/2)->c7)&2)) - return i; - return 0; + if(a38 && w == 'p') { + if(sym01 && i == 5) i = 4; + if(symRotation && i < 4) i = 0; + return i; } - int patterndir(cell *c, char w) { - if(w != 'H') { - if(a46) return patterndir46(c, w == 'z' ? 3 : w == 'p' ? 2 : 1); - if(a4) return patterndir457(c); - if(a38) return patterndir38(c); - if(sphere) return valsphere(c).dir; - } - switch(w) { - case 'z': { - int t = zebra40(c); - - if(euclid) return (t*4) % 6; - - int t4 = t>>2, tcdir = 0; - - if(nontruncated) tcdir = t^1; - - else if(t4 == 10) tcdir = t-20; - else if(t4 >= 4 && t4 < 7) tcdir = 40 + (t&3); - else if(t4 >= 1 && t4 < 4) tcdir = t+12; - else if(t4 >= 7 && t4 < 10) tcdir = t-24; - - for(int i=0; itype; i++) if(c->mov[i] && zebra40(c->mov[i]) == tcdir) - return i; - - // printf("fail to fintd %d -> %d\n", t, tcdir); - - return 0; - } - - case 'f': { - int t = emeraldval(c); - if(euclid) return 0; - int tcdir = 0, tbest = (t&3); - for(int i=0; itype; i++) { - cell *c2 = c->mov[i]; - if(c2) { - int t2 = emeraldval(c2); - if((t&3) == (t2&3) && t2 > tbest) - tbest = t2, tcdir = i; - } - } - return tcdir; - } - - case 'p': { - int tcdir = -1, tbest = -1; - int pa = polara50(c); - int pb = polarb50(c); - for(int i=0; itype; i++) { - cell *c2 = c->mov[i]; - if(c2 && polara50(c2) == pa && polarb50(c2) == pb) { - int t2 = fiftyval049(c2); - if(t2 > tbest) tbest = t2, tcdir = i; - } - } - return tcdir; - } - - case 'H': - return downdir(c); - - case 0: { - if(euclid) return 0; - int u = nopattern(c); - - if(u == 6) { - for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) - return i; - } - - else if(u == 2 || u == 3 || u == 8) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,i))) - return i; - } - - else if(u == 4 || u == 10) { - for(int i=0; itype; i+=2) if(!isWarped(createMov(c,i))) - return i; - } - - else if(u == 6) { - for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) - return i; - } - - else if(u == 5) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+3)%7)) && !isWarped(createMov(c,(i+4)%7))) - return i; - } - - else if(u == 9) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+2)%7)) && !isWarped(createMov(c,(i+5)%7))) - return i; - } - - else if(u == 11) { - for(int i=0; itype; i++) if(isWarped(createMov(c,(i)%7)) && isWarped(createMov(c,(i+1)%7))) - return i; - } - - else if(u == 12) { - for(int i=0; itype; i+=2) if(isWarped(createMov(c,i))) - return i; - } - - else if(u == 7) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+1)%7)) && !isWarped(createMov(c,(i+6)%7))) - return i; - } - - else if(u < 2) return 0; - -#if LOCAL - printf("unhandled: u=%d\n", u); -#endif - } + if(w == 'z' || w == 'f' || w == 'p') { + if((sym01?1:0)+(sym02?1:0)+(sym03?1:0) >= 2) i &= ~3; + if(sym01 && (i&1)) i ^= 1; + if(sym02 && (i&2)) i ^= 2; + if(sym03 && (i&2)) i ^= 3; + } + + if(w == 'z' && symRotation) { + if(a4 && !a46) { + if(i >= 4 && i < 7) i -= 4; } - return 0; + else { + if(i >= 8 && i < 12) i -= 4; + if(i >= 12 && i < 16) i -= 8; + if(i >= 20 && i < 24) i -= 4; + if(i >= 24 && i < 28) i -= 8; + if(i >= 32 && i < 36) i -= 4; + if(i >= 36 && i < 40) i -= 8; + } + } + + if(w == 'p' && stdhyperbolic && symRotation && i >= 3) + i -= ((i/4-1) % 7) * 4; + + return i; + } + + int subpattern(cell *c, char w) { + return subpattern(realpattern(c, w), w); } string infix; @@ -536,7 +397,6 @@ namespace mapeditor { cellwalker copysource; - bool symRotation, sym01, sym02, sym03; int whichpart; const char *mapeditorhelp = @@ -746,6 +606,8 @@ namespace mapeditor { dialog::addItem(XLAT("dark rainbow landscape"), 'd'); dialog::addItem(XLAT("football"), 'F'); + dialog::addItem(XLAT("nice coloring"), 'T'); + dialog::addSelItem(XLAT("emerald pattern"), "emerald", 'e'); dialog::addSelItem(XLAT("four elements"), "palace", 'b'); @@ -970,99 +832,6 @@ namespace mapeditor { return 1; } - int subpatternEmerald(int i) { - if(euclid) return (symRotation && (i<3)) ? 0 : i; - if((sym01?1:0)+(sym02?1:0)+(sym03?1:0) >= 2) i &= ~3; - if(sym01 && (i&1)) i ^= 1; - if(sym02 && (i&2)) i ^= 2; - if(sym03 && (i&2)) i ^= 3; - return i; - } - - int subpatternZebra(int i) { - if(euclid) return (symRotation && (i<3)) ? 0 : i; - i = subpatternEmerald(i); - if(symRotation) { - if(a4 && !a46) { - if(i >= 4 && i < 7) i -= 4; - } - else { - if(i >= 8 && i < 12) i -= 4; - if(i >= 12 && i < 16) i -= 8; - if(i >= 20 && i < 24) i -= 4; - if(i >= 24 && i < 28) i -= 8; - if(i >= 32 && i < 36) i -= 4; - if(i >= 36 && i < 40) i -= 8; - } - } - return i; - } - - int subpatternPalace(int i) { - if(euclid) return i; - i = subpatternEmerald(i); - if(symRotation && i >= 3) i -= ((i/4-1) % 7) * 4; - return i; - } - - int subpattern(cell *c) { - switch(whichPattern) { - case 'z': - return subpatternZebra(zebra40(c)); // 4 to 43 - case 'f': - return subpatternEmerald(emeraldval(c)); // 44 to 99 - case 'p': { - if(a46) return subpatternEmerald(val46(c)); - if(a38) return val38(c); - if(sphere) return subpatternEmerald(valsphere(c).id); - int i = fiftyval049(c); - i *= 4; - if(polara50(c)) i|=1; - if(polarb50(c)) i|=2; - return subpatternPalace(i); - } - case 'P': - return fiftyval(c); - case 'H': - case 'F': - return realpattern(c); - } - return nopattern(c); - } - - int realpattern(cell *c) { - switch(whichPattern) { - case 'z': - return zebra40(c); // 4 to 43 - case 'f': - return emeraldval(c); // 44 to 99 - case 'p': { - if(a46) return val46(c); - if(a38) return val38(c); - if(sphere) return valsphere(c).id; - int i = fiftyval049(c); - i *= 4; - if(polara50(c)) i|=1; - if(polarb50(c)) i|=2; - return i; - } - case 'H': - return towerval(c); - case 'F': { - if(euclid) - // use the torus ID - return fieldpattern::fieldval_uniq(c); - else if(nontruncated) - // use the actual field codes - return fieldpattern::fieldval(c).first; - else - // use the small numbers from windmap - return windmap::getId(c); - } - } - return nopattern(c); - } - int cellShapeGroup() { if(whichPattern == 'f') return 4; if(whichPattern == 'p') return 5; @@ -1085,17 +854,10 @@ namespace mapeditor { return subpattern(drawcell); } - int subpatternShape(int i) { - if(whichPattern == 'z') return subpatternZebra(i); - if(whichPattern == 'f') return subpatternEmerald(i); - if(whichPattern == 'p') return subpatternPalace(i); - return i; - } - bool editingShape(int group, int id) { if(group != mapeditor::drawcellShapeGroup()) return false; if(group < 3) return id == drawcellShapeID(); - return subpatternShape(id) == subpattern(drawcell); + return subpattern(id, whichPattern) == subpattern(drawcell); } void editCell(const pair& where) { @@ -2055,7 +1817,13 @@ namespace mapeditor { return (0x202020 + col[0] + (col[1] << 8) + (col[2] << 16)) >> (err?2:0); } if(whichCanvas == 'F') { - return ishept(c) ? 0x202020 : 0xC0C0C0; + return pseudohept(c) ? 0x202020 : 0xC0C0C0; + } + if(whichCanvas == 'T') { + static unsigned int fcol[8] = { 0x800000, 0x008000, 0x000080, 0x404040, + 0x800080, 0x008080, 0x808000, 0xD0D0D0 }; + int fv = pattern_threecolor(c); + return fcol[fv&7]; } return canvasback; } diff --git a/pattern2.cpp b/pattern2.cpp new file mode 100644 index 00000000..ca5d8aec --- /dev/null +++ b/pattern2.cpp @@ -0,0 +1,700 @@ +// HyperRogue patterns: compute codes for actual cells + +// Copyright (C) 2011-2017 Zeno Rogue, see 'hyper.cpp' for details + +int eupattern(cell *c) { + if(torus) return (decodeId(c->master)*2) % 3; + eucoord x, y; + decodeMaster(c->master, x, y); + short z = (short(y+2*x))%3; + z %= 3; + if(z<0) z += 3; + return z; + } + +bool ishept(cell *c) { + // EUCLIDEAN + if(euclid) return eupattern(c) == 0; + else return c->type != S6; + } + +bool ishex1(cell *c) { + // EUCLIDEAN + if(euclid) return eupattern(c) == 1; + else return c->type != S6; + } + +int val46(cell *c) { + return ctof(c) ? c->master->emeraldval : + ((c->master->emeraldval & 1) ^ ((c->master->emeraldval & 2)>>1) ^ (c->spin(0)&1)) ? 8 : 4; + } + +int emeraldval(cell *c) { + if(euclid) return eupattern(c); + if(a46) return val46(c); + if(sphere) return 0; + if(ctof(c)) + return c->master->emeraldval >> 3; + else { + return emerald_hexagon( + emeraldval(createMov(c,0)), + emeraldval(createMov(c,2)), + emeraldval(createMov(c,4)) + ); + } + } + +// === FIFTYVALS === + +unsigned bitmajority(unsigned a, unsigned b, unsigned c) { + return (a&b) | ((a^b)&c); + } + +int eufifty(cell *c) { + eucoord x, y; + if(torus) { + if(c->land == laWildWest) return decodeId(c->master) % 37; + else return decodeId(c->master) % 27; + } + decodeMaster(c->master, x, y); + int ix = short(x) + 99999 + short(y); + int iy = short(y) + 99999; + if(c->land == laWildWest) + return (ix + iy * 26 + 28) % 37; + else { + ix += (iy/3) * 3; + iy %= 3; ix %= 9; + return iy * 9 + ix; + } + } + +int val38(cell *c) { + if(ctof(c)) return (c->master->fiftyval >> 1) & 3; + else return 4 ^ (c->master->fiftyval & 1) ^ (c->spin(0) & 1); + } + +int fiftyval(cell *c) { + if(a38) return val38(c); + if(euclid) return eufifty(c) * 32; + if(sphere || S7>7 || S6>6) return 0; + if(ctof(c)) + return c->master->fiftyval; + else { + return bitmajority( + fiftyval(createMov(c,0)), + fiftyval(createMov(c,2)), + fiftyval(createMov(c,4))) + 512; + } + } + +int cdist50(cell *c) { + if(sphere || S7>7 || S6>6) return 0; + if(euclid) { + if(c->land == laWildWest) + return "0123333332112332223322233211233333322"[eufifty(c)] - '0'; + else return "012333321112322232222321123"[eufifty(c)] - '0'; + } + if(c->type != 6) return cdist50(fiftyval(c)); + int a0 = cdist50(createMov(c,0)); + int a1 = cdist50(createMov(c,2)); + int a2 = cdist50(createMov(c,4)); + if(a0 == 0 || a1 == 0 || a2 == 0) return 1; + return a0+a1+a2-5; + } + +int land50(cell *c) { + if(c->type != 6) return land50(fiftyval(c)); + else if(sphere || euclid) return 0; + else { + if(cdist50(createMov(c,0)) < 3) return land50(createMov(c,0)); + if(cdist50(createMov(c,2)) < 3) return land50(createMov(c,2)); + if(cdist50(createMov(c,4)) < 3) return land50(createMov(c,4)); + return 0; + } + } + +int polara50(cell *c) { + if(c->type != 6) return polara50(fiftyval(c)); + else if(sphere || euclid || S7>7 || S6>6) return 0; + else { + if(cdist50(createMov(c,0)) < 3) return polara50(createMov(c,0)); + if(cdist50(createMov(c,2)) < 3) return polara50(createMov(c,2)); + if(cdist50(createMov(c,4)) < 3) return polara50(createMov(c,4)); + return 0; + } + } + +int polarb50(cell *c) { + if(euclid) return true; + if(c->type != 6) return polarb50(fiftyval(c)); + else if(sphere || euclid || S7>7 || S6>6) return true; + else { + if(cdist50(createMov(c,0)) < 3) return polarb50(createMov(c,0)); + if(cdist50(createMov(c,2)) < 3) return polarb50(createMov(c,2)); + if(cdist50(createMov(c,4)) < 3) return polarb50(createMov(c,4)); + return 0; + } + } + +int elhextable[28][3] = { + {0,1,2}, {1,2,9}, {1,9,-1}, {1,8,-1}, {1,-1,-1} + }; + +int fiftyval049(cell *c) { + if(c->type != 6 || euclid) return fiftyval(c) / 32; + else if(sphere) return 0; + else { + int a[3], qa=0; + int pa = polara50(c), pb = polarb50(c); + for(int i=0; i<6; i+=2) { + cell *c2 = c->mov[i]; + if(polara50(c2) == pa && polarb50(c2) == pb) + a[qa++] = fiftyval049(c2); + } + // 0-1-2 + sort(a, a+qa); + if(qa == 1) return 43+a[0]-1; + if(qa == 2 && a[1] == a[0]+7) return 36+a[0]-1; + if(qa == 2 && a[1] != a[0]+7) return 29+a[0]-1; + if(a[1] == 1 && a[2] == 7) + return 15 + 6; + if(a[2] >= 1 && a[2] <= 7) + return 15 + a[1]-1; + if(a[0] == 1 && a[1] == 7 && a[2] == 8) + return 22; + if(a[1] <= 7 && a[2] >= 8) + return 22 + a[1]-1; + return 0; + } + } + +/* +{0,1,2} 15+0..15+6 +{1,2,9},22+0..22+6 +{1,9} 29+0..29+6 +{1,8} 36+0..36+6 +{1} 43+0..43+6 +*/ + +// zebraval + +int dir_truncated457(cell *c) { + int wset = 0; + for(int i=0; i<4; i++) + if(zebra40(createMov(c, i*2))&2) wset |= (1<master->zebraval/10); + else if(a4) { + int ws = dir_truncated457(c); + if(ws < 0) return -ws; + return 16 + (ws/2); + } + else if(sphere) return 0; + else if(euclid) return eupattern(c); + else if(S3 == 4 && S7 == 6) { + return 8 + ((c->master->zebraval / 10 + c->spin(0))%2) * 2; + } + else { + int ii[3], z; + ii[0] = (c->mov[0]->master->zebraval/10); + ii[1] = (c->mov[2]->master->zebraval/10); + ii[2] = (c->mov[4]->master->zebraval/10); + for(int r=0; r<2; r++) + if(ii[1] < ii[0] || ii[2] < ii[0]) + z = ii[0], ii[0] = ii[1], ii[1] = ii[2], ii[2] = z; + for(int i=0; i<28; i++) + if(zebratable6[i][0] == ii[0] && zebratable6[i][1] == ii[1] && + zebratable6[i][2] == ii[2]) { + int ans = 16+i; + // if(ans >= 40) ans ^= 2; + // if(ans >= 4 && ans < 16) ans ^= 2; + return ans; + } + return 0; + } + } + +int zebra3(cell *c) { + if(c->type != 6) return (c->master->zebraval/10)/4; + else if(sphere || S7>7 || S6>6) return 0; + else { + int ii[3]; + ii[0] = (c->mov[0]->master->zebraval/10)/4; + ii[1] = (c->mov[2]->master->zebraval/10)/4; + ii[2] = (c->mov[4]->master->zebraval/10)/4; + if(ii[0] == ii[1]) return ii[0]; + if(ii[1] == ii[2]) return ii[1]; + if(ii[2] == ii[0]) return ii[2]; + return 0; + } + } + +namespace fieldpattern { + +pair fieldval(cell *c) { + if(ctof(c)) return make_pair(c->master->fieldval, false); + else return make_pair(btspin(c->master->fieldval, c->spin(0)), true); + } + +int fieldval_uniq(cell *c) { + if(sphere) { + 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 if(torus) { + return decodeId(c->master); + } + else if(euclid) { + eucoord x, y; + decodeMaster(c->master, x, y); + int i = (short int)(x) * torusconfig::dx + (short int)(y) * torusconfig::dy; + i %= torusconfig::qty; + if(i<0) i += torusconfig::qty; + return i; + } + if(ctof(c)) return c->master->fieldval/S7; + else { + int z = 0; + for(int u=0; umaster->fieldval, c->spin(u))); + return -1-z; + } + } + +int fieldval_uniq_rand(cell *c, int randval) { + if(sphere || torus || euclid) + // we do not care in these cases + return fieldval_uniq(c); + if(ctof(c)) return currfp.gmul(c->master->fieldval, randval)/7; + else { + int z = 0; + for(int u=0; u<6; u+=2) + z = max(z, btspin(currfp.gmul(createMov(c, u)->master->fieldval, randval), c->spin(u))); + return -1-z; + } + } + +int subpathid = currfp.matcode[currfp.strtomatrix("RRRPRRRRRPRRRP")]; +int subpathorder = currfp.order(currfp.matrices[subpathid]); + +pair subval(cell *c, int _subpathid = subpathid, int _subpathorder = subpathorder) { + if(!ctof(c)) { + auto m = subval(createMov(c, 0)); + for(int u=2; u pbest, pcur; + pcur.first = c->master->fieldval; + pcur.second = 0; + pbest = pcur; + for(int i=0; i<_subpathorder; i++) { + pcur.first = currfp.gmul(pcur.first, _subpathid); + pcur.second++; + if(pcur < pbest) pbest = pcur; + } + return pbest; + } + } + +} + +int getHemisphere(cell *c, int which) { + if(torus) return 0; + if(ctof(c)) { + int id = c->master->fiftyval; + if(S7 == 5) { + int hemitable[3][12] = { + { 6, 3, 3, 3, 3, 3,-6,-3,-3,-3,-3,-3}, + { 6, 3, 6, 3, 0, 0,-6,-3,-6,-3, 0, 0}, + {-3, 0, 3, 0,-6,-6, 3, 0,-3, 0, 6, 6} + }; + return hemitable[which][id]; + } + else if(S7 == 4) { + int hemitable[3][6] = { + { 2, 2, 2,-1,-1,-1}, + { 2,-1, 2, 2,-1,-1}, + { 2,-1,-1, 2, 2,-1}, + }; + return hemitable[which][id]; + } + else if(S7 == 3) { + int hemitable[3][4] = { + { 2, 2,-1,-1}, + { 2,-1, 2,-1}, + { 2,-1,-1, 2}, + }; + return hemitable[which][id]; + } + else return 0; + } + else { + int score = 0; + for(int i=0; i<6; i+=2) + score += getHemisphere(c->mov[i], which) * (c->mirror(i) ? -1 : 1); + return score/3; + } + } + +struct sphereinfo { + int id; + int dir; + bool reflect; + }; + +sphereinfo valsphere(cell *c) { + sphereinfo si; + if(ctof(c)) { + int d = c->master->fieldval; + si.id = (d < siblings[d]) ? 0 : 1; + for(int i=0; imaster->move[i]->fieldval; + if(di == siblings[d]) si.dir = i; + } + si.reflect = false; + } + else { + int ids = 0, tids = 0, td = 0; + for(int i=0; imov[i*2]->master->fieldval; + ids |= (1<mov[i*2]->master->fieldval; + if(ids & (1<mov[i*2]->master->fieldval; + if(!(ids & (1<mov[0]); + int di = si2.dir - c->spin(0); + di %= S7; + if(di<0) di += S7; + si.reflect = di > S7/2; + } + } + return si; + } + +namespace mapeditor { + + int nopattern(cell *c) { + if(isWarped(c) && !euclid) { + int u = ishept(c)?1:0; + int qhex = 0; + for(int v=0; vtype; v++) if(c->mov[v] && !isWarped(c->mov[v])) { + u += 2; + if(!ishept(c->mov[v])) qhex++; + } + if(u == 8 && qhex == 2) return 12; + if(u == 2 && qhex == 1) return 8; + if(u == 6 && qhex == 2) return 10; + return u; + } + return ishept(c) ? 1 : ishex1(c) ? 2 : 0; // 0 to 1 + } + + int downdir(cell *c, cellfunction *cf = coastvalEdge) { + cell *c2 = chosenDown(c, 1, 1, cf); + if(!c2) return 0; + return neighborId(c, c2); + } + + int realpattern(cell *c, char code) { + switch(code) { + case 'z': + return zebra40(c); // 4 to 43 + case 'f': + return emeraldval(c); // 44 to 99 + case 'p': { + if(a46) return val46(c); + if(a38) return val38(c); + if(sphere) return valsphere(c).id; + int i = fiftyval049(c); + i *= 4; + if(polara50(c)) i|=1; + if(polarb50(c)) i|=2; + return i; + } + case 'H': + return towerval(c); + case 'F': { + if(euclid) + // use the torus ID + return fieldpattern::fieldval_uniq(c); + else if(nontruncated) + // use the actual field codes + return fieldpattern::fieldval(c).first; + else + // use the small numbers from windmap + return windmap::getId(c); + } + } + return nopattern(c); + } + + int patterndir46(cell *c, int bits) { + if(ctof(c)) { + int b = c->master->emeraldval & bits; + return (b&1) ^ (b & 2 ? 1 : 0); + } + else + return ((c->mov[0]->master->emeraldval + c->spin(0)) & 1) ? 2 : 0; + } + + int patterndir38(cell *c) { + if(ctof(c)) return c->master->fiftyval | (c->master->fiftyval & 8 ? 0 : 2); + return 0; + } + + int patterndir457(cell *c) { + if(!ctof(c)) { + int d = dir_truncated457(c); + if(d >= 0) return d; + return 0; + } + for(int i=0; itype; i++) + if((zebra40(createStep(c->master, i + S7/2)->c7)&2) == (zebra40(createStep(c->master, i + 1 + S7/2)->c7)&2)) + return i; + return 0; + } + + bool reflectPatternAt(cell *c, char p) { + if(p == 'p' && sphere) return valsphere(c).reflect; + if(p == 'p' && polarb50(c)) return true; + if(p == 0) { + int np = nopattern(c); + if(np == 4) { + int d = patterndir(c); + return !isWarped(createMov(c, (d+1)%6)); + } + if(np == 12) { + int d = patterndir(c); + return !isWarped(createMov(c, (d+1)%6)); + } + } + return false; + } + + int patterndir(cell *c, char w) { + if(w != 'H') { + if(a46) return patterndir46(c, w == 'z' ? 3 : w == 'p' ? 2 : 1); + if(a4) return patterndir457(c); + if(a38) return patterndir38(c); + if(sphere) return valsphere(c).dir; + } + switch(w) { + case 'z': { + int t = zebra40(c); + + if(euclid) return (t*4) % 6; + + int t4 = t>>2, tcdir = 0; + + if(nontruncated) tcdir = t^1; + + else if(t4 == 10) tcdir = t-20; + else if(t4 >= 4 && t4 < 7) tcdir = 40 + (t&3); + else if(t4 >= 1 && t4 < 4) tcdir = t+12; + else if(t4 >= 7 && t4 < 10) tcdir = t-24; + + for(int i=0; itype; i++) if(c->mov[i] && zebra40(c->mov[i]) == tcdir) + return i; + + // printf("fail to fintd %d -> %d\n", t, tcdir); + + return 0; + } + + case 'f': { + int t = emeraldval(c); + if(euclid) return 0; + int tcdir = 0, tbest = (t&3); + for(int i=0; itype; i++) { + cell *c2 = c->mov[i]; + if(c2) { + int t2 = emeraldval(c2); + if((t&3) == (t2&3) && t2 > tbest) + tbest = t2, tcdir = i; + } + } + return tcdir; + } + + case 'p': { + int tcdir = -1, tbest = -1; + int pa = polara50(c); + int pb = polarb50(c); + for(int i=0; itype; i++) { + cell *c2 = c->mov[i]; + if(c2 && polara50(c2) == pa && polarb50(c2) == pb) { + int t2 = fiftyval049(c2); + if(t2 > tbest) tbest = t2, tcdir = i; + } + } + return tcdir; + } + + case 'H': + return downdir(c); + + case 0: { + if(euclid) return 0; + int u = nopattern(c); + + if(u == 6) { + for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) + return i; + } + + else if(u == 2 || u == 3 || u == 8) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,i))) + return i; + } + + else if(u == 4 || u == 10) { + for(int i=0; itype; i+=2) if(!isWarped(createMov(c,i))) + return i; + } + + else if(u == 6) { + for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) + return i; + } + + else if(u == 5) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+3)%7)) && !isWarped(createMov(c,(i+4)%7))) + return i; + } + + else if(u == 9) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+2)%7)) && !isWarped(createMov(c,(i+5)%7))) + return i; + } + + else if(u == 11) { + for(int i=0; itype; i++) if(isWarped(createMov(c,(i)%7)) && isWarped(createMov(c,(i+1)%7))) + return i; + } + + else if(u == 12) { + for(int i=0; itype; i+=2) if(isWarped(createMov(c,i))) + return i; + } + + else if(u == 7) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+1)%7)) && !isWarped(createMov(c,(i+6)%7))) + return i; + } + + else if(u < 2) return 0; + +#if LOCAL + printf("unhandled: u=%d\n", u); +#endif + } + } + return 0; + } + + } + +int geosupport_threecolor() { + if(!nontruncated) { + if(S7 % 2) return 1; + return 2; + } + if((S7 % 2 == 0) && (S3 == 3)) + return 2; + return 0; + } + +int geosupport_graveyard() { + // always works in truncated geometries + if(!nontruncated) return 2; + + // always works in patterns supporting three-color + return geosupport_threecolor(); + } + +int pattern_threecolor(cell *c) { + if(a38) { + int i = val38(c); + if(nontruncated) return i; + else return i < 4 ? 0 : (1+(i&1)); + } + if(a46 && !nontruncated) { + int i = val46(c); + return i >> 2; + } + if(S7 == 4) { + int codesN[6] = {0,1,2,1,2,0}; + if(nontruncated) + return codesN[c->master->fiftyval]; + if(ctof(c)) + return 0; + else for(int i=0; i<3; i++) { + cell *c2 = c->mov[i]; + if(c2->master->fiftyval == 0) + return 1 + (c->spin(i)&1); + if(c2->master->fiftyval == 5) + return 2 - (c->spin(i)&1); + } + } + if(stdhyperbolic && nontruncated) { + int z = zebra40(c); + if(z == 5 || z == 8 || z == 15) return 0; + if(z == 10 || z == 12 || z == 7) return 2; + if(z == 6 || z == 9) return 3; + if(z == 14 || z == 11) return 4; + return 1; + } + if(S7 == 5 && nontruncated) { + const int codes[12] = {1, 2, 0, 3, 2, 0, 0, 1, 3, 1, 2, 3}; + return codes[c->master->fiftyval]; + } + if(S7 == 3 && nontruncated) + return c->master->fiftyval; + if(euclid) return eupattern(c); + return 3; + } + +// returns ishept in the normal tiling; +// in the 'pure heptagonal' tiling, returns true for a set of cells +// which roughly corresponds to the heptagons in the normal tiling +bool pseudohept(cell *c) { + if(nontruncated) { + if(bigsphere) + return + c->master == getDodecahedron(3) || + c->master == getDodecahedron(5) || + c->master == getDodecahedron(6); + if(S7 == 3) + return c->master == getDodecahedron(0); + else + return pattern_threecolor(c) == 0; + } + else return ishept(c); + } + diff --git a/patterns.cpp b/patterns.cpp index 46e9b0d1..9ba60e1e 100644 --- a/patterns.cpp +++ b/patterns.cpp @@ -1,4 +1,4 @@ -// HyperRogue patterns +// HyperRogue patterns: tables to give codes to heptagons // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details @@ -1116,3 +1116,20 @@ int zebra_heptagon(int parent, int dir) { return zebratable[parent/10-4][(70+dir-(parent%10))%7]; } +int fifty_38(int f, int d) { + // This creates the 'p' pattern for the a38 geometry. + // Hexagons have codes 4 and 5, while octagons have 0, 1, 2. + + // f&1 is which direction is the hexagon with code '4' + + // c=((f>>1)&3) is 0, 1, or 2 + int c = ((f>>1)&3); + + // f&8: in which direction is c increasing by one + int step = (f&8) ? 1 : 2; if(d&1) step ^= 3; + + return + ((f ^ d ^ 1) & 1) ++ (((c + step) % 3) << 1) + + (step==2?8:0); + }