1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2025-07-05 19:22:48 +00:00

rulegen:: improved shortcut generation

This commit is contained in:
Zeno Rogue 2021-08-24 03:36:50 +02:00
parent 4d127e824a
commit 25c636c54a

View File

@ -96,6 +96,8 @@ struct tcell {
short code; short code;
/** direction to the parent in the tree */ /** direction to the parent in the tree */
short parent_dir; short parent_dir;
/** direction to anyone closer */
short any_nearer;
/** can we assume that dist is correct? if we assumed that the dist is correct but then find out it was wrong, throw an error */ /** can we assume that dist is correct? if we assumed that the dist is correct but then find out it was wrong, throw an error */
bool is_solid; bool is_solid;
bool distance_fixed; bool distance_fixed;
@ -296,6 +298,7 @@ EX void unify(twalker pw1, twalker pw2) {
} }
pw2.at->unified_to = pw1 - pw2.spin; pw2.at->unified_to = pw1 - pw2.spin;
tunified++; tunified++;
fix_distances(pw1.at);
} }
EX vector<tcell*> t_origin; EX vector<tcell*> t_origin;
@ -352,46 +355,26 @@ vector<int> root_path(twalker cw) {
} }
} }
EX void shortcut_found(tcell *c, tcell *alt, const vector<twalker> &walkers, const vector<twalker> &walkers2, const vector<int>& walkerdir, const vector<int>& walkerdir2) { EX void shortcut_found(tcell *c, tcell *alt, vector<twalker> &walkers, vector<twalker> &walkers2, const vector<int>& walkerdir, const vector<int>& walkerdir2, int wpos) {
auto at0 = walkers2.back().at;
tcell* at = at0;
twalker at1; at1.at = nullptr;
for(int i=isize(walkers)-1; i>=1; i--) if(at == walkers[i].at) at1 = walkers[i];
if(!at1.at) return; /* made obsolete by unification */
vector<int> pre; vector<int> pre;
for(int i=isize(walkers)-1; i>=1; i--) if(at == walkers[i].at) { for(int i=wpos; i>=1; i--) pre.push_back(walkerdir[i]);
pre.push_back(walkerdir[i]); at = walkers[i].peek();
}
if(at != c) {
if(parent_debug) println(hlog, "did not return to c");
return;
}
at = at0;
vector<int> post;
for(int i=isize(walkers2)-1; i>=1; i--) if(at == walkers2[i].at) {
post.push_back(walkerdir2[i]); at = walkers2[i].peek();
}
if(at != alt) {
if(parent_debug) println(hlog, "did not return to alt");
return;
}
reverse(pre.begin(), pre.end()); reverse(pre.begin(), pre.end());
vector<int> post;
for(int i=isize(walkers2)-1; i>=1; i--) post.push_back(walkerdir2[i]);
reverse(post.begin(), post.end()); reverse(post.begin(), post.end());
int delta = at1.to_spin(walkers2.back().spin); int delta = walkers[wpos].to_spin(walkers2.back().spin);
for(auto& s: shortcuts[c->id]) if(s->pre == pre && s->post == post) { for(auto& s: shortcuts[c->id]) if(s->pre == pre && s->post == post) {
if(parent_debug) println(hlog, "already knew that ", pre, " ~ ", post); if(parent_debug)
println(hlog, "already knew that ", pre, " ~ ", post);
return; return;
} }
if(debugflags & DF_GEOM) if(debugflags & DF_GEOM)
println(hlog, "new shortcut found, pre = ", pre, " post = ", post, " pre reaches ", at1, " post reaches ", walkers2.back(), " of type ", at1.at->id, " sample = ", c); println(hlog, "new shortcut found, pre = ", pre, " post = ", post, " pre reaches ", walkers[wpos], " post reaches ", walkers2.back(), " of type ", walkers[wpos].at->id, " sample = ", c);
if(isize(pre) > 500) { if(isize(pre) > 500) {
debuglist = { c }; debuglist = { c };
@ -415,7 +398,7 @@ EX void shortcut_found(tcell *c, tcell *alt, const vector<twalker> &walkers, con
} }
} }
EX void find_new_shortcuts(tcell *c, int d, tcell *alt, int delta) { EX void find_new_shortcuts(tcell *c, int d, tcell *alt, int newdir, int delta) {
debuglist.push_back(c); debuglist.push_back(c);
solid_errors++; solid_errors++;
@ -425,49 +408,57 @@ EX void find_new_shortcuts(tcell *c, int d, tcell *alt, int delta) {
ufindc(c); ufindc(c);
if(debugflags & DF_GEOM) if(debugflags & DF_GEOM)
println(hlog, "solid ", c, " changes ", c->dist, " to ", d, " alt=", alt); println(hlog, "solid ", c, " changes ", c->dist, " to ", d, " alt=", alt);
if(newdir == c->any_nearer) return;
/* {
throw rulegen_failure("direction did not change");
} */
if(c->dist == MYSTERY) if(c->dist == MYSTERY)
throw rulegen_failure("find_new_shortcuts with MYSTERY distance"); throw rulegen_failure("find_new_shortcuts with MYSTERY distance");
set<tcell*> seen;
map<tcell*, int> seen;
vector<twalker> walkers; vector<twalker> walkers;
vector<int> walkerdir = {-1}; vector<int> walkerdir = {-1};
seen.insert(c); seen[c] = 0;
walkers.push_back(c); walkers.push_back(c);
for(int j=0; j<isize(walkers); j++) { for(int j=0; j<isize(walkers); j++) {
auto w = walkers[j]; auto w = walkers[j];
if(w.at->dist == 0) break;
for(int s=0; s<w.at->type; s++) { for(int s=0; s<w.at->type; s++) {
twalker w1 = w + s; twalker w1 = w + s;
if(w1.peek() && w1.peek()->dist == w.at->dist - 1 && !seen.count(w1.peek())) { if(w1.peek() && w1.spin == w.at->any_nearer && !seen.count(w1.peek())) {
seen.insert(w1.peek()); seen[w1.peek()] = isize(walkers);
walkers.push_back(w1 + wstep); walkers.push_back(w1 + wstep);
walkerdir.push_back(s); walkerdir.push_back(s);
} }
} }
} }
set<tcell*> seen2; /* prevent loops */
c->dist = d; c->dist = d;
set<tcell*> seen2; c->any_nearer = gmod(newdir, c->type);
fix_distances(c);
vector<twalker> walkers2; vector<twalker> walkers2;
vector<int> walkerdir2 = {-1}; vector<int> walkerdir2 = {-1};
walkers2.push_back(twalker(alt, delta)); walkers2.push_back(twalker(alt, delta));
for(int j=0; j<isize(walkers2); j++) { for(int j=0; j<isize(walkers2); j++) {
auto w = walkers2[j]; auto w = walkers2[j];
if(j == 0 || !seen.count(w.at)) if(w.at->dist == 0) return;
for(int s=0; s<w.at->type; s++) { for(int s=0; s<w.at->type; s++) {
twalker w1 = w + s; twalker w1 = w + s;
ufind(w1);
if(w1.spin != w.at->any_nearer) continue;
if(!w1.peek()) continue; if(!w1.peek()) continue;
if(w1.peek()->dist == w.at->dist - 1 && !seen2.count(w1.peek())) { if(seen2.count(w1.peek())) break;
seen2.insert(w1.peek()); seen2.insert(w1.peek());
if(true) {
walkers2.push_back(w1 + wstep); walkers2.push_back(w1 + wstep);
walkerdir2.push_back(s); walkerdir2.push_back(s);
if(seen.count(w1.peek())) { if(seen.count(w1.peek())) {
shortcut_found(c, alt, walkers, walkers2, walkerdir, walkerdir2); shortcut_found(c, alt, walkers, walkers2, walkerdir, walkerdir2, seen[w1.peek()]);
if(flags & w_single_shortcut) return; return;
/* we do not want to go further */
for(auto& w: walkers) ufind(w);
for(auto& w: walkers2) ufind(w);
seen.clear(); for(auto& w: walkers) seen.insert(w.at);
seen2.clear(); for(auto& w: walkers2) seen2.insert(w.at);
} }
} }
} }
@ -486,7 +477,7 @@ EX void remove_parentdir(tcell *c) {
queue<tcell*> bfs_queue; queue<tcell*> bfs_queue;
void fix_distances(tcell *c) { EX void fix_distances(tcell *c) {
if(flags & w_bfs) while(true) { if(flags & w_bfs) while(true) {
ufindc(c); ufindc(c);
if(c->dist != MYSTERY) return; if(c->dist != MYSTERY) return;
@ -516,12 +507,14 @@ void fix_distances(tcell *c) {
ufindc(c); ufindc(c);
c1 = c->cmove(i); c1 = c->cmove(i);
auto& d1 = c1->dist; auto& d1 = c1->dist;
if(d > d1+1) { d = d1+1; remove_parentdir(c); goto restart; } if(d > d1+1) { d = d1+1; c->any_nearer = i; remove_parentdir(c); goto restart; }
if(d1 > d+1) { if(d1 > d+1) {
int i1 = c->c.spin(i);
if(c1->is_solid) { if(c1->is_solid) {
find_new_shortcuts(c1, d+1, c1, 0); find_new_shortcuts(c1, d+1, c1, i1, 0);
} }
d1 = d+1; d1 = d+1;
c1->any_nearer = i1;
remove_parentdir(c1); remove_parentdir(c1);
q.push_back(c1); q.push_back(c1);
} }
@ -538,10 +531,10 @@ EX void unify_distances(tcell *c1, tcell *c2, int delta) {
int d1 = c1->dist; int d1 = c1->dist;
int d2 = c2->dist; int d2 = c2->dist;
int d = min(d1, d2); int d = min(d1, d2);
if(c1->is_solid && d != d1) { solid_errors++; find_new_shortcuts(c1, d, c2, delta); remove_parentdir(c1); } if(c1->is_solid && d != d1) { solid_errors++; find_new_shortcuts(c1, d, c2, c2->any_nearer - delta, +delta); remove_parentdir(c1); }
if(d != d1) fix_distances(c1); if(d != d1) fix_distances(c1);
c1->dist = d; c1->dist = d;
if(c2->is_solid && d != d2) { solid_errors++; find_new_shortcuts(c2, d, c1, -delta); remove_parentdir(c2); } if(c2->is_solid && d != d2) { solid_errors++; find_new_shortcuts(c2, d, c1, c1->any_nearer + delta, -delta); remove_parentdir(c2); }
if(d != d2) fix_distances(c2); if(d != d2) fix_distances(c2);
c2->dist = d; c2->dist = d;
c1->distance_fixed = c2->distance_fixed = c1->distance_fixed || c2->distance_fixed; c1->distance_fixed = c2->distance_fixed = c1->distance_fixed || c2->distance_fixed;
@ -665,7 +658,6 @@ EX int get_parent_dir(tcell *c) {
int bestd = -1; int bestd = -1;
vector<int> bestrootpath; vector<int> bestrootpath;
look_for_shortcuts(c);
be_solid(c); be_solid(c);
if(c->dist > 0) { if(c->dist > 0) {