mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-24 01:00:25 +00:00
rulegen:: flags to test variants of the algorithm
This commit is contained in:
parent
3654ca58aa
commit
6db8f857e1
189
rulegen.cpp
189
rulegen.cpp
@ -52,6 +52,28 @@ EX int hard_parents = 0;
|
||||
EX int single_live_branches = 0;
|
||||
/** the number of roots with double live branches */
|
||||
EX int double_live_branches = 0;
|
||||
/** the number of treestates pre-minimization */
|
||||
EX int states_premini = 0;
|
||||
|
||||
/** change some flags -- they usually make it worse */
|
||||
static const flagtype w_numerical = Flag(1); /*< build trees numerically (to be implemented) */
|
||||
static const flagtype w_single_shortcut = Flag(2); /*< generate just one shortcut */
|
||||
static const flagtype w_no_shortcut = Flag(3); /*< generate no shortcuts */
|
||||
static const flagtype w_no_restart = Flag(4); /*< do not restart at powers of two */
|
||||
static const flagtype w_no_sidecache = Flag(5); /*< do not cache get_side */
|
||||
static const flagtype w_no_relative_distance = Flag(6); /*< do not build relative distances into codes */
|
||||
static const flagtype w_examine_once = Flag(7); /*< restart after first conflict found in analysis */
|
||||
static const flagtype w_examine_all = Flag(8); /*< focus on all conflicts found in analysis even if we know them */
|
||||
static const flagtype w_conflict_all = Flag(9); /*< full extension in case of conflicts */
|
||||
static const flagtype w_parent_always = Flag(10); /*< always consider the full parent rule */
|
||||
static const flagtype w_parent_reverse = Flag(11); /*< reverse paths in parent_dir */
|
||||
static const flagtype w_parent_side = Flag(12); /*< allow side paths in parent_dir */
|
||||
static const flagtype w_parent_never = Flag(13); /*< never consider the full parent rule */
|
||||
static const flagtype w_always_clean = Flag(14); /*< restart following phases after any distance errors */
|
||||
static const flagtype w_single_origin = Flag(15); /*< consider only one origin */
|
||||
static const flagtype w_slow_side = Flag(16); /*< do not try get_side optimization */
|
||||
|
||||
EX flagtype flags = 0;
|
||||
|
||||
#if HDR
|
||||
struct tcell* tmove(tcell *c, int d);
|
||||
@ -372,6 +394,9 @@ 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) {
|
||||
|
||||
if(flags & w_no_shortcut) return;
|
||||
|
||||
ufindc(c);
|
||||
if(debugflags & DF_GEOM)
|
||||
println(hlog, "solid ", c, " changes ", c->dist, " to ", d, " alt=", alt);
|
||||
@ -412,6 +437,7 @@ EX void find_new_shortcuts(tcell *c, int d, tcell *alt, int delta) {
|
||||
walkerdir2.push_back(s);
|
||||
if(seen.count(w1.peek())) {
|
||||
shortcut_found(c, alt, walkers, walkers2, walkerdir, walkerdir2);
|
||||
if(flags & w_single_shortcut) return;
|
||||
/* we do not want to go further */
|
||||
for(auto& w: walkers) ufind(w);
|
||||
for(auto& w: walkers2) ufind(w);
|
||||
@ -484,6 +510,7 @@ EX void handle_distance_errors() {
|
||||
solid_errors = 0;
|
||||
if(b && !no_errors) {
|
||||
sidecache.clear();
|
||||
if(flags & w_always_clean) clean_data();
|
||||
throw hr_solid_error();
|
||||
}
|
||||
}
|
||||
@ -559,17 +586,19 @@ EX void look_for_shortcuts(tcell *c) {
|
||||
look_for_shortcuts(c, *shortcuts[c->id][i]);
|
||||
}
|
||||
|
||||
EX bool try_to_resolve_confusion = true;
|
||||
|
||||
void trace_root_path(vector<int>& rp, twalker cw) {
|
||||
auto d = cw.peek()->dist;
|
||||
cw += wstep;
|
||||
|
||||
bool side = (flags & w_parent_side);
|
||||
|
||||
next:
|
||||
if(d > 0) {
|
||||
ufind(cw);
|
||||
handle_distance_errors();
|
||||
int di = side ? -1 : get_parent_dir(cw.at);
|
||||
for(int i=0; i<cw.at->type; i++) {
|
||||
if((!side) && (cw+i).spin != di) continue;
|
||||
tcell *c1 = (cw+i).peek();
|
||||
if(!c1) continue;
|
||||
be_solid(c1);
|
||||
@ -583,6 +612,7 @@ void trace_root_path(vector<int>& rp, twalker cw) {
|
||||
}
|
||||
}
|
||||
rp.push_back(cw.to_spin(0));
|
||||
if(flags & w_parent_reverse) reverse(rp.begin(), rp.end());
|
||||
}
|
||||
|
||||
/** which neighbor will become the parent of c */
|
||||
@ -624,6 +654,9 @@ EX int get_parent_dir(tcell *c) {
|
||||
return get_parent_dir(c);
|
||||
}
|
||||
|
||||
bool failed = false;
|
||||
if(flags & w_parent_always) {failed = true; goto resolve; }
|
||||
|
||||
// celebrity identification problem
|
||||
|
||||
for(auto ne: nearer)
|
||||
@ -633,28 +666,31 @@ EX int get_parent_dir(tcell *c) {
|
||||
if(parent_debug) for(auto ne: nearer) println(hlog, "beats", tie(ne, bestd), " = ", beats(ne, bestd));
|
||||
|
||||
for(auto ne: nearer)
|
||||
if(ne != bestd && beats(ne, bestd)) {
|
||||
if(ne != bestd && beats(ne, bestd))
|
||||
failed = true;
|
||||
|
||||
if(try_to_resolve_confusion) {
|
||||
hard_parents++;
|
||||
vector<int> best;
|
||||
int bestfor = ne;
|
||||
trace_root_path(best, twalker(c, ne));
|
||||
|
||||
for(auto ne1: nearer) {
|
||||
vector<int> other;
|
||||
trace_root_path(other, twalker(c, ne1));
|
||||
if(other < best) best = other, bestfor = ne1;
|
||||
}
|
||||
|
||||
bestd = bestfor;
|
||||
break;
|
||||
}
|
||||
if(failed) {
|
||||
|
||||
if(flags & w_parent_never) {
|
||||
debuglist = { c };
|
||||
throw rulegen_failure("still confused");
|
||||
}
|
||||
|
||||
resolve:
|
||||
hard_parents++;
|
||||
vector<int> best;
|
||||
int bestfor = nearer[0];
|
||||
trace_root_path(best, twalker(c, nearer[0]));
|
||||
|
||||
for(auto ne1: nearer) {
|
||||
vector<int> other;
|
||||
trace_root_path(other, twalker(c, ne1));
|
||||
if(other < best) best = other, bestfor = ne1;
|
||||
}
|
||||
|
||||
bestd = bestfor;
|
||||
}
|
||||
|
||||
if(bestd == -1) {
|
||||
throw rulegen_failure("should not happen");
|
||||
}
|
||||
@ -809,51 +845,62 @@ void treewalk(twalker& cw, int delta) {
|
||||
EX std::map<twalker, int> sidecache;
|
||||
|
||||
int get_side(twalker what) {
|
||||
auto ww = at_or_null(sidecache, what);
|
||||
if(ww) return *ww;
|
||||
twalker w = what;
|
||||
twalker tw = what + wstep;
|
||||
auto adv = [] (twalker& cw) {
|
||||
int d = get_parent_dir(cw.at);
|
||||
ufind(cw);
|
||||
if(cw.at->move(d)->dist >= cw.at->dist) {
|
||||
handle_distance_errors();
|
||||
if(debugflags & DF_GEOM)
|
||||
println(hlog, "get_parent_dir error at ", cw, " and ", cw.at->move(d), ": ", cw.at->dist, "::", cw.at->move(d)->dist);
|
||||
throw rulegen_failure("get_parent_dir error");
|
||||
}
|
||||
cw.spin = d;
|
||||
cw += wstep;
|
||||
};
|
||||
int steps = 0;
|
||||
while(w.at != tw.at) {
|
||||
steps++; if(steps > max_getside) {
|
||||
debuglist = {what, w, tw};
|
||||
throw rulegen_failure("qsidefreeze");
|
||||
}
|
||||
ufind(w); ufind(tw);
|
||||
if(w.at->dist > tw.at->dist)
|
||||
adv(w);
|
||||
else if(w.at->dist < tw.at->dist)
|
||||
adv(tw);
|
||||
else {
|
||||
adv(w); adv(tw);
|
||||
}
|
||||
}
|
||||
int d = get_parent_dir(w.at);
|
||||
|
||||
if(d >= 0 && !single_live_branch_close_to_root.count(w.at)) {
|
||||
twalker last(w.at, d);
|
||||
return sidecache[what] = last.to_spin(w.spin) - last.to_spin(tw.spin);
|
||||
bool side = !(flags & w_no_sidecache);
|
||||
bool fast = !(flags & w_slow_side);
|
||||
|
||||
if(side) {
|
||||
auto ww = at_or_null(sidecache, what);
|
||||
if(ww) return *ww;
|
||||
}
|
||||
|
||||
int res = 99;
|
||||
int steps = 0;
|
||||
|
||||
if(fast) {
|
||||
twalker w = what;
|
||||
twalker tw = what + wstep;
|
||||
auto adv = [] (twalker& cw) {
|
||||
int d = get_parent_dir(cw.at);
|
||||
ufind(cw);
|
||||
if(cw.at->move(d)->dist >= cw.at->dist) {
|
||||
handle_distance_errors();
|
||||
if(debugflags & DF_GEOM)
|
||||
println(hlog, "get_parent_dir error at ", cw, " and ", cw.at->move(d), ": ", cw.at->dist, "::", cw.at->move(d)->dist);
|
||||
throw rulegen_failure("get_parent_dir error");
|
||||
}
|
||||
cw.spin = d;
|
||||
cw += wstep;
|
||||
};
|
||||
while(w.at != tw.at) {
|
||||
steps++; if(steps > max_getside) {
|
||||
debuglist = {what, w, tw};
|
||||
throw rulegen_failure("qsidefreeze");
|
||||
}
|
||||
ufind(w); ufind(tw);
|
||||
if(w.at->dist > tw.at->dist)
|
||||
adv(w);
|
||||
else if(w.at->dist < tw.at->dist)
|
||||
adv(tw);
|
||||
else {
|
||||
adv(w); adv(tw);
|
||||
}
|
||||
}
|
||||
int d = get_parent_dir(w.at);
|
||||
|
||||
if(d >= 0 && !single_live_branch_close_to_root.count(w.at)) {
|
||||
twalker last(w.at, d);
|
||||
res = last.to_spin(w.spin) - last.to_spin(tw.spin);
|
||||
}
|
||||
}
|
||||
|
||||
// failed to solve this in the simple way (ended at the root) -- go around the tree
|
||||
twalker wl = what;
|
||||
twalker wr = wl;
|
||||
auto to_what = what + wstep;
|
||||
auto ws = what; treewalk(ws, 0); if(ws == to_what) return 0;
|
||||
auto ws = what; treewalk(ws, 0); if(ws == to_what) res = 0;
|
||||
|
||||
while(true) {
|
||||
while(res == 99) {
|
||||
handle_distance_errors();
|
||||
steps++; if(steps > max_getside) {
|
||||
debuglist = {what, to_what, wl, wr};
|
||||
@ -863,13 +910,16 @@ int get_side(twalker what) {
|
||||
bool gr = wl.at->dist >= wr.at->dist;
|
||||
if(gl) {
|
||||
treewalk(wl, -1);
|
||||
if(wl == to_what) return sidecache[what] = +1;
|
||||
if(wl == to_what) { res = 1; }
|
||||
}
|
||||
if(gr) {
|
||||
treewalk(wr, +1);
|
||||
if(wr == to_what) return sidecache[what] = -1;
|
||||
if(wr == to_what) {res = -1; }
|
||||
}
|
||||
}
|
||||
|
||||
if(side) sidecache[what] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
code_t id_at_spin(twalker cw) {
|
||||
@ -899,7 +949,9 @@ code_t id_at_spin(twalker cw) {
|
||||
ufind(cs); ufind(cs2); be_solid(cs2.at);
|
||||
fix_distances(cs.at);
|
||||
int y = cs.at->dist - cs.peek()->dist;
|
||||
if(y == 1) x = C_NEPHEW;
|
||||
|
||||
if(!(flags & w_no_relative_distance)) x = C_EQUAL;
|
||||
else if(y == 1) x = C_NEPHEW;
|
||||
else if(y == 0) x = C_EQUAL;
|
||||
else if(y == -1) x = C_UNCLE;
|
||||
else throw rulegen_failure("distance problem y=" + its(y) + lalign(0, " cs=", cs, " cs2=", cs2, " peek=", cs.peek(), " dist=", cs.at->dist, " dist2=", cs2.at->dist));
|
||||
@ -1063,7 +1115,9 @@ void rules_iteration_for(tcell *c) {
|
||||
|
||||
extend_analyzer(cwmain, z, k, mismatches, treestates[id].giver);
|
||||
mismatches++;
|
||||
throw rulegen_retry("mismatch error");
|
||||
|
||||
if(!(flags & w_conflict_all))
|
||||
throw rulegen_retry("mismatch error");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1220,7 +1274,8 @@ void verified_treewalk(twalker& tw, int id, int dir) {
|
||||
auto co = get_code(tw.cpeek());
|
||||
if(co.second != id || co.first != (tw+wstep).spin) {
|
||||
handle_distance_errors();
|
||||
if(!treestates[co.second].known) {
|
||||
|
||||
if(!treestates[co.second].known || (flags & w_examine_all)) {
|
||||
treestates[co.second].known = true;
|
||||
important.push_back(tw.at);
|
||||
if(debugflags & DF_GEOM)
|
||||
@ -1307,7 +1362,9 @@ void examine_branch(int id, int left, int right) {
|
||||
else throw rulegen_failure("cannot advance while examining");
|
||||
}
|
||||
}
|
||||
catch(verify_advance_failed&) { }
|
||||
catch(verify_advance_failed&) {
|
||||
if(flags & w_examine_once) throw rulegen_retry("advance failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* == main algorithm == */
|
||||
@ -1355,7 +1412,7 @@ EX void clean_parents() {
|
||||
EX void rules_iteration() {
|
||||
try_count++;
|
||||
|
||||
if((try_count & (try_count-1)) == 0) {
|
||||
if((try_count & (try_count-1)) == 0) if(!(flags & w_no_restart)) {
|
||||
clean_data();
|
||||
}
|
||||
|
||||
@ -1515,7 +1572,13 @@ EX void generate_rules() {
|
||||
hard_parents = single_live_branches = double_live_branches = 0;
|
||||
|
||||
t_origin.clear();
|
||||
for(auto& ts: arb::current.shapes) {
|
||||
|
||||
if(flags & w_single_origin) {
|
||||
tcell *c = gen_tcell(0);
|
||||
c->dist = 0;
|
||||
t_origin.push_back(c);
|
||||
}
|
||||
else for(auto& ts: arb::current.shapes) {
|
||||
tcell *c = gen_tcell(ts.id);
|
||||
c->dist = 0;
|
||||
t_origin.push_back(c);
|
||||
|
Loading…
Reference in New Issue
Block a user