hyperrogue/rogueviz/newconf.cpp

1011 lines
29 KiB
C++

// newconformist explorable explanation
// example commandline: -noplayer -rugtsize 4096 -smart 1 -canvas B -ncee
// set CAP_NCONF (and change the path) if you have access to newconformist
#include "rogueviz.h"
#if CAP_NCONF
#ifndef CAP_DRAW
#define CAP_DRAW 0
#endif
#define main nconf_main
#undef self
#include "nconf.cpp"
#undef main
#endif
namespace hr {
namespace nconf2 {
string rfname;
enum class ptype : char { outside, inside, inside_left_up, inside_left_down, top, bottom, left_inf, right_inf, marked };
dqi_line& queueline1(const hyperpoint& H1, const hyperpoint& H2, color_t col, int prf = 0, PPR prio = PPR::LINE) {
return queueline(shiftless(H1), shiftless(H2), col, prf, prio);
}
void add_border(vector<string>& v, int cy) {
int Y = isize(v), X = isize(v[0]);
char nx = '6';
for(int y=0; y<Y; y++)
for(int x=0; x<X; x++)
if(v[y][x] != '1')
if((y && v[y-1][x] == '1') || (y<Y-1 && v[y+1][x] == '1') || (x && v[y][x-1] == '1') || (x<X-1 && v[y][x+1] == '1'))
v[y][x] = y < cy ? '4' : y > cy ? '5' : (nx++);
}
vector<string> gensquare(int X, int Y) {
vector<string> res(Y+4, string (X+4, '0'));
for(int y=0; y<Y; y++)
for(int x=0; x<X; x++)
res[y+2][x+2] = '1';
add_border(res, 2+Y/2);
return res;
}
vector<string> genellipse(int D, ld alpha) {
vector<string> res(D+4, string (D+4, '0'));
ld R = (D-1.) / 2;
for(int y=0; y<D; y++)
for(int x=0; x<D; x++) {
ld ax = (x-R);
ld ay = (y-R);
ld bx = ax * cos(alpha) - ay * sin(alpha);
ld by = ay * cos(alpha) + ax * sin(alpha);
bx /= R;
by /= R;
res[y+2][x+2] = bx*bx+by*by*2 < 1 ? '1' : '0';
}
add_border(res, 2+R);
return res;
}
vector<string> gent(int X, int Y) {
vector<string> res(Y+X+4, string (Y+X+X+4, '0'));
for(int y=0; y<Y; y++)
for(int x=0; x<X+X+Y; x++)
res[y+2][x+2] = '1';
for(int y=0; y<Y; y++)
for(int x=0; x<X; x++)
res[x+2+Y][y+2+X] = '1';
add_border(res, 2+Y/2);
return res;
}
vector<string> fmap = gensquare(13, 13);
vector<string> snake = {
"00000000000000000000000000000000000",
"00444444444444444444444444444444400",
"04111111111111111111111111111111140",
"04111111111111111111111111111111140",
"06111111111111111111111111111111140",
"05111111111111111111111111111111140",
"05111111111111111111111111111111140",
"00555555555555555555555555511111140",
"00000000000000000000000000051111140",
"00555555555555555555555555511111140",
"05111111111111111111111111111111140",
"05111111111111111111111111111111140",
"05111111111111111111111111111111140",
"05111111111111111111111111111111140",
"05111111111111111111111111111111140",
"05111111444444444444444444444444400",
"05111114000000000000000000000000000",
"05111111444444444444444444444444400",
"05111111111111111111111111111111140",
"05111111111111111111111111111111140",
"05111111111111111111111111111111170",
"05111111111111111111111111111111150",
"05111111111111111111111111111111150",
"00555555555555555555555555555555500",
"00000000000000000000000000000000000"
};
struct coord {
int x, y;
coord operator + (int d) {
coord res = *this;
d &= 3;
if(d == 0) res.x++;
if(d == 1) res.y++;
if(d == 2) res.x--;
if(d == 3) res.y--;
return res;
}
};
char out = '-';
char& fmap_at(coord c) { return c.x >= 0 && c.x < isize(fmap[0]) && c.y >= 0 && c.y < isize(fmap) ? fmap[c.y][c.x] : out; }
ld vx[256][256], vy[256][256];
void reset_vxy() { for(int y=0; y<256; y++) for(int x=0; x<256; x++) vy[y][x] = vx[y][x] = 0; }
ld cscale;
bool pretty = true;
void iterate() {
int Y = isize(fmap);
int X = isize(fmap[0]);
for(int y=0; y<Y; y++)
for(int x=0; x<X; x++) {
if(fmap[y][x] == '6')
vy[y][x] = 0, vx[y][x] = -1;
else if(fmap[y][x] == '7')
vy[y][x] = 0, vx[y][x] = +1;
else if(fmap[y][x] == '4')
vy[y][x] = -1;
else if(fmap[y][x] == '5')
vy[y][x] = +1;
else if(fmap[y][x] == '1')
vy[y][x] = (vy[y-1][x] + vy[y+1][x] + vy[y][x-1] + vy[y][x+1]) / 4;
if(among(fmap[y][x], '1', '4', '5')) {
int qty = 0;
ld total = 0;
auto in = [&] (char c) { return pretty ? c > '0' : among(c, '1', '6', '7'); };
if(y > 0 && in(fmap[y-1][x])) qty++, total += vx[y-1][x];
if(y < Y-1 && in(fmap[y+1][x])) qty++, total += vx[y+1][x];
if(x > 0 && in(fmap[y][x-1])) qty++, total += vx[y][x-1];
if(x < X-1 && in(fmap[y][x+1])) qty++, total += vx[y][x+1];
vx[y][x] = total / qty;
}
}
vector<ld> xes;
for(int y=0; y<Y-1; y++) for(int x=0; x<X-1; x++)
if(fmap[y][x] == '1' && fmap[y+1][x] == '1' && fmap[y][x+1] == '1') {
hyperpoint here = point2(vx[y][x], vy[y][x]);
hyperpoint v0 = point2(vx[y][x+1], vy[y][x+1]) - here;
hyperpoint v1 = point2(vx[y+1][x], vy[y+1][x]) - here;
ld det = (v0 ^ v1)[2];
if(det == 0) continue;
hyperpoint ba2 = point2(v1[1], -v0[1]) / det;
hyperpoint ca2 = point2(-v1[0], v0[0]) / det;
ld d = (ba2|ba2);
if(d == 0) continue;
ld good = (ca2^ba2)[2] / d;
xes.push_back(good);
}
sort(xes.begin(), xes.end());
if(isize(xes))
cscale = -xes[isize(xes) / 2];
// println(hlog, "cscale = ", cscale);
}
#if CAP_NCONF
void nconf_solve() {
nconf::SY = isize(fmap);
nconf::SX = isize(fmap[0]);
nconf::resize_pt();
for(int y=0; y<nconf::SY; y++)
for(int x=0; x<nconf::SX; x++) {
auto& p = nconf::pts[y][x];
p.type = (nconf::ptype)(fmap[y][x] - '0');
p.side = 0;
}
nconf::pretty_borders = pretty;
nconf::draw_progress = false;
nconf::text_progress = false;
nconf::computemap(nconf::pts);
for(int y=0; y<nconf::SY; y++)
for(int x=0; x<nconf::SX; x++) {
if(fmap[y][x] == '1')
vx[y][x] = nconf::pts[y][x].x[0] * 2 - 1,
vy[y][x] = nconf::pts[y][x].x[1] * 2 - 1;
if(pretty && (fmap[y][x] == '4' || fmap[y][x] == '5'))
vx[y][x] = nconf::pts[y][x].x[0] * 2 - 1;
}
printf("nconf solved\n");
}
#endif
basic_textureinfo nctinf, nctinf2;
vector<glvertex> vs;
bool viewmap = true;
void fix_border() {
int Y = isize(fmap);
int X = isize(fmap[0]);
for(string& s: fmap) for(char& c: s) if(c == '5') c = '4';
coord cc;
for(int y=0; y<Y; y++) for(int x=0; x<X; x++) if(fmap[y][x] == '6') cc = coord{x,y};
int dir = 0;
while(fmap_at(cc+dir) != '1') dir++;
cc = cc + dir;
dir += 2;
while(true) {
if(fmap_at(cc+dir) == '1') cc = cc + dir, dir++;
else {
if(fmap_at(cc+dir) == '4') fmap_at(cc+dir) = '5';
if(fmap_at(cc+dir) == '7') break;
dir--;
}
}
}
void doublemap() {
for(string& s: fmap) {
string res = "";
for(char c: s) res += c, res += c;
s = res;
}
fmap.resize(isize(fmap) * 2);
for(int y=isize(fmap)-1; y>=0; y--) fmap[y] = fmap[y/2];
int Y = isize(fmap);
int X = isize(fmap[0]);
for(int y=Y-1; y>=0; y--) for(int x=X-1; x>=0; x--)
vx[y][x] = vx[y/2][x/2], vy[y][x] = vy[y/2][x/2];
for(int y=0; y<Y; y++) for(int x=0; x<X; x++) {
coord cc{x,y};
auto& us = fmap[y][x];
if(us >= '4') {
bool live = false;
for(int k=0; k<4; k++) if(fmap_at(cc+k) == '1') live = true;
if(!live) us = '0';
}
}
bool found6 = false, found7 = false;
for(int y=0; y<Y; y++) for(int x=0; x<X; x++) {
if(fmap[y][x] == '6') {
if(found6) fmap[y][x] = '4'; else found6 = true;
}
if(fmap[y][x] == '7') {
if(found7) fmap[y][x] = '5'; else found7 = true;
}
fix_border();
}
}
int pointmode;
bool show_mapping = true;
bool show_mgrid = true;
ld mapping_split = .75;
char paintmode;
void changepoint(int x, int y, bool can_add) {
int Y = isize(fmap);
int X = isize(fmap[0]);
if(x < 0 || y < 0 || x >= X || y >= Y) return;
if(pointmode) {
if(fmap[y][x] < '4') return;
for(string& s: fmap) for(char& c: s) if(c == pointmode) c = '4';
fmap[y][x] = pointmode;
fix_border();
return;
}
if(y == 0) {
paintmode = 0;
fmap.emplace_back();
for(int i=Y-1; i>=0; i--) fmap[i+1] = fmap[i];
for(char& c: fmap[0]) c = '0';
}
if(y == Y-1) {
paintmode = 0;
fmap.push_back(fmap[0]);
for(char& c: fmap.back()) c = '0';
}
if(x == 0) {
paintmode = 0;
for(string& s: fmap) s = '0' + s;
}
if(x == X-1) {
paintmode = 0;
for(string& s: fmap) s = s + '0';
}
coord cc{x,y};
auto& us = fmap[y][x];
if(fmap[y][x] >= '4') {
if(fmap[y][x] > '5') {
int q = 0;
for(int k=0; k<4; k++) if(fmap_at(cc+k) == '0') q++;
if(q != 1) return;
}
else {
for(int k=0; k<4; k++) if(fmap_at(cc+k) == (us^ '1')) return;
int q = 0;
for(int k=0; k<4; k++) if(fmap_at(cc+k) >= '4') q++;
if(q > 2) return;
}
for(int k=0; k<4; k++)
if(fmap_at(cc+k) != '1')
if(fmap_at(cc+k+(k+1)) == '1')
if(fmap_at(cc+(k+1)) != '1')
return;
for(int k=0; k<4; k++)
if(fmap_at(cc+k) != '1')
if(fmap_at(cc+k+k) == '1')
if(fmap_at(cc+k+(k+1)) != '1')
if(fmap_at(cc+k+(k-1)) != '1')
return;
if(fmap[y-1][x] == '0') fmap[y-1][x] = us;
if(fmap[y][x-1] == '0') fmap[y][x-1] = us;
if(fmap[y+1][x] == '0') fmap[y+1][x] = us;
if(fmap[y][x+1] == '0') fmap[y][x+1] = us;
us = '1';
}
else if(us == '1') {
int q = 0;
for(int k=0; k<4; k++) if(fmap_at(cc+k) == '1') q++;
if(q == 0) return;
if(q == 4) return;
if(q == 3) {
for(int k=0; k<4; k++) if(fmap_at(cc+k) != '1') {
int nei = 0;
if(fmap_at(cc+k+(k+1)) == '1') nei++;
if(fmap_at(cc+k+(k+3)) == '1') nei++;
if(nei == 2) return;
us = fmap_at(cc+k);
if(nei == 0) fmap_at(cc+k) = '0';
}
return;
}
if(q == 2 && fmap_at(cc+0) == '1' && fmap_at(cc+2) == '1') return;
if(q == 2 && fmap_at(cc+1) == '1' && fmap_at(cc+3) == '1') return;
for(int k=0; k<4; k++) if(fmap_at(cc+k) == '1' && fmap_at(cc+(k+1)) == '1' && fmap_at(cc+k+(k+1)) != '1') return;
bool have4 = false, kill6 = false, kill7 = false, live[4];
for(int k=0; k<4; k++) {
char ch = fmap_at(cc+k);
live[k] = false;
for(int k=0; k<4; k++) {
for(int l=0; l<4; l++) if(k!=(l^2) && fmap_at(cc+k+l) == '1') live[k] = true;
}
switch(ch) {
case '4': have4 = true; break;
case '5': break;
case '6': if(!live[k]) kill6 = true; break;
case '7': if(!live[k]) kill7 = true; break;
};
}
if(kill6 && kill7) return;
if(kill6) us = '6';
else if(kill7) us = '7';
else if(have4) us = '4';
else us = '5';
for(int k=0; k<4; k++) if(!live[k]) fmap_at(cc+k) = '0';
}
}
bool showmenu = true;
void conf_shapes() {
cmode = 0;
dialog::init(XLAT("shapes"));
dialog::addItem("square 11x11", 'a');
dialog::add_action([] { fmap = gensquare(13, 13); reset_vxy(); popScreen(); });
dialog::addItem("rectangle 15x8", 'b');
dialog::add_action([] { fmap = gensquare(15, 8); reset_vxy(); popScreen(); });
dialog::addItem("T-shape", 'c');
dialog::add_action([] { fmap = gent(19, 7); reset_vxy(); popScreen(); });
dialog::addItem("snake", 'd');
dialog::add_action([] { fmap = snake; reset_vxy(); popScreen(); });
dialog::addItem("ellipse 50", 'e');
dialog::add_action([] { fmap = genellipse(50, hrand(180)); reset_vxy(); popScreen(); });
dialog::addBreak(100);
dialog::addBack();
dialog::display();
}
int algo_speed = 10000;
int algo_ticks = 0;
bool in_visualization;
int nconf_pos;
ld steps_to_do;
#define DELTA [] { static int oldticks = ticks; int res = ticks - oldticks; oldticks = ticks; return res; }
auto nconf_delta = DELTA;
#if CAP_NCONF
void nconf_prepare(bool fast) {
// pretend we are solving
nconf_solve();
build_equations(nconf::pts, 1, fast);
nconf_pos = 0;
in_visualization = true;
steps_to_do = 0;
algo_ticks = 0;
nconf_delta();
printf("points: %d\n", isize(nconf::allpoints));
}
void nconf_run() {
int d = nconf_delta();
algo_ticks += d;
steps_to_do += d * algo_speed / 1000.;
while(steps_to_do > 0) {
if(nconf_pos == isize(nconf::allpoints)) { in_visualization = false; break; }
auto co = nconf::allpoints[nconf_pos++];
auto &p = nconf::pts[co];
nconf::eliminate(nconf::pts, co);
printf("point #%d has %d equations\n", nconf_pos-1, hr::isize(p.eqs));
steps_to_do -= pow(hr::isize(p.eqs), 2);
}
}
void pick_algorithm() {
cmode = 0;
dialog::init(XLAT("solving"));
dialog::addItem("iterative/reset", 'r');
dialog::add_action([] { reset_vxy(); algo_ticks = 0; popScreen(); });
dialog::addItem("solve linear equations", 's');
dialog::add_action([] { nconf_solve(); algo_ticks = 0; popScreen(); });
dialog::addItem("visualize (slow)", 'a');
dialog::add_action([] { nconf_prepare(false); popScreen(); });
dialog::addItem("visualize (fast)", 'b');
dialog::add_action([] { nconf_prepare(true); popScreen(); });
dialog::addSelItem("visualization speed", its(algo_speed), 'v');
dialog::add_action([] { dialog::editNumber(algo_speed, 100, 1000000, 0.1, 10000, "", ""), dialog::scaleLog(), dialog::dialogflags = sm::NOSCR; });
dialog::addBreak(50);
dialog::addBoolItem_action("pretty corners", pretty, 'p');
dialog::addBreak(50);
dialog::addBack();
dialog::display();
}
#endif
void ncee_work();
bool animated_pattern = false;
int redraws;
void redraw_texture() {
View = Id;
if(arcm::in()) View = View * spin(45._deg);
dynamicval<int> cgl(vid.cells_generated_limit, 9999999);
dynamicval<int> cdl(vid.cells_drawn_limit, 9999999);
dynamicval<bool> r(mousing, false);
rug::rugged = true;
rug::prepareTexture();
rug::rugged = false;
}
template<class T> void chg_pattern(const T& f) {
tactic::on = true;
autocheat = true;
reptilecheat = true;
stop_game();
set_geometry(gNormal);
set_variation(eVariation::bitruncated);
f();
start_game();
clearMessages();
redraws = 1;
}
void pick_pattern() {
cmode = sm::SIDE | sm::MAYDARK | sm::DIALOG_STRICT_X;
ncee_work();
dialog::init(XLAT("patterns"));
dialog::addItem("green football", 'g');
dialog::add_action([] {
chg_pattern([] {
enable_canvas();
patterns::whichCanvas = 'B';
});
});
dialog::addItem("Goldberg football", 'G');
dialog::add_action([] {
chg_pattern([] {
gp::param.first = 9;
gp::param.second = 0;
set_variation(eVariation::goldberg);
enable_canvas();
patterns::whichCanvas = 'F';
});
});
dialog::addItem("octagons", 'o');
dialog::add_action([] {
chg_pattern([] {
set_geometry(gOctagon);
enable_canvas();
patterns::whichCanvas = 'T';
});
});
dialog::addItem("windy plains", 'w');
dialog::add_action([] {
chg_pattern([] {
firstland = specialland = laWhirlwind;
});
vid.smart_range_detail = 2.5;
});
dialog::addItem("reptiles", 'r');
dialog::add_action([] {
chg_pattern([] {
firstland = specialland = laReptile;
});
});
dialog::addItem("zebra", 'z');
dialog::add_action([] {
chg_pattern([] {
firstland = specialland = laZebra;
});
});
dialog::addItem("colored squares", 's');
dialog::add_action([] {
chg_pattern([] {
set_variation(eVariation::pure);
arcm::current.parse("4^5");
set_geometry(gArchimedean);
enable_canvas();
patterns::whichCanvas = 'A';
});
});
if(specialland == laWhirlwind) {
dialog::addBoolItem_action("animated", animated_pattern, 'a');
}
else dialog::addBreak(100);
dialog::addBreak(50);
dialog::addBack();
dialog::display();
}
namespace ncee_scr {
int X, Y, xc, yc, x0, y0, siz;
}
void draw_ncee() {
using namespace ncee_scr;
auto cd = current_display;
Y = isize(fmap);
X = isize(fmap[0]);
siz = min((cd->ysize / (show_mapping ? 2 : 1) - 5) / Y, showmenu ? (cd->xcenter -5 )*2/X : (cd->xsize - 5) / X);
xc = 0;
yc = vid.yres * (show_mapping ? mapping_split : 1) / 2 - cd->ycenter;
x0 = - int(siz * X / 2);
y0 = - int(siz * Y / 2);
ld period;
if(geometry == gNormal) {
auto cw = heptspin(cwt.at->master, 0);
cw = cw + wstep + 3 + wstep + 5 + wstep;
period = hdist0(tC0(currentmap->relative_matrix(cwt.at, cw.at->c7, C0)));
if(specialland == laWhirlwind)
period *= 9;
if(specialland == laZebra)
period *= 6;
if(specialland == laReptile)
period *= 3;
}
else if(geometry == gOctagon) {
period = 2 * hdist0(tC0(currentmap->adj(cwt.at->master, 0)));
}
else {
period = 2 * hdist0(tC0(currentmap->adj(cwt.at, 0)));
}
period /= 90._deg;
dynamicval<eModel> pm(pmodel, mdPixel);
dynamicval<eGeometry> pg(geometry, gEuclid);
initquickqueue();
nctinf2.texture_id = rug::glbuf->renderedTexture;
nctinf2.tvertices.clear();
ld map_ypos = vid.yres * (mapping_split + 1) / 2 - cd->ycenter;
ld sca2 = (vid.yres * (1-mapping_split) / 2 - 10) / pconf.scale;
if(show_mapping) {
for(int iter=-10; iter<=10; iter++) {
ld maxx = period * pconf.scale / 4;
ld scax = sca2 * maxx / 0.5;
ld xpos = scax * 2 * iter;
curvepoint(hpxy(xpos-scax, map_ypos-sca2));
nctinf2.tvertices.push_back(glhr::makevertex(0.5-maxx, 0, 0));
curvepoint(hpxy(xpos-scax, map_ypos+sca2));
nctinf2.tvertices.push_back(glhr::makevertex(0.5-maxx, 1, 0));
curvepoint(hpxy(xpos+scax, map_ypos-sca2));
nctinf2.tvertices.push_back(glhr::makevertex(0.5+maxx, 0, 0));
curvepoint(hpxy(xpos-scax, map_ypos+sca2));
nctinf2.tvertices.push_back(glhr::makevertex(0.5-maxx, 1, 0));
curvepoint(hpxy(xpos+scax, map_ypos-sca2));
nctinf2.tvertices.push_back(glhr::makevertex(0.5+maxx, 0, 0));
curvepoint(hpxy(xpos+scax, map_ypos+sca2));
nctinf2.tvertices.push_back(glhr::makevertex(0.5+maxx, 1, 0));
}
auto& q = queuecurve(shiftless(Id), 0, show_mgrid ? 0x404040FF : 0xFFFFFFFF, PPR::LINE);
q.tinf = &nctinf2;
q.flags |= POLY_TRIANGLES;
q.offset_texture = 0;
}
auto h = [&] (int x, int y) { return hpxy(x0 + x * siz + xc, y0 + y * siz + yc); };
auto hc = [&] (int x, int y) { return hpxy(x0 + x * siz + siz/2 + xc, y0 + y * siz + siz/2 + yc); };
color_t typecols[8] = {
0x101010FF, 0xD0D0D0FF, 0, 0, 0xF04040FF, 0x4040F0FF, 0xF0F040FF, 0x40F0F0FF
};
for(int x=0; x<X; x++) for(int y=0; y<Y; y++) {
curvepoint(h(x,y));
curvepoint(h(x+1,y));
curvepoint(h(x+1,y+1));
curvepoint(h(x,y+1));
#if CAP_NCONF
bool ineq =
in_visualization && fmap[y][x] == '1';
#endif
queuecurve(shiftless(Id), 0,
#if CAP_NCONF
(ineq && nconf::pts[y][x].state == 1) ? 0xFF8000FF :
(ineq && nconf::pts[y][x].state == 2) ? 0x00FF00FF :
#endif
(fmap[y][x] == '1' && show_mgrid && show_mapping) ? 0x404040FF : typecols[fmap[y][x] - '0'], PPR::LINE);
}
if(inHighQual) for(int x=0; x<X; x++) for(int y=0; y<Y; y++) {
curvepoint(h(x,y));
curvepoint(h(x,y+1));
curvepoint(h(x+1,y+1));
curvepoint(h(x+1,y));
queuecurve(shiftless(Id), 0,
typecols[fmap[y][x] - '0'], PPR::LINE);
}
quickqueue();
initquickqueue();
nctinf.texture_id = rug::glbuf->renderedTexture;
nctinf.tvertices.clear();
static int z = 0;
auto tri = [&] (const array<coord,3>& c) {
int id = -1;
for(int i=0; i<3; i++) if(fmap_at(c[i])) id = i;
if(id == -1) return;
ld delta = (int((vx[c[id].y][c[id].x]) / cscale / period + 1000.5) - 1000) * period;
z = !z;
for(int s=0; s<3; s++) {
curvepoint(hc(c[s].x, c[s].y));
nctinf.tvertices.push_back(glhr::makevertex((vx[c[s].y][c[s].x]/cscale-delta)*pconf.scale/2+.5, vy[c[s].y][c[s].x]*pconf.scale/2+.5, 0));
}
};
if(viewmap && !in_visualization) for(int x=0; x<X-1; x++) for(int y=0; y<Y-1; y++) {
if(fmap[y][x+1] > '0' && fmap[y+1][x] > '0') {
if(fmap[y][x] > '0') tri(make_array(coord{x,y}, coord{x+1,y}, coord{x,y+1}));
if(fmap[y+1][x+1] > '0') tri(make_array(coord{x+1,y+1}, coord{x+1,y}, coord{x,y+1}));
}
else if(fmap[y][x] > '0' && fmap[y+1][x+1] > '0') {
if(fmap[y][x+1] > '0') tri(make_array(coord{x,y}, coord{x+1,y}, coord{x+1,y+1}));
if(fmap[y+1][x] > '0') tri(make_array(coord{x,y}, coord{x,y+1}, coord{x+1,y+1}));
}
}
auto& q = queuecurve(shiftless(Id), 0, (show_mgrid && show_mapping) ? 0x404040FF : 0xFFFFFFFF, PPR::LINE);
q.tinf = &nctinf;
q.flags |= POLY_TRIANGLES;
q.offset_texture = 0;
hyperpoint vmap[256][256];
pair<int, int> mpt = {(mousex - xc - cd->xcenter - x0) / siz, (mousey - yc - cd->ycenter - y0) / siz};
queueline1(h(0,0), h(0,-1), 0x1010101);
const color_t gridcol = 0xFFFFFFFF;
if(inHighQual) ;
else if(show_mapping && show_mgrid && !in_visualization) {
for(int x=0; x<X-1; x++) for(int y=0; y<Y-1; y++)
if(fmap[y][x] > '0')
vmap[y][x] = hpxy(vx[y][x]/cscale * sca2 / 2, vy[y][x] * sca2 / 2+ map_ypos);
for(int x=0; x<X-1; x++) for(int y=0; y<Y-1; y++) {
if(y < Y-2 && fmap[y][x] > '0' && fmap[y+1][x] > '0') {
color_t col = (make_pair(x,y) == mpt || make_pair(x,y+1) == mpt) ? 0xFFFF00FF : gridcol;
dynamicval<ld> lw(vid.linewidth, vid.linewidth * (col == 0xFFFF00FF ? 4 : 1));
queueline1(hc(x, y), hc(x, y+1), col, 0, PPR::CIRCLE);
queueline1(vmap[y][x], vmap[y+1][x], col, 0, PPR::CIRCLE);
}
if(x < X-2 && fmap[y][x] > '0' && fmap[y][x+1] > '0') {
color_t col = (make_pair(x,y) == mpt || make_pair(x+1,y) == mpt) ? 0xFFFF00FF : gridcol;
dynamicval<ld> lw(vid.linewidth, vid.linewidth * (col == 0xFFFF00FF ? 4 : 1));
queueline1(hc(x, y), hc(x+1, y), col, 0, PPR::CIRCLE);
queueline1(vmap[y][x], vmap[y][x+1], col, 0, PPR::CIRCLE);
}
}
}
else {
int x = mpt.first;
int y = mpt.second;
vid.linewidth *= 3;
color_t col = 0;
if(x >= 0 && y >= 0 && x < X && y < Y) {
if(pointmode != 0)
col = 0x00FF00FF;
else if(mousepressed)
col = paintmode == '1' ? 0xFF0000FF : 0xFFFF00FF;
else if(fmap[y][x] == '1')
col = 0xFF0000FF;
else if(fmap[y][x] == '4' || fmap[y][x] == '5')
col = 0xFFFF00FF;
}
queueline1(h(x,y), h(x,y+1), col);
queueline1(h(x,y), h(x+1,y), col);
queueline1(h(x+1,y), h(x+1,y+1), col);
queueline1(h(x,y+1), h(x+1,y+1), col);
vid.linewidth /= 3;
}
for(int x=0; x<=X; x++) queueline1(h(x,0), h(x,Y), 0x80808080);
for(int y=0; y<=Y; y++) queueline1(h(0,y), h(X,y), 0x80808080);
queueline1(h(0,0), h(0,-1), 0x1010101);
quickqueue();
glflush();
}
int ncee_map_prepared;
void prepare_ncee_map() {
ncee_map_prepared = 5;
pmodel = mdBand;
dynamicval<int> cgl(vid.cells_generated_limit, 9999999);
dynamicval<bool> r(rug::display_warning, false);
// vid.consider_shader_projection = false;
pconf.scale = 0.5;
rug::init();
rug::prepareTexture();
rug::rugged = false;
}
void ncee_work() {
if(specialland != laWhirlwind)
animated_pattern = false;
if(redraws > 0) {
redraws--;
vid.consider_shader_projection = false;
redraw_texture();
}
if(animated_pattern) {
vid.consider_shader_projection = true;
redraw_texture();
}
calcparam();
if(ncee_map_prepared < 5) { cmode = sm::NORMAL | sm::DARKEN; ncee_map_prepared++; if(ncee_map_prepared == 5) prepare_ncee_map(); gamescreen(); return; }
#if CAP_NCONF
if(in_visualization)
nconf_run();
else
#endif
iterate();
draw_ncee();
}
void ncee() {
cmode = showmenu ? (sm::SIDE | sm::MAYDARK | sm::DIALOG_STRICT_X) : 0;
ncee_work();
using namespace ncee_scr;
auto cd = current_display;
getcstat = '-';
if(paintmode && mousepressed) {
int x = (mousex - cd->xcenter - xc - x0) / siz;
int y = (mousey - cd->ycenter - yc - y0) / siz;
if(fmap[y][x] == paintmode)
changepoint(x, y, false);
}
if(showmenu) {
dialog::init(XLAT("newconformist"));
dialog::addBoolItem("edit shape", pointmode == 0, 'e');
dialog::addBoolItem("set left end", pointmode == '6', 'a');
dialog::addBoolItem("set right end", pointmode == '7', 'b');
dialog::addBreak(50);
dialog::addBoolItem("show the end result", viewmap, 'm');
dialog::addBoolItem("display the band model", show_mapping, 's');
if(show_mapping)
dialog::addBoolItem("display the grid on model", show_mgrid, 'g');
else
dialog::addBreak(100);
dialog::addBreak(50);
if(show_mapping)
dialog::addSelItem("mapping split", fts(mapping_split), 'y');
else
dialog::addBreak(100);
dialog::addSelItem("double precision", its(isize(fmap[0])) + "x" + its(isize(fmap)), 'd');
#if CAP_NCONF
dialog::addItem("solving method", 'l');
#endif
dialog::addItem("shapes", 't');
dialog::addItem("patterns", 'p');
dialog::addItem("hide the menu", 'v');
dialog::addItem("stop", 'x');
dialog::display();
}
else
displayButton(vid.xres - 8, 8 + vid.fsize, XLAT("(v) menu"), 'v', 16);
if(algo_ticks)
displaystr(8, 8 + vid.fsize, 0, vid.fsize * 2, format("%d.%03d", algo_ticks/1000, algo_ticks%1000), 0xFFFFFF, 0);
keyhandler = [=] (int sym, int uni) {
// dialog::handleNavigation(sym, uni);
if(uni == 'z')
prepare_ncee_map();
if(uni == 'x') {
popScreen();
// rug::rugged = true;
rug::close();
}
if(uni == 'e') pointmode = 0;
if(uni == 'a') pointmode = '6';
if(uni == 'b') pointmode = '7';
#if CAP_NCONF
if(uni == 'l') pushScreen(pick_algorithm);
#endif
if(uni == 'p') pushScreen(pick_pattern);
// if(uni == 'w') edit_whatever('f', 0);
if(uni == 'd') doublemap();
if(uni == 'm') viewmap = !viewmap;
if(uni == 's') show_mapping = !show_mapping;
if(uni == 'g') show_mgrid = !show_mgrid;
if(uni == 't') pushScreen(conf_shapes);
if(uni == 'y') dialog::editNumber(mapping_split, 0, 1, 0.05, 0.75, "", ""), dialog::dialogflags = sm::NOSCR;
if(uni == '-') {
int x = (mousex - cd->xcenter - xc - x0) / siz;
int y = (mousey - cd->ycenter - yc - y0) / siz;
if(x < 0 || y < 0 || x >= X || y >= Y) return;
paintmode = fmap[y][x];
changepoint(x, y, true);
}
if(uni == 'v') showmenu = !showmenu;
if(uni == 'X') {
int D = 100;
fmap = genellipse(D, -10._deg), reset_vxy();
#if CAP_NCONF
nconf_solve();
#endif
iterate();
iterate();
iterate();
int slow = 2;
for(int i=-100; i<180*slow; i++) {
ticks = anims::period * i / 180 / slow;
redraw_texture();
fmap = genellipse(D, i * degree / slow);
println(hlog, "i = ", i);
for(int a=0; a<10; a++) iterate();
if(i >= 0) shot::take(format(rfname.c_str(), i), draw_ncee);
}
}
};
}
extern "C" {
void nconf_view(int i) {
if(i == 1)
show_mapping = false, viewmap = false;
else if(i == 2)
show_mapping = false, viewmap = true;
else if(i == 3)
show_mapping = true, viewmap = true, show_mgrid = true;
else if(i == 4)
showmenu = false;
else if(i == 5)
showmenu = true;
else if(i == 6)
reset_vxy(), algo_ticks = 0;
#if CAP_NCONF
else if(i == 7)
nconf_solve(), algo_ticks = 0;
else if(i == 8)
nconf_prepare(false);
else if(i == 9)
nconf_prepare(true);
#endif
else if(i == 10)
doublemap();
else if(i == 11)
fmap = gensquare(13, 13), reset_vxy();
else if(i == 12)
fmap = gensquare(15, 8), reset_vxy();
else if(i == 13)
fmap = gensquare(19, 7), reset_vxy();
else if(i == 14)
fmap = snake, reset_vxy();
else if(i == 15)
pushScreen(pick_pattern);
}
}
int niceArgs() {
using namespace arg;
if(0) ;
else if(argis("-ncee")) {
PHASE(3);
pushScreen(ncee);
showstartmenu = false;
clearMessages();
}
else if(argis("-ncv")) {
PHASE(3);
shift();
nconf_view(argi());
}
else if(argis("-ncvid")) {
shift(); rfname = args();
}
else return 1;
return 0;
}
auto nhook =
addHook(hooks_args, 100, niceArgs)
+ 0;
}
}