1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-30 15:39:54 +00:00
hyperrogue/cell.cpp

1133 lines
32 KiB
C++
Raw Normal View History

2016-08-26 09:58:03 +00:00
// Hyperbolic Rogue -- cells
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
2015-08-08 13:57:52 +00:00
/** \file cell.cpp
* \brief General cells and maps
*
* Start with locations.cpp
*/
2015-08-08 13:57:52 +00:00
#include "hyper.h"
namespace hr {
2019-08-09 23:56:00 +00:00
#if HDR
struct hrmap {
virtual heptagon *getOrigin() { return NULL; }
virtual cell *gamestart() { return getOrigin()->c7; }
virtual ~hrmap() { };
virtual vector<cell*>& allcells();
2019-08-09 23:56:00 +00:00
virtual void verify() { }
virtual void link_alt(const cellwalker& hs) { }
2019-10-10 11:09:31 +00:00
virtual void generateAlts(heptagon *h, int levs = IRREGULAR ? 1 : S3 >= OINF ? 1 : S3-3, bool link_cdata = true);
2019-08-09 23:56:00 +00:00
heptagon *may_create_step(heptagon *h, int direction) {
if(h->move(direction)) return h->move(direction);
return create_step(h, direction);
}
virtual heptagon *create_step(heptagon *h, int direction) {
printf("create_step called unexpectedly\n"); exit(1);
return NULL;
}
2019-11-26 23:39:41 +00:00
virtual struct transmatrix relative_matrix(heptagon *h2, heptagon *h1, const hyperpoint& hint) {
2019-08-09 23:56:00 +00:00
printf("relative_matrix called unexpectedly\n");
return Id;
}
2019-11-26 23:39:41 +00:00
virtual struct transmatrix relative_matrix(cell *c2, cell *c1, const hyperpoint& hint) {
return relative_matrix(c2->master, c1->master, hint);
2019-08-09 23:56:00 +00:00
}
2019-11-26 23:39:41 +00:00
virtual struct transmatrix adj(cell *c, int i) { return adj(c->master, i); }
virtual struct transmatrix adj(heptagon *h, int i);
struct transmatrix iadj(cell *c, int i) { cell *c1 = c->cmove(i); return adj(c1, c->c.spin(i)); }
2019-11-26 23:39:41 +00:00
transmatrix iadj(heptagon *h, int d) { return adj(h->cmove(d), h->c.spin(d)); }
2019-08-09 23:56:00 +00:00
virtual void draw() {
printf("undrawable\n");
}
virtual vector<hyperpoint> get_vertices(cell*);
virtual void virtualRebase(heptagon*& base, transmatrix& at) {
printf("virtualRebase called unexpectedly\n");
return;
}
static constexpr ld SPIN_NOT_AVAILABLE = 1e5;
virtual ld spin_angle(cell *c, int d) { return SPIN_NOT_AVAILABLE; }
virtual transmatrix spin_to(cell *c, int d, ld bonus=0) {
ld sa = spin_angle(c, d);
if(sa != SPIN_NOT_AVAILABLE) { return spin(bonus + sa); }
transmatrix T = rspintox(tC0(adj(c, d)));
if(WDIM == 3) return T * cspin(2, 0, bonus);
return T * spin(bonus);
}
virtual transmatrix spin_from(cell *c, int d, ld bonus=0) {
ld sa = spin_angle(c, d);
if(sa != SPIN_NOT_AVAILABLE) { return spin(bonus - sa); }
2019-11-14 18:23:27 +00:00
transmatrix T = spintox(tC0(adj(c, d)));
if(WDIM == 3) return T * cspin(2, 0, bonus);
return T * spin(bonus);
}
virtual double spacedist(cell *c, int i) { return hdist0(tC0(adj(c, i))); }
2019-08-09 23:56:00 +00:00
};
2019-11-26 23:44:33 +00:00
/** hrmaps which are based on regular non-Euclidean 2D tilings, possibly quotient
* Operators can be applied to these maps.
* Liskov substitution warning: maps which produce both tiling like above and 3D tilings
* (e.g. Euclidean and Crystal) also inherit from hrmap_standard
**/
2019-08-09 23:56:00 +00:00
struct hrmap_standard : hrmap {
void draw() override;
2019-11-26 23:39:41 +00:00
transmatrix relative_matrix(heptagon *h2, heptagon *h1, const hyperpoint& hint) override;
transmatrix relative_matrix(cell *c2, cell *c1, const hyperpoint& hint) override;
2019-08-09 23:56:00 +00:00
heptagon *create_step(heptagon *h, int direction) override;
2019-11-15 13:24:17 +00:00
transmatrix adj(cell *c, int d) override;
2019-11-26 23:39:41 +00:00
transmatrix adj(heptagon *h, int d) override;
2019-11-15 13:24:17 +00:00
ld spin_angle(cell *c, int d) override;
double spacedist(cell *c, int i) override;
2019-08-09 23:56:00 +00:00
};
void clearfrom(heptagon*);
void verifycells(heptagon*);
struct hrmap_hyperbolic : hrmap_standard {
heptagon *origin;
hrmap_hyperbolic();
hrmap_hyperbolic(heptagon *origin);
heptagon *getOrigin() override { return origin; }
~hrmap_hyperbolic() {
// verifycells(origin);
// printf("Deleting hyperbolic map: %p\n", this);
clearfrom(origin);
}
void verify() override { verifycells(origin); }
void virtualRebase(heptagon*& base, transmatrix& at) override;
2019-08-09 23:56:00 +00:00
};
#endif
2019-11-26 23:39:41 +00:00
transmatrix hrmap::adj(heptagon *h, int i) { return relative_matrix(h->cmove(i), h, C0); }
vector<cell*>& hrmap::allcells() {
static vector<cell*> default_allcells;
if(bounded && !(cgflags & qHUGE_BOUNDED) && !(prod && product::csteps == 0)) {
celllister cl(gamestart(), 1000000, 1000000, NULL);
default_allcells = cl.lst;
return default_allcells;
}
if(isize(dcal) <= 1) {
extern cellwalker cwt;
celllister cl(cwt.at, 1, 1000, NULL);
default_allcells = cl.lst;
return default_allcells;
}
return dcal;
}
2019-08-09 19:00:52 +00:00
EX int dirdiff(int dd, int t) {
2016-08-26 09:58:03 +00:00
dd %= t;
if(dd<0) dd += t;
if(t-dd < dd) dd = t-dd;
return dd;
}
2019-08-09 19:00:52 +00:00
EX int cellcount = 0;
2015-08-08 13:57:52 +00:00
2019-08-09 19:00:52 +00:00
EX cell *newCell(int type, heptagon *master) {
cell *c = tailored_alloc<cell> (type);
2015-08-08 13:57:52 +00:00
c->type = type;
c->master = master;
initcell(c);
return c;
}
// -- hrmap ---
2019-08-09 19:00:52 +00:00
EX hrmap *currentmap;
EX vector<hrmap*> allmaps;
2019-08-09 19:00:52 +00:00
EX hrmap *newAltMap(heptagon *o) { return new hrmap_hyperbolic(o); }
// --- hyperbolic geometry ---
EX heptagon* hyperbolic_origin() {
int odegree = geometry == gBinaryTiling ? 6 : S7;
heptagon *origin = tailored_alloc<heptagon> (odegree);
heptagon& h = *origin;
h.s = hsOrigin;
h.emeraldval = a46 ? 0 : 98;
h.zebraval = 40;
h.fiftyval = 0;
h.fieldval = 0;
h.rval0 = h.rval1 = 0;
h.cdata = NULL;
h.alt = NULL;
h.distance = 0;
if(IRREGULAR) irr::link_start(origin);
2019-11-14 20:18:50 +00:00
else h.c7 = newCell(odegree, origin);
return origin;
}
hrmap_hyperbolic::hrmap_hyperbolic(heptagon *o) { origin = o; }
hrmap_hyperbolic::hrmap_hyperbolic() { origin = hyperbolic_origin(); }
/** very similar to createMove in heptagon.cpp */
2019-08-09 19:00:52 +00:00
EX cell *createMov(cell *c, int d) {
if(d<0 || d>= c->type) {
printf("ERROR createmov\n");
}
2015-08-08 13:57:52 +00:00
if(c->move(d)) return c->move(d);
else if(hybri)
hybrid::find_cell_connection(c, d);
2019-07-25 10:24:02 +00:00
#if CAP_BT
else if(penrose)
kite::find_cell_connection(c, d);
#endif
2019-02-17 17:28:20 +00:00
#if CAP_IRR
else if(IRREGULAR) {
2018-07-16 18:05:23 +00:00
irr::link_cell(c, d);
}
2019-02-17 17:28:20 +00:00
#endif
#if CAP_GP
else if(GOLDBERG) {
2018-04-09 15:40:12 +00:00
gp::extend_map(c, d);
if(!c->move(d)) {
2018-04-03 21:39:18 +00:00
printf("extend failed to create for %p/%d\n", c, d);
exit(1);
}
}
2019-02-17 17:28:20 +00:00
#endif
#if CAP_ARCM
2018-08-30 00:11:43 +00:00
else if(archimedean && PURE) {
if(arcm::id_of(c->master) < arcm::current.N * 2) {
2018-08-17 11:29:00 +00:00
heptspin hs = heptspin(c->master, d) + wstep + 2 + wstep + 1;
c->c.connect(d, hs.at->c7, hs.spin, hs.mirrored);
2018-08-17 11:29:00 +00:00
}
else c->c.connect(d, c, d, false);
2018-08-17 11:29:00 +00:00
}
2018-08-30 00:11:43 +00:00
else if(archimedean && DUAL) {
if(arcm::id_of(c->master) >= arcm::current.N * 2) {
heptagon *h2 = createStep(c->master, d*2);
int d1 = c->master->c.spin(d*2);
c->c.connect(d, h2->c7, d1/2, false);
}
else {
printf("bad connection\n");
c->c.connect(d,c,d,false);
}
}
2019-02-17 17:28:20 +00:00
#endif
2018-08-30 00:11:43 +00:00
else if(archimedean || PURE) {
2016-08-26 09:58:03 +00:00
heptagon *h2 = createStep(c->master, d);
c->c.connect(d, h2->c7,c->master->c.spin(d), c->master->c.mirror(d));
2016-08-26 09:58:03 +00:00
}
2017-10-28 08:04:28 +00:00
else if(c == c->master->c7) {
cell *n = newCell(S6, c->master);
2015-08-08 13:57:52 +00:00
2018-05-01 17:34:09 +00:00
heptspin hs(c->master, d, false);
2015-08-08 13:57:52 +00:00
int alt3 = c->type/2;
int alt4 = alt3+1;
2017-10-28 08:04:28 +00:00
2018-05-01 17:34:09 +00:00
for(int u=0; u<S6; u+=2) {
if(hs.mirrored && (S7%2 == 0)) hs++;
hs.at->c7->c.connect(hs.spin, n, u, hs.mirrored);
if(hs.mirrored && (S7%2 == 0)) hs--;
2018-05-01 17:34:09 +00:00
hs = hs + alt3 + wstep - alt4;
2017-10-28 08:04:28 +00:00
}
2017-03-23 10:53:57 +00:00
extern void verifycell(cell *c);
verifycell(n);
2015-08-08 13:57:52 +00:00
}
2017-10-28 08:04:28 +00:00
else {
2018-05-01 17:34:09 +00:00
cellwalker cw(c, d, false);
cellwalker cw2 = cw - 1 + wstep - 1 + wstep - 1;
c->c.connect(d, cw2);
2015-08-08 13:57:52 +00:00
}
return c->move(d);
2015-08-08 13:57:52 +00:00
}
2019-08-09 19:00:52 +00:00
EX void eumerge(cell* c1, int s1, cell *c2, int s2, bool mirror) {
2015-08-08 13:57:52 +00:00
if(!c2) return;
c1->move(s1) = c2; c1->c.setspin(s1, s2, mirror);
c2->move(s2) = c1; c2->c.setspin(s2, s1, mirror);
}
2015-08-08 13:57:52 +00:00
// map<pair<eucoord, eucoord>, cell*> euclidean;
2019-09-08 10:24:10 +00:00
EX hookset<hrmap*()> *hooks_newmap;
2018-11-30 13:37:59 +00:00
/** create a map in the current geometry */
2019-08-09 19:00:52 +00:00
EX void initcells() {
2019-05-12 23:57:40 +00:00
DEBB(DF_INIT, ("initcells"));
2017-03-23 10:53:57 +00:00
2018-11-30 13:37:59 +00:00
hrmap* res = callhandlers((hrmap*)nullptr, hooks_newmap);
if(res) currentmap = res;
else if(asonov::in()) currentmap = asonov::new_map();
else if(nonisotropic || hybri) currentmap = nisot::new_map();
2019-02-17 17:28:20 +00:00
#if CAP_CRYSTAL
else if(cryst) currentmap = crystal::new_map();
2019-02-17 17:28:20 +00:00
#endif
#if CAP_ARCM
2018-11-30 13:37:59 +00:00
else if(archimedean) currentmap = arcm::new_map();
2019-02-17 17:28:20 +00:00
#endif
2019-11-27 00:01:20 +00:00
else if(euclid && !penrose) currentmap = euclid3::new_map();
2019-07-25 10:24:02 +00:00
#if CAP_BT
else if(penrose) currentmap = kite::new_map();
#endif
#if MAXMDIM >= 4
2019-05-08 16:33:08 +00:00
else if(WDIM == 3 && !binarytiling) currentmap = reg3::new_map();
#endif
else if(sphere) currentmap = new_spherical_map();
else if(quotient) currentmap = quotientspace::new_map();
#if CAP_BT
else if(binarytiling) currentmap = binary::new_map();
#endif
2019-10-10 11:08:06 +00:00
else if(S3 >= OINF) currentmap = inforder::new_map();
else currentmap = new hrmap_hyperbolic;
2015-08-08 13:57:52 +00:00
allmaps.push_back(currentmap);
2017-10-27 18:07:58 +00:00
2019-02-17 17:33:15 +00:00
#if CAP_FIELD
windmap::create();
2019-02-17 17:33:15 +00:00
#endif
// origin->emeraldval =
2015-08-08 13:57:52 +00:00
}
2019-08-09 19:00:52 +00:00
EX void clearcell(cell *c) {
2015-08-08 13:57:52 +00:00
if(!c) return;
2019-05-12 23:57:40 +00:00
DEBB(DF_MEMORY, (format("c%d %p\n", c->type, c)));
for(int t=0; t<c->type; t++) if(c->move(t)) {
2019-05-12 23:57:40 +00:00
DEBB(DF_MEMORY, (format("mov %p [%p] S%d\n", c->move(t), c->move(t)->move(c->c.spin(t)), c->c.spin(t))));
if(c->move(t)->move(c->c.spin(t)) != NULL &&
c->move(t)->move(c->c.spin(t)) != c) {
2019-05-12 23:57:40 +00:00
DEBB(DF_MEMORY | DF_ERROR, (format("cell error: type = %d %d -> %d\n", c->type, t, c->c.spin(t))));
2015-08-08 13:57:52 +00:00
exit(1);
}
c->move(t)->move(c->c.spin(t)) = NULL;
2015-08-08 13:57:52 +00:00
}
2019-05-12 23:57:40 +00:00
DEBB(DF_MEMORY, (format("DEL %p\n", c)));
tailored_delete(c);
2015-08-08 13:57:52 +00:00
}
2019-08-09 19:00:52 +00:00
EX heptagon deletion_marker;
2015-08-08 13:57:52 +00:00
2018-04-10 22:16:33 +00:00
template<class T> void subcell(cell *c, const T& t) {
if(GOLDBERG) {
forCellEx(c2, c) if(c2->move(0) == c && c2 != c2->master->c7) {
2018-04-10 22:16:33 +00:00
subcell(c2, t);
}
}
else if(BITRUNCATED && !archimedean && !binarytiling)
2018-04-10 22:16:33 +00:00
forCellEx(c2, c) t(c2);
t(c);
}
2019-08-09 19:00:52 +00:00
EX void clearHexes(heptagon *at) {
if(at->c7 && at->cdata) {
delete at->cdata;
at->cdata = NULL;
}
2019-02-17 17:28:20 +00:00
if(0);
#if CAP_IRR
else if(IRREGULAR) irr::clear_links(at);
#endif
2018-08-17 19:37:33 +00:00
else if(at->c7) subcell(at->c7, clearcell);
2017-03-23 10:53:57 +00:00
}
void unlink_cdata(heptagon *h) {
if(h->alt && h->c7) {
if(h->alt->cdata == (cdata*) h)
h->alt->cdata = NULL;
}
}
EX void clear_heptagon(heptagon *at) {
clearHexes(at);
tailored_delete(at);
}
2019-08-09 19:00:52 +00:00
EX void clearfrom(heptagon *at) {
2019-03-06 15:36:10 +00:00
if(!at) return;
2015-08-08 13:57:52 +00:00
queue<heptagon*> q;
unlink_cdata(at);
2015-08-08 13:57:52 +00:00
q.push(at);
at->alt = &deletion_marker;
//int maxq = 0;
while(!q.empty()) {
at = q.front();
// if(q.size() > maxq) maxq = q.size();
q.pop();
2019-05-12 23:57:40 +00:00
DEBB(DF_MEMORY, ("from %p", at));
if(!at->c7) {
heptagon *h = (heptagon*) at->cdata;
if(h) {
2019-05-12 23:57:40 +00:00
if(h->alt != at) { DEBB(DF_MEMORY | DF_ERROR, ("alt error :: h->alt = ", h->alt)); }
cell *c = h->c7;
2018-04-10 22:16:33 +00:00
subcell(c, destroycellcontents);
h->alt = NULL;
at->cdata = NULL;
}
}
int edges = at->degree();
2019-05-08 16:33:08 +00:00
if(binarytiling && WDIM == 2) edges = at->c7->type;
for(int i=0; i<edges; i++) if(at->move(i)) {
if(at->move(i)->alt != &deletion_marker)
q.push(at->move(i));
unlink_cdata(at->move(i));
at->move(i)->alt = &deletion_marker;
2019-05-12 23:57:40 +00:00
DEBB(DF_MEMORY, ("!mov ", at->move(i), " [", at->move(i)->move(at->c.spin(i)), "]"));
if(at->move(i)->move(at->c.spin(i)) != NULL &&
at->move(i)->move(at->c.spin(i)) != at) {
2019-05-12 23:57:40 +00:00
DEBB(DF_MEMORY | DF_ERROR, ("hept error"));
2015-08-08 13:57:52 +00:00
exit(1);
}
at->move(i)->move(at->c.spin(i)) = NULL;
at->move(i) = NULL;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
clearHexes(at);
tailored_delete(at);
2015-08-08 13:57:52 +00:00
}
//printf("maxq = %d\n", maxq);
}
2019-08-09 19:00:52 +00:00
EX void verifycell(cell *c) {
2015-08-08 13:57:52 +00:00
int t = c->type;
for(int i=0; i<t; i++) {
cell *c2 = c->move(i);
2015-08-08 13:57:52 +00:00
if(c2) {
2019-11-27 00:01:20 +00:00
if(BITRUNCATED && c == c->master->c7) verifycell(c2);
if(c2->move(c->c.spin(i)) && c2->move(c->c.spin(i)) != c) {
printf("cell error %p:%d [%d] %p:%d [%d]\n", c, i, c->type, c2, c->c.spin(i), c2->type);
2017-03-23 10:53:57 +00:00
exit(1);
}
2015-08-08 13:57:52 +00:00
}
}
}
2019-08-09 19:00:52 +00:00
EX void verifycells(heptagon *at) {
if(GOLDBERG || IRREGULAR || archimedean) return;
for(int i=0; i<at->type; i++) if(at->move(i) && at->move(i)->move(at->c.spin(i)) && at->move(i)->move(at->c.spin(i)) != at) {
printf("hexmix error %p [%d s=%d] %p %p\n", at, i, at->c.spin(i), at->move(i), at->move(i)->move(at->c.spin(i)));
2015-08-08 13:57:52 +00:00
}
if(!sphere && !quotient)
for(int i=0; i<S7; i++) if(at->move(i) && at->c.spin(i) == 0 && at->s != hsOrigin)
verifycells(at->move(i));
2015-08-08 13:57:52 +00:00
verifycell(at->c7);
}
2019-08-09 19:00:52 +00:00
EX int eudist(int sx, int sy) {
2015-08-08 13:57:52 +00:00
int z0 = abs(sx);
int z1 = abs(sy);
if(a4 && BITRUNCATED)
return (z0 == z1 && z0 > 0) ? z0+1: max(z0, z1);
2017-12-18 12:00:36 +00:00
if(a4) return z0 + z1;
2015-08-08 13:57:52 +00:00
int z2 = abs(sx+sy);
return max(max(z0,z1), z2);
}
2019-08-09 19:00:52 +00:00
EX int compdist(int dx[]) {
2017-10-28 23:57:34 +00:00
int mi = dx[0];
for(int u=0; u<S3; u++) mi = min(mi, dx[u]);
for(int u=0; u<S3; u++)
if(dx[u] > mi+2)
return -1; // { printf("cycle error!\n"); exit(1); }
for(int u=0; u<S3; u++)
if(dx[u] == mi+2)
return mi+1;
int cnt = 0;
for(int u=0; u<S3; u++)
if(dx[u] == mi) cnt++;
if(cnt < 2)
2017-03-23 10:53:57 +00:00
return mi+1;
return mi;
}
2019-08-09 19:00:52 +00:00
EX int celldist(cell *c) {
2019-08-10 17:34:12 +00:00
if(experimental) return 0;
if(hybri) {
auto w = hybrid::get_where(c);
if(sl2) w.second = 0;
int d;
hybrid::in_underlying_map([&] { d = celldist(w.first) + abs(w.second); });
return d;
}
2019-11-02 21:19:32 +00:00
if(nil && !quotient) return DISTANCE_UNKNOWN;
if(euclid && (penrose || archimedean)) return celldistance(currentmap->gamestart(), c);
2019-10-02 17:22:43 +00:00
if(sphere || binarytiling || WDIM == 3 || cryst || solnih || penrose) return celldistance(currentmap->gamestart(), c);
2019-02-17 17:28:20 +00:00
#if CAP_IRR
if(IRREGULAR) return irr::celldist(c, false);
2019-02-17 17:28:20 +00:00
#endif
if(archimedean || ctof(c)) return c->master->distance;
2019-02-17 17:28:20 +00:00
#if CAP_GP
if(GOLDBERG) return gp::compute_dist(c, celldist);
2019-02-17 17:28:20 +00:00
#endif
2017-10-28 23:57:34 +00:00
int dx[MAX_S3];
for(int u=0; u<S3; u++)
2015-08-08 13:57:52 +00:00
dx[u] = createMov(c, u+u)->master->distance;
2017-03-23 10:53:57 +00:00
return compdist(dx);
2015-08-08 13:57:52 +00:00
}
2019-08-09 19:00:52 +00:00
#if HDR
static const int ALTDIST_BOUNDARY = 99999;
static const int ALTDIST_UNKNOWN = 99998;
static const int ALTDIST_ERROR = 90000;
#endif
2016-01-02 10:09:13 +00:00
2019-08-09 19:00:52 +00:00
EX int celldistAlt(cell *c) {
2019-08-10 17:34:12 +00:00
if(experimental) return 0;
if(hybri) {
2019-09-12 12:24:02 +00:00
if(in_s2xe()) return hybrid::get_where(c).second;
auto w = hybrid::get_where(c);
int d = c->master->alt && c->master->alt->alt ? c->master->alt->alt->fieldval : 0;
d = sl2 ? 0 : abs(w.second - d);
hybrid::in_underlying_map([&] { d += celldistAlt(w.first); });
return d;
}
2019-02-17 17:28:20 +00:00
#if CAP_BT
2019-10-02 17:22:43 +00:00
if(binarytiling || solnih) return c->master->distance + (specialland == laCamelot && !tactic::on? 30 : 0);
2019-02-17 17:28:20 +00:00
#endif
2019-08-06 18:59:43 +00:00
if(nil) return c->master->zebraval + abs(c->master->emeraldval) + (specialland == laCamelot && !tactic::on? 30 : 0);;
2019-02-17 17:28:20 +00:00
#if CAP_CRYSTAL
if(cryst)
return crystal::dist_alt(c);
2019-02-17 17:28:20 +00:00
#endif
2017-10-30 21:47:07 +00:00
if(sphere || quotient) {
return celldist(c) - 3;
}
#if MAXMDIM >= 4
2019-05-08 16:33:08 +00:00
if(euclid && WDIM == 3) return euclid3::dist_alt(c);
if(hyperbolic && WDIM == 3) return reg3::altdist(c->master);
#endif
2017-03-23 10:53:57 +00:00
if(!c->master->alt) return 0;
2019-02-17 17:28:20 +00:00
#if CAP_IRR
if(IRREGULAR) return irr::celldist(c, true);
2019-02-17 17:28:20 +00:00
#endif
2017-10-28 23:57:34 +00:00
if(ctof(c)) return c->master->alt->distance;
2019-02-17 17:28:20 +00:00
#if CAP_GP
if(GOLDBERG) return gp::compute_dist(c, celldistAlt);
2019-02-17 17:28:20 +00:00
#endif
2017-10-30 21:47:07 +00:00
int dx[MAX_S3]; dx[0] = 0;
2017-10-28 23:57:34 +00:00
for(int u=0; u<S3; u++) if(createMov(c, u+u)->master->alt == NULL)
2015-08-08 13:57:52 +00:00
return ALTDIST_UNKNOWN;
2017-10-28 23:57:34 +00:00
for(int u=0; u<S3; u++)
2015-08-08 13:57:52 +00:00
dx[u] = createMov(c, u+u)->master->alt->distance;
2017-10-28 23:57:34 +00:00
// return compdist(dx); -> not OK because of boundary conditions
int mi = dx[0];
for(int i=1; i<S3; i++) mi = min(mi, dx[i]);
for(int i=0; i<S3; i++) if(dx[i] > mi+2)
2015-08-08 13:57:52 +00:00
return ALTDIST_BOUNDARY; // { printf("cycle error!\n"); exit(1); }
2017-10-28 23:57:34 +00:00
for(int i=0; i<S3; i++) if(dx[i] == mi+2)
2015-08-08 13:57:52 +00:00
return mi+1;
return mi;
}
2019-08-09 19:00:52 +00:00
#if HDR
static const int RPV_MODULO = 5;
static const int RPV_RAND = 0;
static const int RPV_ZEBRA = 1;
static const int RPV_EMERALD = 2;
static const int RPV_PALACE = 3;
static const int RPV_CYCLE = 4;
#endif
2016-08-26 09:58:03 +00:00
// x mod 5 = pattern type
// x mod (powers of 2) = pattern type specific
// (x/5) mod 15 = picture for drawing floors
// x mod 7 = chance of pattern-specific pic
// whole = randomization
2019-08-09 19:00:52 +00:00
EX bool randpattern(cell *c, int rval) {
2016-01-02 10:09:13 +00:00
int i, sw=0;
2016-08-26 09:58:03 +00:00
switch(rval%5) {
2016-01-02 10:09:13 +00:00
case 0:
2016-08-26 09:58:03 +00:00
if(rval&1) {
return hrandpos() < rval;
}
else {
int cd = getCdata(c, 0);
return !((cd/(((rval/2)&15)+1))&1);
}
2016-01-02 10:09:13 +00:00
case 1:
i = zebra40(c);
if(i&1) { if(rval&4) sw^=1; i &= ~1; }
if(i&2) { if(rval&8) sw^=1; i &= ~2; }
i >>= 2;
i--; i /= 3;
if(rval & (16<<i)) sw^=1;
return sw;
case 2:
i = emeraldval(c);
if(i&1) { if(rval&4) sw^=1; i &= ~1; }
if(i&2) { if(rval&8) sw^=1; i &= ~2; }
2016-08-26 09:58:03 +00:00
i >>= 2; i--;
2016-01-02 10:09:13 +00:00
if(rval & (16<<i)) sw^=1;
return sw;
case 3:
if(polara50(c)) { if(rval&4) sw^=1; }
if(polarb50(c)) { if(rval&8) sw^=1; }
2016-08-26 09:58:03 +00:00
i = fiftyval049(c); i += 6; i /= 7;
2016-01-02 10:09:13 +00:00
if(rval & (16<<i)) sw^=1;
return sw;
2016-08-26 09:58:03 +00:00
case 4:
i = (rval&3);
if(i == 1 && (celldist(c)&1)) sw ^= 1;
if(i == 2 && (celldist(c)&2)) sw ^= 1;
if(i == 3 && ((celldist(c)/3)&1)) sw ^= 1;
if(rval & (4<<towerval(c, celldist))) sw ^= 1;
return sw;
2016-01-02 10:09:13 +00:00
}
return 0;
}
2019-08-09 19:00:52 +00:00
EX string describeRPM(eLand l) {
2016-08-26 09:58:03 +00:00
int rval = randompattern[l];
switch(rval%5) {
case 0:
if(rval&1)
return "R:"+its(rval/(HRANDMAX/100))+"%";
else
return "Landscape/"+its(((rval/2)&15)+1);
case 1:
return "Z/"+its((rval>>2)&3)+"/"+its((rval>>4)&15);
case 2:
return "E/"+its((rval>>2)&3)+"/"+its((rval>>4)&2047);
case 3:
return "P/"+its((rval>>2)&3)+"/"+its((rval>>4)&255);
case 4:
return "C/"+its(rval&3)+"/"+its((rval>>2)&65535);
}
return "?";
}
2019-08-09 19:00:52 +00:00
EX int randpatternCode(cell *c, int rval) {
2016-08-26 09:58:03 +00:00
switch(rval % RPV_MODULO) {
2016-01-02 10:09:13 +00:00
case 1:
return zebra40(c);
case 2:
return emeraldval(c);
case 3:
return fiftyval049(c) + (polara50(c)?50:0) + (polarb50(c)?1000:0);
2016-08-26 09:58:03 +00:00
case 4:
return towerval(c, celldist) * 6 + celldist(c) % 6;
2016-01-02 10:09:13 +00:00
}
return 0;
}
#if HDR
2016-01-02 10:09:13 +00:00
#define RANDITER 31
#endif
2016-01-02 10:09:13 +00:00
char rpm_memoize[3][256][RANDITER+1];
2019-08-09 19:00:52 +00:00
EX void clearMemoRPM() {
2016-01-02 10:09:13 +00:00
for(int a=0; a<3; a++) for(int b=0; b<256; b++) for(int i=0; i<RANDITER+1; i++)
rpm_memoize[a][b][i] = 2;
}
2019-08-09 19:00:52 +00:00
EX bool randpatternMajority(cell *c, int ival, int iterations) {
2016-01-02 10:09:13 +00:00
int rval = 0;
if(ival == 0) rval = randompattern[laCaves];
if(ival == 1) rval = randompattern[laLivefjord];
if(ival == 2) rval = randompattern[laEmerald];
2016-08-26 09:58:03 +00:00
if(rval%RPV_MODULO == RPV_RAND) return randpattern(c, rval);
2016-01-02 10:09:13 +00:00
int code = randpatternCode(c, rval);
char& memo(rpm_memoize[ival][code][iterations]);
if(memo < 2) return memo;
int z = 0;
if(iterations) for(int i=0; i<c->type; i++) {
if(randpatternMajority(createMov(c,i), ival, iterations-1))
z++;
else
z--;
}
if(z!=0) memo = (z>0);
else memo = randpattern(c, rval);
// printf("%p] rval = %X code = %d iterations = %d result = %d\n", c, rval, code, iterations, memo);
return memo;
}
2016-08-26 09:58:03 +00:00
#define RVAL_MASK 0x10000000
#define DATA_MASK 0x20000000
cdata orig_cdata;
2019-08-09 19:00:52 +00:00
EX bool geometry_supports_cdata() {
if(hybri) return PIU(geometry_supports_cdata());
2019-07-21 20:56:10 +00:00
return among(geometry, gEuclid, gEuclidSquare, gNormal, gOctagon, g45, g46, g47, gBinaryTiling) || (archimedean && !sphere);
}
2016-08-26 09:58:03 +00:00
void affect(cdata& d, short rv, signed char signum) {
if(rv&1) d.val[0]+=signum; else d.val[0]-=signum;
if(rv&2) d.val[1]+=signum; else d.val[1]-=signum;
if(rv&4) d.val[2]+=signum; else d.val[2]-=signum;
if(rv&8) d.val[3]+=signum; else d.val[3]-=signum;
int id = (rv>>4) & 63;
if(id < 32)
d.bits ^= (1 << id);
}
void setHeptagonRval(heptagon *h) {
if(!(h->rval0 || h->rval1)) {
h->rval0 = hrand(0x10000);
h->rval1 = hrand(0x10000);
}
}
2019-08-09 19:00:52 +00:00
EX bool dmeq(int a, int b) { return (a&3) == (b&3); }
2019-07-21 20:56:10 +00:00
/* kept for compatibility: Racing etc. */
cdata *getHeptagonCdata_legacy(heptagon *h) {
if(h->cdata) return h->cdata;
if(sphere || quotient) h = currentmap->gamestart()->master;
if(h == currentmap->getOrigin()) {
h->cdata = new cdata(orig_cdata);
for(int& v: h->cdata->val) v = 0;
h->cdata->bits = reptilecheat ? (1 << 21) - 1 : 0;
if(yendor::on && specialland == laVariant) h->cdata->bits |= (1 << 8) | (1 << 9) | (1 << 12);
return h->cdata;
}
cdata mydata = *getHeptagonCdata_legacy(h->move(0));
for(int di=3; di<5; di++) {
heptspin hs(h, di, false);
int signum = +1;
while(true) {
heptspin hstab[15];
hstab[7] = hs;
for(int i=8; i<12; i++) {
hstab[i] = hstab[i-1];
hstab[i] += ((i&1) ? 4 : 3);
hstab[i] += wstep;
hstab[i] += ((i&1) ? 3 : 4);
}
for(int i=6; i>=3; i--) {
hstab[i] = hstab[i+1];
hstab[i] += ((i&1) ? 3 : 4);
hstab[i] += wstep;
hstab[i] += ((i&1) ? 4 : 3);
}
if(hstab[3].at->distance < hstab[7].at->distance) {
hs = hstab[3]; continue;
}
if(hstab[11].at->distance < hstab[7].at->distance) {
hs = hstab[11]; continue;
}
int jj = 7;
for(int k=3; k<12; k++) if(hstab[k].at->distance < hstab[jj].at->distance) jj = k;
int ties = 0, tiespos = 0;
for(int k=3; k<12; k++) if(hstab[k].at->distance == hstab[jj].at->distance)
ties++, tiespos += (k-jj);
// printf("ties=%d tiespos=%d jj=%d\n", ties, tiespos, jj);
if(ties == 2) jj += tiespos/2;
if(jj&1) signum = -1;
hs = hstab[jj];
break;
}
hs = hs + 3 + wstep;
setHeptagonRval(hs.at);
affect(mydata, hs.spin ? hs.at->rval0 : hs.at->rval1, signum);
}
return h->cdata = new cdata(mydata);
}
2016-08-26 09:58:03 +00:00
cdata *getHeptagonCdata(heptagon *h) {
2019-08-26 19:24:19 +00:00
if(hybri) { cdata *x; hybrid::in_underlying_map([&] { x = getHeptagonCdata(h); }); return x; }
if(geometry == gNormal && BITRUNCATED) return getHeptagonCdata_legacy(h);
2016-08-26 09:58:03 +00:00
if(h->cdata) return h->cdata;
if(sphere || quotient) h = currentmap->gamestart()->master;
2019-07-21 20:56:10 +00:00
bool starting = h->s == hsOrigin;
if(binarytiling) {
if(binary::mapside(h) == 0) starting = true;
for(int i=0; i<h->type; i++) if(binary::mapside(h->cmove(i)) == 0) starting = true;
}
2017-03-23 10:53:57 +00:00
2019-07-21 20:56:10 +00:00
if(starting) {
h->cdata = new cdata(orig_cdata);
for(int& v: h->cdata->val) v = 0;
h->cdata->bits = reptilecheat ? (1 << 21) - 1 : 0;
if(yendor::on && specialland == laVariant) h->cdata->bits |= (1 << 8) | (1 << 9) | (1 << 12);
return h->cdata;
2016-08-26 09:58:03 +00:00
}
2019-07-21 20:56:10 +00:00
int dir = binarytiling ? 5 : 0;
cdata mydata = *getHeptagonCdata(h->cmove(dir));
2016-08-26 09:58:03 +00:00
2019-10-10 11:09:31 +00:00
if(S3 >= OINF) {
setHeptagonRval(h);
affect(mydata, h->rval0, 1);
}
else if(S3 == 4) {
2019-07-21 20:56:10 +00:00
heptspin hs(h, 0);
while(dmeq((hs+1).cpeek()->dm4, (hs.at->dm4 - 1))) hs = hs + 1 + wstep + 1;
while(dmeq((hs-1).cpeek()->dm4, (hs.at->dm4 - 1))) hs = hs - 1 + wstep - 1;
setHeptagonRval(hs.at);
affect(mydata, hs.at->rval0, 1);
}
else for(int di: {0,1}) {
heptspin hs(h, dir, false);
hs -= di;
2016-08-26 09:58:03 +00:00
while(true) {
2019-07-21 20:56:10 +00:00
heptspin hs2 = hs + wstep + 1 + wstep - 1;
if(dmeq(hs2.at->dm4, hs.at->dm4 + 1)) break;
hs = hs2;
}
while(true) {
heptspin hs2 = hs + 1 + wstep - 1 + wstep;
if(dmeq(hs2.at->dm4, hs.at->dm4 + 1)) break;
hs = hs2;
2016-08-26 09:58:03 +00:00
}
setHeptagonRval(hs.at);
2019-07-21 20:56:10 +00:00
affect(mydata, hs.spin == dir ? hs.at->rval0 : hs.at->rval1, 1);
2016-08-26 09:58:03 +00:00
}
return h->cdata = new cdata(mydata);
}
2019-11-27 00:01:20 +00:00
cdata *getEuclidCdata(gp::loc h) {
2017-06-09 01:41:33 +00:00
int x, y;
2019-11-27 00:01:20 +00:00
tie(x,y) = h;
auto& data = archimedean ? arcm::get_cdata() : get_cdata();
2019-07-21 20:56:10 +00:00
// hrmap_euclidean* euc = dynamic_cast<hrmap_euclidean*> (currentmap);
if(data.count(h)) return &(data[h]);
2017-06-09 01:41:33 +00:00
2016-08-26 09:58:03 +00:00
if(x == 0 && y == 0) {
cdata xx;
for(int i=0; i<4; i++) xx.val[i] = 0;
xx.bits = 0;
2019-07-21 20:56:10 +00:00
return &(data[h] = xx);
2016-08-26 09:58:03 +00:00
}
int ord = 1, bid = 0;
while(!((x|y)&ord)) ord <<= 1, bid++;
for(int k=0; k<3; k++) {
int x1 = x + (k<2 ? ord : 0);
int y1 = y - (k>0 ? ord : 0);
2016-08-26 09:58:03 +00:00
if((x1&ord) || (y1&ord)) continue;
int x2 = x - (k<2 ? ord : 0);
int y2 = y + (k>0 ? ord : 0);
2016-08-26 09:58:03 +00:00
2019-11-27 00:01:20 +00:00
cdata *d1 = getEuclidCdata({x1,y1});
cdata *d2 = getEuclidCdata({x2,y2});
2016-08-26 09:58:03 +00:00
cdata xx;
double disp = pow(2, bid/2.) * 6;
for(int i=0; i<4; i++) {
double dv = (d1->val[i] + d2->val[i])/2 + (hrand(1000) - hrand(1000))/1000. * disp;
xx.val[i] = floor(dv);
if(hrand(1000) / 1000. < dv - floor(dv)) xx.val[i]++;
}
xx.bits = 0;
for(int b=0; b<32; b++) {
bool gbit = ((hrand(2)?d1:d2)->bits >> b) & 1;
int flipchance = (1<<bid);
if(flipchance > 512) flipchance = 512;
if(hrand(1024) < flipchance) gbit = !gbit;
if(gbit) xx.bits |= (1<<b);
}
2019-07-21 20:56:10 +00:00
return &(data[h] = xx);
2016-08-26 09:58:03 +00:00
}
// impossible!
return NULL;
}
2019-07-21 20:56:10 +00:00
int ld_to_int(ld x) {
return int(x + 1000000.5) - 1000000;
}
2019-11-27 00:01:20 +00:00
EX gp::loc pseudocoords(cell *c) {
2019-07-21 20:56:10 +00:00
transmatrix T = arcm::archimedean_gmatrix[c->master].second;
2019-11-27 00:01:20 +00:00
return {ld_to_int(T[0][LDIM]), ld_to_int((spin(60*degree) * T)[0][LDIM])};
2019-07-21 20:56:10 +00:00
}
2019-08-09 19:00:52 +00:00
EX cdata *arcmCdata(cell *c) {
2019-07-21 20:56:10 +00:00
heptagon *h2 = arcm::archimedean_gmatrix[c->master].first;
dynamicval<eGeometry> g(geometry, gNormal);
dynamicval<hrmap*> cm(currentmap, arcm::current_altmap);
return getHeptagonCdata(h2);
}
2019-08-09 19:00:52 +00:00
EX int getCdata(cell *c, int j) {
2019-11-27 00:01:20 +00:00
if(euclid) return getEuclidCdata(euc2_coordinates(c))->val[j];
2019-07-21 20:56:10 +00:00
else if(archimedean && euclid)
return getEuclidCdata(pseudocoords(c))->val[j];
else if(archimedean && hyperbolic)
return arcmCdata(c)->val[j]*3;
else if(!geometry_supports_cdata()) return 0;
else if(ctof(c)) return getHeptagonCdata(c->master)->val[j]*3;
2016-08-26 09:58:03 +00:00
else {
int jj = 0;
auto ar = gp::get_masters(c);
for(int k=0; k<3; k++)
2018-07-16 18:05:23 +00:00
jj += getHeptagonCdata(ar[k])->val[j];
2016-08-26 09:58:03 +00:00
return jj;
}
}
2019-08-09 19:00:52 +00:00
EX int getBits(cell *c) {
2019-11-27 00:01:20 +00:00
if(euclid) return getEuclidCdata(euc2_coordinates(c))->bits;
2019-07-21 20:56:10 +00:00
else if(archimedean && euclid)
return getEuclidCdata(pseudocoords(c))->bits;
else if(archimedean && (hyperbolic || sl2))
2019-07-21 20:56:10 +00:00
return arcmCdata(c)->bits;
else if(!geometry_supports_cdata()) return 0;
else if(c == c->master->c7) return getHeptagonCdata(c->master)->bits;
2016-08-26 09:58:03 +00:00
else {
auto ar = gp::get_masters(c);
2018-07-16 18:05:23 +00:00
int b0 = getHeptagonCdata(ar[0])->bits;
int b1 = getHeptagonCdata(ar[1])->bits;
int b2 = getHeptagonCdata(ar[2])->bits;
2016-08-26 09:58:03 +00:00
return (b0 & b1) | (b1 & b2) | (b2 & b0);
}
}
2019-08-09 19:00:52 +00:00
EX cell *heptatdir(cell *c, int d) {
2017-03-23 10:53:57 +00:00
if(d&1) {
cell *c2 = createMov(c, d);
int s = c->c.spin(d);
2017-03-23 10:53:57 +00:00
s += 3; s %= 6;
return createMov(c2, s);
}
else return createMov(c, d);
}
2019-08-09 19:00:52 +00:00
EX int heptdistance(heptagon *h1, heptagon *h2) {
2018-04-06 21:28:58 +00:00
// very rough distance
int d = 0;
2019-02-17 17:28:20 +00:00
#if CAP_CRYSTAL
if(cryst) return crystal::space_distance(h1->c7, h2->c7);
2019-02-17 17:28:20 +00:00
#endif
2019-09-13 17:50:12 +00:00
#if CAP_SOLV
2019-10-03 18:10:48 +00:00
if(solnih) return solnihv::approx_distance(h1, h2);
2019-09-13 17:50:12 +00:00
#endif
2018-04-06 21:28:58 +00:00
while(true) {
if(h1 == h2) return d;
for(int i=0; i<S7; i++) if(h1->move(i) == h2) return d + 1;
2018-04-06 21:28:58 +00:00
int d1 = h1->distance, d2 = h2->distance;
2019-08-02 20:08:47 +00:00
if(d1 >= d2) d++, h1 = createStep(h1, binary::updir());
if(d2 > d1) d++, h2 = createStep(h2, binary::updir());
2018-04-06 21:28:58 +00:00
}
}
2019-08-09 19:00:52 +00:00
EX int heptdistance(cell *c1, cell *c2) {
2019-02-17 17:28:20 +00:00
#if CAP_CRYSTAL
if(cryst) return crystal::space_distance(c1, c2);
2019-02-17 17:28:20 +00:00
#endif
2019-05-08 16:33:08 +00:00
if(!hyperbolic || quotient || WDIM == 3) return celldistance(c1, c2);
2018-04-06 21:28:58 +00:00
else return heptdistance(c1->master, c2->master);
}
map<pair<cell*, cell*>, int> saved_distances;
2018-04-10 05:59:48 +00:00
set<cell*> keep_distances_from;
set<cell*> dists_computed;
int perma_distances;
2019-08-09 19:00:52 +00:00
EX void compute_saved_distances(cell *c1, int max_range, int climit) {
celllister cl(c1, max_range, climit, NULL);
for(int i=0; i<isize(cl.lst); i++)
saved_distances[make_pair(c1, cl.lst[i])] = cl.dists[i];
}
2019-08-09 19:00:52 +00:00
EX void permanent_long_distances(cell *c1) {
keep_distances_from.insert(c1);
if(racing::on)
compute_saved_distances(c1, 300, 1000000);
else
compute_saved_distances(c1, 120, 200000);
}
2019-08-09 19:00:52 +00:00
EX void erase_saved_distances() {
saved_distances.clear(); dists_computed.clear();
for(auto c: keep_distances_from) compute_saved_distances(c, 120, 200000);
perma_distances = isize(saved_distances);
}
EX int max_saved_distance(cell *c) {
int maxsd = 0;
for(auto& p: saved_distances) if(p.first.first == c) maxsd = max(maxsd, p.second);
return maxsd;
}
2019-08-09 19:00:52 +00:00
EX cell *random_in_distance(cell *c, int d) {
vector<cell*> choices;
for(auto& p: saved_distances) if(p.first.first == c && p.second == d) choices.push_back(p.first.second);
println(hlog, "choices = ", isize(choices));
if(choices.empty()) return NULL;
return choices[hrand(isize(choices))];
}
2019-08-09 19:00:52 +00:00
EX int celldistance(cell *c1, cell *c2) {
2019-08-18 13:32:46 +00:00
if(prod) {
auto w1 = hybrid::get_where(c1), w2 = hybrid::get_where(c2);
int d;
hybrid::in_underlying_map([&] { d = celldistance(w1.first, w2.first) + abs(w1.second - w2.second); });
return d;
}
2017-03-23 10:53:57 +00:00
2019-02-17 17:33:15 +00:00
#if CAP_FIELD
if(geometry == gFieldQuotient && !GOLDBERG)
return currfp.getdist(fieldpattern::fieldval(c1), fieldpattern::fieldval(c2));
2019-02-17 17:33:15 +00:00
#endif
2018-11-30 14:26:50 +00:00
if(bounded) {
int limit = 6000;
if(asonov::in()) {
c2 = asonov::get_at(asonov::get_coord(c2->master) - asonov::get_coord(c1->master))->c7;
c1 = currentmap->gamestart();
limit = 100000000;
}
2018-04-10 05:59:48 +00:00
if(saved_distances.count(make_pair(c1,c2)))
return saved_distances[make_pair(c1,c2)];
celllister cl(c1, 100, limit, NULL);
2018-06-22 12:47:24 +00:00
for(int i=0; i<isize(cl.lst); i++)
2018-04-10 05:59:48 +00:00
saved_distances[make_pair(c1, cl.lst[i])] = cl.dists[i];
if(saved_distances.count(make_pair(c1,c2)))
return saved_distances[make_pair(c1,c2)];
return DISTANCE_UNKNOWN;
2018-04-10 05:59:48 +00:00
}
2019-02-17 17:28:20 +00:00
#if CAP_CRYSTAL
if(cryst) return crystal::precise_distance(c1, c2);
2019-02-17 17:28:20 +00:00
#endif
2019-11-27 00:01:20 +00:00
if(archimedean || quotient || solnih || (penrose && euclid) || experimental || sl2 || nil) {
2018-04-10 05:59:48 +00:00
if(saved_distances.count(make_pair(c1,c2)))
return saved_distances[make_pair(c1,c2)];
if(dists_computed.count(c1)) return DISTANCE_UNKNOWN;
2018-06-21 06:38:11 +00:00
if(isize(saved_distances) > perma_distances + 1000000) erase_saved_distances();
compute_saved_distances(c1, 64, 1000);
dists_computed.insert(c1);
if(saved_distances.count(make_pair(c1,c2)))
return saved_distances[make_pair(c1,c2)];
return DISTANCE_UNKNOWN;
2017-03-23 10:53:57 +00:00
}
2019-10-10 11:08:06 +00:00
if(S3 >= OINF) return inforder::celldistance(c1, c2);
2019-02-21 17:47:32 +00:00
#if CAP_BT && MAXMDIM >= 4
2019-05-08 16:33:08 +00:00
if(binarytiling && WDIM == 3)
return binary::celldistance3(c1, c2);
#endif
#if MAXMDIM >= 4
2019-11-27 00:01:20 +00:00
if(euclid && !penrose && !archimedean)
return euclid3::celldistance(c1, c2);
2019-03-02 23:43:31 +00:00
2019-05-08 16:33:08 +00:00
if(hyperbolic && WDIM == 3) return reg3::celldistance(c1, c2);
#endif
2019-02-24 21:12:32 +00:00
return hyperbolic_celldistance(c1, c2);
2016-08-26 09:58:03 +00:00
}
2019-08-09 19:00:52 +00:00
EX vector<cell*> build_shortest_path(cell *c1, cell *c2) {
2019-02-17 17:28:20 +00:00
#if CAP_CRYSTAL
if(cryst) return crystal::build_shortest_path(c1, c2);
2019-02-17 17:28:20 +00:00
#endif
2018-12-04 21:35:00 +00:00
vector<cell*> p;
if(euclid) {
2018-12-04 21:35:00 +00:00
p.push_back(c1);
hyperpoint h = tC0(calc_relative_matrix(c2, c1, C0));
2018-12-04 21:35:00 +00:00
cell *x = c1;
transmatrix T1 = rspintox(h);
2018-12-04 21:35:00 +00:00
int d = celldistance(c1, c2);
int steps = d * 10;
ld step = hdist0(h) / steps;
for(int i=0; i< steps; i++) {
T1 = T1 * xpush(step);
2019-11-14 18:33:55 +00:00
virtualRebase(x, T1);
println(hlog, "x = ", x, "p length = ", isize(p), " dist = ", hdist0(tC0(T1)), " dist from end = ", hdist(tC0(T1), tC0(calc_relative_matrix(c2, x, C0))));
while(x != p.back()) {
forCellCM(c, p.back())
if(celldistance(x, c) < celldistance(x, p.back())) {
p.push_back(c);
break;
}
}
2018-12-04 21:35:00 +00:00
}
if(isize(p) != d + 1)
println(hlog, "warning: path size ", isize(p), " should be ", d+1);
}
else if(c2 == currentmap->gamestart()) {
while(c1 != c2) {
p.push_back(c1);
forCellCM(c, c1) if(celldist(c) < celldist(c1)) { c1 = c; goto next1; }
throw hr_shortest_path_exception();
2018-12-04 21:35:00 +00:00
next1: ;
}
p.push_back(c1);
}
else if(c1 == currentmap->gamestart()) {
p = build_shortest_path(c2, c1);
reverse(p.begin(), p.end());
}
else {
while(c1 != c2) {
p.push_back(c1);
forCellCM(c, c1) if(celldistance(c, c2) < celldistance(c1, c2)) { c1 = c; goto next; }
throw hr_shortest_path_exception();
2018-12-04 21:35:00 +00:00
next: ;
}
p.push_back(c1);
}
return p;
}
2019-08-09 19:00:52 +00:00
EX void clearCellMemory() {
2018-06-22 12:47:24 +00:00
for(int i=0; i<isize(allmaps); i++)
if(allmaps[i])
delete allmaps[i];
allmaps.clear();
last_cleared = NULL;
2018-04-10 05:59:48 +00:00
saved_distances.clear();
dists_computed.clear();
keep_distances_from.clear(); perma_distances = 0;
pd_from = NULL;
gp::gp_adj.clear();
2017-03-23 10:53:57 +00:00
}
2017-07-10 18:47:38 +00:00
auto cellhooks = addHook(clearmemory, 500, clearCellMemory);
2017-03-23 10:53:57 +00:00
}