mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 22:12:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			596 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			596 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "rogueviz.h"
 | |
| 
 | |
| // Impossible Triangle visualization
 | |
| 
 | |
| // used in: https://www.youtube.com/watch?v=YmFDd49WsrY
 | |
| 
 | |
| // settings:
 | |
| // ./mymake -O3 rogueviz/triangle
 | |
| // ./hyper -geo Nil -canvas x -tstep 8 -nilperiod 3 3 3
 | |
| 
 | |
| // also used in: https://youtu.be/RPL4-Ydviug
 | |
| 
 | |
| // ./hyper -geo Nil -nilwidth .9 -canvas x -tstep 1 -nilperiod 1 10 1 -triset 32 31 992
 | |
| 
 | |
| // network of triangles:
 | |
| 
 | |
| // ./hyper -geo Nil -canvas x -tri-net
 | |
| 
 | |
| namespace rogueviz {
 | |
| namespace itri {
 | |
| 
 | |
| bool on = false;
 | |
| 
 | |
| bool net = false;
 | |
| 
 | |
| hyperpoint operator+(hyperpoint x) { return x; }
 | |
| 
 | |
| // do not change this
 | |
| int shape = 1;
 | |
| 
 | |
| // how many cubes to subdivide edges to
 | |
| int how = 8;
 | |
| 
 | |
| // how many cubes to draw (should be smaller than how because they are not really cubes and thus they get into each other)
 | |
| int how1 = how - 1;
 | |
| 
 | |
| // precision: number of substeps to simulate (best if divisible by how and how1)
 | |
| int isteps = 4 * 1024;
 | |
| 
 | |
| /* the generators correspond to: (unused) */
 | |
| 
 | |
| void build_gens() {
 | |
|   nilv::mvec a(1,0,0);
 | |
|   nilv::mvec b(0,1,0);
 | |
|   nilv::mvec c = (a * b).inverse();
 | |
|   vector<nilv::mvec> gens = { a, b, c, a.inverse(), b.inverse(), c.inverse() };
 | |
|   }
 | |
| 
 | |
| struct triangledata {
 | |
|   hyperpoint at;
 | |
|   bool computed;
 | |
|   int tcolor;
 | |
|   int id;
 | |
|   // each color group (i.e., each face direction) is a different hpcshape
 | |
|   triangledata(hyperpoint h) : at(h), computed(false) { tcolor = 0; id = 0; }
 | |
|   };
 | |
| 
 | |
| struct trianglemaker {
 | |
| 
 | |
|   geometry_information *icgi;
 | |
| 
 | |
|   map<cell*, vector<triangledata> > tds;
 | |
| 
 | |
|   array<hpcshape, 6> ptriangle;
 | |
| 
 | |
|   array<hpcshape, 6> pcube;
 | |
|   
 | |
|   hyperpoint ds[4], uds[4], dmoves[6];
 | |
|   
 | |
|   ld scale;
 | |
|   
 | |
|   void init() {
 | |
| 
 | |
|     icgi = &cgi;
 | |
| 
 | |
|     ld rest = sqrt(8/9.);
 | |
|     ld rex = sqrt(1 - 1/9. - pow(rest/2., 2));
 | |
|   
 | |
|     ds[0] = point3(rex, -rest/2, -1/3.);
 | |
|     ds[1] = point3(0, rest, -1/3.);
 | |
|     ds[2] = point3(-rex, -rest/2, -1/3.);
 | |
|     ds[3] = point3(0, 0, +1);
 | |
|     
 | |
|     hyperpoint start = point31(0, 0, 0);
 | |
|       
 | |
|     double ca;
 | |
|     
 | |
|     // compute how to scale this in Nil so that everything fits
 | |
|     
 | |
|     ld amin = 0, amax = 1;
 | |
|     
 | |
|     for(int it=0; it<100; it++) {
 | |
|       ld a = (amin + amax) / 2;
 | |
|       ca = a;
 | |
|       hyperpoint at = start;
 | |
|       for(int d=0; d<3; d++) {
 | |
|         for(int i=0; i<isteps; i++) {
 | |
|           at = nisot::translate(at) * (start + ds[d] * a);
 | |
|           }
 | |
|         }
 | |
|       
 | |
|       println(hlog, "at = ", at, " for a = ", a, " sq = ", at[2] / a / a);
 | |
|       if(at[2] > 0) {
 | |
|         amax = a;
 | |
|         }
 | |
|       else {
 | |
|         amin = a;
 | |
|         }
 | |
|       }
 | |
|     
 | |
|     // compute the shift between the cubes
 | |
|   
 | |
|     for(int d=0; d<3; d++) {
 | |
|       hyperpoint at = start;
 | |
|       for(int i=0; i<isteps/how; i++) {
 | |
|         at = nisot::translate(at) * (start + ds[d] * ca);
 | |
|         }
 | |
|       uds[d] = (at - start) / 2.;
 | |
|       }
 | |
|     
 | |
|     // println(hlog, "uds = ", uds);
 | |
|   
 | |
|     for(int a=0; a<3; a++) println(hlog, sqhypot_d(3, inverse_exp(shiftless(start + ds[a] * ca))));
 | |
|   
 | |
|     for(int a=0; a<3; a++) println(hlog, sqhypot_d(3, inverse_exp(shiftless(uds[a]))));
 | |
|     
 | |
|     // compute cube vertices
 | |
|   
 | |
|     hyperpoint verts[8];
 | |
|     for(int a=0; a<8; a++) {
 | |
|       verts[a] = start;
 | |
|       for(int k=0; k<3; k++) 
 | |
|         verts[a] += (a&(1<<k)) ? uds[k] : -uds[k];
 | |
|       }
 | |
|     
 | |
|     // since Nil does not really have cubes, we need to move the vertices a bit so that it looks nicer
 | |
|     
 | |
|     // ugliness of the current vertices
 | |
|     
 | |
|     auto errf = [&] {
 | |
|       ld res = 0;
 | |
|       for(int s=0; s<8; s++)
 | |
|       for(int t=0; t<3; t++) {
 | |
|         if((s & (1<<t)) == 0) {
 | |
|           int s1 = s | (1<<t);
 | |
|           ld dix = sqhypot_d(3, inverse(nisot::translate(nisot::translate(start + 2*uds[t]) * verts[s])) * verts[s1]);
 | |
|           // println(hlog, tie(s, t), "di = ", dix);
 | |
|           res += dix * dix;
 | |
|           }
 | |
|         }
 | |
|       return res;
 | |
|       };
 | |
|     
 | |
|     // minimize the ugliness
 | |
|   
 | |
|     ld curerr = errf();
 | |
|     println(hlog, "curerr = ", curerr);
 | |
|     int att = 0;
 | |
|     if(1) while(true) {
 | |
|       int id = rand() % 8;
 | |
|       int j = rand() % 3;
 | |
|       ld eps = (rand() % 100 - rand() % 100) / 100000.;
 | |
|       verts[id][j] += eps;
 | |
|       ld nerr = errf();
 | |
|       if(nerr < curerr) {
 | |
|         curerr = nerr;
 | |
|         println(hlog, "curerr = ", curerr, " # ", att);
 | |
|         att = 0;
 | |
|         }
 | |
|       else {
 | |
|         verts[id][j] -= eps;
 | |
|         }
 | |
|       att++;
 | |
|       if(att > 50000) break;
 | |
|       }
 | |
|   
 | |
|     for(int s=0; s<8; s++)
 | |
|     for(int t=0; t<3; t++) {
 | |
|       if((s & (1<<t)) == 0) {
 | |
|         int s1 = s | (1<<t);
 | |
|         ld dix = sqhypot_d(3, inverse(nisot::translate(nisot::translate(start + 2*uds[t]) * verts[s])) * verts[s1]);
 | |
|         println(hlog, tie(s, t), "di = ", dix);
 | |
|         }
 | |
|       }
 | |
|       
 | |
|     scale = 1;
 | |
| 
 | |
|     for(int si=0; si<6; si++) {
 | |
|       auto textured_square = [&] (auto f) {
 | |
|         texture_order([&] (ld ix, ld iy) { f(.5 + ix/2 + iy/2, .5 + ix/2 - iy/2); });
 | |
|         texture_order([&] (ld ix, ld iy) { f(.5 - ix/2 - iy/2, .5 - ix/2 + iy/2); });
 | |
|         texture_order([&] (ld ix, ld iy) { f(.5 + ix/2 - iy/2, .5 - ix/2 - iy/2); });
 | |
|         texture_order([&] (ld ix, ld iy) { f(.5 - ix/2 + iy/2, .5 + ix/2 + iy/2); });
 | |
|         };
 | |
|   
 | |
|       auto cube_at = [&] (hyperpoint online) {
 | |
|   
 | |
|         auto sidesquare1 = [&] (hyperpoint a00, hyperpoint a01, hyperpoint a10, hyperpoint a11) {
 | |
|           textured_square( [&] (ld ix, ld iy) {
 | |
|             hyperpoint shf = lerp(lerp(a00, a01, ix), lerp(a10, a11, ix), iy);
 | |
|             if(scale) shf = shf * scale - start * (scale-1);
 | |
|             cgi.hpcpush(nisot::translate(online) * (shf));
 | |
|             });
 | |
|           };
 | |
|             
 | |
|         if(si == 0) sidesquare1(verts[0], verts[2], verts[4], verts[6]);
 | |
|         if(si == 1) sidesquare1(verts[1], verts[3], verts[5], verts[7]);
 | |
|         if(si == 2) sidesquare1(verts[0], verts[1], verts[4], verts[5]);
 | |
|         if(si == 3) sidesquare1(verts[2], verts[3], verts[6], verts[7]);
 | |
|         if(si == 4) sidesquare1(verts[0], verts[1], verts[2], verts[3]);
 | |
|         if(si == 5) sidesquare1(verts[4], verts[5], verts[6], verts[7]);
 | |
|         };
 | |
|       
 | |
|       scale = 2;
 | |
|       cgi.bshape(pcube[si], PPR::WALL);
 | |
|       cube_at(start);
 | |
|       cgi.last->flags |= POLY_TRIANGLES;
 | |
|       cgi.last->tinf = &floor_texture_vertices[0];
 | |
|       cgi.last->texture_offset = 0;
 | |
|       
 | |
|       scale = 1;
 | |
|       
 | |
|       cgi.bshape(ptriangle[si], PPR::WALL);
 | |
|       hyperpoint at = start;
 | |
|       
 | |
|       vector<hyperpoint> atx = {start};
 | |
|       
 | |
|       cube_at(start);
 | |
|   
 | |
|       for(int dx: {0, 1, 2}) {
 | |
|         int d = dx;
 | |
|         if(net) at = start;
 | |
|         else cube_at(at);
 | |
|         int d1 = (d+1) % 3;
 | |
|         int d2 = (d+2) % 3;
 | |
|   
 | |
|         vector<hyperpoint> path(isteps+1);
 | |
|         for(int i=0; i<isteps; i++) {
 | |
|           path[i] = at;
 | |
|           at = nisot::translate(at) * (start + ds[d] * ca * (dx >= 3 ? -1 : 1));
 | |
|           }
 | |
|         path[isteps] = at;
 | |
|         
 | |
|         auto &u = uds[d];
 | |
|         auto &v = uds[d1];
 | |
|         auto &w = uds[d2];
 | |
|         
 | |
|         auto sidewall = [&] (hyperpoint wide, hyperpoint shift) {
 | |
|           textured_square( [&] (ld ix, ld iy) {
 | |
|             hyperpoint online = path[int(ix * isteps + .1)];
 | |
|             hyperpoint shf = lerp(u, -u, ix) + lerp(-wide, wide, iy) + shift;
 | |
|             shf *= scale;
 | |
|             cgi.hpcpush(nisot::translate(online) * (start + shf));
 | |
|             });
 | |
|           };
 | |
|     
 | |
|         auto sidesquare = [&] (hyperpoint wx, hyperpoint wy, hyperpoint shift, ld p) {
 | |
|           textured_square( [&] (ld ix, ld iy) {
 | |
|             hyperpoint online = path[int(p * isteps + .1)];
 | |
|             hyperpoint shf = lerp(wx, -wx, ix) + lerp(wy, -wy, iy) + shift;
 | |
|             shf *= scale;
 | |
|             cgi.hpcpush(nisot::translate(online) * (start + shf));
 | |
|             });
 | |
|           };
 | |
|         
 | |
|         if(shape == 0) {
 | |
|           if(si == d2*2) sidewall(v, w);
 | |
|           if(si == d1*2) sidewall(w, v);
 | |
|           if(si == d2*2+1) sidewall(v, -w);
 | |
|           if(si == d1*2+1) sidewall(w, -v);
 | |
|           
 | |
|           if(si == d2*2) sidesquare(u, v, w, 0);
 | |
|           if(si == d1*2) sidesquare(w, u, v, 0);
 | |
|           if(si == d1*2+1) sidesquare(u, w, -v, 0);
 | |
|           if(si == d*2+1) sidesquare(w, v, -u, 0);
 | |
|           }
 | |
|         
 | |
|         if(shape == 1) for(int a=1; a<how1; a++) {
 | |
|           ld c = a * 1. / how1;
 | |
|           
 | |
|           cube_at(path[int(c * isteps + .1)]);
 | |
|           }
 | |
|         
 | |
|         dmoves[d] = at;        
 | |
|         }
 | |
|     
 | |
|       cgi.last->flags |= POLY_TRIANGLES;
 | |
|       cgi.last->tinf = &floor_texture_vertices[0];
 | |
|       cgi.last->texture_offset = 0;
 | |
|       cgi.finishshape();
 | |
|       cgi.extra_vertices();
 | |
|       }
 | |
| 
 | |
|     tds[cwt.at].emplace_back(start);
 | |
|     dmoves[3] = inverse(nisot::translate(dmoves[0])) * C0;
 | |
|     dmoves[4] = inverse(nisot::translate(dmoves[1])) * C0;
 | |
|     dmoves[5] = inverse(nisot::translate(dmoves[2])) * C0;
 | |
|     }
 | |
| 
 | |
|   void compute(triangledata &td, cell *c) {
 | |
|     if(td.computed) return;
 | |
|     td.computed = true;
 | |
|     if(!net) return;
 | |
| 
 | |
|     hyperpoint at;
 | |
|     
 | |
|     for(int d=0; d<6; d++) {
 | |
|       hyperpoint at = nisot::translate(td.at) * dmoves[d];
 | |
|       cell *c0 = c;
 | |
|       virtualRebase(c0, at);
 | |
|       
 | |
|       bool newat = true;
 | |
|       for(auto& td: tds[c0]) {
 | |
|         ld d = sqhypot_d(3, at - td.at);
 | |
|         if(d < .01) {      
 | |
|           if(d>1e-5) println(hlog, "d = ", d);
 | |
|           newat = false;
 | |
|           }
 | |
|         }
 | |
|       
 | |
|       if(newat) {
 | |
|         triangledata ntd = at;
 | |
|         ntd.id = td.id + 1;
 | |
|         tds[c0].push_back(ntd);
 | |
|         tds[c0].back().tcolor = (td.tcolor + (d < 3 ? 1 : 2)) % 3;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     
 | |
|   };
 | |
| 
 | |
| trianglemaker *mkr;
 | |
| 
 | |
| void reset() {
 | |
|   if(mkr) delete mkr;
 | |
|   mkr = nullptr;
 | |
|   }
 | |
| 
 | |
| // Magic Cube (aka Rubik Cube) colors
 | |
| 
 | |
| color_t magiccolors[6] = { 0xFFFF00FF, 0xFFFFFFFF, 0x0000FFFF, 0x00FF00FF, 0xFF0000FF, 0xFF8000FF};
 | |
| 
 | |
| #define CTO (isize(cnts))
 | |
| 
 | |
|   vector<int> cnts;
 | |
|   vector<ld> coef;
 | |
|   int valid_from;
 | |
|   int tested_to;
 | |
|   int coefficients_known;
 | |
| 
 | |
| bool verify(int id) {
 | |
|   if(id < isize(coef)) return false;
 | |
|   ld res = 0;
 | |
|   for(int t=0; t<isize(coef); t++)
 | |
|     res += coef[t] * cnts[id-t-1];
 | |
|   return abs(res - cnts[id]) < .5;
 | |
|   }
 | |
| 
 | |
| 
 | |
| int valid(int v, int step) {
 | |
|   if(step < 0) return 0;
 | |
|   if(step+v+v+5 >= CTO) return 0;
 | |
|   ld matrix[100][128];
 | |
|   for(int i=0; i<v; i++)
 | |
|   for(int j=0; j<v+1; j++)
 | |
|     matrix[i][j] = cnts[step+i+j];
 | |
|   
 | |
|   for(int k=0; k<v; k++) {
 | |
|     int nextrow = k;
 | |
|     while(nextrow < v && std::abs(matrix[nextrow][k]) < 1e-6)
 | |
|       nextrow++;
 | |
|     if(nextrow == v) return 1;
 | |
|     if(nextrow != k) {
 | |
|       // printf("swap %d %d\n", k, nextrow);
 | |
|       for(int l=0; l<=v; l++) swap(matrix[k][l], matrix[nextrow][l]);
 | |
|       // display();
 | |
|       }
 | |
|     ld divv = 1. / matrix[k][k];
 | |
|     for(int k1=k; k1<=v; k1++) matrix[k][k1] *= divv;
 | |
|     // printf("divide %d\n", k);
 | |
|     // display();
 | |
|     for(int k1=k+1; k1<v; k1++) if(matrix[k1][k] != 0) {
 | |
|       ld coef = -matrix[k1][k];
 | |
|       for(int k2=k; k2<=v; k2++) matrix[k1][k2] += matrix[k][k2] * coef;
 | |
|       }
 | |
|     // printf("zeros below %d\n", k);
 | |
|     // display();
 | |
|     }
 | |
|   
 | |
|   for(int k=v-1; k>=0; k--)
 | |
|   for(int l=k-1; l>=0; l--)
 | |
|     if(matrix[l][k]) matrix[l][v] -= matrix[l][k] * matrix[k][v];
 | |
|   
 | |
|   coef.resize(v);
 | |
|   for(int i=0; i<v; i++) coef[i] = matrix[v-1-i][v];
 | |
|     
 | |
|   println(hlog, "coef = ", coef);
 | |
|   for(int t=step+v; t<step+v+v+5; t++) {
 | |
|     println(hlog, "verify(", t, ") = ", verify(t));
 | |
|     if(!verify(t)) return 2;
 | |
|     }
 | |
|   println(hlog, "got here");
 | |
|   tested_to = step+v+v+5;
 | |
|   while(tested_to < CTO) {
 | |
|     if(!verify(tested_to)) return 2;
 | |
|     tested_to++;
 | |
|     }
 | |
|   
 | |
|   valid_from = step+v;
 | |
|   return 3;
 | |
|   }
 | |
| 
 | |
| void find_coefficients() {
 | |
|   if(coefficients_known) return;
 | |
|   for(int v=1; v<25; v++) 
 | |
|   for(int step=0; step<1000; step++) { 
 | |
|     int val = valid(v, step);
 | |
|     if(val == 0) break;
 | |
|     println(hlog, "v=", v, "step=", step, " val=", val);
 | |
|     if(val == 3) { coefficients_known = 2; return; }
 | |
|     }
 | |
|   coefficients_known = 1;
 | |
|   }
 | |
| 
 | |
| void growthrate() {
 | |
| 
 | |
|   cnts.resize(20);
 | |
| 
 | |
|   for(int a=0; a<CTO; a++) {
 | |
|     int cnt = 0;
 | |
|     map<cell*, int> howmany;
 | |
|     for(auto& p: mkr->tds) cnt += (howmany[p.first] = isize(p.second));
 | |
|     for(auto& p: howmany) for(int i=0; i<p.second; i++) {
 | |
|       // println(hlog, p.first, mkr->tds[p.first][i].at, mkr->tds[p.first][i].computed);
 | |
|       mkr->compute(mkr->tds[p.first][i], p.first);
 | |
|       }
 | |
|     println(hlog, "cnt = ", cnt, " / ", cnt / pow(1+a, 4));
 | |
|     cnts[a] = cnt;
 | |
|     if(a >= 4) println(hlog, "D4 = ", cnts[a-4] - 4 * cnts[a-3] + 6 * cnts[a-2] - 4 * cnts[a-1] + cnts[a]);
 | |
|     println(hlog, "cnts = ", cnts);
 | |
|     }
 | |
|   
 | |
|   auto cnt2 = cnts;
 | |
|   for(int i=isize(cnt2)-1; i>=1; i--) cnt2[i] -= cnt2[i-1];
 | |
|   println(hlog, "cnts dif = ", cnt2);
 | |
|   
 | |
|   // this was computed on integers, not using the program above
 | |
| 
 | |
|   cnts = 
 | |
|   {1,6,24,80,186,368,644,1046,1574,2260,3128,4198,5482,7006,8788,10860,13228,15918,18948,22350,26130,30314,34926,39986,45506,51518,58034,65086,72680,80842,89596,98968,108964,119610,130930,142950,155676,169140,183354,198350,214140,230744,248186,266492,285668,305746,326744,348688,371584,395464,420346,446256,473206,501216,530310,560520,591846,624320,657960,692792,728828,766094,804608,844396,885470,927856,971572,1016650,1063090,1110924,1160176,1210866,1263006,1316622,1371732,1428368,1486536,1546262,1607564,1670474,1734998,1801162,1868990,1938502,2009710,2082646,2157322,2233770,2311996,2392026,2473884,2557596,2643168,2730626,2819994,2911298,3004544,3099764,3196970,3296194,3397448,3500752,3606130,3713608,3823192};
 | |
|   
 | |
|   println(hlog, "coefficients_known = ", coefficients_known);
 | |
|   if(coefficients_known == 2) {
 | |
|     string fmt = "a(d+" + its(isize(coef)) + ") = ";
 | |
|     bool first = true;
 | |
|     for(int i=0; i<isize(coef); i++) if(kz(coef[i])) {
 | |
|       if(first && !kz(coef[i]-1)) ;
 | |
|       else if(first) fmt += fts(coef[i]);
 | |
|       else if(!kz(coef[i]-1)) fmt += " + ";
 | |
|       else if(!kz(coef[i]+1)) fmt += " - ";
 | |
|       else if(coef[i] > 0) fmt += " + " + fts(coef[i]);
 | |
|       else if(coef[i] < 0) fmt += " - " + fts(-coef[i]);
 | |
|       fmt += "a(d";
 | |
|       if(i != isize(coef) - 1)
 | |
|         fmt += "+" + its(isize(coef) - 1 - i);
 | |
|       fmt += ")";
 | |
|       first = false;
 | |
|       }
 | |
|     fmt += " (d>" + its(valid_from-1) + ")";
 | |
|     println(hlog, fmt);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| color_t tcolors[3] = { 0xFF0000FF, 0x00FF00FF, 0x0000FFFF };
 | |
| 
 | |
| 
 | |
| bool draw_ptriangle(cell *c, const shiftmatrix& V) {
 | |
| 
 | |
|   if(!on) return false;
 | |
|   
 | |
|   if(mkr && mkr->icgi != &cgi) reset();
 | |
|      
 | |
|   if(!mkr) { mkr = new trianglemaker; mkr->init(); 
 | |
|     // growthrate();
 | |
|     }
 | |
|   
 | |
|   for(auto& td: mkr->tds[c]) {
 | |
|     mkr->compute(td, c);
 | |
|     for(int side=0; side<6; side++) {
 | |
|       auto &s = queuepoly(V * nisot::translate(td.at), mkr->ptriangle[side], magiccolors[side]);
 | |
|       ensure_vertex_number(*s.tinf, s.cnt);
 | |
| 
 | |
|       /* auto& s1 = queuepoly(V * nisot::translate(td.at), mkr->pcube[side], gradient(tcolors[td.tcolor], magiccolors[side], 0, .2, 1));
 | |
|       ensure_vertex_number(*s1.tinf, s1.cnt); */
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   return false;
 | |
|   }
 | |
| 
 | |
| #if CAP_RVSLIDES
 | |
| void slide_itri(tour::presmode mode, int id) {
 | |
|   using namespace tour;
 | |
|   setPlainCanvas(mode);
 | |
|   
 | |
|   if(mode == pmStart) {
 | |
|     stop_game();
 | |
|     set_geometry(gNil);
 | |
|     tour::slide_backup(on, true);
 | |
|     tour::slide_backup(net, id == 2 ? true : false);
 | |
|     tour::on_restore(nilv::set_flags);
 | |
|     if(id == 0)
 | |
|       tour::slide_backup(nilv::nilperiod, make_array(3, 3, 3));
 | |
|     if(id == 1) {
 | |
|       tour::slide_backup(nilv::nilperiod, make_array(1, 10, 1));
 | |
|       tour::slide_backup(nilv::nilwidth, .9);
 | |
|       tour::slide_backup(how, 32);
 | |
|       tour::slide_backup(how1, 31);
 | |
|       tour::slide_backup(isteps, 992);
 | |
|       }
 | |
|     nilv::set_flags();
 | |
|    /* do nothing for id == 2 */
 | |
|     start_game();
 | |
|     playermoved = false;
 | |
|     tour::on_restore(reset);
 | |
|     }     
 | |
|   rogueviz::pres::non_game_slide_scroll(mode);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| string cap = "Impossible architecture in Nil/";
 | |
| 
 | |
| auto hchook = addHook(hooks_drawcell, 100, draw_ptriangle)
 | |
| 
 | |
| + addHook(hooks_args, 100, [] {
 | |
|   using namespace arg;
 | |
|            
 | |
|   if(0) ;
 | |
|   else if(argis("-triset")) {
 | |
|     shift(); how = argi();
 | |
|     shift(); how1 = argi();
 | |
|     shift(); isteps = argi();
 | |
|     }
 | |
|   else if(argis("-tri-net")) {
 | |
|     on = true; net = true;
 | |
|     }
 | |
|   else if(argis("-tri-one")) {
 | |
|     on = true; net = false;
 | |
|     }
 | |
|   else return 1;
 | |
|   return 0;
 | |
|   });
 | |
| 
 | |
| #if CAP_RVSLIDES
 | |
| auto hcslides =
 | |
|   addHook_rvslides(166, [] (string s, vector<tour::slide>& v) {
 | |
|   using namespace tour;
 | |
|   if(s != "noniso") return;
 | |
| 
 | |
|   v.push_back(
 | |
|     tour::slide{cap+"impossible triangle", 18, LEGAL::NONE | QUICKGEO, 
 | |
|       "This form of impossible triangle was first created by Oscar Reutersvärd. "
 | |
|       "It was later independently discovered by Lionel Penrose and Roger Penrose, and popularized by M. C. Escher.\n\n"
 | |
|       "Move with mouse/arrows/PgUpDn. Press '5' to enable animation, 'o' to change ring size.",
 | |
|    
 | |
|   [] (presmode mode) {
 | |
|   
 | |
|     slide_itri(mode, 0);
 | |
|     }});
 | |
| 
 | |
|   v.push_back(
 | |
|     tour::slide{cap+"impossible triangle chainmail", 18, LEGAL::NONE | QUICKGEO, 
 | |
|       "Here we try to link the impossible triangles into a construction reminiscent of a chainmail.",
 | |
|    
 | |
|   [] (presmode mode) {
 | |
|   
 | |
|     slide_itri(mode, 1);
 | |
|     }});
 | |
| 
 | |
|   v.push_back(
 | |
|     tour::slide{cap+"impossible triangle network", 18, LEGAL::NONE | QUICKGEO, 
 | |
|       "It is not possible to reconstruct Escher's Waterfall in Nil geometry, because one of the three triangles there "
 | |
|       "has opposite orientation. For this reason, that one triangle would not connect correctly. Penrose triangles "
 | |
|       "in Nil would not create a planar structure, but rather a three-dimensional one. This slide shows the picture. "
 | |
|       "Note that, while the structure is three-dimensional, the number of nodes connected in d steps grows as the "
 | |
|       "fourth power of d.",
 | |
|     
 | |
|   [] (presmode mode) {
 | |
|   
 | |
|     slide_itri(mode, 2);
 | |
|     }});
 | |
|   });
 | |
| #endif
 | |
| 
 | |
| }
 | |
| } | 
