// 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; ginf[gCrystal].vertex = 4; 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; ginf[gCrystal].vertex = 3; ginf[gCrystal].distlimit = {7, 5}; 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; a