mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-18 23:10:26 +00:00
532 lines
14 KiB
C++
532 lines
14 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;
|
|
};
|
|
}
|
|
|
|
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 0; }
|
|
|
|
ld rot_plane(hyperpoint h) {
|
|
return h[0] * h[1] / 2;
|
|
}
|
|
|
|
ld f_rot_well(hyperpoint h) {
|
|
return h[0] * h[1] / 2 + h[0] * h[0] + h[1] * h[1];
|
|
}
|
|
|
|
ld long_x(hyperpoint h) {
|
|
return h[0] * h[1];
|
|
}
|
|
|
|
ld geodesics_0(hyperpoint h) {
|
|
ld r = hypot_d(2, h);
|
|
ld phi = atan2(h[1], h[0]);
|
|
|
|
ld z = (phi / 2 / M_PI) * (M_PI * r * r + 2 * M_PI);
|
|
return z + rot_plane(h);
|
|
}
|
|
|
|
ld geodesics_at_4(hyperpoint h) {
|
|
ld r = 4;
|
|
ld phi = atan2(h[1], h[0]);
|
|
|
|
ld z = (phi / 2 / M_PI) * (M_PI * r * r + 2 * M_PI);
|
|
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}
|
|
};
|
|
|
|
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"
|
|
}},
|
|
{'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",
|
|
}},
|
|
};
|
|
|
|
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 slop edownwards.\n"
|
|
"Your unicycle is powered only by the gravity. Use that to your advantage!"
|
|
,
|
|
|
|
-7.5*dft_block, 7.5*dft_block, 8.5*dft_block, -8.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)},
|
|
goal{0xFFD500, "Collect all the triangles in below 38 seconds", basic_check(38, 999)}
|
|
}
|
|
);
|
|
|
|
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)},
|
|
// 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)},
|
|
// 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)},
|
|
}
|
|
);
|
|
|
|
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*degree, 3*dft_block, 225*degree, 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)}
|
|
}
|
|
);
|
|
|
|
level geodesical4(
|
|
"Helical Geodesic", 's', nrlPolar,
|
|
"The main road here is a helical geodesic. Orthogonal lines are horizontal.",
|
|
-80*degree, 8.5*dft_block, 260*degree, 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)}
|
|
}
|
|
);
|
|
|
|
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, 8.5*dft_block, -8.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)}
|
|
}
|
|
);
|
|
|
|
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, 8.5*dft_block, -8.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)}
|
|
}
|
|
);
|
|
|
|
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, 8.5*dft_block/2, -8.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)}
|
|
}
|
|
);
|
|
|
|
level *curlev = &rotplane;
|
|
|
|
vector<level*> all_levels = {
|
|
&rotplane, &longtrack, &geodesical, &geodesical4, &heisenberg0, &rotwell, &labyrinth
|
|
};
|
|
|
|
}
|