mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-30 15:39:54 +00:00
147 lines
4.4 KiB
C++
147 lines
4.4 KiB
C++
|
// computing pairs of vertices in each distance using dynamic programming (as described in the paper)
|
||
|
|
||
|
namespace dhrg {
|
||
|
|
||
|
bool segmentValid(mycell *cl, mycell *cr) {
|
||
|
if(cl == cr) return true;
|
||
|
mycell *c1 = cl;
|
||
|
int d = 0;
|
||
|
for(; d<7 && c1 != cr; d++) {
|
||
|
c1->build(); c1 = c1->grightsibling();
|
||
|
}
|
||
|
if(d == 7) return false;
|
||
|
cr->build();
|
||
|
cl = cl->grightsibling()->gleftchild();
|
||
|
cr = cr->gleftchild();
|
||
|
return segmentValid(cl, cr);
|
||
|
}
|
||
|
|
||
|
vector<segment*> all_child_segments(segment *s) {
|
||
|
vector<segment*> res;
|
||
|
for(auto m1: allchildren(s->left, -1))
|
||
|
for(auto m2: allchildren(s->right, +1))
|
||
|
if(segmentValid(m1, m2))
|
||
|
res.push_back(getsegment(m1,m2,0,true));
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
// returns 0 if not in segment, 1-based index if in segment
|
||
|
int insegment(mycell *mc, segment *s1) {
|
||
|
mycell *l = s1->left;
|
||
|
int i = 1;
|
||
|
while(true) {
|
||
|
if(l == mc) return i;
|
||
|
if(l == s1->right) return 0;
|
||
|
l->build(); l = l->grightsibling();
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int segmentcode(segment *s) {
|
||
|
mycell *l = s->left;
|
||
|
int code = 0;
|
||
|
while(true) {
|
||
|
code += l->gettype();
|
||
|
if(l == s->right) return code;
|
||
|
l->build(); l = l->grightsibling();
|
||
|
code *= 8;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int compute_descendants(segment *s, int d) {
|
||
|
|
||
|
auto memokey = make_tuple(segmentcode(s), d);
|
||
|
static map<decltype(memokey), int> mem;
|
||
|
if(mem.count(memokey)) return mem[memokey];
|
||
|
|
||
|
if(d == 0) return s->left == s->right ? 1 : 0;
|
||
|
int total = 0;
|
||
|
for(auto s1: all_child_segments(s))
|
||
|
total += compute_descendants(s1, d-1);
|
||
|
return mem[memokey] = total;
|
||
|
}
|
||
|
|
||
|
// returns 0 if segments are not crossing, positive number if crossing
|
||
|
// for segments with equal codes, equal numbers = the same way of crossing
|
||
|
int segmentcross(segment *s1, segment *s2) {
|
||
|
int i1;
|
||
|
i1 = insegment(s1->left, s2);
|
||
|
if(i1) return 4*i1+1;
|
||
|
i1 = insegment(s1->right, s2);
|
||
|
if(i1) return 4*i1+2;
|
||
|
i1 = insegment(s2->left, s1);
|
||
|
if(i1) return 4*i1+3;
|
||
|
i1 = insegment(s2->right, s1);
|
||
|
if(i1) return 4*i1+4;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
set<int> allsegments;
|
||
|
|
||
|
int compute_in_dist(segment *s1, segment *s2, int d1, int d2, int dex) {
|
||
|
// if(d1 + d2 + 4 < dex) return 0;
|
||
|
int d = -segmentcross(s1,s2);
|
||
|
if(!d) d = segmentdist(s1, s2, 0);
|
||
|
|
||
|
if(d > 2 || d1 == 0 || d2 == 0) {
|
||
|
if(d < 0) d = 0;
|
||
|
return d1+d2+d == dex ? compute_descendants(s1,d1) * compute_descendants(s2,d2) : 0;
|
||
|
}
|
||
|
else {
|
||
|
mycell *ss1 = s1->right, *ss2 = s2->right;
|
||
|
if(d > 0) {
|
||
|
int side = 0;
|
||
|
while(true) {
|
||
|
ss1->build(); ss1 = ss1->grightsibling(); if(ss1 == s2->left) { side=1; break; }
|
||
|
ss2->build(); ss2 = ss2->grightsibling(); if(ss2 == s1->left) { side=2; break; }
|
||
|
}
|
||
|
d += 100 * side;
|
||
|
}
|
||
|
allsegments.insert(segmentcode(s1));
|
||
|
allsegments.insert(segmentcode(s2));
|
||
|
auto memokey = make_tuple(segmentcode(s1), segmentcode(s2), d, d1, d2, dex);
|
||
|
static map<decltype(memokey), int> mem;
|
||
|
if(mem.count(memokey)) return mem[memokey];
|
||
|
int total = 0;
|
||
|
for(auto s3: all_child_segments(s1))
|
||
|
for(auto s4: all_child_segments(s2))
|
||
|
total += compute_in_dist(s3, s4, d1-1, d2-1, dex);
|
||
|
if(0) if(mem.count(memokey) && mem[memokey] != total) {
|
||
|
printf("%d vs %d :: %x %x d=%d %d,%d,%d\n", mem[memokey], total, segmentcode(s1), segmentcode(s2), d, d1, d2, dex);
|
||
|
return mem[memokey];
|
||
|
}
|
||
|
return mem[memokey] = total;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void do_analyze_dists(int rad) {
|
||
|
|
||
|
println(hlog, "do_analyze_dists (", rad, ")");
|
||
|
indenter_finish indf;
|
||
|
auto m = mroot;
|
||
|
|
||
|
auto seg = getsegment(m, m, 0, true);
|
||
|
|
||
|
// compute the correct answer, but not if this requires creating more than 1500 cells
|
||
|
celllister cl(croot(), rad, 1500, NULL);
|
||
|
vector<int> correct(2*rad+4, 0);
|
||
|
|
||
|
for(cell *c1: cl.lst) if(celldist(c1) == rad)
|
||
|
for(cell *c2: cl.lst) if(celldist(c2) == rad)
|
||
|
correct[celldistance(c1,c2)]++;
|
||
|
|
||
|
int total = 0;
|
||
|
for(int a=0; a<2*rad+4; a++) {
|
||
|
int cd = compute_in_dist(seg, seg, rad, rad, a);
|
||
|
printf("%2d: %d/%d\n", a, cd, correct[a]);
|
||
|
total += cd;
|
||
|
}
|
||
|
|
||
|
printf("total = %d (%d)\n", total, cgi.expansion->get_descendants(5).approx_int() * cgi.expansion->get_descendants(5).approx_int());
|
||
|
printf("all segments = %d\n", isize(allsegments));
|
||
|
|
||
|
// printf("descendants = %d (%d)\n", compute_descendants(seg, 5), int(.1+expansion.get_descendants(5).approx_int()));
|
||
|
}
|
||
|
|
||
|
}
|