diff --git a/bigstuff.cpp b/bigstuff.cpp index 21e4d358..e4ed236f 100644 --- a/bigstuff.cpp +++ b/bigstuff.cpp @@ -1268,7 +1268,7 @@ void moreBigStuff(cell *c) { } if(d == 1) { // roughly as many knights as table cells - if(hrand(PURE ? 2618 : 1720) < 1000) + if(hrand(1000000) < 1000000 / expansion.get_growth()) c->monst = moKnight; if(!eubinary) for(int i=0; imaster->move(i)); for(int i=0; itype; i++) diff --git a/compileunits.h b/compileunits.h index 5ff4f942..7ce4dbb0 100644 --- a/compileunits.h +++ b/compileunits.h @@ -33,6 +33,7 @@ #include "archimedean.cpp" #include "language.cpp" #include "cell.cpp" +#include "expansion.cpp" #include "goldberg.cpp" #include "irregular.cpp" #include "pattern2.cpp" diff --git a/game.cpp b/game.cpp index c3d8e6a5..9be9a607 100644 --- a/game.cpp +++ b/game.cpp @@ -6931,44 +6931,6 @@ void roundTableMessage(cell *c2) { } } -long long circlesize[100], disksize[100]; -ld circlesizeD[10000]; -int lastsize; - -bool sizes_known() { - return euclid || (geometry == gNormal && STDVAR); - } - -void computeSizes() { - lastsize = PURE ? 44 : 76; - - circlesize[0] = 1; - - if(euclid) { - for(int i=1; i<100; i++) circlesize[i] = 6 * i; - } - - else if(BITRUNCATED) { - circlesize[1] = 1*7; - circlesize[2] = 2*7; - circlesize[3] = 4*7; - circlesize[4] = 7*7; - for(int i=5; i<100; i++) - circlesize[i] = circlesize[i-1] + circlesize[i-2] + circlesize[i-3] - circlesize[i-4]; - } - else { - // actually these are each second Fibonacci number - circlesize[1] = 1*7; - circlesize[2] = 3*7; - for(int i=3; i<100; i++) - circlesize[i] = 3*circlesize[i-1] - circlesize[i-2]; - } - - disksize[0] = 0; - for(int i=1; i<100; i++) - disksize[i] = disksize[i-1] + circlesize[i-1]; - } - void knightFlavorMessage(cell *c2) { if(!euclid && !c2->master->alt) { @@ -6981,8 +6943,6 @@ void knightFlavorMessage(cell *c2) { return; } - computeSizes(); - bool grailfound = grailWasFound(c2); int rad = roundTableRadius(c2); bool tooeasy = (rad < newRoundTableRadius()); @@ -7016,14 +6976,11 @@ void knightFlavorMessage(cell *c2) { else if(msgid == 7 && items[itSpice] < 10 && !peace::on) { addMessage(XLAT("\"Train in the Desert first!\"")); } - else if(msgid == 8 && sizes_known()) { - if(rad <= lastsize) - addMessage(XLAT("\"Our Table seats %1 Knights!\"", llts(circlesize[rad]))); - else - addMessage(XLAT("\"By now, you should have your own formula, you know?\"")); + else if(msgid == 8 && sizes_known() && !tactic::on) { + addMessage(XLAT("\"Our Table seats %1 Knights!\"", expansion.get_descendants(rad).get_str(100))); } - else if(msgid == 9 && rad <= lastsize && sizes_known()) { - addMessage(XLAT("\"There are %1 floor tiles inside our Table!\"", llts(disksize[rad]))); + else if(msgid == 9 && sizes_known() && !tactic::on) { + addMessage(XLAT("\"There are %1 floor tiles inside our Table!\"", expansion.get_descendants(rad-1, expansion.diskid).get_str(100))); } else if(msgid == 10 && !items[itPirate] && !items[itWhirlpool] && !peace::on) { addMessage(XLAT("\"Have you tried to take a boat and go into the Ocean? Try it!\"")); diff --git a/hud.cpp b/hud.cpp index 2a5ba4ef..e569d198 100644 --- a/hud.cpp +++ b/hud.cpp @@ -346,46 +346,8 @@ bool nofps = false; void drawStats() { if(nohud || stereo::mode == stereo::sLR) return; if(callhandlers(false, hooks_prestats)) return; - if(viewdists && sidescreen) { - distcolors[0] = forecolor; - dialog::init(""); - int qty[64]; - vector& ac = currentmap->allcells(); - for(int i=0; i<64; i++) qty[i] = 0; - for(int i=0; i= 0 && d < 64) qty[d]++; - } - - if(geometry == gNormal && BITRUNCATED) - for(int i=8; i<=15; i++) - qty[i] = qty[i-1] + qty[i-2] + qty[i-3] - qty[i-4]; - - if(geometry == gNormal && PURE) - for(int i=6; i<=15; i++) - qty[i] = 3*qty[i-1] - qty[i-2]; - - if(geometry == gEuclid) - for(int i=8; i<=15; i++) qty[i] = 6*i; - for(int i=0; i<64; i++) if(qty[i]) - dialog::addInfo(its(qty[i]), distcolors[i&7]); - - if(geometry == gNormal && BITRUNCATED) { - dialog::addBreak(200); - dialog::addHelp("a(d+4) = a(d+3) + a(d+2) + a(d+1) - a(d)"); - dialog::addInfo("a(d) ~ 1.72208ᵈ", forecolor); - } - if(geometry == gNormal && PURE) { - dialog::addBreak(200); - dialog::addHelp("a(d+2) = 3a(d+1) - a(d+2)"); - dialog::addInfo("a(d) ~ 2.61803ᵈ", forecolor); - } - if(geometry == gEuclid) { - dialog::addBreak(300); - dialog::addInfo("a(d) = 6d", forecolor); - } - dialog::display(); - } + if(viewdists && sidescreen) + expansion.view_distances_dialog(); if(sidescreen) return; { diff --git a/hyper.h b/hyper.h index ab1629fc..add99374 100644 --- a/hyper.h +++ b/hyper.h @@ -4106,5 +4106,69 @@ namespace anims { extern int animation_lcm; extern ld animation_factor; ld parseld(const string& s); +pair vec_to_pair(int vec); + +struct bignum { + static const int BASE = 1000000000; + static const long long BASE2 = BASE * (long long)BASE; + vector digits; + bignum() {} + bignum(int i) : digits() { digits.push_back(i); } + void be(int i) { digits.resize(1); digits[0] = i; } + bignum& operator +=(const bignum& b); + string get_str(int max_length); + ld approx() { + if(digits.empty()) return 0; + return digits.back() * pow(BASE, isize(digits) - 1); + } + + int approx_int() { + if(isize(digits) > 1) return BASE; + if(digits.empty()) return 0; + return digits[0]; + } + + long long approx_ll() { + if(isize(digits) > 2) return BASE2; + if(digits.empty()) return 0; + if(isize(digits) == 1) return digits[0]; + return digits[0] + digits[1] * (long long) BASE; + } + }; + +struct expansion_analyzer { + vector gettype(cell *c); + int N; + vector samples; + map, int> codeid; + vector > children; + int rootid, diskid; + int coefficients_known; + vector coef; + int valid_from, tested_to; + ld growth; + + int sample_id(cell *c); + void preliminary_grouping(); + void reduce_grouping(); + vector> descendants; + bignum& get_descendants(int level); + bignum& get_descendants(int level, int type); + void find_coefficients(); + void reset(); + + expansion_analyzer() { reset(); } + + string approximate_descendants(int d, int max_length); + void view_distances_dialog(); + ld get_growth(); + + private: + bool verify(int id); + int valid(int v, int step); + }; + +extern expansion_analyzer expansion; + } diff --git a/quit.cpp b/quit.cpp index 71d72e67..ee65061e 100644 --- a/quit.cpp +++ b/quit.cpp @@ -31,25 +31,6 @@ void noaction() {} function cancel = noaction; -string circlesizestr(int r) { - computeSizes(); - string s; - int last = lastsize; - if(r <= last) - return llts(circlesize[r]); - else { - double d = log(circlesize[last]) + (log(circlesize[last]) - log(circlesize[last-1]))*(r-last); - int dlost = 0; - while(d > 10 * log(10)) d -= log(10), dlost++; - char buf[300]; sprintf(buf, "%.0f", exp(d)); - string ss = XLAT("about ") + buf; - while(dlost % 9) dlost--, ss += '0'; - for(int r = 0; r < 50 && dlost; r++) dlost -= 9, ss += " 000000000"; - if(dlost) ss += XLAT(" (%1 more digits)", its(dlost)); - return ss; - } - } - hint hints[] = { { @@ -246,13 +227,13 @@ hint hints[] = { 0, []() { return !canmove && sizes_known() && celldist(cwt.at) >= 50; }, []() { - int c = celldist(cwt.at); - string s = circlesizestr(c); + int d = celldist(cwt.at); + string s = expansion.approximate_descendants(d, 10000); dialog::addHelp(XLAT( "You are %1 cells away from the starting point, or " "the place where you used an Orb of Safety last time. " "There are %2 such cells.\n", - its(c), s + its(d), s )); dialog::addBreak(50); dialog::addItem(XLAT("expansion"), 'z'); diff --git a/system.cpp b/system.cpp index 44d1cba8..7dd9ef29 100644 --- a/system.cpp +++ b/system.cpp @@ -1267,6 +1267,7 @@ void start_game() { game_active = true; if(need_reset_geometry) resetGeometry(), need_reset_geometry = false; initcells(); + expansion.reset(); if(randomPatternsMode) { for(int i=0; i