/* some extra routines for debugging and testing the rulegen algorithm */ #include "../hyper.h" #include namespace hr { namespace rulegen { string testroot = "devmods/rulegen-tests/"; string testdir = testroot; struct hrmap_testproto : hrmap { map counterpart; map counterpart2; heptagon* clone(tcell *o) { auto& h = counterpart2[o]; if(!h) { h = tailored_alloc (o->type); counterpart[h] = o; h->zebraval = 0; h->emeraldval = 0; h->distance = 0; h->cdata = nullptr; h->c7 = newCell(o->type, h); } return h; } ~hrmap_testproto() { println(hlog, "clearing ", isize(counterpart), " heptagons from testproto"); for(auto p: counterpart) { auto& at = p.first; if(at->cdata) delete at->cdata; destroy_cell(at->c7); tailored_delete(at); } } heptagon *getOrigin() override { return clone(t_origin[0]); } heptagon *create_step(heptagon *h, int d) override { auto ch = counterpart[h]; if(!ch->move(d)) { h->c.connect(d, &oob, 0, false); h->c7->c.connect(d, &out_of_bounds, 0, false); out_of_bounds.master = &oob; oob.c7 = &out_of_bounds; return &oob; } auto ch1 = ch->cmove(d); auto d1 = ch->c.spin(d); auto h1 = clone(ch1); if(ch == ch1) throw rulegen_failure("connected to self??"); if(h == h1) throw rulegen_failure("connected to self on hept level??"); h->c.connect(d, h1, d1, false); return h1; } void find_cell_connection(cell *c, int d) { heptagon *h2 = createStep(c->master, d); if(h2 == &oob) return; c->c.connect(d, h2->c7,c->master->c.spin(d), c->master->c.mirror(d)); } transmatrix adj(heptagon *h, int dir) override { return arb::get_adj(arb::current_or_slided(), shvid(h->c7), dir, -1, h->c.move(dir) ? h->c.spin(dir) : -1); } int shvid(cell *c) override { if(!counterpart.count(c->master)) { /* may happen while handling floorshapes */ return arb::id_of(c->master); } auto cc = counterpart[c->master]; return cc->id; } bool strict_tree_rules() { return true; } }; reaction_t clear_debug = [] {}; map sprawl_shown; void view_debug() { auto m = dynamic_cast (currentmap); if(m) { int ah = addHook(hooks_drawcell, 50, [m] (cell *c, const shiftmatrix& V) { tcell *tc = m->counterpart[c->master]; string s; auto label = (tc->code == MYSTERY ? "?" : its(tc->code)) + "/" + (tc->dist == MYSTERY ? "?" : its(tc->dist)); color_t col = 0xFFFFFF + 0x512960 * tc->code; if(pointer_indices.count(tc)) label += " " + index_pointer(tc); queuestr(V, 0.4, label, col, 1); if(tc->parent_dir >= 0 && tc->parent_dir < tc->type) { vid.linewidth *= 8; queueline(V * C0, V * currentmap->adj(c, tc->parent_dir) * C0, 0xFFFFFFFF); vid.linewidth /= 8; } if(sprawl_shown.count(tc)) queuepoly(V, cgi.shDisk, 0xFF0000FF); return false; }); vector dh; dh.push_back(addHook(hooks_o_key, 15, [m] (o_funcs& v) { v.push_back(named_functionality("sprawl", [m] { tcell *c = m->counterpart[centerover->master]; auto [d, id] = get_code(c); twalker cw(c, d); auto res = spread(get_analyzer(cw), cw); println(hlog, "sprawl result = ", res); sprawl_shown.clear(); for(int i=0; iclone(dw.at)->c7, dw.spin, dw.mirrored); centerover = cwt.at; View = Id; })); })); clear_debug = [ah, dh] { delHook(hooks_drawcell, ah); for(auto dhk: dh) delHook(hooks_o_key, dhk); clear_debug = [] {}; }; } else if(currentmap->strict_tree_rules()) { int ah = addHook(hooks_drawcell, 50, [] (cell *c, const shiftmatrix& V) { string s; int id = get_state(c); auto label = its(id); color_t col = 0xFFFFFF + 0x512960 * id; if(pointer_indices.count(c->master)) label += " " + index_pointer(c->master); queuestr(V, 0.3, label, col, 1); vid.linewidth *= 8; queueline(V * C0, V * currentmap->adj(c, 0) * C0, 0xFFFFFFFF, 4); vid.linewidth /= 8; return false; }); clear_debug = [ah] { delHook(hooks_drawcell, ah); }; } } int test_rotate_val = 0; int test_count = 10000; void test_rules() { cell *c = currentmap->gamestart(); int N = isize(treestates); if(!N) { println(hlog, "no states generated"); return; } vector howmany(N); howmany[0] = 1; celllister cl(c, 100, test_count, nullptr); vector bydist(64, 0); for(cell *cc: cl.lst) { int d = cl.getdist(cc); if(d < 64) bydist[d]++; } vector vals; vector seq; for(int iter=0; iter<30; iter++) { bignum total; for(auto& h: howmany) total += h; seq.push_back(total.get_str(100)); println(hlog, iter, " : ", total.get_str(100), " vs ", bydist[iter]); if(bydist[iter] && bydist[iter] != total.approx_ll()) println(hlog, "ERROR count mismatch"); vector next(N); for(int id=0; id= 0) next[s] += howmany[id]; howmany = std::move(next); } println(hlog, "sequence: ", seq); } void list_sequence() { int N = isize(treestates); if(!N) { println(hlog, "no states generated"); return; } vector howmany(N); howmany[0] = 1; vector seq; for(int iter=0; iter<30; iter++) { bignum total; for(auto& h: howmany) total += h; seq.push_back(total.get_str(100)); vector next(N); for(int id=0; id= 0) next[s] += howmany[id]; howmany = std::move(next); } println(hlog, "sequence: ", seq); } void print_rules(); string rule_name(int r) { if(r == DIR_UNKNOWN) return "??"; else if(r == DIR_MULTI_GO_LEFT) return "ML"; else if(r == DIR_MULTI_GO_RIGHT) return "MR"; else if(r == DIR_LEFT) return "L"; else if(r == DIR_RIGHT) return "R"; else if(r == DIR_PARENT) return "P"; else return its(r); } void print_rules() { for(int i=0; iis_solid) qsolid++; if(c->code != MYSTERY) qcode++; if(c->dist != MYSTERY) qdist++; c = c->next; } println(hlog, "after rulegen: tcellcount = ", tcellcount, "-", tunified, " qsolid = ", qsolid, " qdist = ", qdist, " qcode = ", qcode, " radius = ", prepare_around_radius, " try_count = ", try_count, " ticks = ", tstart); println(hlog, "CSV;", euclid ? "E" : hyperbolic ? "H" : "?", ";", status, ";", tcellcount, ";", tunified, ";", qsolid, ";", qdist, ";", qcode, ";", prepare_around_radius, ";", try_count, ";", tstart, ";", isize(treestates), ";", arb::current.filename); fflush(stdout); print_rules(); /* for(auto& a: analyzers) println(hlog, "analyzer ", a.first, " size is ", isize(a.second.spread)); */ fflush(stdout); list_sequence(); fflush(stdout); } void out_reg() { println(hlog, "X ", int(geometry), " ", int(variation), " ", int(gp::param.first), " ", int(gp::param.second)); } void test_all_regular(vector glist) { for(eGeometry g: glist) { set_geometry(g); set_variation(eVariation::pure); out_reg(); set_geometry(g); set_variation(eVariation::bitruncated); out_reg(); for(int a=1; a<5; a++) for(int b=0; b<=a; b++) { if(a==1 && b == 0) continue; if(a==1 && b == 1 && S3 == 3) continue; stop_game(); set_geometry(g); gp::param = {a, b}; set_variation(eVariation::goldberg); out_reg(); if(S3 == 4 && (geometry == g46 || ((a+b)%2 == 0))) { stop_game(); set_variation(eVariation::unrectified); out_reg(); } if(S3 == 3 && (geometry == gOctagon || (a-b)%3 == 0)) { stop_game(); set_variation(eVariation::untruncated); out_reg(); stop_game(); set_variation(eVariation::warped); out_reg(); } } } } void set_dir(string s) { testdir = testroot + s; system(("mkdir -p " + testdir).c_str()); } void test_from_file(string list) { set_dir("devmods/rulegen-tests/" + list); vector filenames; std::ifstream is("devmods/rulegen-tests/" + list + ".lst"); string s; while(getline(is, s)) { if(s != "") filenames.push_back(s); } int trv = test_rotate_val; int id = 0; for(const string& s: filenames) { if(trv) { trv--; id++; continue; } stop_game(); set_geometry(gArbitrary); try { println(hlog, "loading ", s, "... ", id++, "/", isize(filenames)); arb::load(s); } catch(hr_parse_exception& ex) { println(hlog, "failed: ", ex.s); continue; } catch(arb::hr_polygon_error& ex) { println(hlog, "poly error"); continue; } catch(hr_exception& ex) { println(hlog, "other exception"); continue; } if(cgflags & qAFFINE) { println(hlog, "illgeal tessellation found: affine"); continue; } if(sphere) { println(hlog, "illgeal tessellation found: spherical"); continue; } test_current(); } } void test_all_geoms(int i) { if(i&1) { set_dir("regular/"); test_all_regular({gNormal, gOctagon, g45, g46, g47, gEuclid, gEuclidSquare}); } } int testargs() { using namespace arg; if(0) ; else if(argis("-testproto")) { restart_game_on(new hrmap_testproto); println(hlog, "creatad a testproto map with ", tcellcount, " cells"); } else if(argis("-test-this")) { PHASEFROM(3); try { test_current(); } catch(rulegen_failure& e) { } } else if(argis("-test-list")) { PHASEFROM(3); shift(); test_from_file(args()); } else if(argis("-test-all")) { PHASEFROM(3); shift(); test_all_geoms(argi()); start_game(); } else if(argis("-trv")) { shift(); test_rotate_val = argi(); } else if(argis("-view-debug")) view_debug(); else if(argis("-clear-debug")) clear_debug(); else return 1; return 0; } auto testhooks = addHook(hooks_args, 100, testargs); } }