hyperrogue/generators/patterngen.cpp

461 lines
11 KiB
C++

// Hyperbolic Rogue pattern generator
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
namespace hr {
void spill50(cell *c, eWall w, int r) {
c->wall = w;
if(r) for(int i=0; i<c->type; i++) spill50(createMov(c, i), w, r-1);
}
int style = 3;
struct state50 {
bool polarity1;
bool polarity2;
color_t color, color2, wc2;
};
void progress(cell *c, state50 s);
#include <map>
map<cell*, state50> map50;
void initPatternFifty(cell *c) {
state50 s;
s.polarity1 = 0;
s.polarity2 = 0;
s.color = 0;
s.color2 = 1;
s.wc2 = 0;
map50[c] = s;
}
int par;
int haverule[1<<24][8];
void saveCode(heptagon *H1, int d, heptagon *H2) {
/*
if(!H1 || !H2) return;
if(H1->move[d] != H2) exit(1);
int h1 = H1->fiftyval;
int h2 = H2->fiftyval;
if(!h1 || !h2) return;
if(haverule[h1][d] && haverule[h1][d] != h2) {
printf("rule conflict: %06x, %d, %06x/%06x\n",
h1, d, h2, haverule[h1][d]);
// exit(1);
}
if(!haverule[h1][d]) {
haverule[h1][d] = h2;
printf("RULE50(0x%06x, %d, 0x%06x)\n", h1, d, h2);
} */
fflush(stdout);
}
void saveCode(cell *c) {
/* heptagon *hept = c->master;
if(hept != &origin)
saveCode(hept->move[0], hept->spin[0], hept); */
bool allcodes = c->master->fiftyval >= 0;
for(int i=0; i<7; i++)
if(c->master->move[i] && c->master->move[i]->fiftyval >= 0) ;
else allcodes = false;
if(allcodes) {
printf("RULE50(0x%03x", c->master->fiftyval);
int rulebase = 0;
for(int i=0; i<7; i++)
if(c->master->move[i]->fiftyval < c->master->move[rulebase]->fiftyval)
rulebase = i;
for(int i=0; i<7; i++) printf(", 0x%03x", c->master->move[(rulebase+i)%7]->fiftyval);
printf(")\n");
}
// hept->fiftyused = true;
}
void encode(cell *c, state50 s, int mod, int spn) {
/*int i = 0;
i *= 16; i += s.color;
i *= 16; i += s.color2;
i *= 16; i += s.polarity1;
i *= 16; i += s.polarity2;
i *= 16; i += mod;
i *= 16; i += spn;
if(c->master->fiftyval) { printf("multiply 50val\n"); exit(1); }
c->master->fiftyval = i; c->master->fiftyused = false; */
c->master->fiftyval =
s.color + s.polarity1 * 8 + s.polarity2 * 16 + mod * 32;
// s.color * 16 + (s.polarity1 ? 128 : 0) + (s.polarity2 ? 256 :0) + mod;
saveCode(c);
for(int i=0; i<7; i++)
saveCode(createStep(c->master, i)->c7);
/* for(int i=0; i<7; i++) if(c->master->move[i]) {
saveCode(c->master, i, c->master->move[i]);
saveCode(c->master->move[i], c->master->spin[i], c->master);
} */
}
eWall colorwalls[4] = {waCIsland, waCIsland2, waMineOpen, waDeadfloor };
void patternFiftyAt(cell *c) {
if(!map50.count(c)) return;
state50 s = map50[c];
// c->wall = waCIsland;
// if(c->heat > ii) return;
// printf("pfifty %p\n", c);
if(style == 1 && s.polarity2) {
spill50(c, waCamelot, 3);
spill50(c, waNone, 2);
for(int i=0; i<c->type; i++) {
cellwalker cw(c, i);
cellwalker cw1 = cw + wstep + 4 + wstep;
(cw1+3+wstep).at->wall = waFloorA;
(cw1+4+wstep).at->wall = waFloorA;
}
}
/*switch(ii) {
case 0:
spill50(c, waNone, 3);
break;
case 1:
spill50(c, waNone, 3);
break;
case 2:
spill50(c, waNone, 3);
break;
case 3:
spill50(c, waNone, 3);
break;
} */
if(style == 2) {
spill50(c, waCavefloor, 2);
spill50(c, waFloorA, 1);
}
if(style == 3) {
spill50(c, colorwalls[s.color], 3);
// c->item = itGold;
// if(s.polarity2) return;
}
encode(c, s, 0, 0);
int sgn = s.polarity2 ? 1 : -1;
int sgn1 = s.polarity1 ? 1 : -1;
color_t col2 = s.color2, sw = s.wc2;
while(col2 != 7-s.color) {
sw += (s.polarity1?1:-1); sw %= 7;
while(true) { col2++; col2 &= 7; if(col2 != s.color) break; }
}
for(int i=0; i<c->type; i++) {
auto cw = cellwalker(c, sw) + (sgn1 * i) + wstep + (sgn * 4) + wstep;
if(cw.spin < 0 || cw.spin >= 7 || cw.at->type != 7) exit(1);
encode(cw.c, s, 1+i, cw.spin);
}
for(int i=0; i<c->type; i++) {
auto cw = cellwalker(c, sw) + (sgn1 * i) + wstep + 3 + wstep + 3 + wstep;
if(cw.spin < 0 || cw.spin >= 7 || cw.at->type != 7) exit(1);
encode(cw.c, s, 8+i, cw.spin);
}
// c->heat = s.color +
for(int i=0; i<c->type; i++) {
cellwalker cw(c, s.wc2);
cw += (sgn1 * i);
cw += wstep;
if(style == 0) cw.at->wall = waCamelot;
// cw.at->item = itSilver;
cw += (sgn*4); //6
cw += wstep; if(style == 0) cw.at->wall = waFloorA;
// cw.at->item = itSilver;
cw += (sgn*4); //7
cw += wstep; if(style == 0) cw.at->wall = waFloorA;
// cw.at->item = itSilver;
cw += (3); //6
cw += wstep; if(style == 0) cw.at->wall = waFloorA;
// cw.at->item = itSilver;
cw += (3); //6
cw += wstep; if(style == 0) cw.at->wall = waFloorA;
// cw.at->item = itSilver;
cw += (sgn*3); //7
cw += wstep; if(style == 0) cw.at->wall = waCamelot;
// cw.at->item = itSilver;
cw += (sgn*2); //6
cw += wstep; // cw.at->item = itGold;
// setdist(cw.c, 8, NULL);
state50 s2 = s; s2.polarity1 = !s.polarity1;
s2.wc2 = (cw.spin + sgn1 * i + sgn + 42) % 7;
progress(cw.c, s2);
// printf("heat set %f\n", cw.at->heat);
}
int newcol = s.color2;
// if(s.polarity2) return;
for(int i=0; i<c->type; i++) {
cellwalker cw(c, s.wc2);
cw += (sgn1 * i);
cw += wstep; // cw.at->item = itSilver;
// cw.at->item = itDiamond;
cw += (3); // 6
cw += wstep; // cw.at->item = itSilver;
// cw.at->item = itDiamond;
cw += (sgn*4); // 6
cw += wstep; // cw.at->item = itSilver;
// cw.at->item = itDiamond;
cw += (sgn*2); // 6
cw += wstep; // cw.at->item = itSilver;
// cw.at->item = itDiamond;
cw += (3); // 6
cw += wstep; // cw.at->item = itSilver;
// cw.at->item = itDiamond;
cw += (sgn*3); // 7
cw += wstep; // cw.at->item = itSilver;
// cw.at->item = itDiamond;
cw += (sgn*4); // 6
cw += wstep; // cw.at->item = itSilver;
// setdist(cw.c, 8, NULL);
state50 s2 = s;
s2.polarity2 = !s.polarity2;
if(s.polarity2) s2.polarity1 = !s.polarity1;
s2.color2 = s2.color;
s2.color = newcol;
s2.wc2 = cw.spin;
progress(cw.c, s2);
while(true) { newcol++; newcol &= 7; if(newcol != s2.color && newcol != s.color) break; }
// printf("heat set %f\n", cw.at->heat);
}
}
void progress(cell *c, state50 s) {
while(s.wc2) {
s.wc2 += (s.polarity1?1:-1); s.wc2 %= 7;
while(true) { s.color2++; s.color2 &= 7; if(s.color2 != s.color) break; }
}
if(map50.count(c)) {
state50 s2 = map50[c];
if(s2.polarity1 != s.polarity1 || s2.polarity2 != s.polarity2) {
printf("Polarity mismatch!\n");
exit(1);
}
else {
if(s2.color != s.color || s2.color2 != s.color2 || s2.wc2 != s.wc2)
printf("%d:%d color= %dv%d color2= %dv%d wc2= %dv%d\n",
s.polarity1, s.polarity2,
s.color, s2.color,
s.color2, s2.color2,
s.wc2, s2.wc2);
}
return;
}
map50[c] = s;
if(c->mpdist <= 7)
patternFiftyAt(c);
}
long long Q; int qconflict;
string allconflict;
void setzebra(cellwalker cwb, int it, int type, string pathcode, int xmods) {
// printf("spin=%d type=%d\n", cwb.spin, type);
if(cwb.spin != 1 && cwb.spin != 3 && cwb.spin != 5) {
printf("S WRONG SPIN %d\n", cwb.spin);
exit(1);
}
if(type < 0 || type > 3) {
printf("S WRONG TYPE %d\n", type);
exit(1);
}
cwb.at->tmp = cwb.spin + 16 * type;
}
void zebra(cellwalker cwb, int it, int type, string pathcode, int xmods) {
if(!it) return;
if(cwb.spin != 1 && cwb.spin != 3 && cwb.spin != 5) {
printf("WRONG SPIN %d\n", cwb.spin);
exit(1);
}
if(type < 0 || type > 3) {
printf("WRONG TYPE %d\n", type);
exit(1);
}
// printf("%p+%d = 0%s\n", cwb.c, cwb.spin, pathcode.c_str());
bool redraw = false;
// int qval = Q + 99;
// redraw = cwb.at->heat == qval;
// cwb.at->heat = qval;
eWall w = colorwalls[type];
cwb.at->wall = w;
for(int i=0; i<6; i+=2) {
cellwalker cw = cwb;
cw += (i);
cw.at->heat = 4 + type + 4 * 9;
cw += wstep; cw += (3); cw.at->wall = w;
int i0 = i; if(type&2 && i0) i0 = 6-i0; i0 /= 2;
cw.at->heat = 4 + type + 4 * (3+i0);
cw += wstep; cw += (3); cw.at->wall = w;
cw.at->heat = 4 + type + 4 * i0;
cw += wstep; cw += (3); cw.at->wall = w;
cw.at->heat = 4 + type + 4 * (6+i0);
cw += wstep; cw += (-3);
cw += wstep; cw += (-3);
cw += wstep; cw += (-3);
cw += wstep; cw += (-i);
cw += (0);
setzebra(cw, it-1, type ^ 1, pathcode +'+'+char('A'+i)+char('0'+type), xmods*2);
}
for(int i=0; i<6; i+=2) {
cellwalker cw = cwb;
cw += ((type&2)?-i:i);
cw += wstep; cw += (3);
cw += wstep; cw += (5);
if(xmods < 2) {
if(cw.at->item && cw.at->item != (1+i) && redraw && i==0) {
qconflict++;
// allconflict += pathcode; allconflict += "-";
// cwb.at->item = itPalace;
// printf("Conflict at %p\n", cwb.at);
}
// cw.at->item = eItem(1 + i);
// cw.at->heat = 4 + type + 4 * (i/2);
}
cw += wstep; cw += (1);
if(type < 2) {
// cw += (i);
cw += (i);
}
else {
cw += (-i);
}
// cw += (((Q >> (4*type)) & 12));
setzebra(cw, it-1, 2^type, pathcode + '+'+char('a'+i)+char('0'+type), xmods+1);
}
}
void zebraPattern() {
// int bqc = 99;
/* for(Q=0; Q<65536; Q++) {
if((Q & (Q>>1)) & 0x5555) continue;
qconflict = false;
cellwalker cw(cwt);
cw += wstep; cw += (1);
qconflict = 0;
allconflict = "";
zebra(cw, 3, 0, "");
if(qconflict < bqc) bqc = qconflict;
// if(qconflict == bqc)
printf("%X - X-%sX\n", Q, allconflict.c_str());
}
Q = 0xFFFB; */
cellwalker cw(cwt);
cw += wstep; cw += (1);
setzebra(cw, 7, 0, "", -999);
// cw.at->
// printf("Conflicts: %d\n", qconflict);
}
int bspin(heptagon *h) {
vector<int> xv;
xv.push_back(999);
int besti = -1;
for(int i=0; i<7; i++) {
vector<int> yv;
for(int j=0; j<7; j++) yv.push_back(int(h->move[(i+j)%7]->c7->heat+.1));
if(yv < xv) xv = yv, besti = i;
}
return besti;
}
void buildAutomatonRule(heptagon *h) {
if(!h->c7->heat) return;
for(int i=0; i<7; i++) if(!h->move[i]) return;
for(int i=0; i<7; i++) for(int j=0; j<7; j++)
if(!h->move[i]->move[j] || !h->move[i]->move[j]->c7->heat)
return;
int bi = bspin(h);
printf("RULEZEBRA(%2d", int(h->c7->heat+.1));
for(int j=0; j<7; j++) {
heptagon *h2 = h->move[(bi+j)%7];
int bi2 = bspin(h2);
printf(", %2d%d", int(h2->c7->heat+.1), fix7(bi2 - h->spin[(bi+j)%7]));
}
printf(")\n");
}
void buildAutomatonRule(cell *c) {
if(c->type == 7)
buildAutomatonRule(c->master);
else {
int ii[3];
for(int i=0; i<6; i+=2) if(!c->move(i) || !c->move(i)->heat || c->move(i)->type != 7) return;
for(int i=0; i<6; i+=2) ii[i/2] = int(c->move(i)->heat);
int z;
for(int r=0; r<2; r++)
if(ii[1] < ii[0] || ii[2] < ii[0])
z = ii[0], ii[0] = ii[1], ii[1] = ii[2], ii[2] = z;
printf("RULEZEBRA6(%d,%d,%d,%d)\n", int(c->heat), int(ii[0]), int(ii[1]), int(ii[2]));
}
}
/*
to drawcell:
if(c->type == 6 && c->tmp > 0) {
int i = c->tmp;
zebra(cellwalker(c, i&15), 1, i>>4, "", 0);
}
c->item = eItem(c->heat / 4);
buildAutomatonRule(c);
#endif
*/
// #define BUILDZEBRA
}