mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-17 10:44:48 +00:00
fractal geometry
This commit is contained in:
parent
121df0d9c7
commit
511ffe8498
135
cell.cpp
135
cell.cpp
@ -402,6 +402,141 @@ EX bool is_in_disk(cell *c) {
|
||||
return *it == c;
|
||||
}
|
||||
|
||||
bool sierpinski3(gp::loc g) {
|
||||
int x = g.first;
|
||||
int y = g.second;
|
||||
set<pair<int, int>> visited;
|
||||
while(true) {
|
||||
if(visited.count({x,y})) return false;
|
||||
visited.insert({x,y});
|
||||
// if(x == -1 && y == -2) return false;
|
||||
// if(x == -2 && y == -3) return false;
|
||||
if(x == 0 && y == 0) return true;
|
||||
if((x&1) == 1 && (y&1) == 1) return false;
|
||||
x >>= 1;
|
||||
y >>= 1;
|
||||
// x--; y++;
|
||||
tie(x, y) = make_pair(-x-y, x);
|
||||
}
|
||||
}
|
||||
|
||||
bool sierpinski46(gp::loc g) {
|
||||
int x = g.first;
|
||||
int y = g.second;
|
||||
set<pair<int, int>> visited;
|
||||
if(S7 == 6)
|
||||
x += 2785684, y += 289080;
|
||||
else
|
||||
x += 75239892, y += 7913772;
|
||||
while(true) {
|
||||
if(visited.count({x,y})) return false;
|
||||
visited.insert({x,y});
|
||||
if(x == 0 && y == 0) return true;
|
||||
int dx = gmod(x, 3);
|
||||
int dy = gmod(y, 3);
|
||||
if(dx == 1 && dy == 1) return false;
|
||||
if(S7 == 6 && dx == dy) return false;
|
||||
x = (x-dx) / 3;
|
||||
y = (y-dy) / 3;
|
||||
}
|
||||
}
|
||||
|
||||
bool menger_sponge(euc::coord c) {
|
||||
c[0] += 528120*9; c[1] += 438924*9; c[2] += 306712*9;
|
||||
set<euc::coord> visited;
|
||||
while(true) {
|
||||
if(visited.count(c)) return false;
|
||||
visited.insert(c);
|
||||
if(c[0] == 0 && c[1] == 0 && c[2] == 0) return true;
|
||||
int ones = 0;
|
||||
for(int i=0; i<3; i++) {
|
||||
int d = gmod(c[i], 3);
|
||||
c[i] = (c[i] - d) / 3;
|
||||
if(d == 1) ones++;
|
||||
}
|
||||
if(ones >= 2) return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool sierpinski_tet(euc::coord c) {
|
||||
set<euc::coord> visited;
|
||||
c[0] += 16 * (1+8+64+512);
|
||||
c[1] += 16 * (1+8+64+512);
|
||||
c[1] += 32 * (1+8+64+512);
|
||||
c[2] += 32 * (1+8+64+512);
|
||||
c[0] += 64 * (1+8+64+512);
|
||||
c[1] += 64 * (1+8+64+512);
|
||||
while(true) {
|
||||
if(visited.count(c)) return false;
|
||||
visited.insert(c);
|
||||
if(c[0] == 0 && c[1] == 0 && c[2] == 0) return true;
|
||||
int ones = 0;
|
||||
for(int i=0; i<3; i++) {
|
||||
int d = gmod(c[i], 2);
|
||||
c[i] = (c[i] - d) / 2;
|
||||
if(d == 1) ones++;
|
||||
}
|
||||
if(ones & 1) return false;
|
||||
}
|
||||
}
|
||||
|
||||
EX bool is_in_fractal(cell *c) {
|
||||
if(fake::in()) return FPIU(is_in_fractal(c));
|
||||
if(mhybrid) { c = hybrid::get_where(c).first; return PIU(is_in_fractal(c)); }
|
||||
switch(geometry) {
|
||||
case gSierpinski3:
|
||||
return sierpinski3(euc::full_coords2(c));
|
||||
case gSierpinski4:
|
||||
case gSixFlake:
|
||||
return sierpinski46(euc::full_coords2(c));
|
||||
case gMengerSponge:
|
||||
return menger_sponge(euc::get_ispacemap()[c->master]);
|
||||
case gSierpinskiTet: {
|
||||
return sierpinski_tet(euc::get_ispacemap()[c->master]);
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
EX cell *fractal_rep(cell *c) {
|
||||
switch(geometry) {
|
||||
case gSierpinski3: {
|
||||
auto co = euc::full_coords2(c);
|
||||
co.first += 4;
|
||||
co.first &= ~15;
|
||||
co.first -= 4;
|
||||
co.second += 2;
|
||||
co.second &= ~15;
|
||||
co.second -= 2;
|
||||
if(co.first == -4 && co.second == -2) co.first = 0, co.second = 0;
|
||||
return euc::get_at(euc::to_coord(co))->c7;
|
||||
}
|
||||
case gSierpinski4:
|
||||
case gSixFlake: {
|
||||
auto co = euc::full_coords2(c);
|
||||
if(S7 == 6) co.first += 4;
|
||||
co.first -= gmod(co.first, 9);
|
||||
co.second -= gmod(co.second, 9);
|
||||
return euc::get_at(euc::to_coord(co))->c7;
|
||||
}
|
||||
case gSierpinskiTet: {
|
||||
auto co = euc::get_ispacemap()[c->master];
|
||||
co[0] &=~7;
|
||||
co[1] &=~7;
|
||||
co[2] &=~7;
|
||||
return euc::get_at(co)->c7;
|
||||
}
|
||||
case gMengerSponge: {
|
||||
auto co = euc::get_ispacemap()[c->master];
|
||||
for(int i=0; i<3; i++) co[i] = co[i] - gmod(co[i], 9);
|
||||
return euc::get_at(co)->c7;
|
||||
}
|
||||
default:
|
||||
throw hr_exception("unknown fractal");
|
||||
}
|
||||
}
|
||||
|
||||
/** create a map in the current geometry */
|
||||
EX void initcells() {
|
||||
DEBB(DF_INIT, ("initcells"));
|
||||
|
@ -1751,6 +1751,22 @@ void celldrawer::draw_features_and_walls_3d() {
|
||||
#if MAXMDIM >= 4
|
||||
color_t dummy;
|
||||
int ofs = currentmap->wall_offset(c);
|
||||
|
||||
if((cgflags & qFRACTAL) && c->wall == waChasm && c->land == laMemory) {
|
||||
for(int a=0; a<c->type; a++) if(c->move(a) && c->move(a)->land != laMemory) {
|
||||
if(anyshiftclick) {
|
||||
auto& poly = queuepoly(V, cgi.shPlainWall3D[ofs+a], 0xFFFFFFFF - 0xF0F0F00 * get_darkval(c, a));
|
||||
poly.tinf = &floor_texture_vertices[cgi.shFullFloor.id];
|
||||
ensure_vertex_number(*poly.tinf, poly.cnt);
|
||||
}
|
||||
else {
|
||||
auto& poly = queuepoly(V, cgi.shWireframe3D[ofs + a], 0);
|
||||
poly.outline = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
if(anyshiftclick) return;
|
||||
}
|
||||
|
||||
if(isWall3(c, wcol)) {
|
||||
if(!no_wall_rendering) {
|
||||
if(c->wall == waChasm && c->land == laMemory && !in_perspective()) {
|
||||
|
10
classes.cpp
10
classes.cpp
@ -751,6 +751,7 @@ enum eGeometry {
|
||||
gSpace345, gSpace353, gSpace354, gSpace355,
|
||||
gHalfBring,
|
||||
gAperiodicHat,
|
||||
gSierpinski3, gSierpinski4, gSixFlake, gMengerSponge, gSierpinskiTet,
|
||||
gGUARD};
|
||||
|
||||
enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere, gcSol, gcNIH, gcSolN, gcNil, gcProduct, gcSL2 };
|
||||
@ -830,6 +831,8 @@ static const flagtype qCAT = Flag(28);
|
||||
static const flagtype qAPERIODIC = Flag(29);
|
||||
static const flagtype qHAT = Flag(30);
|
||||
|
||||
static const flagtype qFRACTAL = Flag(31);
|
||||
|
||||
// note: dnext assumes that x&7 equals 7
|
||||
static const int SEE_ALL = 50;
|
||||
// note: check_football_colorability in arbitrile.cpp assumes OINF is divisible by 3
|
||||
@ -958,7 +961,12 @@ EX vector<geometryinfo> ginf = {
|
||||
{"{3,5,4}","none", "{3,5,4} hyperbolic honeycomb", "354", 20, 5, qIDEAL | qULTRA, giHyperb3, {{7, 2}}, eVariation::pure},
|
||||
{"{3,5,5}","none", "{3,5,5} hyperbolic honeycomb", "355", 20, 5, qIDEAL | qULTRA, giHyperb3, {{7, 2}}, eVariation::pure},
|
||||
{"{5,4}", "pBring", "projective Bring's Surface", "pBring", 5, 4, qsSMALLN, giHyperb2, {{6, 4}}, eVariation::bitruncated},
|
||||
{"hat", "none", "aperiodic hat", "hat", 14, 3, qAPERIODIC | qHAT, giEuclid2, {{7, 7}}, eVariation::pure},
|
||||
{"hat", "none", "aperiodic hat", "hat", 14, 3, qAPERIODIC | qHAT, giEuclid2, {{7, 7}}, eVariation::pure},
|
||||
{"triangle","none", "Sierpiński triangle", "S3", 6, 3, qFRACTAL, giEuclid2, {{10, 10}}, eVariation::pure},
|
||||
{"carpet", "none", "Sierpiński carpet", "S4", 4, 4, qFRACTAL, giEuclid2, {{10, 10}}, eVariation::pure},
|
||||
{"6-flake","none", "6-flake fractal", "S6", 6, 3, qFRACTAL, giEuclid2, {{10, 10}}, eVariation::pure},
|
||||
{"{4,3,4}","none", "Menger sponge", "S8", 6, 4, qFRACTAL, giEuclid3, {{10, 10}}, eVariation::pure},
|
||||
{"rh{4,3,4}","none", "Sierpiński tetrahedron", "S4b", 12, 3, qFRACTAL, giEuclid3, {{10, 10}}, eVariation::pure},
|
||||
};
|
||||
// bits: 9, 10, 15, 16, (reserved for later) 17, 18
|
||||
|
||||
|
@ -46,10 +46,12 @@ EX namespace euc {
|
||||
|
||||
switch(g) {
|
||||
case gCubeTiling:
|
||||
case gMengerSponge:
|
||||
shifttable = { +D0, +D1, +D2 };
|
||||
break;
|
||||
|
||||
case gRhombic3:
|
||||
case gSierpinskiTet:
|
||||
shifttable = { D0+D1, D0+D2, D1+D2, D1-D2, D0-D2, D0-D1 };
|
||||
break;
|
||||
|
||||
@ -58,10 +60,13 @@ EX namespace euc {
|
||||
break;
|
||||
|
||||
case gEuclid:
|
||||
case gSierpinski3:
|
||||
case gSixFlake:
|
||||
shifttable = { D0, D1, D1-D0, -D0, -D1, D0-D1 };
|
||||
break;
|
||||
|
||||
case gEuclidSquare:
|
||||
case gSierpinski4:
|
||||
shifttable = { D0, D1, -D0, -D1 };
|
||||
break;
|
||||
|
||||
|
@ -346,6 +346,8 @@ void set_or_configure_geometry(eGeometry g) {
|
||||
|
||||
/** is g2 the same tiling as the current geometry (geometry)? */
|
||||
bool same_tiling(eGeometry g2) {
|
||||
/* no quotients for fractals */
|
||||
if(cgflags & qFRACTAL) return g2 == geometry;
|
||||
if(g2 == gCrystal)
|
||||
return S3 == 4;
|
||||
if(g2 == gFieldQuotient && (hyperbolic || (geometry == gCubeTiling && reg3::cubes_reg3)) && standard_tiling())
|
||||
@ -602,7 +604,7 @@ EX void select_quotient_screen() {
|
||||
}
|
||||
|
||||
EX void select_quotient() {
|
||||
if(meuclid && !aperiodic && !arcm::in() && !reg3::cubes_reg3) {
|
||||
if(meuclid && !aperiodic && !arcm::in() && !reg3::cubes_reg3 && !(cgflags & qFRACTAL)) {
|
||||
euc::prepare_torus3();
|
||||
pushScreen(euc::show_torus3);
|
||||
}
|
||||
@ -1029,6 +1031,8 @@ EX void showEuclideanMenu() {
|
||||
menuitem_nilwidth('v');
|
||||
}
|
||||
else if((WDIM == 3 || aperiodic || arb::in()) && !reg3::in() && geometry != gCubeTiling) dialog::addBreak(100);
|
||||
else if(cgclass && qFRACTAL)
|
||||
dialog::addBreak(100);
|
||||
else
|
||||
menuitem_change_variation('v');
|
||||
|
||||
|
@ -3970,7 +3970,7 @@ EX int colorhash(color_t i) {
|
||||
|
||||
EX bool isWall3(cell *c, color_t& wcol) {
|
||||
if(isWall(c)) return true;
|
||||
if(c->wall == waChasm && c->land == laMemory) { wcol = 0x606000; return true; }
|
||||
if(c->wall == waChasm && c->land == laMemory && (anyshiftclick || !(cgflags & qFRACTAL))) { wcol = 0x606000; return true; }
|
||||
if(c->wall == waInvisibleFloor) return false;
|
||||
// if(chasmgraph(c)) return true;
|
||||
if(among(c->wall, waMirror, waCloud, waMineUnknown, waMineMine)) return true;
|
||||
|
2
help.cpp
2
help.cpp
@ -240,7 +240,7 @@ EX void buildCredits() {
|
||||
"Kojiguchi Kazuki, baconcow, Alan, SurelyYouJest, hotdogPi, DivisionByZero, xXxWeedGokuxXx, jpystynen, Dmitry Marakasov, Alexandre Moine, Arthur O'Dwyer, "
|
||||
"Triple_Agent_AAA, bluetailedgnat, Allalinor, Shitford, KittyTac, Christopher King, KosGD, TravelDemon, Bubbles, rdococ, frozenlake, MagmaMcFry, "
|
||||
"Snakebird Priestess, roaringdragon2, Stopping Dog, bengineer8, Sir Light IJIJ, ShadeBlade, Saplou, shnourok, Ralith, madasa, 6% remaining, Chimera245, Remik Pi, alien foxcat thing, "
|
||||
"Piotr Grochowski, Ann, still-flow, tyzone, Paradoxica, LottieRatWorld, aismallard, albatross, EncodedSpirit, Jacob Mandelson, CrashTuvai, cvoight, jennlbw, Kali Ranya"
|
||||
"Piotr Grochowski, Ann, still-flow, tyzone, Paradoxica, LottieRatWorld, aismallard, albatross, EncodedSpirit, Jacob Mandelson, CrashTuvai, cvoight, jennlbw, Kali Ranya, spiritbackup"
|
||||
);
|
||||
#ifdef EXTRALICENSE
|
||||
help += EXTRALICENSE;
|
||||
|
24
landgen.cpp
24
landgen.cpp
@ -2226,7 +2226,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
int hardchance = items[itRuby] + yendor::hardness();
|
||||
if(hardchance > 25) hardchance = 25;
|
||||
bool hardivy = hrand(100) < hardchance;
|
||||
if(hat::in() ? buildIvy(c, 0, 4) : (hardivy ? buildIvy(c, 1, 9) : buildIvy(c, 0, c->type)) && !peace::on)
|
||||
if((cgflags & qFRACTAL) ? buildIvy(c, 0, 2) : hat::in() ? buildIvy(c, 0, 4) : (hardivy ? buildIvy(c, 1, 9) : buildIvy(c, 0, c->type)) && !peace::on)
|
||||
c->item = itRuby;
|
||||
}
|
||||
}
|
||||
@ -2826,7 +2826,9 @@ EX void setland_randomwalk(cell *c) {
|
||||
if(c->land) return;
|
||||
if(hrand(10) == 0) setland(c, currentlands[hrand(isize(currentlands))]);
|
||||
else {
|
||||
cell *c2 = c->cmove(hrand(c->type));
|
||||
cell *c2 = nullptr;
|
||||
for(int i=0; i<10 && !(c2 && (!disksize || is_in_disk(c2)) && is_in_fractal(c2)); i++)
|
||||
c2 = c->cmove(hrand(c->type));
|
||||
setland_randomwalk(c2);
|
||||
c->land = c2->land;
|
||||
}
|
||||
@ -2836,6 +2838,11 @@ EX eLand random_land() {
|
||||
return hrand_elt(isize(cheatdest_list) ? cheatdest_list : currentlands);
|
||||
}
|
||||
|
||||
EX void share_land(cell *c, cell *c2) {
|
||||
if(!c2->land) setland(c2, random_land());
|
||||
c->land = c2->land;
|
||||
}
|
||||
|
||||
EX void set_land_for_geometry(cell *c) {
|
||||
|
||||
if(!c->land && isize(currentlands)) {
|
||||
@ -2844,15 +2851,17 @@ EX void set_land_for_geometry(cell *c) {
|
||||
return;
|
||||
}
|
||||
/* note: Nil patched chaos done in setLandNil */
|
||||
if(ls::patched_chaos() && stdeuc) {
|
||||
if(ls::patched_chaos() && (cgflags & qFRACTAL)) {
|
||||
share_land(c, fractal_rep(c));
|
||||
}
|
||||
else if(ls::patched_chaos() && stdeuc) {
|
||||
cell *c2 = c;
|
||||
while(true) {
|
||||
forCellCM(c3, c2) if(cdist50(c3) < cdist50(c2)) { c2 = c3; goto again; }
|
||||
break;
|
||||
again: ;
|
||||
}
|
||||
if(!c2->land) setland(c2, random_land());
|
||||
c->land = c2->land;
|
||||
share_land(c, c2);
|
||||
return;
|
||||
}
|
||||
if(ls::patched_chaos() && aperiodic) {
|
||||
@ -2861,8 +2870,7 @@ EX void set_land_for_geometry(cell *c) {
|
||||
c2 = c->master->cmove(0)->cmove(0)->cmove(1)->cmove(1)->c7;
|
||||
else
|
||||
c2 = c->master->cmove(0)->cmove(0)->cmove(0)->cmove(0)->cmove(0)->cmove(1)->cmove(1)->cmove(1)->cmove(1)->cmove(1)->c7;
|
||||
if(!c2->land) setland(c2, random_land());
|
||||
c->land = c2->land;
|
||||
share_land(c, c2);
|
||||
return;
|
||||
}
|
||||
if(land_structure == lsChaosRW) {
|
||||
@ -3058,7 +3066,7 @@ EX void setdist(cell *c, int d, cell *from) {
|
||||
}
|
||||
}
|
||||
|
||||
if(disksize && !is_in_disk(c)) {
|
||||
if((disksize && !is_in_disk(c)) || ((cgflags & qFRACTAL) && !is_in_fractal(c))) {
|
||||
setland(c, laMemory);
|
||||
if(!isMultitile(c)) c->monst = moNone;
|
||||
c->item = itNone;
|
||||
|
@ -159,6 +159,8 @@ EX void fix_land_structure_choice() {
|
||||
land_structure = lsSingle;
|
||||
if(aperiodic && !among(land_structure, lsChaosRW, lsTotalChaos, lsPatchedChaos, lsSingle))
|
||||
land_structure = lsPatchedChaos;
|
||||
if((cgflags & qFRACTAL) && !among(land_structure, lsChaosRW, lsTotalChaos, lsPatchedChaos, lsSingle))
|
||||
land_structure = lsPatchedChaos;
|
||||
}
|
||||
|
||||
EX bool landUnlockedRPM(eLand n) {
|
||||
|
Loading…
Reference in New Issue
Block a user