mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-01-24 07:56:59 +00:00
ideal Voronoi implemented
This commit is contained in:
parent
50e5cc2c5a
commit
77e5efa28f
174
bigstuff.cpp
174
bigstuff.cpp
@ -219,6 +219,141 @@ void hrmap::extend_altmap(heptagon *h, int levs, bool link_cdata) {
|
||||
}
|
||||
}
|
||||
|
||||
void new_voronoi_root(heptagon *h, int dist, int dir, eLand last, eLand last2) {
|
||||
heptagon *alt = init_heptagon(h->type);
|
||||
allmaps.push_back(newAltMap(alt));
|
||||
alt->s = hsA;
|
||||
alt->alt = alt;
|
||||
alt->cdata = (cdata*) h;
|
||||
alt->distance = dist;
|
||||
h->alt = alt;
|
||||
altmap::relspin(alt) = dir;
|
||||
|
||||
horodisk_land[alt] = getNewLand(last, last2);
|
||||
horodisk_last_land[alt] = last;
|
||||
|
||||
while(alt->distance > -100) {
|
||||
auto alt1 = createStep(alt, 0);
|
||||
alt1->alt = alt->alt;
|
||||
auto h1 = createStep(h, dir);
|
||||
h1->alt = alt1;
|
||||
|
||||
auto dir_alt = alt->c.spin(0);
|
||||
auto dir_h = h->c.spin(dir);
|
||||
|
||||
dir = altmap::relspin(alt1) = gmod(dir_h - dir_alt, alt->type);
|
||||
|
||||
h = h1; alt = alt1;
|
||||
}
|
||||
}
|
||||
|
||||
struct cand_info {
|
||||
int best, bqty;
|
||||
heptagon *candidate;
|
||||
vector<int> free_dirs;
|
||||
};
|
||||
|
||||
cand_info voronoi_candidate(heptagon *h) {
|
||||
cand_info ci;
|
||||
ci.best = 999999; ci.bqty = 0;
|
||||
|
||||
for(int i=0; i<h->type; i++) {
|
||||
heptagon *ho = createStep(h, i);
|
||||
int ri = h->c.spin(i);
|
||||
auto hoa = ho->alt;
|
||||
if(hoa && hoa->alt) {
|
||||
auto relspin = altmap::relspin(hoa);
|
||||
/* we want ho->move(ri) which is hoa->move(ri - relspin) */
|
||||
int dir = gmod(ri - relspin, hoa->type);
|
||||
heptagon *hoa1 = createStep(hoa, dir);
|
||||
if(!hoa1->alt) hoa1->alt = hoa->alt;
|
||||
auto dist = hoa1->distance;
|
||||
if(dist < ci.best) {
|
||||
ci.best = dist;
|
||||
ci.bqty = 0;
|
||||
}
|
||||
if(dist == ci.best && ci.candidate != hoa1) {
|
||||
ci.bqty++;
|
||||
ci.candidate = hoa1;
|
||||
int rb = hoa->c.spin(dir);
|
||||
/* hoa1->alt->move(rb) is h->move(rb+relspin to compute) */
|
||||
altmap::relspin(ci.candidate) = gmod(i - rb, ci.candidate->type);
|
||||
}
|
||||
}
|
||||
else ci.free_dirs.push_back(i);
|
||||
}
|
||||
return ci;
|
||||
}
|
||||
|
||||
void extend_altmap_voronoi(heptagon *h) {
|
||||
if(h->alt) return;
|
||||
|
||||
auto ci = voronoi_candidate(h);
|
||||
|
||||
if(ci.bqty == 0) {
|
||||
new_voronoi_root(h, -30, hrand(h->type), laBarrier, laBarrier);
|
||||
return;
|
||||
}
|
||||
else if(ci.bqty > 0 && isize(ci.free_dirs)) {
|
||||
auto& expansion = get_expansion();
|
||||
ld growth = expansion.get_growth();
|
||||
ld odds = pow(growth, ci.candidate->distance) * isize(ci.free_dirs);
|
||||
if(hrandf() < odds / (1 + odds)) {
|
||||
new_voronoi_root(h, ci.candidate->distance - 1, hrand_elt(ci.free_dirs), horodisk_land[ci.candidate->alt], horodisk_last_land[ci.candidate->alt]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
h->alt = ci.candidate;
|
||||
}
|
||||
|
||||
EX pair<heptagon*, int> get_voronoi_winner(cell *c) {
|
||||
if(c == c->master->c7) {
|
||||
extend_altmap_voronoi(c->master);
|
||||
auto ci = voronoi_candidate(c->master);
|
||||
if(ci.bqty == 1) return { ci.candidate->alt, ci.best };
|
||||
else return { nullptr, ci.best };
|
||||
}
|
||||
else if(!BITRUNCATED) return get_voronoi_winner(c->master->c7);
|
||||
else {
|
||||
vector<heptagon*> nearh;
|
||||
for(int i=0; i<c->type; i++) {
|
||||
c->cmove(i);
|
||||
if(c->move(i)->master->c7 == c->move(i)) nearh.push_back(c->move(i)->master);
|
||||
}
|
||||
for(auto h: nearh) extend_altmap_voronoi(h);
|
||||
for(auto h: nearh) if(!h->alt) return { nullptr, 0 };
|
||||
pair<heptagon*, int> best = {nullptr, 999999};
|
||||
int bqty = 0;
|
||||
for(auto h: nearh) {
|
||||
vector<int> dists;
|
||||
for(auto h1: nearh) {
|
||||
if(h == h1) dists.push_back(h->alt->distance);
|
||||
else {
|
||||
for(int i=0; i<h->type; i++) if(h->cmove(i) == h1) {
|
||||
auto ha1 = createStep(h->alt, gmod(i - altmap::relspin(h->alt), h->type));
|
||||
dists.push_back(ha1->distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
sort(dists.begin(), dists.end());
|
||||
int gdist;
|
||||
if(dists.back() == dists[0]) gdist = dists[0] - 1;
|
||||
else if(dists.back() == dists[0] + 2) gdist = dists[0] + 1;
|
||||
else gdist = dists[0];
|
||||
if(gdist < best.second) {
|
||||
best.second = gdist; bqty = 0;
|
||||
}
|
||||
if(gdist == best.second) {
|
||||
bqty++;
|
||||
if(bqty == 1 || best.first == h->alt->alt) best.first = h->alt->alt;
|
||||
else best.first = nullptr;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
}
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
EX int hrandom_adjacent(cellwalker cw) {
|
||||
auto& da = currentmap->dirdist(cw);
|
||||
@ -1662,6 +1797,7 @@ EX void start_camelot(cell *c) {
|
||||
}
|
||||
|
||||
EX map<heptagon*, eLand> horodisk_land;
|
||||
EX map<heptagon*, eLand> horodisk_last_land;
|
||||
|
||||
EX void build_horocycles(cell *c, cell *from) {
|
||||
|
||||
@ -1674,7 +1810,7 @@ EX void build_horocycles(cell *c, cell *from) {
|
||||
|
||||
// buildbigstuff
|
||||
|
||||
if(ls::any_order() && bearsCamelot(c->land) && can_start_horo(c) && !bt::in() &&
|
||||
if(ls::any_order() && bearsCamelot(c->land) && can_start_horo(c) && !bt::in() && !ls::voronoi_structure() &&
|
||||
#if MAXMDIM >= 4
|
||||
!(hyperbolic && WDIM == 3 && !reg3::in_hrmap_rule_or_subrule()) &&
|
||||
#endif
|
||||
@ -1978,6 +2114,19 @@ EX void moreBigStuff(cell *c) {
|
||||
c->wall = waSea;
|
||||
}
|
||||
|
||||
if(ls::voronoi_structure()) {
|
||||
auto p = get_voronoi_winner(c);
|
||||
auto ph = p.first;
|
||||
if(ph) {
|
||||
eLand l = horodisk_land[ph];
|
||||
setland(c, l);
|
||||
if(isEquidLand(l)) c->landparam = 1-p.second;
|
||||
}
|
||||
else {
|
||||
setland(c, laBarrier);
|
||||
}
|
||||
}
|
||||
|
||||
if(ls::horodisk_structure()) {
|
||||
if(have_alt(c) && masterAlt(c) <= 0) {
|
||||
gen_alt(c);
|
||||
@ -1997,11 +2146,11 @@ EX void moreBigStuff(cell *c) {
|
||||
setland(c, laCrossroads);
|
||||
}
|
||||
|
||||
extend_alt(c, laPalace, laPalace, false, PRADIUS1);
|
||||
if(!ls::hv_structure()) extend_alt(c, laPalace, laPalace, false, PRADIUS1);
|
||||
|
||||
extend_alt(c, laCanvas, laCanvas);
|
||||
|
||||
if(extend_alt(c, laStorms, laStorms, false) && !ls::hv_structure()) {
|
||||
if(!ls::hv_structure() && extend_alt(c, laStorms, laStorms, false)) {
|
||||
int d = celldistAlt(c);
|
||||
if(d <= -2) {
|
||||
c->wall = eubinary ? waCharged : (altmap::which(c->master->alt->alt) & 1) ? waCharged : waGrounded;
|
||||
@ -2020,12 +2169,12 @@ EX void moreBigStuff(cell *c) {
|
||||
c->wall = waColumn;
|
||||
}
|
||||
|
||||
else if(extend_alt(c, laTemple, laRlyeh) && !ls::hv_structure())
|
||||
else if(!ls::hv_structure() && extend_alt(c, laTemple, laRlyeh))
|
||||
gen_temple(c);
|
||||
|
||||
if(c->land == laTemple && ls::hv_structure()) gen_temple(c);
|
||||
if(ls::hv_structure() && c->land == laTemple) gen_temple(c);
|
||||
|
||||
if(extend_alt(c, laClearing, laOvergrown) && !ls::hv_structure()) {
|
||||
if(!ls::hv_structure() && extend_alt(c, laClearing, laOvergrown)) {
|
||||
if(in_single_horo(c, laClearing)) {
|
||||
c->land = laClearing, c->wall = waNone;
|
||||
}
|
||||
@ -2033,16 +2182,21 @@ EX void moreBigStuff(cell *c) {
|
||||
c->wall = waSmallTree, c->monst = moNone, c->item = itNone, c->landparam = 1;
|
||||
}
|
||||
|
||||
if(c->land == laClearing && ls::hv_structure()) {
|
||||
if(ls::horodisk_structure() && c->land == laClearing) {
|
||||
if(celldistAlt(c) >= -1)
|
||||
c->wall = waSmallTree, c->monst = moNone, c->item = itNone, c->landparam = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(extend_alt(c, laMountain, laJungle) && in_single_horo(c, laMountain) && !ls::hv_structure()) {
|
||||
if(ls::voronoi_structure() && c->land == laClearing) {
|
||||
if(celldistAlt(c) == -20)
|
||||
c->wall = waSmallTree, c->monst = moNone, c->item = itNone, c->landparam = 1;
|
||||
}
|
||||
|
||||
if(!ls::hv_structure() && extend_alt(c, laMountain, laJungle) && in_single_horo(c, laMountain)) {
|
||||
c->land = laMountain, c->wall = waNone;
|
||||
}
|
||||
|
||||
if(!ls::horodisk_structure() && extend_alt(c, laWhirlpool, laOcean) && in_single_horo(c, laWhirlpool))
|
||||
if(!ls::hv_structure() && extend_alt(c, laWhirlpool, laOcean) && in_single_horo(c, laWhirlpool))
|
||||
c->land = laWhirlpool, c->wall = waSea, c->monst = moNone, c->item = itNone;
|
||||
}
|
||||
|
||||
|
@ -908,7 +908,8 @@ EX namespace clearing {
|
||||
return;
|
||||
}
|
||||
|
||||
if(c->land == laClearing && ls::hv_structure() && celldistAlt(c) >= -1) return;
|
||||
if(c->land == laClearing && ls::horodisk_structure() && celldistAlt(c) >= -1) return;
|
||||
if(c->land == laClearing && ls::voronoi_structure() && celldistAlt(c) >= -20) return;
|
||||
|
||||
if(!eubinary && !horo_ok()) return;
|
||||
// cell *oc = c;
|
||||
|
12
landgen.cpp
12
landgen.cpp
@ -276,7 +276,7 @@ EX void place_random_gate_continuous(cell *c) {
|
||||
}
|
||||
|
||||
EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
bool fargen = d == min(BARLEV, ls::horodisk_structure() ? 8 : 9);
|
||||
bool fargen = d == min(BARLEV, ls::hv_structure() ? 8 : 9);
|
||||
switch(c->land) {
|
||||
|
||||
case laPrairie: // -------------------------------------------------------------
|
||||
@ -405,7 +405,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
}
|
||||
else {
|
||||
|
||||
if(d == (ls::horodisk_structure() ? 8 : 9)) {
|
||||
if(d == (ls::hv_structure() ? 8 : 9)) {
|
||||
cell *c2 = NONSTDVAR ? c->master->c7 : c;
|
||||
if(cdist50(c2) == 3 && polarb50(c2))
|
||||
c->wall = waPalace;
|
||||
@ -453,7 +453,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
}
|
||||
|
||||
// note: Princess Challenge brings back the normal Palace generation
|
||||
bool lookingForPrincess = !euclid && c->master->alt && !princess::challenge && !ls::horodisk_structure();
|
||||
bool lookingForPrincess = !euclid && c->master->alt && !princess::challenge && !ls::hv_structure();
|
||||
|
||||
bool pgate = false;
|
||||
if(PURE || GOLDBERG) {
|
||||
@ -551,7 +551,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
}
|
||||
|
||||
ONEMPTY {
|
||||
bool lookingForPrincess0 = !euclid && c->master->alt && !ls::horodisk_structure();
|
||||
bool lookingForPrincess0 = !euclid && c->master->alt && !ls::hv_structure();
|
||||
bool lookingForPrincess = lookingForPrincess0 && !princess::challenge;
|
||||
int hardness = lookingForPrincess ? 5 : items[itPalace] + yendor::hardness();
|
||||
|
||||
@ -2090,7 +2090,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
if(d >= 8) c->wall = waSea;
|
||||
if(d == 7 && !safety) {
|
||||
|
||||
if(ls::horodisk_structure() && c->master->alt && horodisk_land[c->master->alt->alt] == laWhirlpool) {
|
||||
if(ls::hv_structure() && c->master->alt && horodisk_land[c->master->alt->alt] == laWhirlpool) {
|
||||
if(hrand(100) < 10) c->wall = waBoat;
|
||||
return;
|
||||
}
|
||||
@ -2267,7 +2267,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
case laClearing:
|
||||
if(d == 7) {
|
||||
clearing::generate(c);
|
||||
if(ls::horodisk_structure() && celldistAlt(c) >= -1) c->monst = moNone;
|
||||
if(ls::hv_structure() && celldistAlt(c) >= -1) c->monst = moNone;
|
||||
if(pseudohept(c)) {
|
||||
int d = -celldistAlt(c);
|
||||
if(hrand_monster(2500) < items[itMutant2] + yendor::hardness() - 10 && !reptilecheat)
|
||||
|
22
landlock.cpp
22
landlock.cpp
@ -99,6 +99,7 @@ EX bool any_order() { return among(land_structure, lsNiceWalls, lsNoWalls, lsHor
|
||||
EX bool nice_walls() { return land_structure == lsNiceWalls; }
|
||||
EX bool no_walls() { return land_structure == lsNoWalls; }
|
||||
EX bool horodisk_structure() { return land_structure == lsHorodisks; }
|
||||
EX bool voronoi_structure() { return land_structure == lsVoronoi; }
|
||||
EX bool hv_structure() { return among(land_structure, lsHorodisks, lsVoronoi); }
|
||||
|
||||
EX bool any_nowall() { return no_walls() || std_chaos(); }
|
||||
@ -137,7 +138,7 @@ EX string land_structure_name(bool which) {
|
||||
case lsHorodisks:
|
||||
return XLAT("horodisks");
|
||||
case lsVoronoi:
|
||||
return XLAT("limit Voronoi");
|
||||
return XLAT("ideal Voronoi");
|
||||
case lsNoWalls:
|
||||
return XLAT("wall-less");
|
||||
default:
|
||||
@ -158,7 +159,7 @@ EX void fix_land_structure_choice() {
|
||||
land_structure = lsNoWalls;
|
||||
if(!nice_walls_available() && land_structure == lsWallChaos)
|
||||
land_structure = lsChaos;
|
||||
if(ls::hv_structure() && !hyperbolic)
|
||||
if(ls::hv_structure() && (!hyperbolic || bt::in() || quotient))
|
||||
land_structure = lsSingle;
|
||||
if(walls_not_implemented() && among(land_structure, lsChaos, lsNoWalls))
|
||||
land_structure = lsSingle;
|
||||
@ -382,7 +383,7 @@ EX bool all_unlocked = false;
|
||||
|
||||
EX vector<eLand> cheatdest_list;
|
||||
|
||||
EX eLand getNewLand(eLand old) {
|
||||
EX eLand getNewLand(eLand old, eLand old2 IS(laBarrier)) {
|
||||
|
||||
#if CAP_LEGACY
|
||||
if(legacy_racing()) {
|
||||
@ -394,7 +395,7 @@ EX eLand getNewLand(eLand old) {
|
||||
eLand l = callhandlers(laNone, hooks_nextland, old);
|
||||
if(l) return l;
|
||||
|
||||
if(cheatdest != old && cheatdest != laElementalWall) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest;
|
||||
if(cheatdest != old && cheatdest != old2 && cheatdest != laElementalWall) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest;
|
||||
|
||||
if(cheatdest_list.size()) {
|
||||
eLand l = cheatdest_list[0];
|
||||
@ -408,7 +409,9 @@ EX eLand getNewLand(eLand old) {
|
||||
while(true) {
|
||||
eLand n = eLand(hrand(landtypes));
|
||||
if(n == old) continue;
|
||||
if(n == old2) continue;
|
||||
if(incompatible(n,old)) continue;
|
||||
if(incompatible(n,old2)) continue;
|
||||
if(!isLandIngame(n)) continue;
|
||||
if(n == laElementalWall || isTechnicalLand(n)) continue;
|
||||
if(n == laWildWest) continue;
|
||||
@ -420,9 +423,9 @@ EX eLand getNewLand(eLand old) {
|
||||
if(markOrb(itOrbLuck)) {
|
||||
int i = items[itOrbLuck];
|
||||
items[itOrbLuck] = 0;
|
||||
eLand l1 = getNewLand(old);
|
||||
eLand l1 = getNewLand(old, old2);
|
||||
for(int i=1; i<3; i++)
|
||||
l1 = pickluck(l1, getNewLand(old));
|
||||
l1 = pickluck(l1, getNewLand(old, old2));
|
||||
items[itOrbLuck] = i;
|
||||
return l1;
|
||||
}
|
||||
@ -446,9 +449,9 @@ EX eLand getNewLand(eLand old) {
|
||||
#endif
|
||||
|
||||
if(tactic::on) return specialland;
|
||||
if(specialland != old && easy_to_find_specialland && specialland != laElementalWall) return specialland;
|
||||
if(specialland != old && specialland != old2 && easy_to_find_specialland && specialland != laElementalWall) return specialland;
|
||||
|
||||
if(specialland != old && easy_specialland && specialland != laElementalWall) {
|
||||
if(specialland != old && specialland != old2 && easy_specialland && specialland != laElementalWall) {
|
||||
easy_specialland--;
|
||||
return specialland;
|
||||
}
|
||||
@ -858,7 +861,8 @@ EX land_validity_t& land_validity(eLand l) {
|
||||
if(l == laMirrorOld && !shmup::on) return not_implemented;
|
||||
}
|
||||
|
||||
if(ls::hv_structure() && among(l, laPrairie, laIvoryTower, laDungeon, laEndorian, laBrownian, laTortoise, laElementalWall)) return not_in_hv;
|
||||
if(ls::hv_structure() && among(l, laPrairie, laIvoryTower, laDungeon, laEndorian, laBrownian, laTortoise, laElementalWall, laWarpCoast, laWarpSea, laHive)) return not_in_hv;
|
||||
if(ls::voronoi_structure() && among(l, laCamelot, laWhirlpool, laClearing)) return not_in_hv;
|
||||
|
||||
if(l == laBrownian) {
|
||||
if(quotient || !hyperbolic || cryst) return dont_work;
|
||||
|
Loading…
Reference in New Issue
Block a user