1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-10-31 19:36:16 +00:00

rulegen:: simpler branch testing

This commit is contained in:
Zeno Rogue 2021-08-17 17:04:17 +02:00
parent bc511cf37b
commit 47c6495652

View File

@ -745,6 +745,13 @@ EX set<tcell*> single_live_branch_close_to_root;
/** is what on the left side, or the right side, of to_what? */ /** is what on the left side, or the right side, of to_what? */
void treewalk(twalker& cw, int delta) {
int d = get_parent_dir(cw.at);
if(cw.spin == d || get_parent_dir(cw.cpeek()) == (cw+wstep).spin)
cw += wstep;
cw+=delta;
}
int get_side(twalker what) { int get_side(twalker what) {
twalker w = what; twalker w = what;
twalker tw = what + wstep; twalker tw = what + wstep;
@ -784,22 +791,16 @@ int get_side(twalker what) {
// failed to solve this in the simple way (ended at the root) -- go around the tree // failed to solve this in the simple way (ended at the root) -- go around the tree
twalker wl = what; twalker wl = what;
twalker wr = wl; twalker wr = wl;
auto go = [&] (twalker& cw, int delta) {
int d = get_parent_dir(cw.at);
if(cw.spin == d || get_parent_dir(cw.cpeek()) == (cw+wstep).spin)
cw += wstep;
cw+=delta;
};
auto to_what = what + wstep; auto to_what = what + wstep;
auto ws = what; go(ws, 0); if(ws == to_what) return 0; auto ws = what; treewalk(ws, 0); if(ws == to_what) return 0;
while(true) { while(true) {
steps++; if(steps > 1000000) { steps++; if(steps > 1000000) {
debuglist = {what, to_what, w, tw}; debuglist = {what, to_what, w, tw};
throw rulegen_failure("get_side freeze II"); throw rulegen_failure("get_side freeze II");
} }
go(wl, -1); treewalk(wl, -1);
go(wr, +1); treewalk(wr, +1);
if(wl == to_what) return +1; if(wl == to_what) return +1;
if(wr == to_what) return -1; if(wr == to_what) return -1;
} }
@ -1096,199 +1097,129 @@ void find_possible_parents() {
/* == branch testing == */ /* == branch testing == */
struct bad_tree : rulegen_retry { void verified_treewalk(twalker& cw, int delta) {
bad_tree() : rulegen_retry("bad tree") {} if((cw+wstep).spin == get_parent_dir(cw.peek())) {
}; }
}
struct branchdata { using tsinfo = pair<int, int>;
int id;
int dir;
twalker at;
int temporary;
void step() {
if(treestates[id].rules[dir] < 0)
throw rulegen_failure("invalid step");
id = treestates[id].rules[dir]; dir = 0; at += wstep;
auto co = get_code(at.at);
auto& d1 = co.first;
auto& id1 = co.second;
if(id != id1 || d1 != at.spin) {
important.push_back(at.at);
if(debugflags & DF_GEOM)
println(hlog, "expected ", id, " found ", id1, " at ", at);
important.push_back(at.at->cmove(get_parent_dir(at.at)));
throw bad_tree();
}
}
void spin(int i) {
at += i;
dir += i;
dir = gmod(dir, isize(treestates[id].rules));
}
};
inline void print(hstream& hs, const branchdata& bd) { print(hs, "[", bd.id,":",bd.dir, " ", bd.at, ":", bd.temporary, "]"); } tsinfo get_tsinfo(twalker tw) {
auto co = get_code(tw.at);
int spin;
if(co.first == -1) spin = tw.spin;
else spin = gmod(tw.spin - co.first, tw.at->type);
return {co.second, spin};
}
void advance(vector<branchdata>& bdata, branchdata at, int dir, bool start_forward, bool stack, int distlimit) { int get_rule(tsinfo s) {
if(start_forward) { return treestates[s.first].rules[s.second];
at.step();
at.spin(dir);
} }
else {
at.spin(dir); set<vector<tsinfo> > verified_branches;
}
vector<branchdata> b; void push_deadstack(vector<tsinfo>& hash, twalker w, tsinfo tsi, int dir) {
int steps = 0;
hash.push_back(tsi);
while(true) { while(true) {
steps++; if(steps == max_adv_steps) tsi.second += dir; w += dir;
throw rulegen_failure("max_adv_steps exceeded"); auto& ts = treestates[tsi.first];
auto& ts = treestates[at.id]; if(tsi.second == 0 || tsi.second == isize(ts.rules)) {
auto r = ts.rules[at.dir]; w += wstep;
if(ts.sub_status[at.dir]) { tsi = get_tsinfo(w);
at.temporary = 0; hash.push_back(tsi);
b.push_back(at);
b.push_back(at);
at.spin(dir);
}
else if(r < 0) {
at.temporary = 0;
b.push_back(at);
break;
}
else if(!treestates[r].is_live) {
advance(b, at, dir, true, false, distlimit);
if(b.back().dir == 0)
b.pop_back();
else
advance(b, at, -dir, true, true, distlimit);
at.spin(dir);
} }
else { else {
at.step(); int r = ts.rules[tsi.second];
if(at.at.at->dist < distlimit || !ts.is_live) at.spin(dir); if(r > 0 && treestates[r].is_live) return;
else {
at.temporary = dir;
b.push_back(at);
break;
}
}
}
if(stack) {
while(b.size()) { bdata.push_back(b.back()); b.pop_back(); }
}
else {
for(auto& bd: b) bdata.push_back(bd);
}
}
void verify_lr(branchdata bd, int dir) {
return;
if(dir) { bd.spin(dir); if(bd.dir == 0) bd.dir = bd.at.at->type; }
auto& r = treestates[bd.id].rules;
for(int i=0; i<isize(r); i++) {
int val = i < bd.dir ? DIR_LEFT : DIR_RIGHT;
int wrong = val ^ DIR_LEFT ^ DIR_RIGHT;
if(r[i] == wrong) {
debuglist = { bd.at };
throw rulegen_failure("assign_lr direction error");
} }
} }
} }
set<vector<int> > branch_hashes; void verified_treewalk(twalker& tw, int id, int dir) {
if(id >= 0) {
auto co = get_code(tw.cpeek());
if(co.second != id || co.first != (tw+wstep).spin) {
important.push_back(tw.at);
important.push_back(tw.cpeek());
if(debugflags & DF_GEOM)
println(hlog, "expected ", make_pair((tw+wstep).spin,id), " found ", co);
debuglist = {tw, tw+wstep};
throw rulegen_retry("verify_advance failed");
}
}
treewalk(tw, dir);
}
void examine_branch(int id, int left, int right) { void examine_branch(int id, int left, int right) {
auto rg = treestates[id].giver; auto rg = treestates[id].giver;
if(debugflags & DF_GEOM) if(debugflags & DF_GEOM)
println(hlog, "need to examine branches ", tie(left, right), " of ", id, " starting from ", rg); println(hlog, "need to examine branches ", tie(left, right), " of ", id, " starting from ", rg);
indenter ind(2); indenter ind(2);
vector<branchdata> bdata;
int dist_at = rg.at->dist;
do { auto wl = rg+left;
if(true) { auto wr = rg+left+1;
auto bl = branchdata{id, left, rg+left, dist_at+dlbonus};
bl.temporary = 0; vector<twalker> lstack, rstack;
if(treestates[id].rules[left] >= 0)
advance(bdata, bl, -1, true, true, dist_at+5);
else bdata.push_back(bl);
}
left++;
if(left == rg.at->type) left = 0;
if(true) {
auto br = branchdata{id, left, rg+left, dist_at+dlbonus};
br.temporary = 0;
if(treestates[id].rules[left] >= 0)
advance(bdata, br, +1, true, false, dist_at+5);
else bdata.push_back(br);
}
}
while(left != right);
int steps = 0; int steps = 0;
while(true) { while(true) {
steps++; steps++;
if(steps > max_examine_branch) {
if(steps == max_examine_branch) { debuglist = { rg+left, wl, wr };
debuglist = { rg };
throw rulegen_failure("max_examine_branch exceeded"); throw rulegen_failure("max_examine_branch exceeded");
} }
if(isize(bdata) > max_bdata) { auto tsl = get_tsinfo(wl);
debuglist = { rg }; auto tsr = get_tsinfo(wr);
throw rulegen_failure("max_bdata exceeded");
auto rl = get_rule(tsl);
auto rr = get_rule(tsr);
// println(hlog, "wl = ", wl, " -> ", wl+wstep, " R", rl, " wr = ", wr, " -> ", wr+wstep, " R", rr, " lstack = ", lstack, " rstack = ", rstack);
if(rl == DIR_RIGHT && rr == DIR_LEFT && lstack.empty() && rstack.empty()) {
vector<tsinfo> hash;
push_deadstack(hash, wl, tsl, -1);
hash.emplace_back(-1, -1);
push_deadstack(hash, wr, tsr, +1);
// println(hlog, "hash = ", hash);
if(verified_branches.count(hash)) return;
verified_branches.insert(hash);
verified_treewalk(wl, rl, -1);
verified_treewalk(wr, rr, +1);
} }
/* advance both */ else if(rl == DIR_RIGHT && !lstack.empty() && lstack.back() == wl+wstep) {
vector<branchdata> bdata2; lstack.pop_back();
int advcount = 0, eatcount = 0; verified_treewalk(wl, rl, -1);
for(int i=0; i<isize(bdata); i+=2) {
if(!bdata[i].temporary && !bdata[i+1].temporary && bdata[i].at + wstep == bdata[i+1].at && min(bdata[i].at.at->dist, bdata[i+1].at.at->dist) <= dist_at) {
println(hlog, "pairing ", bdata[i], " and ", bdata[i+1]);
advcount++;
if(bdata2.size() && !bdata2.back().temporary && bdata2.back().at == bdata[i].at) {
println(hlog, "eating ", bdata2.back(), " and ", bdata[i]);
verify_lr(bdata[i], 0);
eatcount++; bdata2.pop_back();
} }
else
advance(bdata2, bdata[i], -1, false, true, dist_at+dlbonus);
if(i+2 < isize(bdata) && !bdata[i+1].temporary && !bdata[i+2].temporary && bdata[i+1].at == bdata[i+2].at) {
println(hlog, "eating ", bdata[i+1], " and ", bdata[i+2]);
verify_lr(bdata[i+1], +1);
eatcount++; i += 2; bdata2.push_back(bdata[i+1]);
}
else
advance(bdata2, bdata[i+1], +1, false, false, dist_at+dlbonus);
}
else {
if(bdata[i].temporary && bdata[i].at.at->dist <= dist_at+dlbonus-2) {
advcount++;
advance(bdata2, bdata[i], bdata[i].temporary, false, bdata[i].temporary < 0, dist_at+dlbonus);
}
else bdata2.push_back(bdata[i]);
if(bdata[i+1].temporary && bdata[i+1].at.at->dist <= dist_at+3) { else if(rr == DIR_LEFT && !rstack.empty() && rstack.back() == wr+wstep) {
advcount++; rstack.pop_back();
advance(bdata2, bdata[i+1], bdata[i+1].temporary, false, bdata[i+1].temporary < 0, dist_at+dlbonus); verified_treewalk(wr, rr, +1);
} }
else bdata2.push_back(bdata[i+1]);
else if(rl == DIR_LEFT) {
lstack.push_back(wl);
verified_treewalk(wl, rl, -1);
} }
else if(rr == DIR_RIGHT) {
rstack.push_back(wr);
verified_treewalk(wr, rr, +1);
} }
bdata = bdata2;
if(!advcount) dist_at++; else if(rl != DIR_RIGHT)
if(advcount) { verified_treewalk(wl, rl, -1);
vector<int> hash;
for(int i=0; i<isize(bdata); i++) { else if(rr != DIR_RIGHT)
hash.push_back(bdata[i].id); verified_treewalk(wr, rr, +1);
hash.push_back(bdata[i].dir);
hash.push_back(bdata[i].temporary); else throw rulegen_failure("cannot advance while examining");
hash.push_back(bdata[i].at.at->dist - dist_at);
}
if(branch_hashes.count(hash)) {
return;
}
branch_hashes.insert(hash);
}
} }
} }
@ -1407,7 +1338,7 @@ void rules_iteration() {
// print_rules(); // print_rules();
handle_distance_errors(); handle_distance_errors();
branch_hashes.clear(); verified_branches.clear();
int q = isize(single_live_branch_close_to_root); int q = isize(single_live_branch_close_to_root);