1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-24 17:10:36 +00:00

moved SAG, tree and Collatz from rogueviz.cpp to separate files

This commit is contained in:
Zeno Rogue 2020-03-29 13:09:10 +02:00
parent c0f57c28bc
commit 336d04fed8
7 changed files with 136 additions and 1087 deletions

View File

@ -477,6 +477,32 @@ void init_bantar_map() {
}
}
// see: https://twitter.com/ZenoRogue/status/1001127253747658752
// see also: https://twitter.com/ZenoRogue/status/1000043540985057280 (older version)
void bantar_record() {
int TSIZE = rug::texturesize; // recommended 2048
resetbuffer rb;
renderbuffer rbuf(TSIZE, TSIZE, true);
int fr = 0;
for(int i=0; i < 10000; i += 33) {
if(i % 1000 == 999) i++;
ticks = i;
rbuf.enable();
vid.xres = vid.yres = TSIZE;
banachtarski::bantar_frame();
IMAGESAVE(rbuf.render(), ("bantar/" + format("%05d", fr) + IMAGEEXT).c_str());
printf("GL %5d/%5d\n", i, 10000);
fr++;
}
rb.reset();
}
int readArgs() {
using namespace arg;
@ -512,6 +538,15 @@ int readArgs() {
else if(argis("-btry")) {
shift(); notry = argi();
}
else if(argis("-bantar_record")) {
using namespace banachtarski;
PHASE(3);
peace::on = true;
airmap.clear();
ForInfos if(cci.second.c->monst == moAirElemental)
cci.second.c->monst = moFireElemental;
bantar_record();
}
else return 1;
return 0;
}

View File

@ -429,7 +429,7 @@ void create_grigorchuk_geometry() {
gi.shortname = "Grig";
}
int args() {
int readArgsG() {
using namespace arg;
if(0) ;
@ -459,7 +459,7 @@ int args() {
return 0;
}
auto hook = addHook(hooks_args, 100, args)
auto hook = addHook(hooks_args, 100, readArgsG)
+ addHook(hooks_newmap, 100, [] { return geometry == gGrigorchuk ? new hrmap_grigorchuk : nullptr; })
+ addHook(patterns::hooks_generate_canvas, 100, [] (cell* c) {
if(patterns::whichCanvas == 'G' && geometry == gGrigorchuk)

View File

@ -1197,7 +1197,14 @@ void steps() {
}
}
void shift_color(int i) {
whattodraw[i]++;
if(whattodraw[i] == columns) whattodraw[i] = -5;
coloring();
}
void showMenu() {
if(kind != kKohonen) return;
string parts[3] = {"red", "green", "blue"};
for(int i=0; i<3; i++) {
string c;
@ -1209,28 +1216,15 @@ void showMenu() {
else if(whattodraw[i] == -6) c = "sample names to colors";
else c = colnames[whattodraw[i]];
dialog::addSelItem(XLAT("coloring (%1)", parts[i]), c, '1'+i);
dialog::add_action([i] { shift_color(i); });
}
dialog::addItem("coloring (all)", '0');
dialog::addItem("level lines", '4');
}
dialog::add_action([] {
shift_color(0); shift_color(1); shift_color(2);
});
bool handleMenu(int sym, int uni) {
if(uni >= '1' && uni <= '3') {
int i = uni - '1';
whattodraw[i]++;
if(whattodraw[i] == columns) whattodraw[i] = -5;
coloring();
return true;
}
if(uni == '0') {
for(char x: {'1','2','3'}) handleMenu(x, x);
return true;
}
if(uni == '4') {
pushScreen(levelline::show);
return true;
}
return false;
dialog::addItem("level lines", '4');
dialog::add_action_push(levelline::show);
}
void save_compressed(string name) {
@ -1530,8 +1524,17 @@ int readArgs() {
auto hooks = addHook(hooks_args, 100, readArgs);
#endif
bool turn(int delta) {
if(!on) return false;
if(kind == kKohonen) kohonen::steps(), timetowait = 0;
return false;
// shmup::pc[0]->rebase();
}
auto hooks2 = addHook(hooks_frame, 50, levelline::draw)
+ addHook(hooks_mouseover, 100, describe_cell);
+ addHook(hooks_mouseover, 100, describe_cell)
+ addHook(shmup::hooks_turn, 100, turn)
+ addHook(rogueviz::hooks_rvmenu, 100, showMenu);
void clear() {
printf("clearing Kohonen...\n");

View File

@ -15,9 +15,6 @@
// https://bitbucket.org/HaiZhung/hyperbolic-embedder/overview
// (it uses the same format)
// hyper -tol <filename.xml> -- visualize the tree of life,
// based on a XML dump from https://tree.opentreeoflife.org/
// hyper -tess <parameter file> -- visualize a horocyclic tesselation,
#include "../hyper.h"
@ -322,78 +319,6 @@ namespace spiral {
}
}
namespace collatz {
double s2, s3, p2, p3;
double cshift = -1;
transmatrix T2, T3;
edgetype *collatz1, *collatz2;
void start() {
init(); kind = kCollatz;
collatz1 = add_edgetype("1");
collatz2 = add_edgetype("2");
vdata.resize(1);
vertexdata& vd = vdata[0];
createViz(0, cwt.at, xpush(cshift));
virtualRebase(vd.m);
vd.cp = dftcolor;
vd.data = 0;
addedge(0, 0, 1, false, collatz::collatz1);
vd.name = "1";
storeall();
T2 = spin(collatz::s2) * xpush(collatz::p2);
T3 = spin(collatz::s3) * xpush(collatz::p3);
}
void lookup(long long reached, int bits) {
while(reached < (1ll<<bits)) {
if(reached%3 == 2 && (2*reached-1) % 9 && hrand(100) < 50)
reached = (2*reached-1) / 3;
else reached *= 2;
}
printf("reached = %lld\n", reached);
vector<string> seq;
while(reached>1) {
seq.push_back(llts(reached));
if(reached&1) reached += (reached>>1)+1;
else reached >>= 1;
}
// seq.push_back("1");
reverse(seq.begin(), seq.end());
int id = 0;
int next = 0;
int steps = 0;
while(true) {
steps++;
if(std::isnan(View[0][0])) exit(1);
shmup::turn(100);
drawthemap();
centerpc(100); optimizeview();
fixmatrix(View);
bfs(); setdist(cwt.at, 7 - getDistLimit() - genrange_bonus, NULL);
vertexdata& vd = vdata[id];
for(int e=0; e<isize(vd.edges); e++) {
int id2 = vd.edges[e].first;
if(vdata[id2].name == seq[next]) {
id = id2; next++;
cwt.at = vdata[id2].m->base;
if(shmup::on) shmup::pc[0]->base = cwt.at;
if(next == isize(seq)) goto found;
}
}
}
found:
printf("steps = %d\n", steps);
}
}
int readLabel(fhstream& f) {
string s = scan<string>(f);
if(s == "") return -1;
@ -483,575 +408,8 @@ namespace anygraph {
}
namespace tree {
edgetype *tree_edge;
struct treevertex {
int origid;
int parent;
int depth;
int spos, epos;
vector<int> children;
};
vector<treevertex> tol;
void child(int pid, int id) {
if(isize(tol) <= id) tol.resize(id+1);
treevertex& v = tol[id];
v.parent = pid;
tol.push_back(v);
if(pid >= 0) tol[pid].children.push_back(id);
}
void readnode(FILE *f, int pid) {
string lab = "";
while(true) {
int c = fgetc(f);
if(c == EOF) { fprintf(stderr, "Ended prematurely\n"); exit(1); }
if(c == ',') break;
if(c == ')') { int id = getnewid(lab); child(pid, id); return; }
lab += c;
}
int id = getnewid(lab);
child(pid, id);
while(true) {
int c = fgetc(f);
// printf("c=%c at %d/%d\n", c, pid, id);
if(c == EOF) { fprintf(stderr, "Ended prematurely\n"); exit(1); }
if(c == ' ' || c == 10 || c == 13 || c == 9 || c == ',') continue;
else if(c == '(') readnode(f, id);
else if(c == ')') break;
}
}
int xpos;
void spos(int at, int d) {
tol[at].spos = xpos++;
tol[at].depth = d;
for(int i=0; i<isize(tol[at].children); i++)
spos(tol[at].children[i], d+1);
tol[at].epos = ++xpos;
}
void read(string fn) {
fname = fn;
init(); kind = kTree;
tree_edge = add_edgetype("tree edge");
printf("Reading the tree of life...\n");
FILE *f = fopen(fname.c_str(), "rt");
if(!f) { printf("Failed to open tree file: %s\n", fname.c_str()); exit(1); }
if(fgetc(f) != '(') {
printf("Error: bad format\n");
exit(1);
}
readnode(f, -1);
fclose(f);
int N = isize(vdata);
printf("N = %d\n", N);
printf("Assigning spos/epos...\n");
spos(0, 0);
xpos *= 6;
printf("Creating vertices...\n");
for(int i=0; i<N; i++) {
treevertex& lv = tol[i];
vertexdata& vd = vdata[i];
transmatrix h = spin((lv.spos + lv.epos) * M_PI / xpos) * xpush(-1.2 + (log(xpos) - log(lv.epos - lv.spos)));
vd.special = false;
vd.m = new shmup::monster;
vd.m->pid = i;
vd.data = lv.parent;
createViz(i, cwt.at, h);
vd.cp = dftcolor;
if(tol[i].parent >= 0)
addedge(i, tol[i].parent, 1, true, tree_edge);
}
for(int i=0; i<isize(vdata); i++) {
vertexdata& vd = vdata[i];
virtualRebase(vd.m);
}
printf("Clearing the TOL data...\n");
tol.clear();
storeall();
}
}
ld maxweight;
namespace sag {
int sagpar = 0;
enum eSagmode { sagOff, sagHC, sagSA };
eSagmode sagmode; // 0 - off, 1 - hillclimbing, 2 - SA
const char *sagmodes[3] = {"off", "HC", "SA"};
ld temperature = -4;
const int INSNAKE = 117;
int numsnake;
const char *loadfname;
#define MAXSNAKETAB 1000
int sdist[MAXSNAKETAB][MAXSNAKETAB];
int insnaketab = 0;
vector<cell*> snakecells;
vector<int> snakefirst, snakelast;
vector<int> snakenode;
vector<int> snakeid;
vector<int> lpbak;
vector<int> wpbak;
bool snake_enabled;
void setsnake(cellwalker& cw, int i) {
lpbak[i] = cw.at->landparam;
wpbak[i] = cw.at->wparam;
cw.at->landparam = i; cw.at->wparam = INSNAKE;
// cw.at->monst = moWormtail; cw.at->mondir = cw.spin;
snakecells[i] = cw.at;
}
void snakeswitch() {
for(int i=0; i<numsnake; i++) {
cell *c = snakecells[i];
int x;
x = lpbak[i]; lpbak[i] = c->landparam; c->landparam = x;
x = wpbak[i]; wpbak[i] = c->wparam; c->wparam = x;
}
snake_enabled = !snake_enabled;
}
void enable_snake() { if(!snake_enabled) snakeswitch(); }
void disable_snake() { if(snake_enabled) snakeswitch(); }
int snakedist(int i, int j) {
if(i < insnaketab && j < insnaketab) return sdist[i][j];
if(bounded) return celldistance(snakecells[i], snakecells[j]);
int i0 = i, i1 = i, j0 = j, j1 = j;
int cost = 0;
// intersect
while(true) {
if(j0 > i1+1) { j0 = snakefirst[j0], j1 = snakelast[j1]; cost++; }
else if(i0 > j1+1) { i0 = snakefirst[i0], i1 = snakelast[i1]; cost++; }
else if(j1+1 == i0) return cost+1;
else if(i1+1 == j0) return cost+1;
else return cost;
}
}
void initSnake(int n) {
if(bounded) n = isize(currentmap->allcells());
numsnake = n;
snakecells.resize(numsnake);
snakefirst.resize(numsnake);
snakelast.resize(numsnake);
snakenode.resize(numsnake);
lpbak.resize(numsnake);
wpbak.resize(numsnake);
if(bounded) {
for(int i=0; i<n; i++) {
cellwalker cw(currentmap->allcells()[i], 0);
setsnake(cw, i);
}
}
else {
cellwalker cw = cwt;
setsnake(cw, 0);
cw += wstep;
setsnake(cw, 1);
for(int i=2; i<=numsnake; i++) {
if(i == numsnake && sphere) break;
cw += wstep;
snakefirst[i-1] = cw.at->landparam;
while(cw.at->wparam == INSNAKE) {
snakelast[i-1] = cw.at->landparam;
cw = cw + wstep + 1 + wstep;
}
if(i == numsnake) break;
setsnake(cw, i); cw += 1;
}
}
int stab = min(numsnake, MAXSNAKETAB);
for(int i=0; i<stab; i++)
for(int j=0; j<stab; j++)
sdist[i][j] = snakedist(i,j);
insnaketab = stab;
snake_enabled = true;
}
double costat(int vid, int sid) {
if(vid < 0) return 0;
double cost = 0;
vertexdata& vd = vdata[vid];
for(int j=0; j<isize(vd.edges); j++) {
edgeinfo *ei = vd.edges[j].second;
int t2 = vd.edges[j].first;
if(snakeid[t2] != -1) cost += snakedist(sid, snakeid[t2]) * ei->weight2;
}
/* cell *c = snakecells[id];
for(int i=0; i<c->type; i++) {
cell *c2 = c->move(i);
if(c2 && c2->wparam == INSNAKE && snakenode[c2->landparam] >= 0)
cost += 100;
} */
return cost;
}
// std::mt19937 los;
bool infullsa;
double cost;
int N;
vector<double> chgs;
edgetype *sag_edge;
void forgetedges(int id) {
for(int i=0; i<isize(vdata[id].edges); i++)
vdata[id].edges[i].second->orig = NULL;
}
bool chance(double p) {
p *= double(hrngen.max()) + 1;
auto l = hrngen();
auto pv = (decltype(l)) p;
if(l < pv) return true;
if(l == pv) return chance(p-pv);
return false;
}
void saiter() {
aiter:
int t1 = hrand(N);
int sid1 = snakeid[t1];
int sid2;
int s = hrand(6);
if(s == 3) s = 2;
if(s == 4) s = 5;
if((sagpar&1) && (s == 2 || s == 3 || s == 4)) return;
if(s == 5) sid2 = hrand(numsnake);
else {
cell *c;
if(s>=2 && isize(vdata[t1].edges)) c = snakecells[snakeid[hrand(isize(vdata[t1].edges))]];
else c = snakecells[sid1];
int it = s<2 ? (s+1) : s-2;
for(int ii=0; ii<it; ii++) {
int d = hrand(c->type);
c = c->move(d);
if(!c) goto aiter;
if(c->wparam != INSNAKE) goto aiter;
}
sid2 = c->landparam;
}
int t2 = snakenode[sid2];
snakenode[sid1] = -1; snakeid[t1] = -1;
snakenode[sid2] = -1; if(t2 >= 0) snakeid[t2] = -1;
double change =
costat(t1,sid2) + costat(t2,sid1) - costat(t1,sid1) - costat(t2,sid2);
snakenode[sid1] = t1; snakeid[t1] = sid1;
snakenode[sid2] = t2; if(t2 >= 0) snakeid[t2] = sid2;
if(change < 0) chgs.push_back(-change);
if(change > 0 && (sagmode == sagHC || !chance(exp(-change * exp(-temperature))))) return;
snakenode[sid1] = t2; snakenode[sid2] = t1;
snakeid[t1] = sid2; if(t2 >= 0) snakeid[t2] = sid1;
if(vdata[t1].m) vdata[t1].m->base = snakecells[sid2];
if(t2 >= 0 && vdata[t2].m) vdata[t2].m->base = snakecells[sid1];
cost += 2*change;
if(t1 >= 0) forgetedges(t1);
if(t2 >= 0) forgetedges(t2);
}
void organize() {
for(int i=0; i<numsnake; i++) snakenode[i] = -1;
vector<int> freenodes;
for(int i=0; i<N; i++)
if(snakeid[i] != -1)
snakenode[snakeid[i]] = i;
for(int i=0; i<N; i++)
if(snakeid[i] != -1)
if(snakenode[snakeid[i]] != i)
snakeid[i] = -1;
for(int i=0; i<numsnake; i++)
if(snakenode[i] == -1)
freenodes.push_back(i);
int j = 0;
for(int i=0; i<N; i++)
if(snakeid[i] == -1) {
snakeid[i] = freenodes[j];
snakenode[freenodes[j]] = i;
j++;
}
cost = 0; for(int i=0; i<N; i++) cost += costat(i, i);
}
void loadsnake(const string& fname) {
printf("Loading the sag from: %s\n", fname.c_str());
FILE *sf = fopen(fname.c_str(), "rt");
if(!sf) { printf("Failed to open file.\n"); exit(1); }
if(sf) while(true) {
string lab;
while(true) {
int c = fgetc(sf);
if(c == EOF) goto afterload;
else if(c == 10 || c == 13 || c == 32 || c == 9) ;
else if(c == ',' || c == ';') break;
else lab += c;
}
int sid = -1;
int err = fscanf(sf, "%d", &sid);
if(sid < 0 || sid >= numsnake || err < 1) sid = -1;
if(!labeler.count(lab)) {
printf("unknown vertex: %s\n", lab.c_str());
}
else {
int id = getid(lab);
snakeid[id] = sid;
}
}
afterload:
if(sf) fclose(sf);
organize();
for(int i=0; i<N; i++) {
if(vdata[i].m) vdata[i].m->base = snakecells[sag::snakeid[i]];
forgetedges(i);
}
shmup::fixStorage();
}
vector<edgeinfo> sagedges;
/* bool totcmp(int i, int j) {
return totwei[i] > totwei[j];
} */
int ipturn = 100;
int numiter = 0;
int hightemp = 10;
int lowtemp = -15;
void dofullsa(int satime) {
sagmode = sagSA;
enable_snake();
int t1 = SDL_GetTicks();
while(true) {
int t2 = SDL_GetTicks();
double d = (t2-t1) / (1000. * satime);
if(d > 1) break;
temperature = hightemp - (d*(hightemp-lowtemp));
chgs.clear();
for(int i=0; i<50000; i++) {
numiter++;
sag::saiter();
}
DEBB(DF_LOG, (format("it %8d temp %6.4f [1/e at %13.6f] cost = %f ",
numiter, double(sag::temperature), (double) exp(sag::temperature),
double(sag::cost))));
sort(chgs.begin(), chgs.end());
int cc = chgs.size() - 1;
DEBB(DF_LOG, (format("%9.4f .. %9.4f .. %9.4f .. %9.4f .. %9.4f\n",
double(chgs[0]), double(chgs[cc/4]), double(chgs[cc/2]), double(chgs[cc*3/4]), double(chgs[cc]))));
fflush(stdout);
}
temperature = -5;
disable_snake();
sagmode = sagOff;
}
void iterate() {
if(!sagmode) return;
int t1 = SDL_GetTicks();
enable_snake();
for(int i=0; i<ipturn; i++) {
numiter++;
sag::saiter();
}
disable_snake();
int t2 = SDL_GetTicks();
int t = t2 - t1;
if(t < 50) ipturn *= 2;
else if(t > 200) ipturn /= 2;
else ipturn = ipturn * 100 / t;
DEBB(DF_LOG, ("it %8d temp %6.4f [2:%8.6f,10:%8.6f,50:%8.6f] cost = %f\n",
numiter, double(sag::temperature),
(double) exp(-2 * exp(-sag::temperature)),
(double) exp(-10 * exp(-sag::temperature)),
(double) exp(-50 * exp(-sag::temperature)),
(double) sag::cost));
}
void savesnake(const string& fname) {
FILE *f = fopen(fname.c_str(), "wt");
for(int i=0; i<N; i++)
fprintf(f, "%s;%d\n", vdata[i].name.c_str(), snakeid[i]);
fclose(f);
}
void loglik() {
int indist[30], pedge[30];
for(int d=0; d<30; d++) indist[d] = 0, pedge[d] = 0;
for(int i=0; i<N; i++)
for(int j=0; j<i; j++)
indist[snakedist(snakeid[i], snakeid[j])]++;
for(int i=0; i<isize(sagedges); i++) {
edgeinfo& ei = sagedges[i];
if(snakedist(snakeid[ei.i], snakeid[ei.j]) == 0) {
printf("zero between %d (%s) and %d (%s)\n",
snakeid[ei.i], vdata[ei.i].name.c_str(),
snakeid[ei.j], vdata[ei.j].name.c_str());
}
if(ei.weight >= sag_edge->visible_from)
pedge[snakedist(snakeid[ei.i], snakeid[ei.j])]++;
}
for(int d=0; d<30; d++)
if(indist[d])
printf("%2d: %7d/%7d %7.3lf\n",
d, pedge[d], indist[d], double(pedge[d] * 100. / indist[d]));
ld loglik = 0;
for(int d=0; d<30; d++) {
int p = pedge[d], pq = indist[d];
int q = pq - p;
if(p && q)
loglik += p * log(p) + q * log(q) - pq * log(pq);
}
println(hlog, "loglikelihood = ", fts(loglik));
}
void readsag(const char *fname) {
maxweight = 0;
sag_edge = add_edgetype("SAG edge");
fhstream f(fname, "rt");
if(!f.f) { printf("Failed to open SAG file: %s\n", fname); exit(1); }
// while(fgetc(f) != 10 && fgetc(f) != 13 && !feof(f)) ;
while(!feof(f.f)) {
string l1, l2;
while(true) {
int c = fgetc(f.f);
if(c == EOF) return;
else if(c == ';') break;
else if(c == 10 || c == 13 || c == 32 || c == 9) ;
else l1 += c;
}
while(true) {
int c = fgetc(f.f);
if(c == EOF) return;
else if(c == ';') break;
else if(c == 10 || c == 13 || c == 32 || c == 9) ;
else l2 += c;
}
ld wei;
if(!scan(f, wei)) continue;
edgeinfo ei(sag_edge);
ei.i = getid(l1);
ei.j = getid(l2);
ei.weight = wei;
sagedges.push_back(ei);
}
}
ld edgepower=1, edgemul=1;
void read(string fn) {
fname = fn;
init(); kind = kSAG;
temperature = 0; sagmode = sagOff;
readsag(fname.c_str());
N = isize(vdata);
// totwei.resize(N);
// for(int i=0; i<N; i++) totwei[i] = 0;
for(int i=0; i<N; i++) vdata[i].data = 0;
/* for(int i=0; i<isize(sagedges); i++) {
edgeinfo& ei = sagedges[i];
// maxwei[ei.i] = max(maxwei[ei.i], ei.weight);
// maxwei[ei.j] = max(maxwei[ei.j], ei.weight);
// totwei[ei.i] += ei.weight;
// totwei[ei.j] += ei.weight;
} */
for(int i=0; i<isize(sagedges); i++) {
edgeinfo& ei = sagedges[i];
// (ei.weight >= maxwei[ei.i] / 5 || ei.weight >= maxwei[ei.j] / 5);
ei.weight2 = pow((double) ei.weight, (double) edgepower) * edgemul;
// LANG:: pow(ei.weight, .4) / 50;
// ei.weight2 = 0; int w = ei.weight; while(w) { w >>= 1; ei.weight2++; }
/* if(totwei[ei.i] <= 0 || totwei[ei.j] <= 0) {
printf("BAD TOTWEI\n");
exit(1);
}
ei.weight2 = 3 * (
sqrt(ei.weight * 1. / totwei[ei.i]) * log(totwei[ei.i]) * log(totwei[ei.i]) +
sqrt(ei.weight * 1. / totwei[ei.j]) * log(totwei[ei.j]) * log(totwei[ei.j])); */
// printf("%f\n", ei.weight2);
addedge0(ei.i, ei.j, &ei);
}
initSnake(N*2);
printf("numsnake = %d\n", numsnake);
if(numsnake < N) {
printf("Error: snake does not fit\n");
exit(1);
}
snakeid.resize(N);
for(int i=0; i<N; i++) snakeid[i] = -1;
organize();
disable_snake();
for(int i=0; i<N; i++) {
int ii = i;
vertexdata& vd = vdata[ii];
vd.cp = colorpair(dftcolor);
createViz(ii, sag::snakecells[sag::snakeid[i]], Id);
}
storeall();
}
}
bool edgecmp(edgeinfo *e1, edgeinfo *e2) {
return e1->weight > e2->weight;
}
@ -1464,66 +822,8 @@ bool drawVertex(const transmatrix &V, cell *c, shmup::monster *m) {
}
}
if(kind == kCollatz) {
if(c->cpdist > 7 && euclid) ;
else if(vd.data == 2) {
// doubler vertex
string s = vd.name;
colorpair cp = vd.cp;
vd.data = 20;
int i0 = isize(vdata);
vdata.resize(i0+1);
vertexdata& vdn = vdata[i0];
createViz(i0, m->base, m->at * collatz::T2);
virtualRebase(vdn.m);
vdn.cp = perturb(cp);
vdn.data = 0;
addedge(i, i0, 1, false, collatz::collatz1);
vdn.m->store();
int carry = 0;
string s2 = s;
for(int i=isize(s2)-1; i>=0; i--) {
int x = 2*(s2[i] - '0') + carry;
carry = x>=10;
if(carry) x-=10;
s2[i] = '0'+x;
}
if(carry) s2 = "1" + s2;
vdn.name = s2;
int m3 = 0;
for(int i=0; i<isize(s); i++) m3 += s[i] - '0';
if(m3 % 3 == 2 && s != "2" && s != "1") {
vdata.resize(i0+2);
vertexdata& vdn = vdata[i0+1];
createViz(i0+1, m->base, m->at * collatz::T3);
virtualRebase(vdn.m);
vdn.cp = perturb(cp);
vdn.data = 0;
addedge(i, i0+1, 1, false, collatz::collatz2);
vdn.m->store();
int carry = -1;
string s2 = s;
for(int i=isize(s2)-1; i>=0; i--) {
carry += 2 * (s2[i] - '0');
int ncarry = 0;
while(carry % 3) carry += 10, ncarry--;
if(carry >= 30) carry -= 30, ncarry += 3;
s2[i] = '0'+carry/3;
carry = ncarry;
}
if(s2[0] == '0') s2 = s2.substr(1);
vdn.name = s2;
vdn.cp = perturb(vdn.cp);
}
}
else if(vd.data < 2) {
vd.data++;
fixmatrix(vd.m->at);
}
}
if(kind == kCollatz)
collatz::act(vd, c, m, i);
return true;
}
@ -1723,6 +1023,8 @@ void init() {
int search_for = -1;
purehookset hooks_close;
void close() {
search_for = -1;
for(int i=0; i<isize(vdata); i++)
@ -1733,20 +1035,12 @@ void close() {
for(int i=0; i<isize(edgeinfos); i++) delete edgeinfos[i];
edgeinfos.clear();
anygraph::coords.clear();
sag::sagedges.clear();
callhooks(hooks_close);
edgetypes.clear();
on = false;
relmatrices.clear();
}
bool turn(int delta) {
if(!on) return false;
if(kind == kSAG) sag::iterate(), timetowait = 0;
if(kind == kKohonen) kohonen::steps(), timetowait = 0;
return false;
// shmup::pc[0]->rebase();
}
#ifndef CAP_RVSLIDES
#define CAP_RVSLIDES (CAP_TOUR && !ISWEB)
#endif
@ -1771,65 +1065,6 @@ int readArgs() {
shift(); dftcolor = parse(args());
}
// tree visualizer (e.g. Tree of Life)
//-------------------------------------
else if(argis("-tree")) {
PHASE(3); shift(); tree::read(args());
}
// SAG visualizer (e.g. Reddit roguelikes, GitHub languages)
//-----------------------------------------------------------
// (1) configure edge weights
else if(argis("-edgepower")) {
shift_arg_formula(sag::edgepower);
shift_arg_formula(sag::edgemul);
}
// (1) configure temperature (high, low)
else if(argis("-sagtemp")) {
shift(); sag::hightemp = argi();
shift(); sag::lowtemp = argi();
}
else if(argis("-sagmin")) {
shift_arg_formula(default_edgetype.visible_from);
default_edgetype.visible_from_hi = default_edgetype.visible_from;
default_edgetype.visible_from_help = default_edgetype.visible_from;
}
else if(argis("-sagminhi")) {
shift_arg_formula(default_edgetype.visible_from_hi);
}
else if(argis("-sagminhelp")) {
shift_arg_formula(default_edgetype.visible_from_help);
}
// (2) read the edge data
else if(argis("-sagpar")) {
PHASE(3);
shift();
sag::sagpar = argi();
}
else if(argis("-sag")) {
PHASE(3);
shift(); sag::read(args());
}
// (3) load the initial positioning
else if(argis("-gload")) {
PHASE(3); shift(); sag::loadsnake(args());
}
// (4) perform simulated annealing: -fullsa <time in seconds>
else if(argis("-fullsa")) {
shift(); sag::dofullsa(argi());
}
// (5) save the positioning
else if(argis("-gsave")) {
PHASE(3); shift(); sag::savesnake(args());
}
// (6) output loglikelihood
else if(argis("-lik")) {
sag::loglik();
}
// graph visualizer
//------------------
@ -1845,38 +1080,6 @@ int readArgs() {
// example commandline:
// -spiral 2,10000 -spiraledge 0,2 -spiraledge 1,1 -lab -spiralcolor 2 FF4040FF
else if(argis("-collatz")) {
PHASE(3);
using namespace collatz;
shift(); sscanf(argcs(), "%lf,%lf,%lf,%lf", &s2, &p2, &s3, &p3);
start();
}
else if(argis("-collatz-go")) {
if(kind != kCollatz) { printf("not in Collatz\n"); throw hr_exception(); }
shift(); int i = argi(); shift(); int j = argi();
if(i <= 0) i = 763;
if(j < 0 || j > 61) j = 61;
collatz::lookup(i, j);
}
else if(argis("-collatz3")) {
PHASE(3);
using namespace collatz;
s2 = p2 = s3 = p3 = 0;
start();
transmatrix *T = &T2;
while(true) {
lshift();
if(arg::nomore()) break;
else if(argis("fd")) { shift(); *T = *T * xpush(argf()); }
else if(argcs()[0] == 't') { int x = dimid(argcs()[1]); int y = dimid(argcs()[2]); shift(); *T = *T * hr::cspin(x, y, argf()); }
else if(argis("/")) { if(T == &T2) T = &T3; else break; }
else break;
}
unshift();
}
else if(argis("-spiral")) {
PHASE(3);
ld mul = 2;
@ -1944,9 +1147,6 @@ int readArgs() {
else if(argis("-ggamma")) {
shift(); ggamma = argf();
}
else if(argis("-cshift")) {
shift_arg_formula(collatz::cshift);
}
else if(argis("-rvwarp")) {
patterns::whichShape = '8';
}
@ -2075,6 +1275,8 @@ void showVertexSearch() {
}
purehookset hooks_rvmenu;
void showMenu() {
if(staircase::on) { staircase::showMenu(); return; }
cmode = sm::SIDE | sm::MAYDARK | sm::DIALOG_STRICT_X;
@ -2082,51 +1284,37 @@ void showMenu() {
dialog::init(XLAT("rogueviz configuration"));
dialog::addSelItem(XLAT("temperature"), fts(sag::temperature), 't');
if(kind == kSAG)
dialog::addSelItem(XLAT("SAG mode"), sag::sagmodes[sag::sagmode], 'm');
dialog::addBoolItem(XLAT("show labels"), showlabels, 'l');
dialog::addBoolItem(XLAT("mark special vertices"), specialmark, 'x');
dialog::addBoolItem_action(XLAT("show labels"), showlabels, 'l');
dialog::addBoolItem_action(XLAT("mark special vertices"), specialmark, 'x');
dialog::addSelItem(XLAT("background color"), itsh(backcolor), 'b');
if(isize(edgetypes))
dialog::add_action_push([] {backcolor ^= 0xFFFFFF, bordcolor ^= 0xFFFFFF, forecolor ^= 0xFFFFFF; });
if(isize(edgetypes)) {
dialog::addSelItem(XLAT("edge types"), its(isize(edgetypes)), 'g');
dialog::addBoolItem(XLAT("vertices in 3D"), rog3, 'v');
dialog::add_action_push(configure_edge_display);
}
dialog::addBoolItem_action(XLAT("vertices in 3D"), rog3, 'v');
dialog::addSelItem(XLAT("vertex shape"), its(vertex_shape), 'w');
dialog::add_action_push([] { vertex_shape = (1 + vertex_shape) & 3; });
dialog::add_key_action('z', [] {
for(int i=0; i<isize(named)-1; i++) if(named[i] == cwt.at)
swap(named[i], named[i+1]);
if(!isize(named) || named[isize(named)-1] != cwt.at) named.push_back(cwt.at);
printf("named = %d\n", isize(named));
popScreen();
});
dialog::addItem(XLAT("vertex search"), '/');
dialog::add_action_push(showVertexSearch);
if(kind == kKohonen)
kohonen::showMenu();
dialog::addBreak(50);
callhooks(hooks_rvmenu);
dialog::addBreak(50);
dialog::addBack();
dialog::display();
keyhandler = [] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni == 't')
dialog::editNumber(sag::temperature, sag::lowtemp, sag::hightemp, 1, 0, XLAT("temperature"), "");
else if(uni == 'm') {
sag::sagmode = sag::eSagmode( (1+sag::sagmode) % 3 );
}
else if(uni == 'l') showlabels = !showlabels;
else if(uni == 'v') rog3 = !rog3;
else if(uni == 'w') vertex_shape = (1 + vertex_shape) & 3;
else if(uni == 'x') specialmark = !specialmark;
else if(uni == 'b') backcolor ^= 0xFFFFFF, bordcolor ^= 0xFFFFFF, forecolor ^= 0xFFFFFF;
else if(uni == 'g') pushScreen(configure_edge_display);
else if(uni == 'z') {
for(int i=0; i<isize(named)-1; i++) if(named[i] == cwt.at)
swap(named[i], named[i+1]);
if(!isize(named) || named[isize(named)-1] != cwt.at) named.push_back(cwt.at);
printf("named = %d\n", isize(named));
popScreen();
}
else if(kind == kKohonen && kohonen::handleMenu(sym, uni)) ;
else if(doexiton(sym, uni)) popScreen();
};
}
#if CAP_RVSLIDES
@ -2445,7 +1633,6 @@ auto hooks =
addHook(hooks_prestats, 100, rogueviz_hud) +
addHook(shmup::hooks_draw, 100, drawVertex) +
addHook(shmup::hooks_describe, 100, describe_monster) +
addHook(shmup::hooks_turn, 100, turn) +
addHook(shmup::hooks_kill, 100, activate) +
addHook(hooks_o_key, 100, o_key) +
addHook(dialog::hooks_display_dialog, 100, [] () {
@ -2480,7 +1667,6 @@ auto hooks =
#include "kohonen.cpp"
#include "staircase.cpp"
#include "banachtarski.cpp"
#include "video.cpp"
#include "pentagonal.cpp"
#include "functions.cpp"
#include "fundamental.cpp"
@ -2492,3 +1678,6 @@ auto hooks =
#include "grigorchuk.cpp"
#include "qtm.cpp"
#include "rewriting.cpp"
#include "sag.cpp"
#include "collatz.cpp"
#include "tree.cpp"

View File

@ -1,3 +1,5 @@
#ifndef _ROGUEVIZ_H_
#define _ROGUEVIZ_H_
// See: http://www.roguetemple.com/z/hyper/rogueviz.php
namespace rogueviz {
@ -115,7 +117,12 @@ namespace rogueviz {
}
extern colorpair dftcolor;
namespace collatz { extern double s2, s3, p2, p3; void start(); }
namespace collatz {
extern double s2, s3, p2, p3;
void start();
void act(vertexdata&, cell*, shmup::monster*, int);
void lookup(long long reached, int bits);
}
namespace tree { void read(string fn); }
namespace sag { extern ld edgepower, edgemul;
void read(string fn);
@ -130,3 +137,4 @@ namespace rogueviz {
void createViz(int id, cell *c, transmatrix at);
}
#endif

View File

@ -290,6 +290,40 @@ void showMenu() {
};
}
// see: https://www.youtube.com/watch?v=HZNRo6mr5pk
void staircase_video(int from, int num, int step) {
int TSIZE = rug::texturesize; // recommended 4096
resetbuffer rb;
renderbuffer rbuf(TSIZE, TSIZE, true);
vid.stereo_mode = sODS;
for(int i=from; i<num; i+=step) {
ld t = i * 1. / num;
t = pow(t, .3);
staircase::scurvature = t * t * (t-.95) * 4;
staircase::progress = i / 30.;
staircase::strafex = (sin(i / 240.) - sin(i / 501.)) / 2.5;
staircase::strafey = (cos(i / 240.) - cos(i / 501.)) / 2.5;
staircase::make_staircase();
rbuf.enable();
dynamicval<int> vx(vid.xres, TSIZE);
dynamicval<int> vy(vid.yres, TSIZE);
dynamicval<int> vxc(current_display->xcenter, TSIZE/2);
dynamicval<int> vyc(current_display->ycenter, TSIZE/2);
printf("draw scene\n");
rug::drawRugScene();
IMAGESAVE(rbuf.render(), ("staircase/" + format("%05d", i) + IMAGEEXT).c_str());
printf("GL %5d/%5d\n", i, num);
}
rb.reset();
}
#if CAP_COMMANDLINE
int readArgs() {
using namespace arg;
@ -302,6 +336,10 @@ int readArgs() {
pushScreen(showMenu);
}
else if(argis("-staircase_video")) {
staircase_video(0, 128*30, 1); // goal: 168*30
}
else return 1;
return 0;
}

View File

@ -1,224 +0,0 @@
// RogueViz -- source code for creating videos and animations
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
namespace rogueviz {
#if CAP_SDL && CAP_SHOT
// see: https://www.youtube.com/watch?v=4Vu3F95jpQ4&t=6s (Collatz)
// see: https://www.youtube.com/watch?v=mDG3_f8R2Ns (SAG boardgames)
// see: https://www.youtube.com/watch?v=WSyygk_3j9o (SAG roguelikes)
// see: https://www.youtube.com/watch?v=HWQkDkeEUeM (SAG programming languages)
void rvvideo(const string &fname) {
if(kind == kCollatz) {
sightrange_bonus = 3;
genrange_bonus = 3;
dronemode = true; vid.camera_angle = -45; rog3 = true; patterns::whichShape = '8';
vid.aurastr = 512;
collatz::lookup(763, 60);
history::create_playerpath(), models::rotation = 1;
// pmodel = mdBand;
#define STORYCOUNT 24
#define T(m,ss) (60*24*(m)+24*(ss))
#define FRAMECOUNT T(4,55)
printf("framecount = %d\n", FRAMECOUNT);
struct storydata { int s; int e; const char *text; } story[] = {
{T(0,14), T(0,17), "I am flying above a tree of numbers."},
{T(0,17), T(0,20), "It starts with the number 1."},
{T(0,20), T(0,23), "Each number n branches left to 2n."},
{T(0,23), T(0,28), "And it branches right to (2n-1)/3 if possible."},
{T(1, 8), T(1,11), "What I am flying above is not a plane."},
{T(1,11), T(1,14), "It is not a sphere either."},
{T(1,14), T(1,17), "To be honest, the space I live in..."},
{T(1,17), T(1,20), "...is not even Euclidean."},
{T(2,12), T(2,15), "Look, angles of a triangle add up to..."},
{T(2,15), T(2,18), "...less than 180 degrees in this world."},
{T(2,18), T(2,21), "6/7 of 180 degrees, to be exact."},
{T(2,21), T(2,24), "Do you see the regular heptagons?"},
{T(2,36), T(2,42), "And all these lines are straight."},
{T(3, 8), T(3,11), "Lots of space in my world."},
{T(3,11), T(3,14), "In 105 steps from the root..."},
{T(3,14), T(3,17), "...there are trillions of numbers."},
{T(3,17), T(3,20), "That would not fit in your world."},
{T(4,0), T(4,3), "Is every positive number somewhere in the tree?"},
{T(4,3), T(4,6), "Your mathematicians do not know this yet."},
{T(4,6), T(4,10), "Will you find the answer?"},
{T(4,44), T(4,54), "music: Ambient Flow, by Indjenuity"},
{T(2,6), T(2,27), "@triangles"},
{T(2,27), T(2,42), "@network"},
{0, T(0,7), "@fi"},
{T(4,48), T(4,55), "@fo"},
{0,0,NULL}
};
int drawtris=0, drawnet=0;
for(int i=0; i<FRAMECOUNT; i++) {
const char *caption = NULL;
int fade = 255;
bool dt = false, dn = false;
for(int j=0; story[j].text; j++) if(i >= story[j].s && i <= story[j].e) {
if(story[j].text[0] != '@')
caption = story[j].text;
else if(story[j].text[1] == 't')
dt = true;
else if(story[j].text[1] == 'n')
dn = true;
else if(story[j].text[2] == 'i')
fade = 255 * (i - story[j].s) / (story[j].e-story[j].s);
else if(story[j].text[2] == 'o')
fade = 255 * (story[j].e - i) / (story[j].e-story[j].s);
}
if(dt && drawtris < 255) drawtris++;
else if(drawtris && !dt) drawtris--;
linepatterns::patZebraTriangles.color = 0x40FF4000 + drawtris;
if(dn && drawnet < 255) drawnet++;
else if(drawnet && !dn) drawnet--;
linepatterns::patZebraLines.color = 0xFF000000 + drawnet;
vid.grid = drawnet;
history::phase = 1 + (isize(history::v)-3) * i * .95 / FRAMECOUNT;
history::movetophase();
char buf[500];
snprintf(buf, 500, fname.c_str(), i);
if(i == 0) drawthemap();
shmup::turn(100);
printf("%s\n", buf);
shot::shoty = 1080; shot::shotx = 1920;
shot::caption = caption;
shot::fade = fade;
shot::take(buf);
}
return;
}
for(int i=0; i<1800; i++) {
char buf[500];
snprintf(buf, 500, fname.c_str(), i);
shmup::pc[0]->base = currentmap->gamestart();
shmup::pc[0]->at = spin(i * 2 * M_PI / (58*30.)) * xpush(1.7);
if(i == 0) drawthemap();
shmup::turn(100);
if(i == 0) drawthemap();
centerpc(100);
printf("%s\n", buf);
shot::take(buf);
}
}
string its05(int i) { char buf[64]; sprintf(buf, "%05d", i); return buf; }
#define TSIZE 4096
// see: https://www.youtube.com/watch?v=HZNRo6mr5pk
void staircase_video(int from, int num, int step) {
resetbuffer rb;
renderbuffer rbuf(TSIZE, TSIZE, true);
vid.stereo_mode = sODS;
for(int i=from; i<num; i+=step) {
ld t = i * 1. / num;
t = pow(t, .3);
staircase::scurvature = t * t * (t-.95) * 4;
staircase::progress = i / 30.;
staircase::strafex = (sin(i / 240.) - sin(i / 501.)) / 2.5;
staircase::strafey = (cos(i / 240.) - cos(i / 501.)) / 2.5;
staircase::make_staircase();
rbuf.enable();
dynamicval<int> vx(vid.xres, TSIZE);
dynamicval<int> vy(vid.yres, TSIZE);
dynamicval<int> vxc(current_display->xcenter, TSIZE/2);
dynamicval<int> vyc(current_display->ycenter, TSIZE/2);
printf("draw scene\n");
rug::drawRugScene();
IMAGESAVE(rbuf.render(), ("staircase/" + its05(i) + IMAGEEXT).c_str());
printf("GL %5d/%5d\n", i, num);
}
rb.reset();
}
#undef TSIZE
#define TSIZE 2048
// see: https://twitter.com/ZenoRogue/status/1001127253747658752
// see also: https://twitter.com/ZenoRogue/status/1000043540985057280 (older version)
void bantar_record() {
resetbuffer rb;
renderbuffer rbuf(TSIZE, TSIZE, true);
int fr = 0;
for(int i=0; i < 10000; i += 33) {
if(i % 1000 == 999) i++;
ticks = i;
rbuf.enable();
vid.xres = vid.yres = TSIZE;
banachtarski::bantar_frame();
IMAGESAVE(rbuf.render(), ("bantar/" + its05(fr) + IMAGEEXT).c_str());
printf("GL %5d/%5d\n", i, 10000);
fr++;
}
rb.reset();
}
#undef TSIZE
#if CAP_COMMANDLINE
int videoArgs() {
using namespace arg;
if(argis("-rvvideo")) {
shift(); rvvideo(arg::args());
}
else if(argis("-staircase_video")) {
staircase_video(0, 128*30, 1); // goal: 168*30
}
else if(argis("-bantar_record")) {
using namespace banachtarski;
PHASE(3);
peace::on = true;
airmap.clear();
ForInfos if(cci.second.c->monst == moAirElemental)
cci.second.c->monst = moFireElemental;
bantar_record();
}
else return 1;
return 0;
}
auto rv_hooks = addHook(hooks_args, 100, videoArgs);
#endif
#endif
}