mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-30 20:10:35 +00:00
1011 lines
29 KiB
C++
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;
|
|
|
|
}
|
|
|
|
}
|