mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 14:02:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			674 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			674 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "rogueviz.h"
 | |
| 
 | |
| namespace rogueviz {
 | |
| 
 | |
| namespace magic { void magic(int i); }
 | |
| 
 | |
| namespace crystal_sokoban { void run_sb(); }
 | |
| 
 | |
| namespace colorpicker {
 | |
| 
 | |
| int current_step;
 | |
| color_t current_color;
 | |
| cell *current_center;
 | |
| 
 | |
| color_t get_color_at(cell *c) {
 | |
|   crystal::coord oldc = crystal::get_coord(current_center->master);
 | |
|   crystal::coord newc = crystal::get_coord(c->master);
 | |
|   color_t res;
 | |
|   for(int i=0; i<3; i++) {
 | |
|     int val = part(current_color, 2-i) + current_step * ((newc[i] - oldc[i]) / 2);
 | |
|     if(val < 0) val = 0;
 | |
|     if(val > 255) val = 255;
 | |
|     part(res, 2-i) = val;
 | |
|     }
 | |
|   return res;
 | |
|   }
 | |
| 
 | |
| bool color_markers(cell *c, const shiftmatrix& V) {
 | |
|   if(!centerover) return false;
 | |
|   if(centerover != current_center) {
 | |
|     current_color = get_color_at(centerover);
 | |
|     current_center = centerover;
 | |
|     }
 | |
|   c->landparam = get_color_at(c);
 | |
|   return false;
 | |
|   }
 | |
| 
 | |
| bool color_key(int sym, int uni) {
 | |
|   if((cmode & sm::NORMAL) && (uni >= '0' && uni <= '6')) {
 | |
|     current_step = (1 << (uni - '0'));
 | |
|     return true;
 | |
|     }
 | |
|   if((cmode & sm::NORMAL) && uni == '[') {
 | |
|     current_step = (1 + current_step) / 2;
 | |
|     return true;
 | |
|     }
 | |
|   if((cmode & sm::NORMAL) && uni == ']') {
 | |
|     current_step = 2 * current_step;
 | |
|     return true;
 | |
|     }
 | |
|   if((cmode & sm::NORMAL) && uni >= 1000 && uni < 1010) {
 | |
|     current_step = 1 << (uni - 1000);
 | |
|     return true;
 | |
|     }
 | |
|   return false;
 | |
|   }
 | |
| 
 | |
| bool color_prestats() {
 | |
|   nohelp = true;
 | |
|   for(int k= 0; k <= 6; k++) {
 | |
|     int v = 1<< k;
 | |
|     if(displayButtonS(10 + k * vid.fsize * 2, 10 + vid.fsize, its(k), v == current_step ? 0xFF2020 : 0xC0C0C0, 0, vid.fsize)) 
 | |
|       getcstat = 1000 + k;
 | |
|     }
 | |
|   if(mouseover) {
 | |
|     displayButtonS(10 + 7 * vid.fsize * 2, 10 + vid.fsize, itsh(mouseover->landparam & 0xFFFFFF), mouseover->landparam, 0, vid.fsize); 
 | |
|     }
 | |
|   return true;
 | |
|   }
 | |
| 
 | |
| void run_cpick() {
 | |
|   crystal::compass_probability = 0;
 | |
|   stop_game();
 | |
|   crystal::set_crystal(6);
 | |
|   set_variation(eVariation::pure);
 | |
|   enable_canvas();
 | |
|   patterns::whichCanvas = 'g';
 | |
|   patterns::canvasback = 0;
 | |
|   check_cgi();
 | |
|   start_game();
 | |
|   current_center = currentmap->gamestart();
 | |
|   current_color = 0x808080;    
 | |
|   current_step = 32;
 | |
|   mapeditor::drawplayer = false;
 | |
|   vid.smart_range_detail = 1;
 | |
|   vid.use_smart_range = 2;
 | |
|   rv_hook(hooks_drawcell, 100, color_markers);
 | |
|   rv_hook(hooks_handleKey, 50, color_key);
 | |
|   rv_hook(hooks_prestats, 150, color_prestats);
 | |
|   }
 | |
| 
 | |
| auto cphook = addHook(hooks_args, 100, [] {
 | |
|   using namespace arg;
 | |
|            
 | |
|   if(0) ;
 | |
|   else if(argis("-cpick")) {
 | |
|     PHASEFROM(2);
 | |
|     run_cpick();
 | |
|     }
 | |
|   else return 1;
 | |
|   return 0;
 | |
|   });
 | |
|   }
 | |
| 
 | |
| namespace sokoban {
 | |
| 
 | |
| bool on;
 | |
| 
 | |
| bool created;
 | |
| 
 | |
| hpcshape sokowall[10][7];
 | |
| 
 | |
| hyperpoint tpoint[6];
 | |
| 
 | |
| void push3(hyperpoint h) {
 | |
|   cgi.first = false;
 | |
|   cgi.hpc.push_back(h);
 | |
|   }
 | |
| 
 | |
| void create_sokowalls(cell *c) {
 | |
|   for(int a=0; a<6; a++) tpoint[a] = currentmap->adj(c, a) * C0;
 | |
|   const int qfr = 8;
 | |
|   auto v = [&] (int a, int b, int fr) {
 | |
|     hyperpoint h0 = get_corner_position(c, b);
 | |
|     hyperpoint h1 = get_corner_position(c, b+1);
 | |
|     hyperpoint h2 = normalize(h0 * (qfr-fr) + h1 * fr);
 | |
|     return mscale(h2, 1 / (1 - a / 6.1));
 | |
|     };
 | |
|   
 | |
|   for(int a=0; a<9; a++) 
 | |
|   for(int b=0; b<6; b++) {
 | |
|     cgi.bshape(sokowall[a][b], PPR::FLOOR + 2 * a + 1);
 | |
|     for(int f=0; f<=qfr; f++)
 | |
|       push3(v(a, b, f));
 | |
|     for(int f=0; f<=qfr; f++)
 | |
|       push3(v(a+1, b, qfr-f));
 | |
|     push3(v(a, b, 0));
 | |
|     }
 | |
| 
 | |
|   for(int a=0; a<9; a++) {
 | |
|     cgi.bshape(sokowall[a][6], PPR::FLOOR + 2 * a);
 | |
|     for(int b=0; b<6; b++)
 | |
|       for(int f=0; f<qfr; f++)
 | |
|         push3(v(a, b, f));
 | |
|     push3(v(a, 0, 0));
 | |
|     }
 | |
|   
 | |
|   cgi.finishshape();
 | |
|   cgi.extra_vertices();
 | |
|   }
 | |
| 
 | |
| bool sokomap(cell *c, const shiftmatrix& V) {
 | |
|   if(!created) {
 | |
|     created = true;
 | |
|     create_sokowalls(c);
 | |
|     }
 | |
| 
 | |
|   crystal::coord v = crystal::get_coord(c->master);
 | |
|   bool high = (v[0] ^ v[1] ^ v[2]) & 2;
 | |
|   
 | |
| 
 | |
|   color_t col = 0x00C000FF;
 | |
|   
 | |
|   poly_outline = 0xFF;
 | |
|   
 | |
|   int lev = 0;
 | |
|   
 | |
|   int phase = ((v[0] ^ v[2] ^ v[4]) & 2) >> 1;
 | |
|   
 | |
|   // high = v[0] >= 0 && v[0] <= 8 && v[1] >= 0 && v[1] <= 8 && v[2] == 0 && !(v[0] > 0 && v[0] < 8 && v[1] > 0 && v[1] < 8);
 | |
|   // if(high) col = 0xFFFF00FF, lev = 3;
 | |
|   
 | |
|   high = true;
 | |
|   lev = ((v[0] + v[1] + v[2])/2+1) & 3;
 | |
|   if(lev == 0) col = 0x008000FF;
 | |
|   if(lev == 1) col = 0x00C000FF;
 | |
|   if(lev == 2) col = 0x40C000FF;
 | |
|   if(lev == 3) col = 0x80FF00FF;
 | |
|   
 | |
|   // if(v[0] == 4 && v[1] == 4 && v[2] == 0) col = 0xFFFFFFFF;
 | |
|   
 | |
|   c->landparam = lev;
 | |
| 
 | |
|   if(high) {
 | |
|     ld d = hdist0(tC0(V));
 | |
|     color_t dark1 = col - ((col & 0xFCFCFC00) >> 1);
 | |
|     color_t dark2 = col - ((col & 0xFCFCFC00) >> 2);
 | |
|     for(int b=0; b<6; b++) 
 | |
|       for(int a=c->move(b)->landparam; a<lev; a++) if(hdist0(V * tpoint[b]) < d) {
 | |
|         /* auto& p = */
 | |
|         queuepoly(V, sokowall[a][b], (((b+phase)&1) ? dark1 : dark2));
 | |
|         // p.flags |= POLY_PRECISE_WIDE;
 | |
|         // p.linewidth = 2;
 | |
|         }
 | |
|     queuepoly(V, sokowall[lev][6], col);
 | |
|     }
 | |
|   else {
 | |
|     queuepoly(V, sokowall[0][6], col);
 | |
|     }
 | |
| 
 | |
|   c->wall = waInvisibleFloor;
 | |
|   return false;
 | |
|   }
 | |
| 
 | |
| void run_sb() {
 | |
|   crystal::compass_probability = 0;
 | |
|   stop_game();
 | |
|   crystal::set_crystal(6);
 | |
|   set_variation(eVariation::pure);
 | |
|   enable_canvas();
 | |
|   patterns::whichCanvas = 'g';
 | |
|   patterns::canvasback = 0;
 | |
|   check_cgi();
 | |
|   rv_hook(hooks_drawcell, 100, sokomap);
 | |
|   start_game();
 | |
|   mapeditor::drawplayer = false;
 | |
|   vid.smart_range_detail = 1;
 | |
|   vid.use_smart_range = 2;
 | |
|   }
 | |
|   
 | |
| auto sbhook = addHook(hooks_args, 100, [] {
 | |
|   using namespace arg;
 | |
|            
 | |
|   if(0) ;
 | |
|   else if(argis("-sb")) {
 | |
|     PHASEFROM(2);
 | |
|     sokoban::run_sb();
 | |
|     }
 | |
|   else return 1;
 | |
|   return 0;
 | |
|   });
 | |
| 
 | |
| 
 | |
| }
 | |
| 
 | |
| const flagtype VC = 1;
 | |
| const flagtype NO_VC = 2;
 | |
| const flagtype PLAYER = 4;
 | |
| 
 | |
| void sync(int mode, flagtype flags) {
 | |
|   using namespace tour;
 | |
|   if(mode == pmStart) {
 | |
|     crystal::compass_probability = 0;
 | |
|     crystal::crystal_period = 0;
 | |
|     enable_canvas();
 | |
|     mapeditor::drawplayer = (flags & PLAYER);
 | |
|     vid.smart_range_detail = 1;
 | |
|     vid.use_smart_range = 2;
 | |
|     crystal::view_coordinates = (flags & VC);
 | |
|     smooth_scrolling = true;
 | |
|     }
 | |
|   if(mode == pmKey && !(flags & NO_VC))
 | |
|     crystal::view_coordinates = !crystal::view_coordinates;
 | |
|   if(cwt.at != centerover && !playermoved && !(flags & PLAYER)) {
 | |
|     cwt.at = centerover; 
 | |
|     current_display->which_copy = gmatrix[cwt.at].T;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| vector<tour::slide> high_slides;
 | |
| 
 | |
| int shapeid;
 | |
| 
 | |
| int mycanvas(cell *c) {
 | |
| 
 | |
|   int dim = crystal::get_dim();
 | |
| 
 | |
|   auto d = crystal::get_coord(c->master);
 | |
|   for(int i=0; i<dim; i++) d[i] >>= 1;
 | |
|   
 | |
|   color_t col = 0;
 | |
|   
 | |
|   d[0] ++;
 | |
|   
 | |
|   int ones = 0;
 | |
|   for(int i=0; i<dim; i++) if((d[i] & 1) == 1) ones++;
 | |
|   
 | |
|   switch(shapeid) {
 | |
|   
 | |
|     case 0: {
 | |
|       auto dx = d; dx[0] -= 2;
 | |
|       bool grid = false;
 | |
|       for(int i=1; i<dim; i++) if((dx[i] & 3) == 2) grid = true;
 | |
|   
 | |
|       for(int i=0; i<3; i++) part(col, i) = 0xFF + 0x30 * (d[i]-2);
 | |
|       if(grid) col |= 0x1000000;
 | |
|       if(dx == crystal::c0) col = 0x1FFD500;
 | |
|       if(dx[0] == 2 && dx[1] == 0 && dx[2] == 0 && dx[3] == 0 && dx[4] == 0 && dx[5] == 0) col = 0;
 | |
|       if(dx[0] == 6 && dx[1] == 0 && dx[2] == 0 && dx[3] == 0 && dx[4] == 0 && dx[5] == 0) col = 0;
 | |
|       return col;
 | |
|       }
 | |
|     
 | |
|     case 1: {
 | |
|       if(d[1] == 0 && d[2] == 0 && d[3] == 0 && d[4] == 0 && d[5] == 0) ;
 | |
|       else col = gradient(0x1FF0000, 0x1FFFF00, 9, d[0], 16);
 | |
|       part(col, 0) = 0x80 + d[1] * 0x70;
 | |
|       return col;
 | |
|       }
 | |
|     
 | |
|     case 2: {
 | |
|       col = gradient(0xFFFF00, 0x00FF00, 17, d[0], 24);
 | |
|       for(int i=0; i<1; i++) part(col, i) = 0xFF + 0x30 * (d[i+1]-2);
 | |
|       c->landparam = col;
 | |
|       if(ones == dim-1) col |= 0x1000000;
 | |
|       return col;
 | |
|       }
 | |
|       
 | |
|     case 3: {
 | |
|       if(d[3] == 1) col = (ones & 1) ? 0x1C0FFC0 : 0x180FF80;
 | |
|       if(d[3] == -1) col = (ones & 1) ? 0x18080FF : 0x14040FF;
 | |
|       if(d[2] == 1) col = (ones & 1) ? 0x1FFCC00 : 0x1FF8080;
 | |
|       if(d[2] == -1) col = (ones & 1) ? 0x180FFFF : 0x1408080;
 | |
| 
 | |
|       if(d[4] == 1) col = 0x1FFFFFF;
 | |
|       if(d[4] == -1) col = 0x1FFFFFF;
 | |
|       if(d[5] == 1) col = 0x1FFFFFF;
 | |
|       if(d[5] == -1) col = 0x1FFFFFF;
 | |
|       return col;
 | |
|       }
 | |
|     
 | |
|     case 4: {
 | |
|       if(d[3] == 1) col = (ones & 1) ? 0x1C0FFC0 : 0x180FF80;
 | |
|       if(d[3] == -1) col = (ones & 1) ? 0x18080FF : 0x14040FF;
 | |
| 
 | |
|       if(d[4] == 1) col = 0x1FFFFFF;
 | |
|       if(d[4] == -1) col = 0x1FFFFFF;
 | |
|       return col;
 | |
|       }
 | |
|       
 | |
|     case 5: {
 | |
|       if(d[3] == 1) col = (ones & 1) ? 0x1C0FFC0 : 0x180FF80;
 | |
|       if(d[3] == -2) col = (ones & 1) ? 0x180FFFF : 0x140FFFF;
 | |
|       return col;
 | |
|       }
 | |
| 
 | |
|     case 6: {
 | |
|       if(d[3] == 1) col = (ones & 1) ? 0x1FF8080 : 0x1FF6060;
 | |
|       if(d[2] == -1) col = (ones & 1) ? 0x1FFFF70 : 0x1E0E060;
 | |
|       return col;
 | |
|       }
 | |
|     
 | |
|     case 7: {
 | |
|       if(d[1] == 0 || d[2] == 0) ;
 | |
|       else if(d[1] > 0 && d[2] > 0) col = 0x1FF0000;
 | |
|       else if(d[1] > 0 && d[2] < 0) col = 0x1FFFF00;
 | |
|       else if(d[1] < 0 && d[2] < 0) col = 0x100FFFF;
 | |
|       else if(d[1] < 0 && d[2] > 0) col = 0x10000FF;
 | |
|       return col;
 | |
|       }
 | |
|     
 | |
|     case 8: {
 | |
|       int s = d[1] + d[2] + d[3] + d[4] + d[5];
 | |
|       if(s > 0) col = 0x1FFD500;
 | |
|       else if (s < -1) col = 0x17851a9;
 | |
|       return col;
 | |
|       }
 | |
|     
 | |
|     case 9: {
 | |
|       int s = d[1] + d[2] + d[3] + d[4] + d[5] + d[0];
 | |
|       if(s > 0) col = 0x1FF20FF;
 | |
|       else if (s < -1) col = 0x1C0C0C0;
 | |
|       return col;
 | |
|       }
 | |
|     
 | |
|     case 10: /* house */ {
 | |
|       d[0]--;
 | |
|       int is0 = 0, is1 = 0, is2 = 0, ismore = 0;
 | |
|       for(int a=0; a<dim; a++) {
 | |
|         int v = abs(d[a]);
 | |
|         if(v == 0) is0++;
 | |
|         else if(v == 1) is1++;
 | |
|         else if(v == 2) is2++;
 | |
|         else if(v > 2) ismore++;
 | |
|         }
 | |
|       if(d[dim-1]) return 0x101010;
 | |
|       else if(ismore) return 0x101010;
 | |
|       else if(is2) return 0x1800000;
 | |
|       else if(is1) return 0xFFFF00;
 | |
|       else return 0x1FFFFFF;
 | |
|       }
 | |
| 
 | |
|     case 11: /* orthoplex */ {
 | |
|       int s = abs(d[0] - 4) + abs(d[1] - 3) + abs(d[2] - 2) + abs(d[3] - 3);
 | |
|       if(s == 0) return 0x1FFFFFF;
 | |
|       else if(s == 12) return 0x1FF0000;
 | |
|       else if(s < 12) return 0x800000;
 | |
|       // else if(s == 13) return 0x1FF8000;
 | |
|       else return 0x202020;
 | |
|       }
 | |
|     
 | |
|     default:
 | |
|       return -1;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| void enable() {
 | |
|   rv_hook(patterns::hooks_generate_canvas, 100, mycanvas);
 | |
|   }
 | |
| 
 | |
| auto explore_structure(int _shapeid) {
 | |
|   using namespace tour;
 | |
|   return [=] (presmode mode) {
 | |
|     sync(mode, NO_VC);
 | |
|     if(mode == pmStart) {
 | |
|       tour::slide_backup(mapeditor::drawplayer, false);
 | |
|       tour::slide_backup(smooth_scrolling, true);
 | |
|       stop_game();
 | |
|       set_geometry(geometry == gCrystal534 ? gCrystal534 : gCrystal344);
 | |
|       enable_canvas();
 | |
|       patterns::whichCanvas = ' ';
 | |
|       shapeid = _shapeid;
 | |
|       enable();
 | |
|       crystal::crystal_period = 4;
 | |
|       start_game();
 | |
|       #if CAP_RAY
 | |
|       ray::max_cells = 4096;
 | |
|       #endif
 | |
|       }
 | |
|     if(mode == pmKey || mode == pmGeometrySpecial) {
 | |
|       stop_game();
 | |
|       set_geometry(geometry == gCrystal534 ? gCrystal344 : gCrystal534);
 | |
|       enable();
 | |
|       start_game();
 | |
|       }
 | |
|     };
 | |
|   }
 | |
| 
 | |
| void add_explore_structure(vector<tour::slide>& v, int id, string nshort, string nlong) {
 | |
|   string hds = "high-dimensional shapes/";
 | |
|   v.emplace_back(
 | |
|     tour::slide{hds+nshort, 999, tour::LEGAL::SPECIAL, 
 | |
|       nlong + "\n\n"
 | |
|       "In these slides, press 5 to switch between 4-dimensional and 6-dimensional space."
 | |
|       "Press End/Home to move forward/backward.",
 | |
|       explore_structure(id)
 | |
|       });
 | |
|   }
 | |
| 
 | |
| void house(int sides, int shape = 10) {
 | |
|   stop_game();
 | |
|   if(sides < 0)
 | |
|     set_geometry(gCrystal344);
 | |
|   else
 | |
|     crystal::set_crystal(sides);
 | |
|   set_variation(eVariation::pure);
 | |
|   enable_canvas();
 | |
|   patterns::whichCanvas = ' ';
 | |
|   shapeid = shape;
 | |
|   check_cgi();
 | |
|   enable();
 | |
|   start_game();
 | |
|   }
 | |
| 
 | |
| #if CAP_RVSLIDES
 | |
| tour::slide *gen_high_demo() {
 | |
|   high_slides.clear();
 | |
|   using namespace tour;
 | |
|   auto& v = high_slides;
 | |
|   v.emplace_back(
 | |
|     slide{"Introduction/Three-dimensional space", 999, LEGAL::NONE, 
 | |
|       "This is our 2D visualization of 3-dimensional space.\n\n"
 | |
|       "In most slides you can press '5' to enable or disable the coordinate display. "
 | |
|       "You can move the focus with numpad, arrowkeys, or clicking cells with mouse."
 | |
|       ,
 | |
|       [] (presmode mode) {        
 | |
|         sync(mode, VC);
 | |
|         if(mode == pmStart) {        
 | |
|           crystal::set_crystal(6);
 | |
|           patterns::whichCanvas = 'K';
 | |
|           start_game();
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"Introduction/Four-dimensional space", 999, LEGAL::NONE, 
 | |
|       "This is our 2D visualization of 4-dimensional space.",
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, VC);
 | |
|         if(mode == pmStart) {
 | |
|           crystal::set_crystal(8);
 | |
|           patterns::whichCanvas = 'K';
 | |
|           start_game();
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"Introduction/Color picker", 999, LEGAL::NONE, 
 | |
|       "Color picker. You can press '0' to '6' to adjust how fast the colors change.",
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart)
 | |
|           colorpicker::run_cpick();
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"games and puzzles/house 3D", 999, LEGAL::NONE, 
 | |
|       "A house in three dimensions. This is a 5x5 square, its center is white, rest of its interior is yellow, and its perimeter is red. "
 | |
|       "By using the third dimension, you can leave the square, or enter it back.",
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart) {
 | |
|           house(6);
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"games and puzzles/house 4D", 999, LEGAL::NONE, 
 | |
|       "A house in four dimensions. This is a 5x5x5 cube."
 | |
|       ,
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart) {
 | |
|           house(8);
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"games and puzzles/house, 3D visualization", 999, LEGAL::NONE, 
 | |
|       "A house in four dimensions, using the 3D version of our visualization. This visualization is harder to understand. Press End/Home to move forward/backward.",
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart) {
 | |
|           house(-1);
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"games and puzzles/4D orthoplex using 2D", 999, LEGAL::NONE, 
 | |
|       "Try to find the center of the orthoplex in four dimensions. This is a 4D analog of the octahedron.\n\n"
 | |
|       "The faces of the orthoplex are bright red, the outside is dark gray, and the center is white."
 | |
|       ,
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart) {
 | |
|           house(8, 11);
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"games and puzzles/4D orthoplex using 3D", 999, LEGAL::NONE, 
 | |
|       "The same visualization in 3D.",
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart) {
 | |
|           house(8, 11);
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"games and puzzles/basic roguelike", 999, LEGAL::NONE, 
 | |
|       "This is a basic roguelike in three dimensions. Even though it appears that it should be possible to move in such a way that "
 | |
|       "one of the enemies is no longer adjacent to us, it turns out that one of its other 'copies' will always manage "
 | |
|       "to chase us. This is clear when we imagine the actual higher-dimensional space.",
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, NO_VC | PLAYER);
 | |
|         if(mode == pmStart) {
 | |
|           crystal::set_crystal(6);
 | |
|           patterns::whichCanvas = 'c';
 | |
|           colortables['c'][0] = 0x208020;
 | |
|           colortables['c'][1] = 0x105010;
 | |
|           patterns::canvasback = 0x101010;
 | |
|           start_game();
 | |
|           auto & us = vid.cs;
 | |
|           us.charid = 4;
 | |
|           /* us.skincolor = 0xB55239FF;
 | |
|           us.haircolor = 0xB55239FF;
 | |
|           us.dresscolor = 0xB55239FF; */
 | |
|           us.skincolor = 0x202020FF;
 | |
|           us.haircolor = 0x202020FF;
 | |
|           us.dresscolor = 0x202020FF;
 | |
|           us.eyecolor = 0xC000FF;
 | |
|           cwt.at->move(0)->monst = moRedFox;
 | |
|           cwt.at->move(1)->monst = moLavaWolf;
 | |
|           minf[moLavaWolf].color = 0x909090;
 | |
|           minf[moLavaWolf].name = "Wolf";
 | |
|           minf[moRedFox].name = "Fox";
 | |
|           }
 | |
|        }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"games and puzzles/gravity mockup", 999, LEGAL::NONE, 
 | |
|       "A mockup of a 4D game with gravity. We use the 3D version of our visualization, while the gravity dimension is shown using perspective.",
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart) {
 | |
|           sokoban::run_sb();
 | |
|           }
 | |
|        }
 | |
|       });
 | |
|     
 | |
|   add_explore_structure(v, 0, "Cage", "In this series of slides we show various structures in four-dimensional space, using the three-dimensional variant of our visualization.\n\nWe start with a 4x4x4x4 cage with a golden point in the center.");
 | |
|   add_explore_structure(v, 1, "Tunnel", "One-dimensional tunnel");
 | |
|   add_explore_structure(v, 2, "Skeleton", "The 1-skeleton of the tessellation of Z^4 with cubes of edge 2");
 | |
|   add_explore_structure(v, 3, "Tunnel2", "Two-dimensional tunnel");
 | |
|   add_explore_structure(v, 4, "Hyperplanes", "Two hyperplanes in distance 2, i.e., three-dimensional tunnel.");
 | |
|   add_explore_structure(v, 5, "Far hyperplanes", "Two hyperplanes in distance 3.");
 | |
|   add_explore_structure(v, 6, "Orthogonal", "Two orthogonal hyperplanes.");
 | |
|   add_explore_structure(v, 7, "Quarterspaces", "Four quarterspaces.");
 | |
|   add_explore_structure(v, 8, "Diagonal", "Diagonal tunnel in all coordinates except one.");
 | |
|   add_explore_structure(v, 9, "Diagonal", "Diagonal tunnel in all coordinates.");
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"Magic cube/Standard magic cube", 999, LEGAL::NONE, 
 | |
|       "Magic Cube (aka Rubik's Cube) using two dimensions. This is an example of a visualization which is difficult for our method, because we are moving complex objects in the 3D space."
 | |
|       "Press 'r' to rotate the face (while the mouse pointer is on its center -- two coodinates must be 0 and one must be non-zero), Shift+R to reset.",
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart) {
 | |
|           magic::magic(6);
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"Magic cube/Four-dimensional magic cube", 999, LEGAL::NONE, 
 | |
|       "Magic Cube (4D) using two dimensions. Keys are the same as in the previous slide.\n\n"
 | |
|       "Use 'r' to rotate the 2D face under the mouse pointer (two coodinates must be 0 and two must be non-zero)."
 | |
|       ,
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart) {
 | |
|           magic::magic(8);
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"Magic cube/Four-dimensional magic cube, 3D visualization", 999, LEGAL::NONE, 
 | |
|       "Magic Cube (4D) using three dimensions.",
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart) {
 | |
|           magic::magic(-1);
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   v.emplace_back(
 | |
|     slide{"3D Sokoban", 999, LEGAL::NONE,
 | |
|       "A three-dimensional Sokoban puzzle visualized using H2.\n\n"
 | |
|       "The puzzle is designed so that all three dimensions matter.\n\n"
 | |
|       "Press 'r' or Backspace to undo moves.",
 | |
|       [] (presmode mode) {
 | |
|         sync(mode, 0);
 | |
|         if(mode == pmStart) {
 | |
|           crystal_sokoban::run_sb();
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   callhooks(pres::hooks_build_rvtour, "highdim", high_slides);
 | |
|   pres::add_end(v);
 | |
|   return &high_slides[0];
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| auto highdim_hooks  = 
 | |
|     addHook_slideshows(120, [] (tour::ss::slideshow_callback cb) {
 | |
|   
 | |
|     if(high_slides.empty()) gen_high_demo();
 | |
| 
 | |
|     cb(XLAT("visualizing higher-dimensional spaces"), &high_slides[0], 'h');
 | |
|     });
 | |
| 
 | |
| } | 
