mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 05:52:59 +00:00 
			
		
		
		
	files actually added
This commit is contained in:
		
							
								
								
									
										336
									
								
								rogueviz/collatz.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								rogueviz/collatz.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,336 @@ | |||||||
|  | #include "../hyper.h" | ||||||
|  | #include "rogueviz.h" | ||||||
|  |  | ||||||
|  | namespace rogueviz { | ||||||
|  |  | ||||||
|  | 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);     | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   void act(vertexdata& vd, cell *c, shmup::monster *m, int i) { | ||||||
|  |     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 CAP_SHOT | ||||||
|  |  | ||||||
|  | // see: https://www.youtube.com/watch?v=4Vu3F95jpQ4&t=6s (Collatz) | ||||||
|  | void collatz_video(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; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | string its05(int i) { char buf[64]; sprintf(buf, "%05d", i); return buf; } | ||||||
|  |  | ||||||
|  | int readArgs() { | ||||||
|  | #if CAP_COMMANDLINE | ||||||
|  |   using namespace arg; | ||||||
|  |  | ||||||
|  |   if(0) ; | ||||||
|  |  | ||||||
|  |   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(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   #if CAP_SHOT | ||||||
|  |   else if(argis("-rvvideo") && kind == kCollatz) { | ||||||
|  |     shift(); collatz_video(arg::args()); | ||||||
|  |     } | ||||||
|  |   #endif | ||||||
|  |  | ||||||
|  |   else if(argis("-cshift")) { | ||||||
|  |     shift_arg_formula(collatz::cshift); | ||||||
|  |     } | ||||||
|  |   else return 1; | ||||||
|  | #endif | ||||||
|  |   return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | int ah = addHook(hooks_args, 100, readArgs) + | ||||||
|  |   addHook(rvtour::hooks_build_rvtour, 100, [] (vector<tour::slide>& v) { | ||||||
|  |     using namespace tour; | ||||||
|  |     v.push_back( | ||||||
|  |       tour::slide{"Collatz conjecture", 51, LEGAL::UNLIMITED | QUICKGEO, | ||||||
|  |     "The following slide is a visualization of the Collatz conjecture. " | ||||||
|  |     "Press '5' for a spiral rendering of the Collatz conjecture visualization.\n\n" | ||||||
|  |     "Note that this, and many other RogueViz visualizations, have " | ||||||
|  |     "Euclidean versions (press ESC).\n", | ||||||
|  |     rvtour::roguevizslide('d', [] () { | ||||||
|  |       rogueviz::dftcolor = 0x206020FF; | ||||||
|  |        | ||||||
|  |       int fac = euclid ? 2 : 1; | ||||||
|  |  | ||||||
|  |       rogueviz::collatz::s2 = .3; | ||||||
|  |       rogueviz::collatz::p2 = .5 * fac; | ||||||
|  |       rogueviz::collatz::s3 = -.4; | ||||||
|  |       rogueviz::collatz::p3 = .4 * fac; | ||||||
|  |  | ||||||
|  |       rogueviz::showlabels = true; | ||||||
|  |        | ||||||
|  |       rogueviz::on = true; | ||||||
|  |       gmatrix.clear(); | ||||||
|  |       drawthemap(); | ||||||
|  |       gmatrix0 = gmatrix; | ||||||
|  |  | ||||||
|  |       rogueviz::collatz::start(); | ||||||
|  |       }) | ||||||
|  |     }); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | EX } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										628
									
								
								rogueviz/sag.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										628
									
								
								rogueviz/sag.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,628 @@ | |||||||
|  | #include "../hyper.h" | ||||||
|  | #include "rogueviz.h" | ||||||
|  |  | ||||||
|  | // SAG visualizer (e.g. Reddit roguelikes, GitHub languages) | ||||||
|  | //----------------------------------------------------------- | ||||||
|  |  | ||||||
|  | // 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) | ||||||
|  |  | ||||||
|  | namespace rogueviz { | ||||||
|  |  | ||||||
|  | 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(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | int readArgs() { | ||||||
|  | #if CAP_COMMANDLINE | ||||||
|  |   using namespace arg; | ||||||
|  |  | ||||||
|  |   if(0) ; | ||||||
|  |  | ||||||
|  |   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); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | // (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(); | ||||||
|  |     } | ||||||
|  | // (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(); | ||||||
|  |     } | ||||||
|  |   else return 1; | ||||||
|  | #endif | ||||||
|  |   return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | bool turn(int delta) { | ||||||
|  |   if(!on) return false; | ||||||
|  |   if(kind == kSAG) sag::iterate(), timetowait = 0; | ||||||
|  |   return false; | ||||||
|  |   // shmup::pc[0]->rebase(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | int ah = addHook(hooks_args, 100, readArgs) | ||||||
|  |   + addHook(shmup::hooks_turn, 100, turn) | ||||||
|  |   + addHook(rogueviz::hooks_close, 100, [] { sag::sagedges.clear(); }) | ||||||
|  |   + addHook(rogueviz::hooks_rvmenu, 100, [] {  | ||||||
|  |     if(kind != kSAG) return; | ||||||
|  |     dialog::addSelItem(XLAT("temperature"), fts(sag::temperature), 't'); | ||||||
|  |     dialog::add_action([] { | ||||||
|  |       dialog::editNumber(sag::temperature, sag::lowtemp, sag::hightemp, 1, 0, XLAT("temperature"), ""); | ||||||
|  |       }); | ||||||
|  |     dialog::addSelItem(XLAT("SAG mode"), sag::sagmodes[sag::sagmode], 'm');  | ||||||
|  |     dialog::add_action([] { sag::sagmode = sag::eSagmode( (1+sag::sagmode) % 3 ); }); | ||||||
|  |     }) | ||||||
|  |   + addHook(rvtour::hooks_build_rvtour, 100, [] (vector<tour::slide>& v) { | ||||||
|  |     using namespace rvtour; | ||||||
|  |     v.push_back( | ||||||
|  |       slide{"Roguelikes", 63, LEGAL::UNLIMITED | QUICKGEO, | ||||||
|  |         "A visualization of roguelikes, based on discussion on /r/reddit. " | ||||||
|  |         "See: http://www.roguetemple.com/z/hyper/reddit.php", | ||||||
|  |         roguevizslide('0', [] () { | ||||||
|  |           rogueviz::dftcolor = 0x282828FF; | ||||||
|  |      | ||||||
|  |           rogueviz::showlabels = true; | ||||||
|  |           part(rogueviz::default_edgetype.color, 0) = 181; | ||||||
|  |           rogueviz::sag::edgepower = 1; | ||||||
|  |           rogueviz::sag::edgemul = 1; | ||||||
|  |            | ||||||
|  |           rogueviz::on = true; | ||||||
|  |           gmatrix.clear(); | ||||||
|  |           drawthemap(); | ||||||
|  |           gmatrix0 = gmatrix; | ||||||
|  |      | ||||||
|  |           rogueviz::sag::read(RVPATH "roguelikes/edges.csv"); | ||||||
|  |           rogueviz::readcolor(RVPATH "roguelikes/color.csv"); | ||||||
|  |           rogueviz::sag::loadsnake(RVPATH "roguelikes/" + cname()); | ||||||
|  |           })     | ||||||
|  |         } | ||||||
|  |       ); | ||||||
|  |     v.push_back(slide  {"Programming languages of GitHub", 64, LEGAL::UNLIMITED | QUICKGEO, | ||||||
|  |     "A visualization of programming languages.", | ||||||
|  |     roguevizslide('0', [] () { | ||||||
|  |       rogueviz::dftcolor = 0x282828FF; | ||||||
|  |  | ||||||
|  |       rogueviz::showlabels = true; | ||||||
|  |       part(rogueviz::default_edgetype.color, 0) = 128; | ||||||
|  |       rogueviz::sag::edgepower = .4; | ||||||
|  |       rogueviz::sag::edgemul = .02; | ||||||
|  |        | ||||||
|  |       rogueviz::on = true; | ||||||
|  |       gmatrix.clear(); | ||||||
|  |       drawthemap(); | ||||||
|  |       gmatrix0 = gmatrix; | ||||||
|  |  | ||||||
|  |       rogueviz::sag::read(RVPATH "lang/edges.csv"); | ||||||
|  |       rogueviz::readcolor(RVPATH "lang/color.csv"); | ||||||
|  |       rogueviz::sag::loadsnake(RVPATH "lang/" + cname()); | ||||||
|  |       if(euclid) rogueviz::legend.clear(); | ||||||
|  |       }) | ||||||
|  |     }); | ||||||
|  |      | ||||||
|  |     v.push_back(slide {"Boardgames", 62, LEGAL::UNLIMITED | QUICKGEO, | ||||||
|  |         "A visualization of board games, based on discussions on Reddit.", | ||||||
|  |     roguevizslide('0', [] () { | ||||||
|  |       rogueviz::dftcolor = 0x282828FF; | ||||||
|  |  | ||||||
|  |       rogueviz::showlabels = true; | ||||||
|  |       part(rogueviz::default_edgetype.color, 0) = 157; | ||||||
|  |       rogueviz::sag::edgepower = 1; | ||||||
|  |       rogueviz::sag::edgemul = 1; | ||||||
|  |        | ||||||
|  |       rogueviz::on = true; | ||||||
|  |       gmatrix.clear(); | ||||||
|  |       drawthemap(); | ||||||
|  |       gmatrix0 = gmatrix; | ||||||
|  |  | ||||||
|  |       rogueviz::sag::read(RVPATH "boardgames/edges.csv"); | ||||||
|  |       rogueviz::readcolor(RVPATH "boardgames/color.csv"); | ||||||
|  |       rogueviz::sag::loadsnake(RVPATH "boardgames/" + cname()); | ||||||
|  |       }) | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | EX } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										126
									
								
								rogueviz/tree.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								rogueviz/tree.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | |||||||
|  | #include "../hyper.h" | ||||||
|  | #include "rogueviz.h" | ||||||
|  |  | ||||||
|  | // hyper -tol <filename.xml> -- visualize the tree of life, | ||||||
|  | //   based on a XML dump from https://tree.opentreeoflife.org/ | ||||||
|  |  | ||||||
|  | namespace rogueviz { | ||||||
|  |  | ||||||
|  | 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(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | #if CAP_COMMANDLINE | ||||||
|  | int readArgs() { | ||||||
|  |   using namespace arg; | ||||||
|  |  | ||||||
|  |   if(0) ; | ||||||
|  |  | ||||||
|  |   else if(argis("-tol")) { | ||||||
|  |     PHASE(3); shift(); tree::read(args()); | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |   else return 1; | ||||||
|  |   return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | int ah = addHook(hooks_args, 100, readArgs); | ||||||
|  | #endif | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Zeno Rogue
					Zeno Rogue