1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-24 05:17:17 +00:00
hyperrogue/devmods/hatter.cpp
Arthur O'Dwyer ced3bbcad4 Qualify calls to format
C++20 introduces `std::format` and we `using namespace std`,
so some of these would be ambiguous in C++20.
2023-08-21 10:18:44 -07:00

517 lines
18 KiB
C++

/**
* This program was used to generate the rule tables in apeirodic-hat.cpp.
*
* Some data was generated by this program itself, based on manual keyboard+mouse control.
* Some of minor manual control tools have been removed, but the process was as follows:
*
* * Run with `-symbol "12,6,4" -dual -canvas 101010 -smart 1 stamplen=0` and draw the hat shape, the table output is hatcorners
* * Place hats into clusters as shown in the paper, obtaining the table hats[0]
* * Place clusters into superclusters as shown in the paper, obtaining the table hats[1]
* * Repeat for hats[2], hats[3], hats[4] and hats[5] (the paper does not specify precisely the coordinates to arrange the clusters; but we can multiply the previous hats by scaling factor
* * for an approximate, and fix manually so that it matches)
* * 'CON Lx' lines state the rules deduced; the rules should be the same for L1 and L2 (except the matrix codes returned by matcode), so we conjecture that this set of rules is complete
* * Fill the table `hatid` to declare the correspondence between L1 and L2 matrices
* * Run again, and we get rules (prefixed by RULE1 and RULE0)
**/
#include "../rogueviz/rogueviz.h"
namespace rogueviz {
int toplev = 5;
vector<hyperpoint> hatcorners_add;
vector<hyperpoint> hatcorners[2];
vector<transmatrix> hats[8];
vector<int> hattype;
hyperpoint pt(ld x, ld y) { return hpxy(x, y); }
transmatrix rot;
transmatrix sca;
transmatrix U;
transmatrix mt(ld a, ld b, ld c, ld d, ld e, ld f, ld g, ld h, ld i) {
transmatrix T = Id;
T[0][0] = a;
T[0][1] = b;
T[0][2] = c;
T[1][0] = d;
T[1][1] = e;
T[1][2] = f;
T[2][0] = g;
T[2][1] = h;
T[2][2] = i;
return T;
}
map<string, int> hatid;
void init() {
rot = Id;
hatcorners[0] = {
pt(-1.1160254038,1.4330127019),
pt(-0.0915063509,2.0245190528),
pt(0.2500000000,1.4330127019),
pt(-0.0915063509,0.8415063509),
pt(0.9330127019,0.2500000000),
pt(0.9330127019,-0.9330127019),
pt(0.2500000000,-0.9330127019),
pt(-0.0915063509,-1.5245190528),
pt(-1.1160254038,-0.9330127019),
pt(-2.1405444566,-1.5245190528),
pt(-2.4820508076,-0.9330127019),
pt(0,0),
pt(-1.7990381057,0.2500000000),
pt(-1.1160254038,0.2500000000),
};
hatcorners[0][11] = mid(hatcorners[0][10], hatcorners[0][12]);
hatcorners[1] = hatcorners[0];
for(auto& h: hatcorners[1]) h = MirrorX * h;
reverse(hatcorners[1].begin(), hatcorners[1].end());
hats[0] = {
mt(0.5000000000,-0.8660254038,-1.3660254038, -0.8660254038,-0.5000000000,-0.0000000000, 0.0000000000,0.0000000000,1.0000000000) * MirrorX,
mt(0.5000000000,-0.8660254038,0.6830127019, 0.8660254038,0.5000000000,1.6830127019, 0.0000000000,0.0000000000,1.0000000000),
mt(-1.0000000000,0.0000000000,-2.2320508076, -0.0000000000,-1.0000000000,-1.8660254038, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,-0.8660254038,-4.5310889132, 0.8660254038,-0.5000000000,-1.6160254038, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,-0.8660254038,-3.4150635095, 0.8660254038,0.5000000000,1.6830127019, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,-0.0000000000,-2.0490381057, 0.0000000000,1.0000000000,3.5490381057, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,0.8660254038,0.2500000000, -0.8660254038,0.5000000000,3.2990381057, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,-0.8660254038,-5.4641016151, 0.8660254038,0.5000000000,0.5000000000, 0.0000000000,0.0000000000,1.0000000000),
};
hats[1] = {
mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,0.8660254038,-0.8660254038, -0.8660254038,-0.5000000000,7.0980762114, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,0.8660254038,-5.8971143170, -0.8660254038,0.5000000000,4.4820508076, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,-0.0000000000,-6.1471143170, 0.0000000000,1.0000000000,-1.1830127019, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,-0.8660254038,-4.5310889132, 0.8660254038,-0.5000000000,-3.9820508076, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,-0.8660254038,-9.5621778265, 0.8660254038,0.5000000000,-6.5980762114, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,-0.0000000000,-14.3432667397, 0.0000000000,1.0000000000,-3.5490381057, 0.0000000000,0.0000000000,1.0000000000),
};
hattype = {7, 8, 8, 8, 8, 8, 8};
ld q7 = 1, q8 = 0;
ld val;
for(int a=0; a<100; a++) {
ld nq7 = q7 + q8;
ld nq8 = q7 * 5 + q8 * 6;
println(hlog, hr::format("%.20f", val = (nq7 + nq8) / (q7 + q8)));
q7 = nq7; q8 = nq8;
}
val = sqrt(val);
println(hlog, "root: ", hr::format("%.20f", val));
for(int a=-50; a<50; a++)
for(int b=1; b<50; b++)
for(int c=-50; c<50; c++)
for(int d=1; d<50; d++) {
ld err = abs(a*1./b + c * sqrt(1./d) - val);
if(err < 1e-6)
println(hlog, tie(a,b,c,d), " : ", err);
}
val = (3 + sqrt(5)) / 2; // scaling each axis
sca = Id; sca[0][0] = sca[1][1] = val;
hats[2] = {
mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,0.8660254038,1.1830127025, -0.8660254038,-0.5000000000,15.3791651251, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,0.8660254038,-12.0442286339, -0.8660254038,0.5000000000,10.3971143173, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,0.0000000000,-14.3432667399, 0.0000000000,1.0000000000,-3.5490381057, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,-0.8660254038,-12.7272413356, 0.8660254038,-0.5000000000,-13.4461524228, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,-0.8660254038,-25.9544826718, 0.8660254038,0.5000000000,-18.4282032304, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,0.0000000000,-36.8826859024, 0.0000000000,1.0000000000,-9.4641016152, 0.0000000000,0.0000000000,1.0000000000),
};
hats[3] = {
mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,0.8660254038,7.3301270200, -0.8660254038,-0.5000000000,37.8564064623, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,0.8660254038,-28.4365334803, -0.8660254038,0.5000000000,26.9592921447, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,0.0000000000,-36.8826859027, 0.0000000000,1.0000000000,-9.4641016152, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,-0.8660254038,-33.2176223915, 0.8660254038,-0.5000000000,-39.4724318658, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,-0.8660254038,-68.9842828915, 0.8660254038,0.5000000000,-50.3695461828, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,0.0000000000,-96.3047909683, 0.0000000000,1.0000000000,-24.8432667403, 0.0000000000,0.0000000000,1.0000000000),
};
hats[4] = {
mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,0.8660254038,23.7224318656, -0.8660254038,-0.5000000000,97.0070415601, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,0.8660254038,-71.4663337016, -0.8660254038,0.5000000000,70.7307621167, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,0.0000000000,-96.3047909682, 0.0000000000,1.0000000000,-24.8432667399, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,-0.8660254038,-86.4926131352, 0.8660254038,-0.5000000000,-108.0871685769, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,-0.8660254038,-181.6813787030, 0.8660254038,0.5000000000,-134.3634480195, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,0.0000000000,-252.0316870025, 0.0000000000,1.0000000000,-65.0656986057, 0.0000000000,0.0000000000,1.0000000000),
};
hats[5] = {
mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,0.8660254038,66.7522320948, -0.8660254038,-0.5000000000,251.9817055201, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,0.8660254038,-184.1634295166, -0.8660254038,0.5000000000,185.4829942043, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,0.0000000000,-252.0316870019, 0.0000000000,1.0000000000,-65.0656986045, 0.0000000000,0.0000000000,1.0000000000),
mt(-0.5000000000,-0.8660254038,-225.8272043260, 0.8660254038,-0.5000000000,-287.9050992716, 0.0000000000,0.0000000000,1.0000000000),
mt(0.5000000000,-0.8660254038,-476.7428659331, 0.8660254038,0.5000000000,-354.4038105811, 0.0000000000,0.0000000000,1.0000000000),
mt(1.0000000000,0.0000000000,-659.7902700392, 0.0000000000,1.0000000000,-170.3538290768, 0.0000000000,0.0000000000,1.0000000000),
};
hats[6] = hats[5];
auto acs = inverse(sca);
println(hlog, "shifts:");
indenter ind(2);
for(int i=0; i<7; i++) {
transmatrix S = gpushxto0(hats[1][i] * C0) * hats[1][i];
// println(hlog, "S = ", kz(S));
transmatrix S0 = inverse(S);
// transmatrix S1 = S;
auto& t = hats[6][i];
auto& t3 = hats[5][i];
auto& t2 = hats[4][i];
auto& t1 = hats[3][i];
hyperpoint fix2 = t2 * C0 - sca * t1 * C0;
hyperpoint cfix3 = acs * fix2;
hyperpoint rfix3 = t3 * C0 - sca * t2 * C0;
t = sca * t * acs * acs * rgpushxto0(rfix3) * sca;
println(hlog, kz(rfix3-cfix3), " from ", fix2, " .. ", S0 * cfix3 - acs * fix2);
// t = t * rgpushxto0(sca * (t3 * C0 - bt3 * C0));
// t = t *
}
hatid["R0A000L0.000"] = -1;
int nextid = 8;
hatid["R0A011L6.147"] = hatid["R0A014L14.343"] = nextid++;
hatid["R0A016L8.196"] = hatid["R0A015L22.539"] = nextid++;
hatid["R0A016L8.196"] = hatid["R0A015L22.539"] = nextid++;
hatid["R0A191L6.147"] = hatid["R0A194L14.343"] = nextid++;
hatid["R0A196L8.196"] = hatid["R0A195L22.539"] = nextid++;
hatid["R1A023L6.903"] = hatid["R1A019L15.060"] = nextid++;
hatid["R1A126L5.555"] = hatid["R1A131L15.741"] = nextid++;
hatid["R1A185L7.579"] = hatid["R1A191L21.879"] = nextid++;
hatid["R1A238L3.558"] = hatid["R1A232L11.654"] = nextid++;
hatid["R1A327L4.885"] = hatid["R1A320L10.974"] = nextid++;
hatid["R2A037L6.054"] = hatid["R2A025L14.053"] = nextid++;
hatid["R2A092L2.046"] = hatid["R2A096L3.188"] = nextid++;
hatid["R2A138L8.858"] = hatid["R2A145L25.101"] = nextid++;
hatid["R2A221L4.953"] = hatid["R2A226L12.883"] = nextid++;
hatid["R2A300L2.571"] = hatid["R2A279L2.571"] = nextid++;
hatid["R3A226L7.005"] = hatid["R3A233L16.845"] = nextid++;
hatid["R4A000L5.143"] = hatid["R4A339L10.197"] = nextid++;
hatid["R4A097L4.093"] = hatid["R4A085L4.171"] = nextid++;
hatid["R4A152L9.906"] = hatid["R4A156L21.728"] = nextid++;
hatid["R4A198L11.809"] = hatid["R4A205L27.793"] = nextid++;
hatid["R4A281L4.171"] = hatid["R4A286L6.625"] = nextid++;
hatid["R5A087L5.006"] = hatid["R5A080L5.503"] = nextid++;
hatid["R5A143L7.731"] = hatid["R5A139L13.041"] = nextid++;
hatid["R5A246L6.309"] = hatid["R5A251L9.388"] = nextid++;
hatid["R5A305L6.626"] = hatid["R5A311L15.426"] = nextid++;
hatid["R5A358L8.119"] = hatid["R5A352L19.349"] = nextid++;
println(hlog, "nextid = ", nextid);
};
void draw_cross(hyperpoint h) {
transmatrix T = rgpushxto0(h);
shiftmatrix sId = shiftless(Id);
for(int i=0; i<12; i++)
queueline(sId * T * C0, sId * T * xspinpush0(30._deg * i, 0.1), 0xFFFFFFFF);
}
void draw_shape(transmatrix T, vector<hyperpoint> sh, color_t lc, color_t fc) {
for(hyperpoint h: sh) curvepoint(h);
curvepoint(sh[0]);
queuecurve(shiftless(Id) * T, lc, fc, PPR::LINE);
}
/*
void draw_superhat(transmatrix T, const vector<transmatrix>& ms, int q, color_t lc, color_t fc) {
for(auto& m: ms)
draw_shape(T * m, hatcorners, lc, fc);
}
*/
hyperpoint sh;
color_t coltables[8] = { 0xFF000080, 0x00FF0080, 0x0000FF80, 0xFFFF0080, 0xFF00FF80, 0x00FFFF80, 0xFFFFFF80, 0x4080C080 };
vector<int> curlabel;
ld ldist = 9999;
hyperpoint hfound, hfound1;
int connection_mode = 0;
int found_pairs, found_pairs_swap;
using pthash = int;
pthash makehash(hyperpoint h) {
return int(floor(h[0] * 10 + .31)) + int(floor(h[1] * 10 + .31)) * 10000;
}
map<pair<pthash, pthash>, vector<int> > seen_edges;
string name(int x) { return s0 + char('A' + x); }
string matcode(transmatrix T) {
vector<ld> res(3);
hyperpoint h = kz(T * C0);
transmatrix S = gpushxto0(T * C0) * T;
ld alpha = atan2(S * xpush0(1)) / degree;
int ialpha = gmod(floor(alpha + .5), 360);
int hangle = gmod(floor(atan2(h) / degree + .3), 360);
h[2] = ialpha/60;
swap(h[1], h[2]); swap(h[0], h[1]);
// return lalign(0, h);
return hr::format("R%dA%03dL%.3f", ialpha/60, hangle, hypot_d(2, h));
}
int ghatid(string s) {
if(hatid.count(s)) return hatid[s];
return -999;
}
void edge_connect(vector<int> l1, vector<int> l2) {
transmatrix T1 = Id;
transmatrix T2 = Id;
transmatrix W = Id;
int idx = 0;
for(int i=toplev; i>0; i--) {
T1 = T1 * hats[i][l1[idx]];
T2 = T2 * hats[i][l2[idx]];
transmatrix W1 = inverse(T1) * T2;
if(!eqmatrix(W1, Id))
println(hlog, "CON L", i, " ", matcode(W1), " :: ", matcode(W), " ", tie(l1[idx], l2[idx]), " REV ", matcode(inverse(W1)));
if(i == 1) println(hlog, "RULE1 {", l1[idx], ", ", l2[idx], ", ", ghatid(matcode(W1)), ", ", ghatid(matcode(W)), ", ", ghatid(matcode(inverse(W1))), "},");
W = W1;
idx++;
}
println(hlog, "CON L0 ", make_pair(make_pair(l1[idx], name(l1[idx+1])), make_pair(l2[idx], name(l2[idx+1]))), " :: ", matcode(W));
println(hlog, "RULE0 {", l1[idx], ", ", l1[idx+1], ", ", l2[idx], ", ", l2[idx+1], ", ", ghatid(matcode(W)), "},");
}
vector<pair<hyperpoint, hyperpoint> > extedges;
void edge_label(vector<int>& lbl, hyperpoint a, hyperpoint b) {
auto ha = makehash(a);
auto hb = makehash(b);
if(connection_mode >= 2) return;
if(connection_mode == 1) {
if(seen_edges.count({ha, hb})) {
extedges.emplace_back(a, b);
/* vid.linewidth *= 10;
queueline(shiftless(Id) * a, shiftless(Id) * b, 0xFF00FF80);
vid.linewidth /= 10;
*/
}
return;
}
if(seen_edges.count({hb, ha})) {
edge_connect(lbl, seen_edges[{hb, ha}]);
edge_connect(seen_edges[{hb, ha}], lbl);
seen_edges.erase({hb, ha});
found_pairs++;
return;
}
if(seen_edges.count({ha, hb})) {
println(hlog, "CON ", lbl, " TO ", seen_edges[{hb, ha}], " SWAP");
seen_edges.erase({ha, hb});
found_pairs_swap++;
return;
}
seen_edges[{ha, hb}] = lbl;
}
void point_label(vector<int>& lbl, hyperpoint h) {
if(lbl == curlabel) draw_cross(h);
ld dist = hdist(unshift(mouseh), h);
if(dist < ldist) {
ldist = dist;
curlabel = lbl;
hfound = h;
println(hlog, "found: ", lbl, " at: ", dist);
}
}
void draw_superhat_label(transmatrix T, const vector<transmatrix>& ms, int q, color_t lc, color_t fc, vector<int>& label) {
for(int i=0; i<q; i++) {
auto& hc = hatcorners[i == 0];
for(int j=0; j<isize(hc); j++) {
label.push_back(i);
label.push_back(j);
point_label(label, T * ms[i] * hc[j]);
edge_label(label, T * ms[i] * hc[j], T * ms[i] * hc[(j+1)%isize(hc)]);
label.pop_back();
label.pop_back();
}
}
for(int i=0; i<q; i++) {
auto& hc = hatcorners[i == 0];
draw_shape(T * ms[i], hc, lc, fc);
}
}
void draw_recurse_label(transmatrix T, int levs, int t, color_t col, vector<int>& label) {
if(levs == 0) {
draw_superhat_label(T, hats[0], t, 0xFFFFFFFF, col, label);
return;
}
if(connection_mode == 2 && levs == toplev-1) {
int eid = 0;
for(auto e: extedges) {
queueline(shiftless(Id) * T * e.first, shiftless(Id) * T * e.second, col);
label.push_back(eid++);
point_label(label, T * e.first);
label.pop_back();
}
return;
}
transmatrix scap = Id;
for(int i=1; i<levs; i++) scap = scap * sca;
scap = inverse(scap);
for(int i=0; i<t-1; i++) {
auto col1 = col;
if(col == 0) col1 = coltables[i];
label.push_back(i);
draw_recurse_label(T * hats[levs][i], levs-1, hattype[i], col1, label);
label.pop_back();
}
}
int next_hattype = 7;
void hatframe() {
if(isize(hatcorners_add) >= 2) draw_shape(Id, hatcorners_add, 0xFF0000FF, 0xFF000080);
transmatrix B = rgpushxto0( unshift(ggmatrix(cwt.at)) * C0 );
vector<int> glabel;
draw_recurse_label(B, toplev, 8, 0, glabel);
if(connection_mode == 0) {
println(hlog, "CON found = ", found_pairs, " swap = ", found_pairs_swap, " not found = ", isize(seen_edges));
// seen_edges.clear(); found_pairs = 0;
connection_mode = 1;
}
else if(connection_mode == 1) {
connection_mode = 2;
toplev++;
}
draw_cross(C0);
}
string writematrix(transmatrix T) {
return hr::format("mt(%.10f,%.10f,%.10f, %.10f,%.10f,%.10f, %.10f,%.10f,%.10f)",
T[0][0],
T[0][1],
T[0][2],
T[1][0],
T[1][1],
T[1][2],
T[2][0],
T[2][1],
T[2][2]
);
}
void hatter() {
cmode = sm::NORMAL | sm::CENTER | sm::PANNING;
clearMessages();
dialog::init();
gamescreen();
shiftpoint s = mapeditor::full_mouseh();
sh = unshift(s);
dialog::add_key_action('a', [] {
hatcorners_add.push_back(sh);
println(hlog, "hatcorners = {");
for(auto h: hatcorners_add) println(hlog, hr::format(" pt(%.10f,%.10f),", h[0], h[1]));
println(hlog, " }");
});
/* dialog::add_key_action('b', [] {
if(hats.empty()) return;
hats.pop_back();
hattype.pop_back();
}); */
dialog::add_key_action('[', [] {
// hyperpoint h = currentmap->get_corner(cwt.at, 0);
// rot = rot * gpushxto0(h);
rot = rot * spin(60._deg);
// rot = rot * rgpushxto0(h);
});
dialog::add_key_action(']', [] {
// hyperpoint h = currentmap->get_corner(cwt.at, 0);
// rot = rot * gpushxto0(h);
rot = MirrorX * rot;
// rot = rot * rgpushxto0(h);
});
dialog::add_key_action('7', [] { next_hattype = 7; });
dialog::add_key_action('8', [] { next_hattype = 8; });
dialog::add_key_action('f', [] { hfound1 = hfound; });
dialog::add_key_action('b', [] {
int id = curlabel[0];
hats[toplev][id] = rgpushxto0(hfound1 - hfound) * hats[toplev][id];
println(hlog, "hats[", toplev, "] = {");
for(auto h: hats[toplev]) println(hlog, " ", writematrix(h), ",");
println(hlog, " }");
});
dialog::add_key_action('q', [] {
exit(0);
});
dialog::add_key_action('g', [] {
ldist = 9999;
});
keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); };
}
void enable_hatter() {
init();
mapeditor::snapping = true;
rv_hook(hooks_frame, 100, hatframe);
pushScreen(hatter);
}
auto hathook = arg::add3("-hatter", enable_hatter);
}