From fd3b030119f566969e4faac09e7495449f7f7366 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Fri, 30 Nov 2018 16:31:55 +0100 Subject: [PATCH] crystal:: added multi-dimensional geometries (referred to as crystal), available via CLI for now --- cell.cpp | 6 + classes.cpp | 1 + classes.h | 2 +- compileunits.h | 1 + crystal.cpp | 457 +++++++++++++++++++++++++++++++++++++++++++++++++ geometry2.cpp | 4 +- heptagon.cpp | 4 +- hyper.h | 7 + pattern2.cpp | 5 + 9 files changed, 483 insertions(+), 4 deletions(-) create mode 100644 crystal.cpp diff --git a/cell.cpp b/cell.cpp index 3924641c..d614177f 100644 --- a/cell.cpp +++ b/cell.cpp @@ -1170,6 +1170,7 @@ void initcells() { hrmap* res = callhandlers((hrmap*)nullptr, hooks_newmap); if(res) currentmap = res; + else if(geometry == gCrystal) currentmap = crystal::new_map(); else if(archimedean) currentmap = arcm::new_map(); else if(fulltorus) currentmap = new hrmap_torus; else if(euclid) currentmap = new hrmap_euclidean; @@ -1333,6 +1334,8 @@ int compdist(int dx[]) { int celldist(cell *c) { if(fulltorus) return torusmap()->dists[decodeId(c->master)]; + if(geometry == gCrystal) + return crystal::distance(c, currentmap->gamestart()); if(euwrap) return torusconfig::cyldist(decodeId(c->master), 0); if(masterless) @@ -1734,6 +1737,9 @@ int celldistance(cell *c1, cell *c2) { if(geometry == gFieldQuotient && !GOLDBERG) return currfp.getdist(fieldpattern::fieldval(c1), fieldpattern::fieldval(c2)); + + if(geometry == gCrystal) + return crystal::distance(c1, c2); if(bounded) { diff --git a/classes.cpp b/classes.cpp index a5861ebd..71d3f650 100644 --- a/classes.cpp +++ b/classes.cpp @@ -1693,6 +1693,7 @@ vector ginf = { {"Bring's Surface", "Bring", 5, 4, qsSMALL, gcHyperbolic, 0x20200, {{6, 4}}, eVariation::bitruncated}, {"Schmutz's M(3)", "M3", 12, 3, qsSMALL, gcHyperbolic, 0x20400, {{4, 2}}, eVariation::bitruncated}, {"Schmutz's M(4)", "M4", 12, 3, qsSMALL, gcHyperbolic, 0x20600, {{4, 2}}, eVariation::bitruncated}, + {"Crystal", "Crystal", 8, 4, qANYQ, gcHyperbolic, 0x28000, {{3, 2}}, eVariation::pure}, }; // remember to match the following mask when specifying codes for extra geometries: 0x78600 diff --git a/classes.h b/classes.h index a960f634..8f09c7b8 100644 --- a/classes.h +++ b/classes.h @@ -209,7 +209,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, gArchimedean, - gMacbeath, gBring, gSchmutzM2, gSchmutzM3, + gMacbeath, gBring, gSchmutzM2, gSchmutzM3, gCrystal, gGUARD}; enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere }; diff --git a/compileunits.h b/compileunits.h index 7ce4dbb0..030def83 100644 --- a/compileunits.h +++ b/compileunits.h @@ -31,6 +31,7 @@ #include "heptagon.cpp" #include "binary-tiling.cpp" #include "archimedean.cpp" +#include "crystal.cpp" #include "language.cpp" #include "cell.cpp" #include "expansion.cpp" diff --git a/crystal.cpp b/crystal.cpp new file mode 100644 index 00000000..07a7f1fe --- /dev/null +++ b/crystal.cpp @@ -0,0 +1,457 @@ +// Hyperbolic Rogue +// This file implements the multi-dimensional (aka crystal) geometries. +// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details + +namespace hr { + +namespace crystal { + +bool add_bitruncation = false; +bool view_coordinates = false; + +const int MAXDIM = 7; + +typedef array coord; +static const coord c0 = {}; + +int tocode(int cname) { return (1 << (cname >> 1)); } + +void resize2(vector>& v, int a, int b, int z) { + v.clear(); + v.resize(a); + for(auto& w: v) w.resize(b, z); + } + +const int FULLSTEP = 16; +const int HALFSTEP = 8; + +struct crystal_structure { + int dir; + int dim; + + vector> cmap; + vector> next; + vector> prev; + vector> order; + + void coord_to_next() { + resize2(next, 1< poor.dir) { + int which = next[a][poor.dir]; + int a1 = a ^ tocode(which); + + may_next_insert(a1, which^1, poor.dir); + may_next_insert(a ^ mm, which, poor.dir^1); + which = prev[a][poor.dir]; + a1 = a ^ tocode(which); + may_prev_insert(a1, which^1, poor.dir); + } + + // println(hlog, next); + + if(errors) { printf("errors: %d\n", errors); exit(1);; } + + int unf = 0; + for(int a=0; a<(1<= (1<<(dim-1))) take_what = dir-1; + next[i][prev[i][take_what]] = next[i][take_what], + prev[i][next[i][take_what]] = prev[i][take_what], + next[i].resize(dir), + prev[i].resize(dir); + } + } + + void build() { + dir = 4; + dim = 2; + next.resize(4, {2,3,1,0}); + next_to_prev(); + while(dir < S7) { + crystal_structure csx = move(*this); + add_dimension_to(csx); + } + if(dir > S7) remove_half_dimension(); + + next_to_coord(); + + coord_to_order(); + coord_to_next(); + if(count_bugs()) { + printf("bugs found\n"); + } + if(dir > MAX_EDGE || dim > MAXDIM) { + printf("Dimension or directions exceeded -- I have generated it, but won't play"); + exit(0); + } + } + + }; + +struct lwalker { + crystal_structure cs; + int id; + int spin; + }; + +lwalker operator +(lwalker a, int v) { a.spin = gmod(a.spin + v, a.cs.dir); return a; } +lwalker operator +(lwalker a, wstep_t) { + a.spin = a.cs.cmap[a.id][a.spin]; + a.id ^= tocode(a.spin); + a.spin = a.cs.order[a.id][a.spin^1]; + return a; + } + +coord add(coord c, lwalker a, int val) { + int code = a.cs.cmap[a.id][a.spin]; + c[code>>1] += (code&1) ? val : -val; + return c; + } + +map hcoords; +map heptagon_at; + +crystal_structure cs; + +coord add(coord c, int cname, int val) { + int dim = (cname>>1); + c[dim] = (c[dim] + (cname&1?val:-val)); + return c; + } + +lwalker makewalker(crystal_structure& cs, coord c, int d) { + lwalker a; + a.cs = cs; + a.id = 0; + for(int i=0; i (deg); + h->alt = NULL; + h->cdata = NULL; + h->c7 = newCell(deg, h); + h->distance = 0; + for(int i=0; idistance += abs(c[i]); + hcoords[h] = c; + // for(int i=0; i<6; i++) crystalstep(h, i); + return h; + } + +coord get_coord(cell *c) { + if(c->master->c7 != c) { + coord res = c0; + for(int i=0; itype; i+=2) { + coord co = hcoords[c->move(i)->master]; + for(int d=0; dtype/2) / c->type; + return res; + } + else + return hcoords[c->master]; + } + +struct hrmap_crystal : hrmap { + heptagon *getOrigin() { return get_heptagon_at(c0, S7); } + + hrmap_crystal() { + cs.build(); + } + + void verify() { } + }; + +hrmap *new_map() { + return new hrmap_crystal; + } + +bool is_bi(coord co) { + for(int i=0; ic.connect(d, heptspin(get_heptagon_at(c1, S7), lw1.spin)); + } + else { + auto coc = add(add(co, lw, HALFSTEP), lw+1, HALFSTEP); + auto hc = get_heptagon_at(coc, HALFSTEP); + for(int a=0; a<8; a+=2) { + hc->c.connect(a, heptspin(h, lw.spin)); + if(h->modmove(lw.spin-1)) { + hc->c.connect(a+1, heptspin(h, lw.spin) - 1 + wstep - 1); + } + co = add(co, lw, FULLSTEP); + lw = lw + wstep + (-1); + h = get_heptagon_at(co, S7); + } + } + } + +array, MAX_EDGE> distlimit_table = {{ + {SEE_ALL,SEE_ALL}, {SEE_ALL,SEE_ALL}, {SEE_ALL,SEE_ALL}, {SEE_ALL,SEE_ALL}, {15, 10}, + {6, 4}, {5, 3}, {4, 3}, {4, 3}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2} + }}; + +int readArgs() { + using namespace arg; + + if(0) ; + else if(argis("-crystal")) { + stop_game(); + geometry = gCrystal; variation = eVariation::pure; + shift(); int N = argi(); + ginf[gCrystal].sides = N; + if(N < MAX_EDGE) + ginf[gCrystal].distlimit = distlimit_table[N]; + add_bitruncation = false; + } + else if(argis("-crystalb")) { + stop_game(); + geometry = gCrystal; variation = eVariation::bitruncated; + ginf[gCrystal].sides = 8; + add_bitruncation = true; + } + else if(argis("-cview")) { + view_coordinates = true; + } + else return 1; + return 0; + } + +color_t colorize(cell *c) { + coord co = get_coord(c); + color_t res; + res = 0; + for(int i=0; i<3; i++) + res |= ((i == 2 && S7 == 5) ? (co[i] ? 255 : 0) : (128 + co[i] * 3)) << (8*i); + return res; + } + +bool crystal_cell(cell *c, transmatrix V) { + + if(geometry != gCrystal) return false; + + if(view_coordinates && cheater) for(int i=0; imaster->c7 == c) { + transmatrix V1 = cellrelmatrix(c, i); + ld dist = hdist0(V1 * C0); + ld alpha = -atan2(V1 * C0); + transmatrix T = V * spin(alpha) * xpush(dist*.3); + + auto co = hcoords[c->master]; + int our_id = 0; + for(int a=0; a>1] / (add_bitruncation ? HALFSTEP : FULLSTEP)), coordcolors[cx>>1], 1); + } + + if(PURE) { + cellwalker cw(c, i); + cellwalker cw2 = cw; + for(int i=0; i<(add_bitruncation?3:4); i++) cw2 = cw2 + wstep + 1; + if(cw2 != cw) { printf("crystal valence error\n"); cw.at->item = itGold; } + } + } + return false; + } + +int hypot2(coord co1, coord co2) { + int result = 0; + for(int a=0; amaster]; + coord co2 = hcoords[c2->master]; + int result = 0; + for(int a=0; ac.spin(d); return gm * heptmove[sp] * spin(2*M_PI*d/S7) * where; } - if(among(geometry, gFieldQuotient, gBring, gMacbeath)) { + if(among(geometry, gFieldQuotient, gBring, gMacbeath, gCrystal)) { int bestdist = 1000, bestd = 0; for(int d=0; dmove(d)->c7, c1); + int dist = celldistance(h2->cmove(d)->c7, c1); if(dist < bestdist) bestdist = dist, bestd = d; } int sp = h2->c.spin(bestd); diff --git a/heptagon.cpp b/heptagon.cpp index 60f92c43..20395f7c 100644 --- a/heptagon.cpp +++ b/heptagon.cpp @@ -205,13 +205,15 @@ heptagon *createStep(heptagon *h, int d) { d = h->c.fix(d); if(!h->move(d)) callhooks(hooks_createStep, h, d); + if(!h->move(d) && geometry == gCrystal) + crystal::create_step(h, d); if(!h->move(d) && binarytiling) return binary::createStep(h, d); if(!h->move(d) && archimedean) { arcm::create_adjacent(h, d); return h->move(d); } - if(!h->move(0) && h->s != hsOrigin && !binarytiling) { + if(!h->move(0) && h->s != hsOrigin && !binarytiling && (geometry != gCrystal)) { // cheating: int pard=0; if(S3 == 3) diff --git a/hyper.h b/hyper.h index efebe819..a50820f0 100644 --- a/hyper.h +++ b/hyper.h @@ -4135,6 +4135,13 @@ namespace arcm { int fix(heptagon *h, int spin); } +namespace crystal { + color_t colorize(cell *c); + int distance(cell *c1, cell *c2); + hrmap *new_map(); + void create_step(heptagon *h, int d); + } + hyperpoint get_warp_corner(cell *c, int cid); hyperpoint get_corner_position(cell *c, int cid, ld cf = 3); diff --git a/pattern2.cpp b/pattern2.cpp index 0a830f92..8e835c5c 100644 --- a/pattern2.cpp +++ b/pattern2.cpp @@ -1343,6 +1343,8 @@ namespace patterns { int z = currfp.getdist(fieldval(c), make_pair(0,false)); return 255 * (currfp.maxdist+1-z) / currfp.maxdist; } + case 'K': + return crystal::colorize(c); case 'N': { if(!hyperbolic) return canvasback; using namespace fieldpattern; @@ -1446,6 +1448,9 @@ namespace patterns { if(archimedean) dialog::addSelItem(XLAT("Archimedean"), "Archimedean", 'A'); + if(geometry == gCrystal) + dialog::addSelItem(XLAT("Crystal coordinates"), "Crystal", 'K'); + dialog::addSelItem(XLAT("sides"), "sides", 'B'); dialog::addBreak(100);