feat(simulation): Layer-1 topography pipeline — features, sub-biome, orchestrator (#953)

Wire the empty-world topography cascade (D-208/209/210):
- generator.rs: add SubBiomeVariant (11 variants, D-210) + sub_biome and
  terrain_modification_cost fields on GeographicAttractor; AttractorType
  is now Copy.
- features.rs (new, D-209): extract the 7 attractor tags from heightmap +
  drainage. Coast/lake derived from the heightmap (D-209/D-223
  reconciliation — markers are names-only now, no polygons). Deterministic
  (sorted seeds, integer keys, bucket-grid thinning); strength-capped at
  MAX_ATTRACTORS preserving type diversity. Shared TerrainAnalysis
  (masks/slope/moisture/percentile) feeds both extraction and sub-biome.
- subbiome.rs (new, D-210): classify sub-biome + terrain_modification_cost
  from elevation/slope/moisture/latitude. Volcanic stays in the enum but
  is not emitted (no heightmap signal).
- layer1.rs (new): run_layer1 orchestrator + attach_feature_names (D-223
  pool names to largest rivers / Alpine peaks).
- attractor_matching constructors updated for the new fields.

76 atlas tests pass; run_layer1 determinism verified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-23 00:35:39 +02:00
co-authored by Claude Opus 4.7
parent 7cf7614342
commit d418eba8bb
6 changed files with 997 additions and 3 deletions
+5 -1
View File
@@ -18,7 +18,7 @@
use tracing::{error, warn};
use crate::simulation::generator::{
AttractorType, CompatibilityMatrix, GeographicAttractor, SettlementClass,
AttractorType, CompatibilityMatrix, GeographicAttractor, SettlementClass, SubBiomeVariant,
};
// ---------------------------------------------------------------------------
@@ -244,6 +244,8 @@ fn synthetic_attractor(placed: &[CityPlacement], grid_w: u32, grid_h: u32) -> Ge
position: (row, col),
attractor_type: AttractorType::PlainCenter,
strength: 0.5,
sub_biome: SubBiomeVariant::TemperateGrassland,
terrain_modification_cost: 1.0,
}
}
@@ -488,6 +490,8 @@ mod tests {
position: (row, col),
attractor_type: at,
strength,
sub_biome: SubBiomeVariant::TemperateGrassland,
terrain_modification_cost: 1.0,
}
}