crystal:: computing Round Table sizes (not tested)

This commit is contained in:
Zeno Rogue 2018-12-03 12:38:11 +01:00
parent c4fae9dfef
commit 79e396c742
3 changed files with 168 additions and 18 deletions

View File

@ -281,7 +281,7 @@ coord add(coord c, int cname, int val) {
return c;
}
ld hypot2(crystal_structure& cs, ldcoord co1, ldcoord co2) {
ld sqhypot2(crystal_structure& cs, ldcoord co1, ldcoord co2) {
int result = 0;
for(int a=0; a<cs.dim; a++) result += (co1[a] - co2[a]) * (co1[a] - co2[a]);
return result;
@ -307,6 +307,8 @@ struct hrmap_crystal : hrmap {
unordered_map<cell*, unordered_map<cell*, int>> distmemo;
map<cell*, ldcoord> sgc;
cell *camelot_center;
ldcoord camelot_coord;
ld camelot_mul;
crystal_structure cs;
east_structure east;
@ -321,6 +323,7 @@ struct hrmap_crystal : hrmap {
hrmap_crystal() {
cs.build();
camelot_center = NULL;
}
~hrmap_crystal() {
@ -536,7 +539,12 @@ ld space_distance(cell *c1, cell *c2) {
auto m = crystal_map();
ldcoord co1 = m->get_coord(c1);
ldcoord co2 = m->get_coord(c2);
return sqrt(hypot2(m->cs, co1, co2));
return sqrt(sqhypot2(m->cs, co1, co2));
}
ld space_distance_camelot(cell *c) {
auto m = crystal_map();
return m->camelot_mul * sqrt(sqhypot2(m->cs, m->get_coord(c), m->camelot_coord));
}
int dist_relative(cell *c) {
@ -549,18 +557,23 @@ int dist_relative(cell *c) {
cc = start;
while(precise_distance(cc, start) < r + 5)
cc = cc->cmove(hrand(cc->type));
m->camelot_coord = m->get_coord(m->camelot_center);
if(m->cs.dir % 2)
m->camelot_coord[m->cs.dim-1] = 2;
m->camelot_mul = 1;
m->camelot_mul *= (r+5) / space_distance_camelot(start);
}
if(pure())
return precise_distance(c, cc) - r;
ld sdmul = (r+5) / space_distance(cc, start);
ld dis = space_distance(cc, c) * sdmul;
println(hlog, "dis = ", dis);
ld dis = space_distance_camelot(c);
if(dis < r)
return int(dis) - r;
else {
forCellCM(c1, c) if(space_distance(cc, c1) * sdmul < r)
forCellCM(c1, c) if(space_distance_camelot(c1) < r)
return 0;
return int(dis) + 1 - r;
}
@ -663,7 +676,7 @@ int dist_alt(cell *c) {
if(pure())
return precise_distance(c, m->camelot_center);
if(c == m->camelot_center) return 0;
return 1 + int(4 * space_distance(m->camelot_center, c));
return 1 + int(2 * space_distance_camelot(c));
}
else {
m->prepare_east();
@ -877,6 +890,110 @@ void show() {
auto crystalhook = addHook(hooks_args, 100, readArgs)
+ addHook(hooks_drawcell, 100, crystal_cell);
map<pair<int, int>, bignum> volume_memo;
bignum& compute_volume(int dim, int rad) {
auto p = make_pair(dim, rad);
int is = volume_memo.count(p);
auto& m = volume_memo[p];
if(is) return m;
if(dim == 0) { m = 1; return m; }
m = compute_volume(dim-1, rad);
for(int r=0; r<rad; r++)
m.addmul(compute_volume(dim-1, r), 2);
return m;
}
// shift_data_zero.children[x1].children[x2]....children[xk].result[r2]
// is the number of grid points in distance at most sqrt(r2) from (x1,x2,...,xk)
struct eps_comparer {
bool operator() (ld a, ld b) const { return a < b-1e-6; }
};
struct shift_data {
shift_data *parent;
ld shift;
map<ld, shift_data, eps_comparer> children;
map<ld, bignum, eps_comparer> result;
shift_data() { parent = NULL; }
bignum& compute(ld rad2) {
if(result.count(rad2)) return result[rad2];
// println(hlog, "compute ", format("%p", this), " [shift=", shift, "], r2 = ", rad2);
// indenter i(2);
auto& b = result[rad2];
if(!parent) {
if(rad2 >= 0) b = 1;
}
else if(rad2 >= 0) {
for(int x = -2-sqrt(rad2); x <= sqrt(rad2)+2; x++) {
ld ax = x - shift;
if(ax*ax <= rad2)
b.addmul(parent->compute(rad2 - (ax*ax)), 1);
}
}
// println(hlog, "result = ", b.get_str(100));
return b;
}
};
shift_data shift_data_zero;
string get_table_volume() {
if(!pure()) {
auto m = crystal_map();
m->prepare_east();
bignum res;
manual_celllister cl;
cl.add(m->gamestart());
ld rad2 = pow(roundTableRadius(NULL) / m->camelot_mul / 4, 2) + 1e-4;
for(int i=0; i<isize(cl.lst); i++) {
cell *c = cl.lst[i];
ld mincoord = 9, maxcoord = -9;
auto co = m->get_coord(c);
for(int i=0; i<m->cs.dim; i++) {
if(co[i] < mincoord) mincoord = co[i];
if(co[i] > maxcoord) maxcoord = co[i];
}
static const ld eps = 1e-4;
if(mincoord >= 0-eps && maxcoord < 4-eps) {
auto cshift = (co - m->camelot_coord) / 4;
auto sd = &shift_data_zero;
for(int i=0; i<m->cs.dim; i++) {
ld val = cshift[i] - floor(cshift[i]);
if(!sd->children.count(val)) {
sd->children[val].parent = sd;
sd->children[val].shift = val;
}
sd = &sd->children[val];
}
res.addmul(sd->compute(rad2), 1);
}
if(mincoord < -2 || maxcoord > 6) continue;
forCellCM(c2, c) cl.add(c2);
}
return res.get_str(100);
}
int s = ginf[gCrystal].sides;
int r = roundTableRadius(NULL);
if(s % 2 == 0)
return compute_volume(s/2, r-1).get_str(100);
else
return (compute_volume(s/2, r-1) + compute_volume(s/2, r-2)).get_str(100);
}
string get_table_boundary() {
if(!pure()) return "";
int r = roundTableRadius(NULL);
int s = ginf[gCrystal].sides;
if(s % 2 == 0)
return (compute_volume(s/2, r) - compute_volume(s/2, r-1)).get_str(100);
else
return (compute_volume(s/2, r) - compute_volume(s/2, r-2)).get_str(100);
}
}
}

View File

@ -6936,6 +6936,15 @@ void roundTableMessage(cell *c2) {
}
}
bool in_full_game() {
if(chaosmode) return true;
if(geometry == gEuclid && isCrossroads(specialland)) return true;
if(weirdhyperbolic && specialland == laCrossroads4) return true;
if(geometry == gCrystal && specialland == laCrossroads) return true;
if(geometry == gNormal && !NONSTDVAR) return true;
return false;
}
void knightFlavorMessage(cell *c2) {
if(!eubinary && !c2->master->alt) {
@ -6966,37 +6975,55 @@ void knightFlavorMessage(cell *c2) {
else if(msgid == 2 && !tooeasy) {
addMessage(XLAT("\"The Holy Grail is in the center of the Round Table.\""));
}
else if(msgid == 3 && !peace::on) {
else if(msgid == 3 && geometry == gCrystal) {
if(crystal::pure())
addMessage(XLAT("\"Each piece of the Round Table is exactly %1 steps away from the Holy Grail.\"", its(roundTableRadius(c2))));
else
addMessage(XLAT("\"According to Merlin, the Round Table is a perfect Euclidean sphere in %1 dimensions.\"", its(ginf[gCrystal].sides/2)));
}
else if(msgid == 3 && !peace::on && in_full_game()) {
addMessage(XLAT("\"I enjoy watching the hyperbug battles.\""));
}
else if(msgid == 4) {
else if(msgid == 4 && in_full_game()) {
addMessage(XLAT("\"Have you visited a temple in R'Lyeh?\""));
}
else if(msgid == 5) {
else if(msgid == 5 && in_full_game()) {
addMessage(XLAT("\"Nice castle, eh?\""));
}
else if(msgid == 6 && items[itSpice] < 10 && !peace::on) {
else if(msgid == 6 && items[itSpice] < 10 && !peace::on && in_full_game()) {
addMessage(XLAT("\"The Red Rock Valley is dangerous, but beautiful.\""));
}
else if(msgid == 7 && items[itSpice] < 10 && !peace::on) {
else if(msgid == 7 && items[itSpice] < 10 && !peace::on && in_full_game()) {
addMessage(XLAT("\"Train in the Desert first!\""));
}
else if(msgid == 8 && sizes_known() && !tactic::on) {
addMessage(XLAT("\"Our Table seats %1 Knights!\"", expansion.get_descendants(rad).get_str(100)));
string s = "";
if(geometry == gCrystal)
s = crystal::get_table_boundary();
else if(!quotient)
s = expansion.get_descendants(rad).get_str(100);
if(s == "") { msgid++; goto retry; }
addMessage(XLAT("\"Our Table seats %1 Knights!\"", s));
}
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)));
string s = "";
if(geometry == gCrystal)
s = crystal::get_table_volume();
else if(!quotient)
s = expansion.get_descendants(rad-1, expansion.diskid).get_str(100);
if(s == "") { msgid++; goto retry; }
addMessage(XLAT("\"There are %1 floor tiles inside our Table!\"", s));
}
else if(msgid == 10 && !items[itPirate] && !items[itWhirlpool] && !peace::on) {
else if(msgid == 10 && !items[itPirate] && !items[itWhirlpool] && !peace::on && in_full_game()) {
addMessage(XLAT("\"Have you tried to take a boat and go into the Ocean? Try it!\""));
}
else if(msgid == 11 && !princess::saved) {
else if(msgid == 11 && !princess::saved && in_full_game()) {
addMessage(XLAT("\"When I visited the Palace, a mouse wanted me to go somewhere.\""));
}
else if(msgid == 12 && !princess::saved) {
else if(msgid == 12 && !princess::saved && in_full_game()) {
addMessage(XLAT("\"I wonder what was there...\""));
}
else if(msgid == 13 && !peace::on) {
else if(msgid == 13 && !peace::on && in_full_game()) {
addMessage(XLAT("\"Be careful in the Rose Garden! It is beautiful, but very dangerous!\""));
}
else if(msgid == 14) {

View File

@ -4156,6 +4156,9 @@ namespace crystal {
int dist_relative(cell *c);
void show();
void init_rotation();
string get_table_volume();
string get_table_boundary();
bool pure();
}
hyperpoint get_warp_corner(cell *c, int cid);
@ -4431,6 +4434,9 @@ struct bignum {
if(isize(digits) == 1) return digits[0];
return digits[0] + digits[1] * (long long) BASE;
}
friend inline bignum operator +(bignum a, const bignum& b) { a.addmul(b, 1); return a; }
friend inline bignum operator -(bignum a, const bignum& b) { a.addmul(b, -1); return a; }
};
struct expansion_analyzer {