mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-23 21:07:17 +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
|
|
};
|
|
|
|
}
|