diff --git a/geometry2.cpp b/geometry2.cpp index 34fb854c..840732a6 100644 --- a/geometry2.cpp +++ b/geometry2.cpp @@ -808,5 +808,172 @@ int brm_hook = addHook(hooks_clearmemory, 0, []() { brm_structure.clear(); }); +EX bool exhaustive_distance_appropriate() { + if(euclid && (kite::in() || arcm::in() || arb::in() || quotient)) return true; + #if MAXMDIM >= 4 + if(nil && quotient) return true; + #endif + #if CAP_SOLV + if(asonov::in() && asonov::period_xy && asonov::period_xy <= 256) return true; + #endif + + if(bounded) return true; + + return false; + } + +#if HDR +struct pathgen { + cellwalker start; + vector path; + bignum full_id_0; + int last_id; + }; +#endif + +EX pathgen generate_random_path_randomdir(cellwalker start, int length, bool for_yendor) { + start.spin = hrand(start.at->type); + return generate_random_path(start, length, for_yendor); + } + +EX pathgen generate_random_path(cellwalker start, int length, bool for_yendor) { + pathgen p; + p.start = start; + p.path.resize(length+1); + p.path[0] = start.at; + p.last_id = 0; + + int turns = 0; + + if(exhaustive_distance_appropriate()) { + permanent_long_distances(start.at); + int dist = max_saved_distance(start.at); + dist = min(dist, length); + auto at = random_in_distance(start.at, dist); + permanent_long_distances(at); + for(int a=length-1; a>=0; a--) { + p.path[a+1] = at; + vector prev; + forCellCM(c2, at) if(celldistance(start.at, c2) == a) prev.push_back(c2); + if(isize(prev)) at = prev[hrand(isize(prev))]; + } + p.path[0] = start.at; + } + + else if(hybri) { + /* I am lazy */ + for(int i=1; i<=length; i++) p.path[i] = p.path[i-1]->cmove(p.path[i-1]->type-1); + } + + else { + int t = -1; + bignum full_id; + bool onlychild = true; + + cellwalker ycw = start; + ycw--; if(S3 == 3) ycw--; + if(for_yendor) setdist(p.path[0], 7, NULL); + + for(int i=0; i ds; + for(int d=0; dtype; d++) { + bool increase; + if(sol) + increase = i < YDIST / 4 || i > 3 * YDIST / 4; + else + increase = i < YDIST/2; + if(increase) { + if(celldistAlt((ycw+d).cpeek()) < celldistAlt(ycw.at)) + ds.push_back(d); + } + else { + if(celldistAlt((ycw+d).cpeek()) > celldistAlt(ycw.at) && (ycw+d).cpeek() != p.path[i-1]) + ds.push_back(d); + } + } + if(isize(ds)) ycw += ds[hrand(isize(ds))]; + } + + else if(trees_known()) { + if(i == 0) { + t = type_in(expansion, start.at, [start] (cell *c) { return celldistance(start.at, c); }); + bignum b = expansion.get_descendants(length, t); + p.full_id_0 = full_id = hrand(b); + } + + #if DEBUG_YENDORGEN + printf("#%3d t%d %s / %s\n", i, t, full_id.get_str(100).c_str(), expansion.get_descendants(length-i, t).get_str(100).c_str()); + for(int tch: expansion.children[t]) { + printf(" t%d %s\n", tch, expansion.get_descendants(length-i-1, t).get_str(100).c_str()); + } + #endif + + if(i == 1) + onlychild = true; + if(!onlychild) ycw++; + if(valence() == 3) ycw++; + + onlychild = false; + + for(int tch: expansion.children[t]) { + ycw++; + if(i == 1) + tch = type_in(expansion, ycw.cpeek(), [start] (cell *c) { return celldistance(start.at, c); }); + auto& sub_id = expansion.get_descendants(length-1-i, tch); + if(full_id < sub_id) { t = tch; break; } + + full_id.addmul(sub_id, -1); + onlychild = true; + } + } + + else if(WDIM == 3) { + int d = celldistance(p.path[0], ycw.at); + vector next; + forCellCM(c, ycw.at) if(celldistance(p.path[0], c) > d) next.push_back(c); + if(!isize(next)) { + printf("error: no more cells"); + ycw.at = ycw.at->move(hrand(ycw.at->type)); + } + else { + ycw.at = next[hrand(isize(next))]; + } + p.path[i+1] = ycw.at; + } + + else { + // stupid + ycw += rev; + // well, make it a bit more clever on bitruncated a4 grids + if(a4 && BITRUNCATED && S7 <= 5) { + if(ycw.at->type == 8 && ycw.cpeek()->type != 8) + ycw++; + if(hrand(100) < 10) { + if(euclid ? (turns&1) : (hrand(100) < 50)) + ycw+=2; + else + ycw-=2; + turns++; + } + } + } + + if(for_yendor) while(p.last_id < i && (p.path[p.last_id]->land == laMirror || inmirror(p.path[p.last_id]))) { + p.last_id++; + setdist(p.path[p.last_id], 7, nullptr); + } + + if(for_yendor && inmirror(ycw.at)) ycw = mirror::reflect(ycw); + ycw += wstep; + p.path[i+1] = ycw.at; + } + } + return p; + } } diff --git a/pattern2.cpp b/pattern2.cpp index a5707aab..d7c51112 100644 --- a/pattern2.cpp +++ b/pattern2.cpp @@ -1818,7 +1818,7 @@ EX namespace patterns { } case 'P': { cell *s = currentmap->gamestart()->move(0); - if(yendor::exhaustive_distance_appropriate() && !keep_distances_from.count(s)) + if(exhaustive_distance_appropriate() && !keep_distances_from.count(s)) permanent_long_distances(s); int d = celldistance(s, c); color_t res = distcolors[d]; diff --git a/racing.cpp b/racing.cpp index 43dcb029..6f3546ab 100644 --- a/racing.cpp +++ b/racing.cpp @@ -458,7 +458,7 @@ EX void generate_track() { makeEmpty(s); cview(); // needed for some virtualRebases - use_exhaustive_distance = yendor::exhaustive_distance_appropriate(); + use_exhaustive_distance = exhaustive_distance_appropriate(); if(use_exhaustive_distance) permanent_long_distances(s); diff --git a/yendor.cpp b/yendor.cpp index 2fb7220a..1b89dc4a 100644 --- a/yendor.cpp +++ b/yendor.cpp @@ -140,7 +140,7 @@ EX namespace yendor { EX yendorlevel& clev() { return levels[challenge]; } - eLand changeland(int i, eLand l) { + EX eLand changeland(int i, eLand l) { if(l == laIvoryTower) return laNone; if((clev().flags & YF_START_ANY) && i < 20 && l != clev().l) return clev().l; if((clev().flags & YF_END) && i > 80 && l == clev().l) return laIce; @@ -195,20 +195,46 @@ EX namespace yendor { return ysUntouched; } - EX bool exhaustive_distance_appropriate() { - if(euclid && (kite::in() || arcm::in() || arb::in() || quotient)) return true; - #if MAXMDIM >= 4 - if(nil && quotient) return true; - #endif - #if CAP_SOLV - if(asonov::in() && asonov::period_xy && asonov::period_xy <= 256) return true; - #endif - - if(bounded) return true; - + EX bool control(pathgen& p, int i, cellwalker& ycw) { + + // change lands in the Challenge + if(i > BARLEV-6) { + p.last_id = i+7-BARLEV; + setdist(p.path[p.last_id], 7, p.path[i+6-BARLEV]); + if(yendor::challenge && !euclid && ycw.at->land != laIvoryTower) { + eLand ycl = yendor::changeland(i, ycw.at->land); + if(ycl) { + if(weirdhyperbolic) { + buildBarrierNowall(ycw.at, ycl); + } + else if(hyperbolic && ishept(ycw.at)) { + int bd = 2 + hrand(2) * 3; + buildBarrier(ycw.at, bd, ycl); + if(ycw.at->bardir != NODIR && ycw.at->bardir != NOBARRIERS) + extendBarrier(ycw.at); + } + } + } + } + + // follow the branch in Yendorian + if(ycw.at->land == laEndorian) { + int bestval = -2000; + int best = 0, qbest = 0; + for(int d=0; dtype; d++) { + setdist(ycw.at, 7, ycw.peek()); + cell *c1 = (ycw+d).cpeek(); + int val = d * (ycw.at->type - d); + if(c1->wall == waTrunk) val += (i < YDIST-20 ? 1000 : -1000); + if(val > bestval) qbest = 0, bestval = val; + if(val == bestval) if(hrand(++qbest) == 0) best = d; + } + ycw += best; + return true; + } return false; } - + EX bool check(cell *yendor) { int byi = isize(yi); for(int i=0; i=0; a--) { - nyi.path[a+1] = at; - vector prev; - forCellCM(c2, at) if(celldistance(yendor, c2) == a) prev.push_back(c2); - if(isize(prev)) at = prev[hrand(isize(prev))]; - } - nyi.path[0] = yendor; - } - - else if(hybri) { - /* I am lazy */ - for(int i=1; i<=YDIST-1; i++) nyi.path[i] = nyi.path[i-1]->cmove(nyi.path[i-1]->type-1); - } - - else { - int t = -1; - bignum full_id; - bool onlychild = true; - - cellwalker ycw(yendor, odir = hrand(yendor->type)); - ycw--; if(S3 == 3) ycw--; - setdist(nyi.path[0], 7, NULL); - - int last_id = 0; - - for(int i=0; i BARLEV-6) { - last_id = i+7-BARLEV; - setdist(nyi.path[last_id], 7, nyi.path[i+6-BARLEV]); - if(challenge && !euclid && ycw.at->land != laIvoryTower) { - eLand ycl = changeland(i, ycw.at->land); - if(ycl) { - if(weirdhyperbolic) { - buildBarrierNowall(ycw.at, ycl); - } - else if(hyperbolic && ishept(ycw.at)) { - int bd = 2 + hrand(2) * 3; - buildBarrier(ycw.at, bd, ycl); - if(ycw.at->bardir != NODIR && ycw.at->bardir != NOBARRIERS) - extendBarrier(ycw.at); - } - } - } - } - - if(ycw.at->land == laEndorian) { - // follow the branch in Yendorian - int bestval = -2000; - int best = 0, qbest = 0; - for(int d=0; dtype; d++) { - setdist(ycw.at, 7, ycw.peek()); - cell *c1 = (ycw+d).cpeek(); - int val = d * (ycw.at->type - d); - if(c1->wall == waTrunk) val += (i < YDIST-20 ? 1000 : -1000); - if(val > bestval) qbest = 0, bestval = val; - if(val == bestval) if(hrand(++qbest) == 0) best = d; - } - ycw += best; - } - - else if(bt::in()) { - // make it challenging - vector ds; - for(int d=0; dtype; d++) { - bool increase; - if(sol) - increase = i < YDIST / 4 || i > 3 * YDIST / 4; - else - increase = i < YDIST/2; - if(increase) { - if(celldistAlt((ycw+d).cpeek()) < celldistAlt(ycw.at)) - ds.push_back(d); - } - else { - if(celldistAlt((ycw+d).cpeek()) > celldistAlt(ycw.at) && (ycw+d).cpeek() != nyi.path[i-1]) - ds.push_back(d); - } - } - if(isize(ds)) ycw += ds[hrand(isize(ds))]; - } - - else if(trees_known()) { - if(i == 0) { - t = type_in(expansion, yendor, [yendor] (cell *c) { return celldistance(yendor, c); }); - bignum b = expansion.get_descendants(YDIST-1, t); - full_id_0 = full_id = hrand(b); - } - - #if DEBUG_YENDORGEN - printf("#%3d t%d %s / %s\n", i, t, full_id.get_str(100).c_str(), expansion.get_descendants(YDIST-1-i, t).get_str(100).c_str()); - for(int tch: expansion.children[t]) { - printf(" t%d %s\n", tch, expansion.get_descendants(YDIST-2-i, t).get_str(100).c_str()); - } - #endif - - if(i == 1) - onlychild = true; - if(!onlychild) ycw++; - if(valence() == 3) ycw++; - - onlychild = false; - - for(int tch: expansion.children[t]) { - ycw++; - if(i == 1) - tch = type_in(expansion, ycw.cpeek(), [yendor] (cell *c) { return celldistance(yendor, c); }); - auto& sub_id = expansion.get_descendants(YDIST-i-2, tch); - if(full_id < sub_id) { t = tch; break; } - - full_id.addmul(sub_id, -1); - onlychild = true; - } - } - - else if(WDIM == 3) { - int d = celldistance(nyi.path[0], ycw.at); - vector next; - forCellCM(c, ycw.at) if(celldistance(nyi.path[0], c) > d) next.push_back(c); - if(!isize(next)) { - printf("error: no more cells"); - ycw.at = ycw.at->move(hrand(ycw.at->type)); - } - else { - ycw.at = next[hrand(isize(next))]; - } - nyi.path[i+1] = ycw.at; - } - - else { - // stupid - ycw += rev; - // well, make it a bit more clever on bitruncated a4 grids - if(a4 && BITRUNCATED && S7 <= 5) { - if(ycw.at->type == 8 && ycw.cpeek()->type != 8) - ycw++; - if(hrand(100) < 10) { - if(euclid ? (turns&1) : (hrand(100) < 50)) - ycw+=2; - else - ycw-=2; - turns++; - } - } - } - - while(last_id < i && (nyi.path[last_id]->land == laMirror || inmirror(nyi.path[last_id]))) { - last_id++; - setdist(nyi.path[last_id], 7, nullptr); - } - - if(inmirror(ycw.at)) ycw = mirror::reflect(ycw); - ycw += wstep; - nyi.path[i+1] = ycw.at; - } - } - nyi.found = false; nyi.foundOrb = false; @@ -405,7 +264,7 @@ EX namespace yendor { setdist(nyi.path[YDIST-1], 7, nyi.path[YDIST-2]); cell *key = nyi.path[YDIST-1]; - generating = false; + yendor::generating = false; for(int b=10; b>=5; b--) setdist(key, b, nyi.path[YDIST-2]); @@ -464,10 +323,10 @@ EX namespace yendor { maxage *= 10; nyi.age = maxage - hrand(maxage/2); - bignum full_id = full_id_0 - nyi.age; + bignum full_id = p.full_id_0 - nyi.age; bool onlychild = true; - cellwalker ycw(yendor, odir); + cellwalker ycw = p.start; ycw--; if(S3 == 3) ycw--; for(int i=0; iitem = itRuby; split_found = true; setdist(ycw.at, 6, NULL); @@ -501,7 +360,7 @@ EX namespace yendor { } full_id.addmul(sub_id, -1); - if(!split_found) full_id_0.addmul(sub_id, -1); + if(!split_found) p.full_id_0.addmul(sub_id, -1); onlychild = true; }