Harden save/load state validation
This commit is contained in:
parent
99f4a925a1
commit
1090d2d46e
12
BUILD.md
12
BUILD.md
@ -84,11 +84,13 @@ CLI flags (applied before the first load/generate):
|
||||
planet.cfg human-editable key=value config of every PlanetConfig parameter;
|
||||
auto-created on first run, reload live with F2. Range-checked on
|
||||
load; an invalid file reverts to safe defaults (not overwritten).
|
||||
planet.save binary snapshot (versioned, currently v17: +geography/atlas; v16
|
||||
+event log; v15 +stateful
|
||||
volcanoes; v13 +Live World clock rate; v12 +step-back history
|
||||
(~40 frames, so a load can rewind storms); v11 +weather systems/storms;
|
||||
v10 +weather fields; v9 +moons; v8 +Live World clock; v7 +biota): seed + config + full planet state; F5
|
||||
planet.save binary snapshot (versioned, currently v22: +diplomacy; v21
|
||||
+conflict/wars; v20 +settlements; v19 +ecoregions; v18
|
||||
+geography salt; v17 +geography/atlas; v16 +event log; v15
|
||||
+stateful volcanoes; v13 +Live World clock rate; v12
|
||||
+step-back history (~40 frames, so a load can rewind storms);
|
||||
v11 +weather systems/storms; v10 +weather fields; v9 +moons;
|
||||
v8 +Live World clock; v7 +biota): seed + config + full planet state; F5
|
||||
writes it, F9 reloads and resumes deterministically. As of v6
|
||||
the config is stored as a self-describing key=value block (like
|
||||
planet.cfg), so adding/removing config fields no longer breaks saves
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
const char* weatherEventName(const WeatherSystem& ws, const Planet& p) {
|
||||
@ -17,6 +19,42 @@ namespace {
|
||||
int eventSeverityForWeather(const WeatherSystem& ws, const Planet& p) {
|
||||
return (ws.tropical && ws.strength >= p.cfg.weatherHurricaneStr) ? 2 : (ws.tropical ? 1 : 0);
|
||||
}
|
||||
bool validFrameWar(const War& w, int settlementCount) {
|
||||
return w.attacker >= 0 && w.attacker < settlementCount
|
||||
&& w.defender >= 0 && w.defender < settlementCount
|
||||
&& w.attacker != w.defender
|
||||
&& w.battles >= 0
|
||||
&& std::isfinite(w.warscore);
|
||||
}
|
||||
bool sanitizeFrameDiplomacy(std::vector<DiploTie>& ties, int settlementCount) {
|
||||
std::set<std::pair<int, int>> seen;
|
||||
for (DiploTie& t : ties) {
|
||||
if (t.a < 0 || t.a >= settlementCount || t.b < 0 || t.b >= settlementCount || t.a == t.b)
|
||||
return false;
|
||||
if (t.a > t.b) std::swap(t.a, t.b);
|
||||
if (!seen.insert({t.a, t.b}).second) return false;
|
||||
if (!std::isfinite(t.attitude)) return false;
|
||||
t.attitude = std::clamp(t.attitude, -1.0, 1.0);
|
||||
if ((uint8_t)t.kind > (uint8_t)DiploKind::Rival) t.kind = DiploKind::Neutral;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool validateFrameCivState(WeatherSnapshot& w, size_t currentSettlements) {
|
||||
if (w.settlementPop.size() > currentSettlements) return false;
|
||||
for (double p : w.settlementPop) if (!std::isfinite(p)) return false;
|
||||
const int settlementCount = (int)w.settlementPop.size();
|
||||
if (!w.settlementAllegiance.empty()) {
|
||||
if ((int)w.settlementAllegiance.size() != settlementCount) return false;
|
||||
for (int a : w.settlementAllegiance)
|
||||
if (a < -1 || a >= settlementCount) return false;
|
||||
}
|
||||
std::set<std::pair<int, int>> warsSeen;
|
||||
for (const War& war : w.wars) {
|
||||
if (!validFrameWar(war, settlementCount)) return false;
|
||||
if (!warsSeen.insert(std::minmax(war.attacker, war.defender)).second) return false;
|
||||
}
|
||||
return sanitizeFrameDiplomacy(w.diplomacy, settlementCount);
|
||||
}
|
||||
}
|
||||
|
||||
bool Viewer::init(int argc, char** argv) {
|
||||
@ -166,21 +204,21 @@ void Viewer::recolor() {
|
||||
? habitabilityColor(hab[i]) : Color{30, 42, 64, 255}; // ocean/ice: dim blue
|
||||
break;
|
||||
case ColorMode::Territory: {
|
||||
int ni = (i < (int)cnat.size()) ? cnat[i] : -1;
|
||||
int ni = (i < cnat.size()) ? cnat[i] : -1;
|
||||
if (ni >= 0) vcolors[i] = nationColor(ni); // owned: realm tint
|
||||
else vcolors[i] = (planet.cells[i].elevation > planet.cfg.seaLevel) // wilderness land vs sea
|
||||
? Color{60, 64, 58, 255} : Color{26, 34, 52, 255};
|
||||
break;
|
||||
}
|
||||
case ColorMode::Culture: {
|
||||
int ci = (i < (int)ccult.size()) ? ccult[i] : -1;
|
||||
int ci = (i < ccult.size()) ? ccult[i] : -1;
|
||||
if (ci >= 0) vcolors[i] = cultureColor(ci); // owned: culture tint
|
||||
else vcolors[i] = (planet.cells[i].elevation > planet.cfg.seaLevel) // uncultured land vs sea
|
||||
? Color{60, 64, 58, 255} : Color{26, 34, 52, 255};
|
||||
break;
|
||||
}
|
||||
case ColorMode::Wealth: {
|
||||
double w = (i < (int)cwealth.size()) ? cwealth[i] : 0.0;
|
||||
double w = (i < cwealth.size()) ? cwealth[i] : 0.0;
|
||||
if (w > 0.0) vcolors[i] = wealthColor(w / wealthMax); // owned land: trade prosperity
|
||||
else vcolors[i] = (planet.cells[i].elevation > planet.cfg.seaLevel) // wilderness land vs sea
|
||||
? Color{40, 42, 46, 255} : Color{22, 30, 44, 255};
|
||||
@ -428,7 +466,9 @@ void Viewer::detectLiveEvents(const std::vector<WeatherSystem>& beforeStorms,
|
||||
// -> realm foundings, tier rises (to a kingdom/empire), and collapses (capital lost/absorbed).
|
||||
void Viewer::detectNationEvents(const std::vector<Nation>& before) {
|
||||
auto byCapital = [](const std::vector<Nation>& v, int cap) -> const Nation* {
|
||||
for (const Nation& nn : v) if (nn.capital == cap) return &nn; return nullptr;
|
||||
for (const Nation& nn : v)
|
||||
if (nn.capital == cap) return &nn;
|
||||
return nullptr;
|
||||
};
|
||||
for (const Nation& nat : planet.nationList()) {
|
||||
if (nat.capital < 0 || nat.capital >= (int)planet.settlements.size()) continue;
|
||||
@ -643,6 +683,7 @@ void Viewer::loadGame(const char* path) {
|
||||
|| !std::isfinite(v.activity) || !std::isfinite(v.baseElev)
|
||||
|| !std::isfinite(v.built) || !std::isfinite(v.timer)
|
||||
|| !std::isfinite(v.ashTimer) || !std::isfinite(v.ashCarry)) historyOk = false;
|
||||
if (!validateFrameCivState(f.w, planet.settlements.size())) historyOk = false;
|
||||
if (historyOk) wxUndo.push_back(std::move(f));
|
||||
}
|
||||
if (!historyOk) { wxUndo.clear(); skippedHistory = true; }
|
||||
|
||||
@ -288,6 +288,11 @@ private:
|
||||
uint32_t rnd();
|
||||
double rndf(); // [0,1)
|
||||
void buildGeometry(); // build icosphere + per-cell unit/neighbors
|
||||
bool readStateImpl(std::istream& is, bool hasBiome, bool hasBiota,
|
||||
bool hasMoons, bool hasWeather, bool hasStorms,
|
||||
bool hasVolcanoes, bool hasStatefulVolcanoes, bool hasGeography,
|
||||
bool hasGeoSalt, bool hasEcoregions, bool hasSettlements,
|
||||
bool hasConflict, bool hasDiplo);
|
||||
void clearDerivedState(); // clear geometry-dependent scratch/derived fields
|
||||
void assignPlates();
|
||||
void seedInitialRelief();
|
||||
|
||||
@ -217,7 +217,7 @@ CivUpdate Planet::stepCivilization(double dtHours, double liveTime) {
|
||||
double siteQ = std::clamp(0.45 + cfg.civSiteVariety * ((coast ? 1.2 : 0.0) + riverQ), 0.3, 6.0);
|
||||
|
||||
double cond = harvest * droughtFactor * coldFactor * floodFactor * ashFactor;
|
||||
double prosp = (k < sProsperity.size()) ? sProsperity[k] : 0.0; // civ Step 7: trade wealth boosts capacity
|
||||
double prosp = ((size_t)k < sProsperity.size()) ? sProsperity[(size_t)k] : 0.0; // civ Step 7: trade wealth boosts capacity
|
||||
double K = cfg.civMaxPopulation * hab * siteQ * cond * (1.0 + cfg.tradeProsperityWeight * prosp);
|
||||
sCivCond[k] = cond; sCivDrought[k] = drought;
|
||||
|
||||
|
||||
@ -277,7 +277,9 @@ std::string Planet::nameNewLand(int cell) {
|
||||
uint32_t seed = geoSeed + (uint32_t)(cell * 2654435761u)
|
||||
+ (uint32_t)geoFeatures.size() * 40503u;
|
||||
auto inUse = [&](const std::string& nm) {
|
||||
for (const GeoFeature& f : geoFeatures) if (f.name == nm) return true; return false;
|
||||
for (const GeoFeature& f : geoFeatures)
|
||||
if (f.name == nm) return true;
|
||||
return false;
|
||||
};
|
||||
std::string nm = namegen::makeName(seed, bank);
|
||||
for (int g = 0; inUse(nm) && g < 128; ++g) nm = namegen::makeName(seed += 0x9E3779B9u, bank);
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
// --- Config file (text) + save/load (binary) --------------------------------
|
||||
|
||||
@ -368,6 +370,16 @@ std::string validateConfig(const PlanetConfig& cfg) {
|
||||
bad.push_back("volcanoDormantMinYears > volcanoDormantMaxYears");
|
||||
if (cfg.volcanoAshMinYears > cfg.volcanoAshMaxYears)
|
||||
bad.push_back("volcanoAshMinYears > volcanoAshMaxYears");
|
||||
if (!(cfg.biomeIceTemp < cfg.biomeTundraTemp && cfg.biomeTundraTemp < cfg.biomeTaigaTemp))
|
||||
bad.push_back("biome temperature thresholds must satisfy Ice < Tundra < Taiga");
|
||||
if (cfg.biomeHillsElev >= cfg.biomeMountainElev)
|
||||
bad.push_back("biomeHillsElev >= biomeMountainElev");
|
||||
if (cfg.civAbandonPop >= cfg.civTownPop || cfg.civTownPop >= cfg.civCityPop)
|
||||
bad.push_back("civilization population thresholds must satisfy Abandon < Town < City");
|
||||
if (cfg.civSeedPopulation <= cfg.civAbandonPop)
|
||||
bad.push_back("civSeedPopulation <= civAbandonPop");
|
||||
if (!(cfg.diploRivalThreshold < cfg.diploNonAggThreshold && cfg.diploNonAggThreshold < cfg.diploAllyThreshold))
|
||||
bad.push_back("diplomacy thresholds must satisfy Rival < NonAggression < Alliance");
|
||||
|
||||
if (bad.empty()) return {};
|
||||
std::string msg = "Bad config:";
|
||||
@ -412,6 +424,34 @@ namespace {
|
||||
bool validBiomeByte(uint8_t b) {
|
||||
return b <= (uint8_t)Biome::Mountains;
|
||||
}
|
||||
bool validWarRecord(const War& w, int settlementCount) {
|
||||
return w.attacker >= 0 && w.attacker < settlementCount
|
||||
&& w.defender >= 0 && w.defender < settlementCount
|
||||
&& w.attacker != w.defender
|
||||
&& w.battles >= 0
|
||||
&& std::isfinite(w.warscore);
|
||||
}
|
||||
bool validateWars(std::vector<War>& wars, int settlementCount) {
|
||||
std::set<std::pair<int, int>> seen;
|
||||
for (const War& w : wars) {
|
||||
if (!validWarRecord(w, settlementCount)) return false;
|
||||
auto key = std::minmax(w.attacker, w.defender);
|
||||
if (!seen.insert(key).second) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool sanitizeDiplo(std::vector<DiploTie>& ties, int settlementCount) {
|
||||
std::set<std::pair<int, int>> seen;
|
||||
for (DiploTie& t : ties) {
|
||||
if (t.a < 0 || t.a >= settlementCount || t.b < 0 || t.b >= settlementCount || t.a == t.b)
|
||||
return false;
|
||||
if (t.a > t.b) std::swap(t.a, t.b);
|
||||
if (!seen.insert({t.a, t.b}).second) return false;
|
||||
if (!std::isfinite(t.attitude)) return false;
|
||||
t.attitude = std::clamp(t.attitude, -1.0, 1.0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Full simulation state. Geometry (unit/neighbors) is NOT stored -- it is rebuilt
|
||||
@ -519,6 +559,20 @@ bool Planet::readState(std::istream& is, bool hasBiome, bool hasBiota, bool hasM
|
||||
bool hasWeather, bool hasStorms, bool hasVolcanoes, bool hasStatefulVolcanoes,
|
||||
bool hasGeography, bool hasGeoSalt, bool hasEcoregions, bool hasSettlements,
|
||||
bool hasConflict, bool hasDiplo) {
|
||||
Planet tmp;
|
||||
tmp.drifting = drifting; // readState never serialized this flag; preserve old caller-visible behavior.
|
||||
if (!tmp.readStateImpl(is, hasBiome, hasBiota, hasMoons, hasWeather, hasStorms, hasVolcanoes,
|
||||
hasStatefulVolcanoes, hasGeography, hasGeoSalt, hasEcoregions,
|
||||
hasSettlements, hasConflict, hasDiplo))
|
||||
return false;
|
||||
*this = std::move(tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Planet::readStateImpl(std::istream& is, bool hasBiome, bool hasBiota, bool hasMoons,
|
||||
bool hasWeather, bool hasStorms, bool hasVolcanoes, bool hasStatefulVolcanoes,
|
||||
bool hasGeography, bool hasGeoSalt, bool hasEcoregions, bool hasSettlements,
|
||||
bool hasConflict, bool hasDiplo) {
|
||||
// Save blocks are append-only by version. If a caller asks for an older prefix,
|
||||
// later blocks cannot exist in that stream even if the default arguments say otherwise.
|
||||
if (!hasBiota) { hasMoons = false; hasWeather = false; hasStorms = false; hasVolcanoes = false; }
|
||||
@ -759,6 +813,7 @@ bool Planet::readState(std::istream& is, bool hasBiome, bool hasBiota, bool hasM
|
||||
if (w.attacker < 0 || w.attacker >= (int)settlements.size()
|
||||
|| w.defender < 0 || w.defender >= (int)settlements.size()) return false;
|
||||
}
|
||||
if (!validateWars(wars, (int)settlements.size())) return false;
|
||||
readPod(is, sWarRng); readPod(is, sWarNextId);
|
||||
if (!sWarRng) sWarRng = cfg.seed ? (cfg.seed ^ 0x5A7B0A11u) : 0x5A7B0A11u;
|
||||
if (!sWarNextId) sWarNextId = 1;
|
||||
@ -776,6 +831,7 @@ bool Planet::readState(std::istream& is, bool hasBiome, bool hasBiota, bool hasM
|
||||
if (t.a < 0 || t.a >= (int)settlements.size()
|
||||
|| t.b < 0 || t.b >= (int)settlements.size()) return false;
|
||||
}
|
||||
if (!sanitizeDiplo(diplomacy, (int)settlements.size())) return false;
|
||||
}
|
||||
computeBiotaDensity(); // derived density scalars for the colour views
|
||||
return (bool)is;
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
// Headless logic test for the Biota stage (flora / fauna / funga). No display.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_biota.cpp src/sim/IcoSphere.cpp \
|
||||
// src/sim/Planet.cpp src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp \
|
||||
// src/sim/PlanetErosion.cpp src/sim/PlanetHydrology.cpp \
|
||||
// src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp \
|
||||
// src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp \
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_biota.cpp src/sim/IcoSphere.cpp
|
||||
// src/sim/Planet.cpp src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp
|
||||
// src/sim/PlanetErosion.cpp src/sim/PlanetHydrology.cpp
|
||||
// src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp
|
||||
// src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp
|
||||
// src/sim/PlanetIO.cpp -o /tmp/tb && /tmp/tb
|
||||
//
|
||||
// Verifies: density ranges, zero life under ice + marine flora/fauna present in the
|
||||
@ -95,8 +95,12 @@ int main() {
|
||||
const auto& B = p.biota();
|
||||
bool slotsOk = true, pointsOk = true, carnGated = true, iceEmpty = true, oceanFungaEmpty = true;
|
||||
bool anyMarineOrg = false;
|
||||
auto cost = [&](const std::vector<Organism>& v) { int s = 0; const auto& AR = biotaArchetypes();
|
||||
for (auto& o : v) s += pointCost(AR[o.archetype].size); return s; };
|
||||
auto cost = [&](const std::vector<Organism>& v) {
|
||||
int s = 0;
|
||||
const auto& AR = biotaArchetypes();
|
||||
for (auto& o : v) s += pointCost(AR[o.archetype].size);
|
||||
return s;
|
||||
};
|
||||
for (int i = 0; i < n; ++i) {
|
||||
const CellBiota& cb = B[i];
|
||||
if (p.cells[i].biome == Biome::Ice) { // ice (land or frozen sea): empty
|
||||
|
||||
14
test_civ.cpp
14
test_civ.cpp
@ -1,12 +1,12 @@
|
||||
// Headless test for civilization Step 2 (habitability + settlements). No display needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_civ.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp \
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp \
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp \
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp \
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp \
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp \
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_civ.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp
|
||||
// src/sim/PlanetIO.cpp -o /tmp/tc && /tmp/tc
|
||||
//
|
||||
// Verifies: habitability range/zeros; placement spacing/cap/land + unique names; food-driven growth
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Headless test for civilization colonization (kingdoms found new settlements + islands). No display.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_colony.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp \
|
||||
// ... (the same source list as test_civ) ... src/sim/PlanetTrade.cpp src/sim/PlanetIO.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_colony.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp
|
||||
// ... (the same source list as test_civ) ... src/sim/PlanetTrade.cpp src/sim/PlanetIO.cpp
|
||||
// -o /tmp/tcol && /tmp/tcol
|
||||
//
|
||||
// Verifies: colonies are founded (the settlement count grows); a colony belongs to its founder's realm
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
// Headless test for civilization Step 5 (conflict, war & shifting borders). No display needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_conflict.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp \
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp \
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp \
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp \
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp \
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp \
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp \
|
||||
// src/sim/PlanetNation.cpp src/sim/PlanetCulture.cpp src/sim/PlanetConflict.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_conflict.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp
|
||||
// src/sim/PlanetNation.cpp src/sim/PlanetCulture.cpp src/sim/PlanetConflict.cpp
|
||||
// src/sim/PlanetIO.cpp -o /tmp/twar && /tmp/twar
|
||||
//
|
||||
// Verifies: wars start between neighbouring realms; conquest sets allegiance so computeTerritory moves
|
||||
@ -146,6 +146,30 @@ int main() {
|
||||
r.computeTerritory();
|
||||
check(r.cellNation() == p2.cellNation(), "territory recomputed after load matches (allegiance honoured)");
|
||||
}
|
||||
{
|
||||
Planet bad = p2;
|
||||
bad.wars.clear();
|
||||
War w; w.attacker = 0; w.defender = (int)bad.settlements.size() + 10;
|
||||
bad.wars.push_back(w);
|
||||
std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
|
||||
bad.writeState(ss);
|
||||
Planet r;
|
||||
check(!r.readState(ss, true, true, true, true, true, true, true, true, true, true, true, true),
|
||||
"readState rejects active wars with invalid settlement endpoints");
|
||||
}
|
||||
if (p2.settlements.size() >= 2) {
|
||||
Planet bad = p2;
|
||||
bad.wars.clear();
|
||||
War a; a.attacker = 0; a.defender = 1;
|
||||
War b; b.attacker = 1; b.defender = 0;
|
||||
bad.wars.push_back(a);
|
||||
bad.wars.push_back(b);
|
||||
std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
|
||||
bad.writeState(ss);
|
||||
Planet r;
|
||||
check(!r.readState(ss, true, true, true, true, true, true, true, true, true, true, true, true),
|
||||
"readState rejects duplicate active wars for the same realm pair");
|
||||
}
|
||||
|
||||
std::printf("Conflict: step-back snapshot round-trip\n");
|
||||
{
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
// Headless test for civilization Step 4 (cultures, beliefs & governments). No display needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_culture.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp \
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp \
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp \
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp \
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp \
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp \
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_culture.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp
|
||||
// src/sim/PlanetNation.cpp src/sim/PlanetCulture.cpp src/sim/PlanetIO.cpp -o /tmp/tc && /tmp/tc
|
||||
//
|
||||
// Verifies: one culture per inhabited continent; every living settlement has a culture; valid
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
// Headless test for civilization Step 6 (diplomacy, alliances & coalitions). No display needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_diplomacy.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp \
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp \
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp \
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp \
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp \
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp \
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp \
|
||||
// src/sim/PlanetNation.cpp src/sim/PlanetCulture.cpp src/sim/PlanetConflict.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_diplomacy.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp
|
||||
// src/sim/PlanetNation.cpp src/sim/PlanetCulture.cpp src/sim/PlanetConflict.cpp
|
||||
// src/sim/PlanetIO.cpp -o /tmp/tdip && /tmp/tdip
|
||||
//
|
||||
// Verifies: alliances + rivalries form; allies never war on each other; coalitions form (allies join a
|
||||
@ -127,6 +127,32 @@ int main() {
|
||||
check(ok, "readState accepts the v22 stream");
|
||||
check(tiesEqual(r.diploList(), p.diploList()), "diplomacy survives save/load");
|
||||
}
|
||||
{
|
||||
Planet bad = p;
|
||||
bad.diplomacy.clear();
|
||||
DiploTie t; t.a = 0; t.b = (int)bad.settlements.size() + 10;
|
||||
bad.diplomacy.push_back(t);
|
||||
std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
|
||||
bad.writeState(ss);
|
||||
Planet r;
|
||||
check(!r.readState(ss, true, true, true, true, true, true, true, true, true, true, true, true, true),
|
||||
"readState rejects diplomacy ties with invalid settlement endpoints");
|
||||
}
|
||||
if (p.settlements.size() >= 2) {
|
||||
Planet odd = p;
|
||||
odd.diplomacy.clear();
|
||||
DiploTie t; t.a = 1; t.b = 0; t.attitude = 99.0; t.kind = (DiploKind)255;
|
||||
odd.diplomacy.push_back(t);
|
||||
std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
|
||||
odd.writeState(ss);
|
||||
Planet r;
|
||||
bool ok = r.readState(ss, true, true, true, true, true, true, true, true, true, true, true, true, true);
|
||||
bool sanitized = ok && r.diploList().size() == 1
|
||||
&& r.diploList()[0].a == 0 && r.diploList()[0].b == 1
|
||||
&& std::fabs(r.diploList()[0].attitude - 1.0) < 1e-12
|
||||
&& r.diploList()[0].kind == DiploKind::Neutral;
|
||||
check(sanitized, "readState canonicalizes and clamps salvageable diplomacy ties");
|
||||
}
|
||||
|
||||
std::printf("Diplomacy: step-back snapshot round-trip\n");
|
||||
{
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
// Headless test for the geography / atlas stage (named feature extraction + naming). No display.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_geography.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp \
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp \
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp \
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp \
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp \
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_geography.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetIO.cpp -o /tmp/tg && /tmp/tg
|
||||
//
|
||||
// Verifies: extraction (continents/oceans/ranges/rivers/lakes), per-cell membership consistency,
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
// Headless test for the Live World stage (insolation + live seasonal temperature).
|
||||
// No display / raylib needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_live.cpp src/sim/IcoSphere.cpp \
|
||||
// src/sim/Planet.cpp src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp \
|
||||
// src/sim/PlanetErosion.cpp src/sim/PlanetHydrology.cpp \
|
||||
// src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp src/sim/PlanetLive.cpp \
|
||||
// src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp src/sim/PlanetFaunaGen.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_live.cpp src/sim/IcoSphere.cpp
|
||||
// src/sim/Planet.cpp src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp
|
||||
// src/sim/PlanetErosion.cpp src/sim/PlanetHydrology.cpp
|
||||
// src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp src/sim/PlanetLive.cpp
|
||||
// src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp src/sim/PlanetFaunaGen.cpp
|
||||
// src/sim/PlanetFungiGen.cpp src/sim/PlanetIO.cpp -o /tmp/tl && /tmp/tl
|
||||
//
|
||||
// Verifies: insolation range; the sub-solar hemisphere is lit and the night side dark;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// Headless logic test for Phase 1 tectonics. No display / raylib needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_logic.cpp src/sim/IcoSphere.cpp \
|
||||
// src/sim/Planet.cpp src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp \
|
||||
// src/sim/PlanetErosion.cpp src/sim/PlanetHydrology.cpp src/sim/PlanetIO.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_logic.cpp src/sim/IcoSphere.cpp
|
||||
// src/sim/Planet.cpp src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp
|
||||
// src/sim/PlanetErosion.cpp src/sim/PlanetHydrology.cpp src/sim/PlanetIO.cpp
|
||||
// -o /tmp/t && /tmp/t
|
||||
//
|
||||
// Verifies the invariants documented in CLAUDE.md so Planet::step() and the
|
||||
@ -234,6 +234,20 @@ int main() {
|
||||
finishManualState(badPlate);
|
||||
Planet rp;
|
||||
check(!rp.readState(badPlate), "readState() rejects invalid cell plate ids");
|
||||
|
||||
Planet victim; victim.generate(cfg);
|
||||
const size_t beforeCells = victim.cells.size();
|
||||
const int beforeSubdiv = victim.cfg.subdivisions;
|
||||
const double beforeElev = victim.cells.empty() ? 0.0 : victim.cells[0].elevation;
|
||||
std::stringstream badAfterBuild(std::ios::in | std::ios::out | std::ios::binary);
|
||||
writeManualStatePrefix(badAfterBuild, "subdivisions = 0\nplateCount = 1\n", 77);
|
||||
finishManualState(badAfterBuild);
|
||||
bool rejected = !victim.readState(badAfterBuild);
|
||||
bool unchanged = victim.cells.size() == beforeCells
|
||||
&& victim.cfg.subdivisions == beforeSubdiv
|
||||
&& !victim.cells.empty()
|
||||
&& victim.cells[0].elevation == beforeElev;
|
||||
check(rejected && unchanged, "failed readState() leaves the existing planet unchanged");
|
||||
}
|
||||
|
||||
std::printf("\n%s (%d failure%s)\n",
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
// Headless test for civilization Step 3 (territory & nations / realms). No display needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_nation.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp \
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp \
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp \
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp \
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp \
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp \
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_nation.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp
|
||||
// src/sim/PlanetNation.cpp src/sim/PlanetIO.cpp -o /tmp/tn && /tmp/tn
|
||||
//
|
||||
// Verifies: territory ownership + wilderness; bigger cities own more; realm grouping (kingdom vs
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
// Headless test for the Live World ocean/sky stage (moons + tides). No display needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_ocean.cpp src/sim/IcoSphere.cpp \
|
||||
// src/sim/Planet.cpp src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp \
|
||||
// src/sim/PlanetErosion.cpp src/sim/PlanetHydrology.cpp \
|
||||
// src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp src/sim/PlanetLive.cpp \
|
||||
// src/sim/PlanetOcean.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp \
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/PlanetIO.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_ocean.cpp src/sim/IcoSphere.cpp
|
||||
// src/sim/Planet.cpp src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp
|
||||
// src/sim/PlanetErosion.cpp src/sim/PlanetHydrology.cpp
|
||||
// src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp src/sim/PlanetLive.cpp
|
||||
// src/sim/PlanetOcean.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/PlanetIO.cpp
|
||||
// -o /tmp/to && /tmp/to
|
||||
//
|
||||
// Verifies: 1-3 moons generated deterministically; moon/sun directions are unit vectors that
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
// Headless test for civilization Step 7 (trade & economy). No display needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_trade.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp \
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp \
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp \
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp \
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp \
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp \
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp \
|
||||
// src/sim/PlanetNation.cpp src/sim/PlanetCulture.cpp src/sim/PlanetConflict.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_trade.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/NameGen.cpp
|
||||
// src/sim/PlanetGeography.cpp src/sim/PlanetEcoregions.cpp src/sim/PlanetCiv.cpp
|
||||
// src/sim/PlanetNation.cpp src/sim/PlanetCulture.cpp src/sim/PlanetConflict.cpp
|
||||
// src/sim/PlanetTrade.cpp src/sim/PlanetIO.cpp -o /tmp/ttr && /tmp/ttr
|
||||
//
|
||||
// Verifies: trade links form (coastal pairs over a longer sea range); hubs are richer than isolated
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
// Headless test for Live World volcanoes (stateful growth, dormancy, explosions, ash,
|
||||
// rewind snapshots and save/load). No display needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_volcano.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp \
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp \
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp \
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp \
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_volcano.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp
|
||||
// src/sim/PlanetVolcano.cpp src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp
|
||||
// src/sim/PlanetFaunaGen.cpp src/sim/PlanetFungiGen.cpp src/sim/PlanetIO.cpp -o /tmp/tv && /tmp/tv
|
||||
|
||||
#include "Planet.hpp"
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
// Headless test for the Live World weather cycle (humidity / cloud / rain). No display needed.
|
||||
//
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_weather.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp \
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp \
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp \
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp \
|
||||
// src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp src/sim/PlanetFaunaGen.cpp \
|
||||
// g++ -std=c++17 -O2 -Isrc/sim test_weather.cpp src/sim/IcoSphere.cpp src/sim/Planet.cpp
|
||||
// src/sim/PlanetTectonics.cpp src/sim/PlanetDrift.cpp src/sim/PlanetErosion.cpp
|
||||
// src/sim/PlanetHydrology.cpp src/sim/PlanetBiomes.cpp src/sim/PlanetClimate.cpp
|
||||
// src/sim/PlanetLive.cpp src/sim/PlanetOcean.cpp src/sim/PlanetWeather.cpp
|
||||
// src/sim/PlanetBiota.cpp src/sim/PlanetFloraGen.cpp src/sim/PlanetFaunaGen.cpp
|
||||
// src/sim/PlanetFungiGen.cpp src/sim/PlanetIO.cpp -o /tmp/tw && /tmp/tw
|
||||
//
|
||||
// Verifies: fields stay in range; oceans (the evaporation source) end up moister than land;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user