mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 14:02:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			990 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			990 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| namespace nilrider {
 | |
| 
 | |
| bool all(checkerparam c) { return c.t->collected_triangles == Flag(isize(c.l->triangles))-1; }
 | |
| 
 | |
| goalchecker basic_check(ld time_limit, ld rev_limit) {
 | |
|   return [=] (checkerparam c) {
 | |
|     if(c.t->timer > time_limit || c.rev > rev_limit) return grFailed;
 | |
|     if(all(c)) return grSuccess;
 | |
|     return grNone;
 | |
|     };
 | |
|   }
 | |
| 
 | |
| eGoalResult ski_check(checkerparam c) {
 | |
|   if(c.t->on_surface && c.t->where[0] >= 8) return grSuccess;
 | |
|   return grNone;
 | |
|   }
 | |
| 
 | |
| goalchecker get_any(ld time_limit, ld rev_limit) {
 | |
|   return [=] (checkerparam c) {
 | |
|     if(c.t->timer > time_limit || c.rev > rev_limit) return grFailed;
 | |
|     if(c.t->collected_triangles) return grSuccess;
 | |
|     return grNone;
 | |
|     };
 | |
|   }
 | |
| 
 | |
| goalchecker get_ordered(ld time_limit, ld rev_limit) {
 | |
|   return [=] (checkerparam c) {
 | |
|     if(c.t->timer > time_limit || c.rev > rev_limit) return grFailed;
 | |
|     if(c.t->collected_triangles & (c.t->collected_triangles+1)) return grFailed;
 | |
|     if(all(c)) return grSuccess;
 | |
|     return grNone;
 | |
|     };
 | |
|   }
 | |
| 
 | |
| goalchecker yplus_check(ld time_limit, ld rev_limit) {
 | |
|   return [=] (checkerparam c) {
 | |
|     if(c.t->timer > time_limit || c.rev > rev_limit) return grFailed;
 | |
|     if(c.t->where[1] < 0) return grFailed;
 | |
|     if(all(c)) return grSuccess;
 | |
|     return grNone;
 | |
|     };
 | |
|   }
 | |
| 
 | |
| goalchecker fullstop_check(ld time_limit, ld rev_limit) {
 | |
|   return [=] (checkerparam c) {
 | |
|     if(c.t->timer > time_limit || c.rev > rev_limit) return grFailed;
 | |
|     if(all(c) && c.t->vel == 0) return grSuccess;
 | |
|     return grNone;
 | |
|     };
 | |
|   }
 | |
| 
 | |
| ld f_heisenberg0(hyperpoint h) { return nilv::convert_bonus(h, nilv::nmHeis, nilv::model_used); }
 | |
| 
 | |
| ld rot_plane(hyperpoint h) { return nilv::convert_bonus(h, nilv::nmSym, nilv::model_used); }
 | |
| 
 | |
| ld f_rot_well(hyperpoint h) {
 | |
|   return rot_plane(h) + h[0] * h[0] + h[1] * h[1];
 | |
|   }
 | |
| 
 | |
| ld long_x(hyperpoint h) {
 | |
|   return rot_plane(h) + h[0] * h[1] / 2;
 | |
|   }
 | |
| 
 | |
| ld cycloid(ld x) {
 | |
|   // for x from 0 to TAU, returns y from 0 to 2
 | |
|   ld alpha = binsearch(0, TAU, [x] (ld a) {
 | |
|     ld ax = a - sin(a);
 | |
|     return ax >= x;
 | |
|     }, 20);
 | |
|   return 1 - cos(alpha);
 | |
|   }
 | |
| 
 | |
| ld cycloid_wave(ld x) {
 | |
|   /* static bool test = true;
 | |
|   if(test) {
 | |
|     for(ld a=0; a<TAU; a += 0.01) printf("%5.3f : %5.3f\n", a, cycloid(a));
 | |
|     exit(1);
 | |
|     } */
 | |
|   int i = floor(x);
 | |
|   ld xf = x - i;
 | |
|   return cycloid(xf * TAU) * ((i&1) ? -1 : 1) / TAU;
 | |
|   }
 | |
| 
 | |
| ld brachistochrone(hyperpoint h) {
 | |
|   return long_x(h) - cycloid_wave(h[0] / 63) * 63 + h[1] * h[1] / 5;
 | |
|   }
 | |
| 
 | |
| ld geodesics_0(hyperpoint h) {
 | |
|   ld r = hypot_d(2, h);
 | |
|   ld phi = atan2(h[1], h[0]);
 | |
|   
 | |
|   ld z = (phi / TAU) * (M_PI * r * r + TAU);
 | |
|   return z + rot_plane(h);
 | |
|   }
 | |
| 
 | |
| ld geodesics_at_4(hyperpoint h) {
 | |
|   ld r = 4;
 | |
|   ld phi = atan2(h[1], h[0]);
 | |
|   
 | |
|   ld z = (phi / TAU) * (M_PI * r * r + TAU);
 | |
|   return z + rot_plane(h);
 | |
|   }
 | |
| 
 | |
| map<char, color_t> bcols = {
 | |
|   {' ', 0xFF101010},
 | |
|   {'W', 0xFFFFFFFF},
 | |
|   {'g', 0xFF008000},
 | |
|   {'h', 0xFF20A020},
 | |
|   {'r', 0xFFFF4040},
 | |
|   {'u', 0xFF4040FF},
 | |
|   {'b', 0xFF804000},
 | |
|   {'l', 0xFF0000C0},
 | |
|   {'f', 0xFF603000},
 | |
|   {'F', 0xFF804000},
 | |
|   {'2', 0xFF404040},
 | |
|   {'4', 0xFF808080},
 | |
|   {'6', 0xFFC0C0C0},
 | |
|   {'!', 0xFF000000},
 | |
|   {'Y', 0xFFFFFF80},
 | |
|   {'y', 0xFFC0C040},
 | |
|   };
 | |
| 
 | |
| const int pixel_per_block = 16;
 | |
| 
 | |
| map<char, array<string, pixel_per_block> > submaps = {
 | |
|   {'o', {
 | |
|     "WWWWWWWWWWWWWWWW",
 | |
|     "W22222222222222W",
 | |
|     "W22222666622222W",
 | |
|     "W22266222266222W",
 | |
|     "W22622222222622W",
 | |
|     "W22622222222622W",
 | |
|     "W26222222222262W",
 | |
|     "W262222WW222262W",
 | |
|     "W262222WW222262W",
 | |
|     "W26222222222262W",
 | |
|     "W22622222222622W",
 | |
|     "W22622222222622W",
 | |
|     "W22266222266222W",
 | |
|     "W22222666622222W",
 | |
|     "W22222222222222W",
 | |
|     "WWWWWWWWWWWWWWWW"
 | |
|     }},
 | |
|   {'x', {
 | |
|     "WWWWWWWWWWWWWWWW",
 | |
|     "W22222222222222W",
 | |
|     "W22222222222222W",
 | |
|     "W22222222222222W",
 | |
|     "W22222222222222W",
 | |
|     "W22222222222222W",
 | |
|     "W22222622622222W",
 | |
|     "W222222rW222222W",
 | |
|     "W222222Wr222222W",
 | |
|     "W22222622622222W",
 | |
|     "W22222222222222W",
 | |
|     "W22222222222222W",
 | |
|     "W22222222222222W",
 | |
|     "W22222222222222W",
 | |
|     "W22222222222222W",
 | |
|     "WWWWWWWWWWWWWWWW"
 | |
|     }},
 | |
|   {'~', {
 | |
|     "WWWWWWWWWWWWWWWW",
 | |
|     "6WWWWWWWWWWWWWWW",
 | |
|     "6WWWWWYWWWWWWWWW",
 | |
|     "6WWWWWWWWWWWWWWW",
 | |
|     "6WYWWWWWWWYWWWWW",
 | |
|     "WWWWWWWWWWWWWWWW",
 | |
|     "6WWWWWWWWWWWWWWW",
 | |
|     "6WWWWWWWWWWWWWWW",
 | |
|     "6WWWWWWYWWWWWWWW",
 | |
|     "6WWWWWWWWWWWWYWW",
 | |
|     "WWWWWWWWWWWWWWWW",
 | |
|     "6WWYWWWWWWWWWWWW",
 | |
|     "6WWWWWWWWWWWWWWW",
 | |
|     "6WWWWWWWWWYWWWWW",
 | |
|     "6WWWWWWWWWWWWWWW",
 | |
|     "WWWWWWWWWWWWWWWW"
 | |
|     }},
 | |
| 
 | |
|   {'b', {
 | |
|     "                ",
 | |
|     " rrr rrr rrr rrr",
 | |
|     "                ",
 | |
|     "rr rrr rrr rrr r",
 | |
|     "                ",
 | |
|     " rrr rrr rrr rrr",
 | |
|     "                ",
 | |
|     "rr rrr rrr rrr r",
 | |
|     "                ",
 | |
|     " rrr rrr rrr rrr",
 | |
|     "                ",
 | |
|     "rr rrr rrr rrr r",
 | |
|     "                ",
 | |
|     " rrr rrr rrr rrr",
 | |
|     "                ",
 | |
|     "rr rrr rrr rrr r",
 | |
|     }},
 | |
|   {'f', {
 | |
|     "FfFfFfFfFfFfFfFf",
 | |
|     "fFfFfFfFfFfFfFfF",
 | |
|     "FfFfFfFfFfFfFfFf",
 | |
|     "fFfFfFfFfFfFfFfF",
 | |
|     "FfFfFfFfFfFfFfFf",
 | |
|     "fFfFfFfFfFfFfFfF",
 | |
|     "FfFfFfFfFfFfFfFf",
 | |
|     "fFfFfFfFfFfFfFfF",
 | |
|     "FfFfFfFfFfFfFfFf",
 | |
|     "fFfFfFfFfFfFfFfF",
 | |
|     "FfFfFfFfFfFfFfFf",
 | |
|     "fFfFfFfFfFfFfFfF",
 | |
|     "FfFfFfFfFfFfFfFf",
 | |
|     "fFfFfFfFfFfFfFfF",
 | |
|     "FfFfFfFfFfFfFfFf",
 | |
|     "fFfFfFfFfFfFfFfF",
 | |
|     }},
 | |
|   {'l', {
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     "llllllllllllllll",
 | |
|     }},
 | |
|   {'g', {
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     }},
 | |
|   {'G', {
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghWhghg",
 | |
|     "ghghrhghghWlWhgh",
 | |
|     "hghrWrhghghWhghg",
 | |
|     "ghghrhghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghlhghghghg",
 | |
|     "ghghghlWlhghghgh",
 | |
|     "hghghghlhghghghg",
 | |
|     "ghghghghghghgrgh",
 | |
|     "hghglghghghgrWrg",
 | |
|     "ghglWlghghghgrgh",
 | |
|     "hghglghghghghghg",
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     }},
 | |
|   {'r', {
 | |
|     "rrrrrrrrrrrrrrru",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "ubbbbbbbbbbbbbbu",
 | |
|     "urrrrrrrrrrrrrrr",
 | |
|     }},
 | |
|   {'*', {
 | |
|     "WWWWWW WW WWWWWW",
 | |
|     "W              W",
 | |
|     "W              W",
 | |
|     "W              W",
 | |
|     "W              W",
 | |
|     "W      rr       W",
 | |
|     "       rr       ",
 | |
|     "W     r  r     W",
 | |
|     "W     r  r     W",
 | |
|     "     r    r     ",
 | |
|     "W    r    r    W",
 | |
|     "W   rrrrrrrr   W",
 | |
|     "W              W",
 | |
|     "W              W",
 | |
|     "W              W",
 | |
|     "WWWWWW WW WWWWWW",
 | |
|     }},
 | |
|   {'+', {
 | |
|     "gh     WW     gh",
 | |
|     "hg     WW     hg",
 | |
|     "       WW       ",
 | |
|     "                ",
 | |
|     "                ",
 | |
|     "       WW       ",
 | |
|     "       WW       ",
 | |
|     "WWW  WWWWWW  WWW",
 | |
|     "WWW  WWWWWW  WWW",
 | |
|     "       WW       ",
 | |
|     "       WW       ",
 | |
|     "                ",
 | |
|     "                ",
 | |
|     "       WW       ",
 | |
|     "gh     WW     gh",
 | |
|     "hg     WW     hg",
 | |
|     }},
 | |
|   {'-', {
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     "                ",
 | |
|     "                ",
 | |
|     "                ",
 | |
|     "                ",
 | |
|     "                ",
 | |
|     "WWW  WWWWWW  WWW",
 | |
|     "WWW  WWWWWW  WWW",
 | |
|     "                ",
 | |
|     "                ",
 | |
|     "                ",
 | |
|     "                ",
 | |
|     "                ",
 | |
|     "ghghghghghghghgh",
 | |
|     "hghghghghghghghg",
 | |
|     }},
 | |
|   {'|', {
 | |
|     "gh     WW     gh",
 | |
|     "hg     WW     hg",
 | |
|     "gh     WW     gh",
 | |
|     "hg            hg",
 | |
|     "gh            gh",
 | |
|     "hg     WW     hg",
 | |
|     "gh     WW     gh",
 | |
|     "hg     WW     hg",
 | |
|     "gh     WW     gh",
 | |
|     "hg     WW     hg",
 | |
|     "gh     WW     gh",
 | |
|     "hg            hg",
 | |
|     "gh            gh",
 | |
|     "hg     WW     hg",
 | |
|     "gh     WW     gh",
 | |
|     "hg     WW     hg",
 | |
|     }},
 | |
|   {'T', { /* trampoline */
 | |
|     "WWWWWWWWWWWWWWWW",
 | |
|     "WYYYYYYYYYYYYYYW",
 | |
|     "WYyyyyyyyyyyyyYW",
 | |
|     "WYyYYYYYYYYYYyYW",
 | |
|     "WYyYyyyyyyyyYyYW",
 | |
|     "WYyYyYYYYYYyYyYW",
 | |
|     "WYyYyYyyyyYyYyYW",
 | |
|     "WYyYyYyYYyYyYyYW",
 | |
|     "WYyYyYyYYyYyYyYW",
 | |
|     "WYyYyYyyyyYyYyYW",
 | |
|     "WYyYyYYYYYYyYyYW",
 | |
|     "WYyYyyyyyyyyYyYW",
 | |
|     "WYyYYYYYYYYYYyYW",
 | |
|     "WYyyyyyyyyyyyyYW",
 | |
|     "WYYYYYYYYYYYYYYW",
 | |
|     "WWWWWWWWWWWWWWWW",
 | |
|     }},
 | |
|   {'V', { /* velocity converter */
 | |
|     "WWWWWWWWWWWWWWWW",
 | |
|     "WrrrrrrrrrrrrrrW",
 | |
|     "WrbbrbbrrbbrbbrW",
 | |
|     "WrbbrbbrrbbrbbrW",
 | |
|     "WrrrrrrrrrrrrrrW",
 | |
|     "WrbbrbbrrbbrbbrW",
 | |
|     "WrbbrbbrrbbrbbrW",
 | |
|     "WrrrrrrrrrrrrrrW",
 | |
|     "WrrrrrrrrrrrrrrW",
 | |
|     "WrbbrbbrrbbrbbrW",
 | |
|     "WrbbrbbrrbbrbbrW",
 | |
|     "WrrrrrrrrrrrrrrW",
 | |
|     "WrbbrbbrrbbrbbrW",
 | |
|     "WrbbrbbrrbbrbbrW",
 | |
|     "WrrrrrrrrrrrrrrW",
 | |
|     "WWWWWWWWWWWWWWWW",
 | |
|     }},
 | |
|   };
 | |
| 
 | |
| level rotplane(
 | |
|   "Trying to be horizontal", 'r', 0,
 | |
|   "Collect all the triangles!\n\n"
 | |
|   "All the lines going through the center are horizontal.\n"
 | |
|   "However, this is Nil geometry. The other lines are NOT horizontal! Clockwise ones slope upwards, and counterclockwise ones slope downwards.\n"
 | |
|   "Your unicycle is powered only by the gravity. Use that to your advantage!"
 | |
|   ,
 | |
| 
 | |
|   -7.5*dft_block, 7.5*dft_block, 7.5*dft_block, -7.5*dft_block,
 | |
|   {
 | |
|   "ggggggggggggggg",
 | |
|   "ggggggfffgggggg",
 | |
|   "ggggggfffgggggg",
 | |
|   "gggg|ggggg|gggg",
 | |
|   "ggg-*-----*-ggg",
 | |
|   "gggg|ggggf|gggg",
 | |
|   "ggGg|g+ggg|grgG",
 | |
|   "gGgg|g|xgo|gggg",
 | |
|   "ggGg|g|ggg|grgg",
 | |
|   "gggg|g|ggg|gggg",
 | |
|   "gg--*-+---*--gg",
 | |
|   "gggg|ggggg|gggg",
 | |
|   "gggggggGGgggggg",
 | |
|   "ggggggggggggggg",
 | |
|   "ggggggggggggggg"
 | |
|   },
 | |
|   6, 6, {},
 | |
|   rot_plane,
 | |
|   {
 | |
|     // the solver[0.25] result is 36.92
 | |
|     goal{0x40FF40, "Collect all the triangles in below 60 seconds", basic_check(60, 999), "ROTPLANE", "Trying to be horizontal"},
 | |
|     goal{0xFFD500, "Collect all the triangles in below 38 seconds", basic_check(38, 999), "ROTPLANE2", ""}
 | |
|     }
 | |
|   );
 | |
| 
 | |
| level longtrack(
 | |
|   "A Long Track", 'l', 0,
 | |
|   "The main street is horizontal, as well as the lines orthogonal to it.",
 | |
|   0*dft_block, +6.5*dft_block, 64*dft_block, -1.5*dft_block,
 | |
|   {
 | |
|   "Ggggggggr!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
 | |
|   "Ggggggggr!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
 | |
|   "Ggggggggr!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!x!",
 | |
|   "Ggggxgggr!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
 | |
|   "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg",
 | |
|   "ggggggggrggggggrggggggggrGggggggggGGggggGGGgggggGGGGggggggggggGG",
 | |
|   "--------------------------------------------------------------*G",
 | |
|   "gggggfffffggggggggggggggggggggggggggggggggggggggggggggggggggggGG"
 | |
|   },
 | |
|   0, 5, {},
 | |
|   long_x,
 | |
|   {
 | |
|     // the solver[0.25] result is 1:08.56 (reduced to 1:08.45 by removing some points)
 | |
|     goal{0xFFD500, "Collect the triangle in below 1:15", basic_check(75, 999), "LONGTRACK", ""},
 | |
|     // the solver[0.25] + some manual modifications achieves 1:37.44
 | |
|     goal{0xFF4040, "Stop where the triangle is in below 1:45", fullstop_check(75, 999), "LONGTRACKSTOP", ""},
 | |
|     // the solver[0.25] result is 1:45.52
 | |
|     goal{0x303030, "Reach the triangle without going on the right side of the road below 2:00", yplus_check(120, 999), "LONGTRACKLEFT", ""},
 | |
| 
 | |
|     goal{0x40FF40, "Stop where the triangle is without reversing time", basic_check(999, 0), "", "A Long Track"},
 | |
|     }
 | |
|   );
 | |
| 
 | |
| level geodesical(
 | |
|   "Roads are Geodesics", 'g', nrlPolar,
 | |
|   "Geodesics are the lines that are (locally) shortest. In the default settings, "
 | |
|   "the space in Nil Rider is rendered according to the Fermat's principle, that is, "
 | |
|   "light rays are assumed to be geodesics.\n\n"
 | |
|   "Geodesics in Nil are horizontal, vertical, and helical. "
 | |
|   "In this level, all the roads are (fragments of) helical geodesics.",
 | |
|   -45._deg, 3*dft_block, 225._deg, 0,
 | |
|   // -8*dft_block, +8*dft_block, +8*dft_block, 0, 
 | |
|   {
 | |
|   "ffffffffffffffff",
 | |
|   "----------------",
 | |
|   "----------------",
 | |
|   "*--------------*",
 | |
|   "----------------",
 | |
|   "----------------",
 | |
|   "----------------",
 | |
|   "bbbbbbbbbbbbbbbb",
 | |
|   },
 | |
|   0, 6, {},
 | |
|   geodesics_0,
 | |
|   {
 | |
|     // the solver[0.25] result is 26.10
 | |
|     goal{0xFFD500, "Collect both triangles in below 30 seconds", basic_check(30, 999), "GEODESICS", ""},
 | |
|     goal{0x40FF40, "Collect both triangles without reversing time", basic_check(999, 0), "", "Roads are Geodesics"}
 | |
|     }
 | |
|   );
 | |
| 
 | |
| level geodesical4(
 | |
|   "Helical Geodesic", 's', nrlPolar,
 | |
|   "The main road here is a helical geodesic. Orthogonal lines are horizontal.",  
 | |
|   -80._deg, 8.5*dft_block, 260._deg, 0.5*dft_block,
 | |
|   // -8*dft_block, +8*dft_block, +8*dft_block, 0, 
 | |
|   {
 | |
|   "!!!!!!!!!!!!!!!!",
 | |
|   "ffffffffffffffff",
 | |
|   "gggggggggggggggg",
 | |
|   "ggGggggggggGgggg",
 | |
|   "+--------------*",
 | |
|   "gggggGggggGggggg",
 | |
|   "gggGgggggGgggggg",
 | |
|   "ffffffffffffffff",
 | |
|   },
 | |
|   0, 5, {},
 | |
|   geodesics_at_4,
 | |
|   {
 | |
|     // the solver[0.25] result is 32.04
 | |
|     goal{0xFFD500, "Collect the triangle in below 35 seconds", basic_check(35, 999), "HELICAL", ""},
 | |
|     goal{0x40FF40, "Collect the triangle without reversing time", basic_check(999, 0), "", "Helical Geodesic"},
 | |
|     }
 | |
|   );
 | |
| 
 | |
| level heisenberg0(
 | |
|   "Heisenberg Zero", 'z', 0,
 | |
|   "This is the plane z=0 in the Heisenberg group model of Nil. The roads are x=0, y=0 axes.",  
 | |
|   -7.5*dft_block, 7.5*dft_block, 7.5*dft_block, -7.5*dft_block,
 | |
|   {
 | |
|   "ggggggg|ggggggg",
 | |
|   "grggggg|gggggrg",
 | |
|   "gg*gggg|gggg*gg",
 | |
|   "gggffgg|ggggggg",
 | |
|   "gggffgg|ggfrggg",
 | |
|   "ggggggg|gggggGg",
 | |
|   "ggggggg|ggggggg",
 | |
|   "-------+-------",
 | |
|   "ggggggg|ggggggg",
 | |
|   "gggGgog|ggggggg",
 | |
|   "ggggggg|ggrgrgg",
 | |
|   "gggGgGg|ggggggg",
 | |
|   "gg*gggg|gggg*gg",
 | |
|   "grggggg|gggggrg",
 | |
|   "ggggggg|ggggggg"
 | |
|   },
 | |
|   8, 8, {},
 | |
|   f_heisenberg0,
 | |
|   {
 | |
|     // the solver[0.25] result is 49:15
 | |
|     goal{0x40FFd0, "Collect all triangles in below 0:55", basic_check(55, 999), "HZERO", ""},
 | |
|     goal{0x40c040, "Collect all triangle without reversing time", basic_check(999, 0), "", "Heisenberg Zero"},
 | |
|     }
 | |
|   );
 | |
| 
 | |
| level rotwell(
 | |
|   "Deep Well", 'd', nrlOrder,
 | |
|   "Can you escape this well?\n\n"
 | |
|   "The sculpture in the center is built around eight helical geodesics which start in a point on the floor, and all cross in a point in the sky. Try to find that point and "
 | |
|   "look below!\n\n"
 | |
|   "Note: you can move the camera freely (using the arrow keys and PageUp/Down/Home/End) while the game is paused."
 | |
|   ,
 | |
|   -7.5*dft_block, 7.5*dft_block, 7.5*dft_block, -7.5*dft_block,
 | |
|   {
 | |
|   "ggggggggggggggg",
 | |
|   "gogggggggggggog",
 | |
|   "ggggg--*--ggggg",
 | |
|   "gggg*ggggg*gggg",
 | |
|   "ggg*ggGfGgg*ggg",
 | |
|   "gg|ggfgggfgg|gg",
 | |
|   "gg|gGgggggGg|gg",
 | |
|   "gg*gfggxggfg*gg",
 | |
|   "gg|gGgggggGg|gg",
 | |
|   "gg|ggfgggfgg|gg",
 | |
|   "ggg*ggGfGgg*ggg",
 | |
|   "gggg*ggggg*gggg",
 | |
|   "ggggg--*--ggggg",
 | |
|   "gogggggggggggog",
 | |
|   "ggggggggggggggg"
 | |
|   },
 | |
|   8, 8, {},
 | |
|   f_rot_well,
 | |
|   {
 | |
|     // the solver[0.5] result is 1:19.54 (obtained using get_ordered)
 | |
|     goal{0xFFD500, "Collect all triangles below 1:25", basic_check(85, 999), "ROTWELL", ""},
 | |
|     goal{0x40c040, "Collect all triangle without reversing time", basic_check(999, 0), "", "Deep Well"}
 | |
|     }
 | |
|   );
 | |
| 
 | |
| level labyrinth(
 | |
|   "Labyrinth", 'l', 0,
 | |
|   "You will have to go clockwise this time!\n\n"
 | |
|   "The squares of this level have half of their usual length.",
 | |
|   -7.5*dft_block/2, 7.5*dft_block/2, 7.5*dft_block/2, -7.5*dft_block/2,
 | |
|   {
 | |
|   "ogggrfffffffffo",
 | |
|   "g*ggrgggggggggg",
 | |
|   "ggggrgggggggggg",
 | |
|   "ggggrgggggggggg",
 | |
|   "ggggrgggrrggggg",
 | |
|   "ggggrgGGGrrgggg",
 | |
|   "ggggrGgggGrgggg",
 | |
|   "ggggrGgxgGrgggg",
 | |
|   "ggggrGgggGrgggg",
 | |
|   "ggggrrGGGrrgggg",
 | |
|   "gggggrrrrrggggg",
 | |
|   "ggggggggggggggg",
 | |
|   "ggggggggggggggg",
 | |
|   "ggggggggggggggg",
 | |
|   "offfffffffffffo",
 | |
|   },
 | |
|   8, 8, {},
 | |
|   rot_plane,
 | |
|   {
 | |
|     // the solver[0.1] result is 1:03.53
 | |
|     // the solver[0.15] result is 1:06.58
 | |
|     // the solver[0.24] result is 1:08.54
 | |
|     // the solver[0.25] result is 1:22.09 (it goes north for some reason)
 | |
|     goal{0xFFD500, "Collect the triangle in below 1:15", basic_check(75, 999), "LABYRINTH", ""},
 | |
|     goal{0x40c040, "Collect all triangle without reversing time", basic_check(999, 0), "", "Labyrinth"}
 | |
|     }
 | |
|   );
 | |
| 
 | |
| level obstacle(
 | |
|   "Obstacle Course", 'o', 0,
 | |
|   "The main street is horizontal, as well as the lines orthogonal to it.",
 | |
|   0*dft_block, 2.5*dft_block, 64*dft_block, -2.5*dft_block,
 | |
|   {
 | |
|   "ggggggGrggGrgggggggggggggggggggggGrxgggggggggGrggggggggGrggggggo",
 | |
|   "ggggggGrggGrgggGrgggggGrgggggggggGrgggggggggggggGrgggggGrggggggo",
 | |
|   "-----------r----r------r----r-----r--r---------r---------------*",
 | |
|   "ggggggGrgggggggGrgggggGrggggggggggggGrggggggGrgggggggggGrggggggo",
 | |
|   "ggggggGrgggggggGrgggggggggggggggggggGrgggggggggGrggggggGrggggggo"
 | |
|   },
 | |
|   0, 4, {},
 | |
|   long_x,
 | |
|   {
 | |
|     goal{0xFFFFC0, "Collect the triangle in below 1:25, reversing time at most 3 times", basic_check(85, 3), "OBSTACLE1", ""},
 | |
|     goal{0xFFD500, "Collect the triangle in below 1:10, reversing time at most 3 times", basic_check(70, 3), "OBSTACLE2", ""},
 | |
|     goal{0x40c040, "Collect the triangle without reversing time", basic_check(999, 0), "", "Obstacle Course"}
 | |
|     }
 | |
|   );
 | |
| 
 | |
| level *curlev = &rotplane;
 | |
| 
 | |
| struct complex_surface {
 | |
|   hyperpoint cur;
 | |
|   map<pair<int, int>, surface_fun> blocks;
 | |
| 
 | |
|   static transmatrix flatpush(hyperpoint h) { return rgpushxto0(nilv::convert(point31(h[0], h[1], 0), nilv::nmSym, nilv::model_used)); }
 | |
|   static transmatrix hpush(hyperpoint h) { h[1] = 0; h[2] = 0; return flatpush(h); }
 | |
|   static transmatrix vpush(hyperpoint h) { h[0] = 0; h[2] = 0; return flatpush(h); }
 | |
| 
 | |
|   static hyperpoint spin_around(hyperpoint h, hyperpoint start, hyperpoint ctr, ld dir) {
 | |
|     auto h1 = h - ctr;
 | |
| 
 | |
|     auto d = hypot_d(2, h1);
 | |
|     ld r = 2;
 | |
|     h1 = h1 * (r / d);
 | |
|     ld phi = atan2(h1[1], h1[0]) + 90._deg;
 | |
|     ld phis = atan2((start-ctr)[1], (start-ctr)[0]) + 90._deg;
 | |
|     cyclefix(phi, phis);
 | |
|     h1 += ctr;
 | |
|     auto z = [&] (ld a) { return point31(r*sin(a), -r*cos(a), (r * r / 2) * (a-sin(a)*cos(a))); };
 | |
| 
 | |
|     if(0) {
 | |
|       // not smooth enough ....
 | |
|       transmatrix q = gpushxto0(z(phis)) * rgpushxto0(z(phi));
 | |
|       hyperpoint arc = rgpushxto0(start) * q * flatpush(h-h1) * C0;
 | |
|       return arc;
 | |
|       }
 | |
| 
 | |
|     hyperpoint h2 = h; if(start[0] == ctr[0]) h2[1] = start[1]; else h2[0] = start[0];
 | |
|     hyperpoint pre = rgpushxto0(start) * flatpush(h2-start) * flatpush(h-h2) * C0;
 | |
| 
 | |
|     hyperpoint last = rgpushxto0(start) * gpushxto0(z(phis)) * rgpushxto0(z(phis + dir * 90._deg)) * C0;
 | |
|     hyperpoint h3 = h; if(start[0] != ctr[0]) h3[1] = last[1]; else h3[0] = last[0];
 | |
|     hyperpoint post = rgpushxto0(last) * flatpush(h3-last) * flatpush(h-h3) * C0;
 | |
| 
 | |
|     ld p = (1+sin((phi-phis)*2 - 90._deg)) / 2.;
 | |
| 
 | |
|     pre[2] = pre[2] + (post[2] - pre[2]) * p;
 | |
| 
 | |
|     // println(hlog, "START = ", start, " LAST = ", last, " h = ", h, " h2 = ", h2, " h3 = ", h3, " p = ", p, " pre = ", pre);
 | |
|     // exit(1);
 | |
| 
 | |
|     return pre;
 | |
|     // flatpush(h1 - start) * flatpush(h - h1) * C0;
 | |
|     }
 | |
| 
 | |
|   static hyperpoint rel(int x, int y) { return point30(x, y, 0); };
 | |
| 
 | |
|   surface_fun& at(hyperpoint h) {
 | |
|     int ax = int(floor(h[0] / 4));
 | |
|     int ay = int(floor(h[1] / 4));
 | |
|     return blocks[{ax, ay}];
 | |
|     };
 | |
| 
 | |
|   void right_block() {
 | |
|     auto c = cur;
 | |
|     println(hlog, "RIGHT at ", c);
 | |
|     auto f = [c] (hyperpoint h) { return rgpushxto0(c) * hpush(h-c) * vpush(h-c) * C0; };
 | |
|     at(c+rel(2, 0)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(4, 0));
 | |
|     }
 | |
| 
 | |
|   void left_block() {
 | |
|     auto c = cur;
 | |
|     println(hlog, "LEFT at ", c);
 | |
|     auto f = [c] (hyperpoint h) { return rgpushxto0(c) * hpush(h-c) * vpush(h-c) * C0; };
 | |
|     at(c+rel(-2, 0)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(-4, 0));
 | |
|     }
 | |
| 
 | |
|   void up_block() {
 | |
|     auto c = cur;
 | |
|     println(hlog, "UP at ", c);
 | |
|     auto f = [c] (hyperpoint h) { return rgpushxto0(c) * vpush(h-c) * hpush(h-c) * C0; };
 | |
|     at(c+rel(0, 2)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(0, 4));
 | |
|     }
 | |
| 
 | |
|   void down_block() {
 | |
|     auto c = cur;
 | |
|     println(hlog, "DOWN at ", c);
 | |
|     auto f = [c] (hyperpoint h) { return rgpushxto0(c) * vpush(h-c) * hpush(h-c) * C0; };
 | |
|     at(c+rel(0, -2)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(0, -4));
 | |
|     }
 | |
| 
 | |
|   /* counterclockwise */
 | |
|   void turn_up_block() {
 | |
|     auto c = cur;
 | |
|     println(hlog, "TURN UP at ", c);
 | |
|     auto f = [c] (hyperpoint h) { return (spin_around(h, c, c+rel(0, 2), 1)); };
 | |
|     at(c+rel(2, 0)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(2, 2));
 | |
|     };
 | |
|   void turn_left_block() {
 | |
|     auto c = cur;
 | |
|     auto f = [c] (hyperpoint h) { return (spin_around(h, c, c+rel(-2, 0), 1)); };
 | |
|     at(c+rel(0, 2)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(-2, 2));
 | |
|     };
 | |
|   void turn_down_block () {
 | |
|     auto c = cur;
 | |
|     auto f = [c] (hyperpoint h) { return (spin_around(h, c, c+rel(0, -2), 1)); };
 | |
|     at(c+rel(-2, 0)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(-2, -2));
 | |
|     };
 | |
|   void turn_right_block() {
 | |
|     auto c = cur;
 | |
|     auto f = [c] (hyperpoint h) { return (spin_around(h, c, c+rel(2, 0), 1)); };
 | |
|     at(c+rel(0, -2)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(2, -2));
 | |
|     };
 | |
| 
 | |
|   /* clockwise */
 | |
|   void turn_up_block2() {
 | |
|     auto c = cur;
 | |
|     println(hlog, "TURN UP at ", c);
 | |
|     auto f = [c] (hyperpoint h) { return (spin_around(h, c, c+rel(0, 2), -1)); };
 | |
|     at(c+rel(-2, 0)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(-2, 2));
 | |
|     };
 | |
|   void turn_left_block2() {
 | |
|     auto c = cur;
 | |
|     auto f = [c] (hyperpoint h) { return (spin_around(h, c, c+rel(-2, 0), -1)); };
 | |
|     at(c+rel(0, -2)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(-2, -2));
 | |
|     };
 | |
|   void turn_down_block2() {
 | |
|     auto c = cur;
 | |
|     auto f = [c] (hyperpoint h) { return (spin_around(h, c, c+rel(0, -2), -1)); };
 | |
|     at(c+rel(2, 0)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(2, -2));
 | |
|     };
 | |
|   void turn_right_block2() {
 | |
|     auto c = cur;
 | |
|     auto f = [c] (hyperpoint h) { return (spin_around(h, c, c+rel(2, 0), -1)); };
 | |
|     at(c+rel(0, 2)) = [f] (hyperpoint h) { return f(h)[2]; };
 | |
|     cur = f(c+rel(2, 2));
 | |
|     };
 | |
| 
 | |
|   ld get(hyperpoint h) {
 | |
|     int ax = int(floor(h[0] / 4));
 | |
|     int ay = int(floor(h[1] / 4));
 | |
|     if(blocks.count({ax, ay})) return blocks[{ax, ay}] (h);
 | |
|     return 0;
 | |
|     }
 | |
| 
 | |
|   complex_surface(hyperpoint h) : cur(h) {}
 | |
|   };
 | |
| 
 | |
| complex_surface *spiral, *hilbert;
 | |
| 
 | |
| ld spiral_level(hyperpoint h) {
 | |
|   if(!spiral) {
 | |
|     spiral = new complex_surface(point31(-4, 2, 0));
 | |
|     spiral->right_block();
 | |
|     spiral->right_block();
 | |
|     spiral->right_block();
 | |
|     spiral->right_block();
 | |
|     spiral->turn_up_block();
 | |
|     spiral->up_block();
 | |
|     spiral->up_block();
 | |
|     spiral->turn_left_block();
 | |
|     spiral->left_block();
 | |
|     spiral->left_block();
 | |
|     spiral->turn_down_block();
 | |
|     spiral->down_block();
 | |
|     spiral->turn_right_block();
 | |
|     spiral->right_block();
 | |
|     spiral->turn_up_block();
 | |
|     spiral->turn_left_block();
 | |
|     spiral->left_block();
 | |
|     }
 | |
|   return spiral->get(h);
 | |
|   }
 | |
| 
 | |
| ld hilbert_level(hyperpoint h) {
 | |
|   if(!hilbert) {
 | |
|     hilbert = new complex_surface(point31(2, 0, 0));
 | |
|     hilbert->up_block();
 | |
|     hilbert->turn_right_block2();
 | |
|     hilbert->turn_down_block2();
 | |
|     hilbert->turn_right_block();
 | |
|     hilbert->right_block();
 | |
|     hilbert->turn_up_block();
 | |
|     hilbert->turn_left_block();
 | |
|     hilbert->turn_up_block2();
 | |
|     hilbert->turn_right_block2();
 | |
|     hilbert->turn_up_block();
 | |
|     hilbert->turn_left_block();
 | |
|     hilbert->left_block();
 | |
|     hilbert->turn_down_block();
 | |
|     hilbert->turn_left_block2();
 | |
|     hilbert->turn_up_block2();
 | |
|     hilbert->up_block();
 | |
|     }
 | |
|   return hilbert->get(h);
 | |
|   }
 | |
| 
 | |
| level spirallev(
 | |
|   "Square Spiral", 's', 0,
 | |
|   "The projection of this track is shaped like a square spiral.",
 | |
|   0.5*dft_block, 16.5*dft_block, 16.5*dft_block, 0.5*dft_block,
 | |
| 
 | |
|   {
 | |
|   "!!!!!!!!!!!!!!!!",
 | |
|   "rgggggggggggggr!",
 | |
|   "g+-----------+g!",
 | |
|   "g|gGgggggggGg|g!",
 | |
|   "g|G!!!!!!!!!G|g!",
 | |
|   "g|g!rgggggr!g|g!",
 | |
|   "g|g!g*---+g!g|g!",
 | |
|   "g|g!rgggg|g!g|g!",
 | |
|   "g|G!!!!!x|g!g|g!",
 | |
|   "g|gGgggGg|g!g|g!",
 | |
|   "g+-------+g!g|g!",
 | |
|   "rgggggggggr!g|g!",
 | |
|   "!!!!!!!!!!!!G|g!",
 | |
|   "fffggggggggGg|g!",
 | |
|   "-------------+g!",
 | |
|   "ggggggggggggggr!"
 | |
|   },
 | |
| 
 | |
|   1, 15.4, {}, spiral_level,
 | |
|   {
 | |
|     // the solver result is 55.239
 | |
|     goal{0xFFD500, "Collect the triangle in below 60 seconds", basic_check(60, 999), "SPIRAL2", ""},
 | |
|     goal{0xFF4040, "Collect the triangle in below 70 seconds", basic_check(70, 999), "SPIRAL1", ""},
 | |
|     goal{0x40c040, "Collect the triangle without reversing time", basic_check(999, 0), "", "Square Spiral"}
 | |
|   }
 | |
|   );
 | |
| 
 | |
| level hilbertlev(
 | |
|   "Hilbert's Curve", 's', 0,
 | |
|   "The projection of this track is shaped like the Hilbert curve.",
 | |
|   0.5*dft_block, 16.5*dft_block, 16.5*dft_block, 0.5*dft_block,
 | |
| 
 | |
|   {
 | |
|   "!!!!!!!!!!!!!!!!",
 | |
|   "ggg!rgggGGGgggr!",
 | |
|   "g*g!gf-------fg!",
 | |
|   "g|g!g|ggGGGgg|g!",
 | |
|   "g|g!g|g!!!!!g|g!",
 | |
|   "g|gxg|g!rgggg|g!",
 | |
|   "gf---fg!gf---fg!",
 | |
|   "rgggggr!g|ggggr!",
 | |
|   "!!!!!!!!g|o!!!!!",
 | |
|   "rgggggr!g|ggggr!",
 | |
|   "gf---fg!gf---fg!",
 | |
|   "g|ggg|g!rgggg|g!",
 | |
|   "g|g!x|g!!!!!g|g!",
 | |
|   "g|g!g|ggGGGgg|g!",
 | |
|   "g|g!gf-------fg!",
 | |
|   "g|g!rgggGGGgggr!"
 | |
|   },
 | |
| 
 | |
|   2.4, 15.4, {}, hilbert_level,
 | |
|   {
 | |
|     // the solver result is 50.94
 | |
|     goal{0xFFD500, "Collect the triangle in below 55 seconds", basic_check(55, 999), "HILBERT", ""},
 | |
|     goal{0xFF4040, "Collect the triangle in below 60 seconds", basic_check(60, 999), "", "Hilbert's Curve"},
 | |
|   }
 | |
|   );
 | |
| 
 | |
| level cycloid_slalom(
 | |
|   "Cycloid slalom", 'c', nrlSwapTriangleOrder,
 | |
|   "The main street is a brachistochrone. If you were not moving north/south, "
 | |
|   "it would be the fastest path to get to the goal. Is it still the case "
 | |
|   "in these physics? Definitely not if you have to collect on the way!",
 | |
|   -0.5*dft_block, 2.5*dft_block, 63.5*dft_block, -2.5*dft_block,
 | |
|   {
 | |
|   "gggggggG*GggggrgggggG*GgggggrggggggG*GgggggrggggG*Rgggggrggggggo",
 | |
|   "gggggggGGGggggggggggGGGggggggggggggGGGggggggggggGGGggggggggggggo",
 | |
|   "---------------------------------------------------------------*",
 | |
|   "gggggggggggggGGGgggggggggggGGGggggggggggggGGGggggggggggGGGgggggo",
 | |
|   "ggggggggrggggG*GgggggrgggggG*GggggggrgggggG*GggggrgggggG*Ggggggo"
 | |
|   },
 | |
|   0, 2, {},
 | |
|   brachistochrone,
 | |
|   {
 | |
|     goal{0xFFFFC0, "Collect all triangles in below 1:25, reversing time at most 3 times", basic_check(85, 3), "CYCLOID1", ""},
 | |
|     goal{0xFFD500, "Collect all triangles in below 1:10, reversing time at most 3 times", basic_check(70, 3), "CYCLOID2", ""},
 | |
|     goal{0x40c040, "Collect the triangle without reversing time", basic_check(999, 0), "", "Cycloid slalom"}
 | |
|     }
 | |
|   );
 | |
| 
 | |
| level multifloor(
 | |
|   "Multi-floor", 'm', 0,
 | |
|   "There are triangles on the floors below. I mean, DIRECTLY below.\n\nHopefully, you can abuse how straight lines work in this geometry to reach them!"
 | |
|   ,
 | |
| 
 | |
|   -1.5*dft_block, 1.5*dft_block, 1.5*dft_block, -1.5*dft_block,
 | |
|   {
 | |
|   "ggg",
 | |
|   "ggg",
 | |
|   "ggg"},
 | |
|   0, 1, {},
 | |
|   rot_plane,
 | |
|   {
 | |
|     goal{0x40FF40, "Collect all the triangles in below 300 seconds, reversing time at most 3 times", basic_check(300, 3), "MULTIFLOOR", ""},
 | |
|     goal{0xFFD500, "Collect all the triangles in below 150 seconds, reversing time at most once", basic_check(150, 1), "MULTIFLOOR2", ""}
 | |
|     }
 | |
|   );
 | |
| 
 | |
| level skijump (
 | |
|   "Ski Jumping", 'r', nrlJumping,
 | |
|   "Try to jump far away!",
 | |
|   -0.5*dft_block, 2.5*dft_block, 15.5*dft_block, -2.5*dft_block,
 | |
|   {
 | |
|   "!!!!!!!!!~~~~~~~",
 | |
|   "!!!!!!!!!~~~~~~~",
 | |
|   "-----!!!!~~~~~*~",
 | |
|   "!!!!!!!!!~~~~~~~",
 | |
|   "!!!!!!!!!~~~~~~~",
 | |
|   },
 | |
|   0, 2, {},
 | |
|   [] (hyperpoint h) {
 | |
|     if(h[0] > 4.6) return h[0] * h[1] / 2;
 | |
|     return h[0] * h[1] / 2 + 4 * (4.5 - h[0]) + 1 / (5 - h[0]);
 | |
|     },
 | |
|   {
 | |
|     goal{0x40c040, "Jump as far as you can", ski_check, "", "Ski Jumping"}
 | |
|     }
 | |
|   );
 | |
| 
 | |
| ld f_bumpy(hyperpoint h) {
 | |
|   ld a = h[0] * 2 + h[1];
 | |
|   ld b = h[1] * 2 - h[0];
 | |
|   return rot_plane(h) + h[0] * h[1] / 2 + sin(a*1.5) * sin(b*1.5) / 3;
 | |
|   }
 | |
| 
 | |
| level bumpy(
 | |
|   "Bumpy Ride", 'b', 0,
 | |
|   "The main street is horizontal, as well as the lines orthogonal to it.",
 | |
|   0*dft_block, 2.5*dft_block, 64*dft_block, -2.5*dft_block,
 | |
|   {
 | |
|   "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~o",
 | |
|   "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~o",
 | |
|   "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*",
 | |
|   "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~o",
 | |
|   "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~o",
 | |
|   },
 | |
|   0, 4, {},
 | |
|   f_bumpy,
 | |
|   {
 | |
|     goal{0xFFFFC0, "Collect the triangle in below 1:25, reversing time at most 3 times", basic_check(85, 3), "BUMPY", "Bumpy Ride"},
 | |
|     }
 | |
|   );
 | |
| 
 | |
| 
 | |
| 
 | |
| vector<level*> all_levels = {
 | |
|   &rotplane, &longtrack, &geodesical, &geodesical4, &heisenberg0, &rotwell, &labyrinth, &obstacle, &spirallev, &hilbertlev, &cycloid_slalom,
 | |
|   &multifloor, &skijump, &bumpy
 | |
|   };
 | |
|   
 | |
| }
 | 
