refactor(simulation): rename DistrictSkeleton→QuarterSkeleton per D-222 (#950)
D-222 renamed the 512m generation cell from District to Quarter (District is now a new 2048m tier above it). Align the generation skeleton code to the canonical vocabulary. Pure naming — no behavior change; all 1296 lib tests + integration tests pass unchanged. Renamed (spatial-cell identifiers): - DistrictSkeleton → QuarterSkeleton, DistrictWorldState → QuarterWorldState - DistrictId → QuarterId, DistrictContext/DistrictBoundaries → Quarter* - field district_id → quarter_id, district_type → quarter_type - BodyWorldState.districts map → .quarters - generate_skeleton → generate_quarter_skeleton Deliberately left as-is (these name functional ZONING, not the spatial tier — orthogonal to D-222): DistrictType, DistrictLayoutMode, the district_mix module (DistrictMix/compute_district_mix), and the GenWorkItem::GenerateSkeleton / GenCompletion::SkeletonGenerated variants. Also aligned the perception "sim tile" → "subtile" vocabulary (D-222: Subtile = 0.5m) in decisions/perception.md and the generation-cascade code comments. Historical D-066/D-094/D-201/D-220 decision bodies keep their existing D-222 amendment notes (not rewritten in place); the public max_offset_sim_tiles fn name is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -45,7 +45,7 @@ fn archetype_step_bp(archetype: &PoliticalArchetype) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Derive the maximum block offset in sim tiles from `block_irregularity`.
|
||||
/// Derive the maximum block offset in subtiles from `block_irregularity`.
|
||||
///
|
||||
/// Used by `DistrictLayoutMode::Organic`: `max_offset = (irregularity × 16.0) as i16`.
|
||||
pub fn max_offset_sim_tiles(irregularity: f32) -> i16 {
|
||||
|
||||
@@ -14,7 +14,7 @@ use bevy_ecs::prelude::Resource;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::atlas::attractor_matching::CityPlacement;
|
||||
use crate::simulation::generator::{DistrictId, DistrictWorldState, GeographicAttractor};
|
||||
use crate::simulation::generator::{GeographicAttractor, QuarterId, QuarterWorldState};
|
||||
|
||||
/// Simulation tick counter — monotonically increasing u64.
|
||||
pub type SimTick = u64;
|
||||
@@ -75,11 +75,11 @@ pub struct BodyWorldState {
|
||||
/// Settlement placements (D-211, #955). Attractor-matched city positions.
|
||||
/// Empty until the Layer-3 placement task completes.
|
||||
pub placements: Vec<CityPlacement>,
|
||||
/// District-level world state, keyed by `DistrictId` (D-230).
|
||||
/// Quarter-level world state, keyed by `QuarterId` (D-230).
|
||||
///
|
||||
/// Populated by `GenCompletion::SkeletonGenerated` after the plan phase
|
||||
/// completes for each city. `BTreeMap` for D-010 determinism.
|
||||
pub districts: BTreeMap<DistrictId, DistrictWorldState>,
|
||||
pub quarters: BTreeMap<QuarterId, QuarterWorldState>,
|
||||
/// Last sim tick this entry was read. Used for LRU eviction.
|
||||
pub last_accessed: SimTick,
|
||||
}
|
||||
@@ -201,7 +201,7 @@ mod tests {
|
||||
drainage_basins: vec![],
|
||||
attractors: vec![],
|
||||
placements: vec![],
|
||||
districts: BTreeMap::new(),
|
||||
quarters: BTreeMap::new(),
|
||||
last_accessed: tick,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ impl CascadeSnapshot {
|
||||
drainage_basins,
|
||||
attractors,
|
||||
placements,
|
||||
districts: std::collections::BTreeMap::new(),
|
||||
quarters: std::collections::BTreeMap::new(),
|
||||
last_accessed: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//!
|
||||
//! **Work item types (D-206):**
|
||||
//! - `AnalyzeBody`: D8 drainage + attractor extraction for a body.
|
||||
//! - `GenerateSkeleton`: Phase 1 DistrictSkeleton for a city.
|
||||
//! - `GenerateSkeleton`: Phase 1 QuarterSkeleton for a city.
|
||||
//! - `FillChunk`: Phase 2 chunk fill for a pre-loaded district.
|
||||
//!
|
||||
//! Completion events are delivered to the main thread via
|
||||
@@ -31,9 +31,9 @@ use crate::atlas::attractor_matching::CityRecord;
|
||||
use crate::atlas::body_world_state::BodyWorldState;
|
||||
use crate::atlas::cascade::{run_cascade_from_heightmap, CascadeLayer};
|
||||
use crate::atlas::heightmap::{load_heightmap_png, GRID_H, GRID_W};
|
||||
use crate::atlas::skeleton_gen::generate_skeleton;
|
||||
use crate::atlas::skeleton_gen::generate_quarter_skeleton;
|
||||
use crate::seed::SeedChain;
|
||||
use crate::simulation::generator::{CityGenerationContext, DistrictWorldState};
|
||||
use crate::simulation::generator::{CityGenerationContext, QuarterWorldState};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Priority
|
||||
@@ -73,7 +73,7 @@ pub enum GenWorkItem {
|
||||
/// (#955); empty if the body has no settlements (cascade stops at Layer 1).
|
||||
cities: Vec<CityRecord>,
|
||||
},
|
||||
/// Generate a Phase 1 DistrictSkeleton for this city.
|
||||
/// Generate a Phase 1 QuarterSkeleton for this city.
|
||||
///
|
||||
/// `context` is the D-199 economic read-set pre-resolved at dispatch time.
|
||||
/// All 6 required fields must be populated before this item is submitted
|
||||
@@ -83,11 +83,11 @@ pub enum GenWorkItem {
|
||||
/// `body_id` routes the resulting `SkeletonGenerated` completion into the
|
||||
/// correct `BodyWorldState` cache entry (D-230).
|
||||
///
|
||||
/// `district_id` is the stable content-addressable id for the generated
|
||||
/// `quarter_id` is the stable content-addressable id for the generated
|
||||
/// district (keyed by city position + world seed).
|
||||
///
|
||||
/// `economic_role`, `population`, and `founding_age_years` are D-199 fields
|
||||
/// carried alongside the context because `generate_skeleton` accepts them as
|
||||
/// carried alongside the context because `generate_quarter_skeleton` accepts them as
|
||||
/// separate parameters (its signature is not changed by this ticket).
|
||||
GenerateSkeleton {
|
||||
city_id: u64,
|
||||
@@ -95,17 +95,17 @@ pub enum GenWorkItem {
|
||||
/// D-199 economic read-set + all other context fields.
|
||||
context: Box<CityGenerationContext>,
|
||||
/// Stable content-addressable district id (D-194/D-230).
|
||||
district_id: u64,
|
||||
quarter_id: u64,
|
||||
/// District-level seed chain (D-224).
|
||||
chain: SeedChain,
|
||||
// D-199 raw fields passed to generate_skeleton separately.
|
||||
// D-199 raw fields passed to generate_quarter_skeleton separately.
|
||||
economic_role: String,
|
||||
population: i64,
|
||||
founding_age_years: u32,
|
||||
},
|
||||
/// Pre-fill a chunk in an existing district.
|
||||
FillChunk {
|
||||
district_id: u64,
|
||||
quarter_id: u64,
|
||||
block_pos: (u32, u32),
|
||||
},
|
||||
}
|
||||
@@ -135,14 +135,14 @@ pub enum GenCompletion {
|
||||
SkeletonGenerated {
|
||||
city_id: u64,
|
||||
/// The body this skeleton belongs to — used to route state into
|
||||
/// `BodyWorldState.districts` (D-230).
|
||||
/// `BodyWorldState.quarters` (D-230).
|
||||
body_id: String,
|
||||
/// District-level world state (skeleton + block tags) produced by the plan phase (D-230).
|
||||
/// Boxed to keep `GenCompletion` variant sizes balanced (D-230 skeleton is ~2.7 KB).
|
||||
state: Box<DistrictWorldState>,
|
||||
state: Box<QuarterWorldState>,
|
||||
},
|
||||
ChunkFilled {
|
||||
district_id: u64,
|
||||
quarter_id: u64,
|
||||
block_pos: (u32, u32),
|
||||
},
|
||||
/// Work item failed — body_id or city_id for logging.
|
||||
@@ -385,7 +385,7 @@ fn run_work_item(item: &GenWorkItem) -> GenCompletion {
|
||||
city_id,
|
||||
body_id,
|
||||
context,
|
||||
district_id,
|
||||
quarter_id,
|
||||
chain,
|
||||
economic_role,
|
||||
population,
|
||||
@@ -394,29 +394,29 @@ fn run_work_item(item: &GenWorkItem) -> GenCompletion {
|
||||
// Build the Phase 1 skeleton from the pre-resolved D-199 context.
|
||||
// `economic_role`, `population`, and `founding_age_years` are the
|
||||
// D-199 raw fields carried alongside the context because
|
||||
// `generate_skeleton` accepts them as separate parameters.
|
||||
let skeleton = generate_skeleton(
|
||||
// `generate_quarter_skeleton` accepts them as separate parameters.
|
||||
let skeleton = generate_quarter_skeleton(
|
||||
context,
|
||||
*population,
|
||||
economic_role,
|
||||
*district_id,
|
||||
*quarter_id,
|
||||
*founding_age_years,
|
||||
*chain,
|
||||
);
|
||||
GenCompletion::SkeletonGenerated {
|
||||
city_id: *city_id,
|
||||
body_id: body_id.clone(),
|
||||
state: Box::new(DistrictWorldState {
|
||||
state: Box::new(QuarterWorldState {
|
||||
skeleton,
|
||||
block_tags: std::collections::BTreeMap::new(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
GenWorkItem::FillChunk {
|
||||
district_id,
|
||||
quarter_id,
|
||||
block_pos,
|
||||
} => GenCompletion::ChunkFilled {
|
||||
district_id: *district_id,
|
||||
quarter_id: *quarter_id,
|
||||
block_pos: *block_pos,
|
||||
},
|
||||
}
|
||||
@@ -493,7 +493,7 @@ mod tests {
|
||||
dominant_bulk_class: BulkClass::NonPhysical,
|
||||
dominant_production_ubiquity: ProductionUbiquity::Common,
|
||||
}),
|
||||
district_id: city_id * 10,
|
||||
quarter_id: city_id * 10,
|
||||
chain: SeedChain::root(42 + city_id),
|
||||
economic_role: "service_mixed".to_string(),
|
||||
population: 500_000,
|
||||
@@ -590,7 +590,7 @@ mod tests {
|
||||
let q = make_queue();
|
||||
q.submit(
|
||||
GenWorkItem::FillChunk {
|
||||
district_id: 99,
|
||||
quarter_id: 99,
|
||||
block_pos: (0, 0),
|
||||
},
|
||||
GenPriority::High,
|
||||
|
||||
@@ -228,7 +228,7 @@ mod tests {
|
||||
drainage_basins: vec![],
|
||||
attractors: vec![],
|
||||
placements: vec![],
|
||||
districts: std::collections::BTreeMap::new(),
|
||||
quarters: std::collections::BTreeMap::new(),
|
||||
last_accessed: 0,
|
||||
});
|
||||
let (_db, resolver) = empty_resolver();
|
||||
|
||||
@@ -93,16 +93,16 @@ fn drain_generation_completions(
|
||||
} => {
|
||||
if !body_id.is_empty() {
|
||||
if let Some(body_state) = cache.peek_mut(&body_id) {
|
||||
// Key by state.skeleton.district_id (D-194/D-230): a city has many
|
||||
// districts, each with its own DistrictId. `city_id` is only the
|
||||
// Key by state.skeleton.quarter_id (D-194/D-230): a city has many
|
||||
// quarters, each with its own QuarterId. `city_id` is only the
|
||||
// dispatch key used in the work item — the canonical insert key is
|
||||
// the district's own stable id. TODO(#957): the stub GenerateSkeleton
|
||||
// returns a default skeleton with district_id=0; real gen (#957) will
|
||||
// the quarter's own stable id. TODO(#957): the stub GenerateSkeleton
|
||||
// returns a default skeleton with quarter_id=0; real gen (#957) will
|
||||
// populate it from CityGenerationContext.
|
||||
let _ = city_id; // used as dispatch key only; district_id is the map key
|
||||
let _ = city_id; // used as dispatch key only; quarter_id is the map key
|
||||
body_state
|
||||
.districts
|
||||
.insert(state.skeleton.district_id, *state);
|
||||
.quarters
|
||||
.insert(state.skeleton.quarter_id, *state);
|
||||
} else {
|
||||
tracing::warn!(
|
||||
city_id,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! Phase 1 district skeleton generator (D-194, D-196, D-211, D-213, D-214).
|
||||
//! Phase 1 quarter skeleton generator (D-194, D-196, D-211, D-213, D-214).
|
||||
//!
|
||||
//! Entry point: [`generate_skeleton`]. Consumes a [`CityGenerationContext`]
|
||||
//! Entry point: [`generate_quarter_skeleton`]. Consumes a [`CityGenerationContext`]
|
||||
//! together with the city's raw population and economic role, and produces a
|
||||
//! fully classified [`DistrictSkeleton`] with:
|
||||
//! fully classified [`QuarterSkeleton`] with:
|
||||
//!
|
||||
//! - [`SettingType`] derived from the surrounding biome context.
|
||||
//! - [`ComplexityTier`] derived from population tier × [`WorldTier`].
|
||||
@@ -22,8 +22,8 @@ use crate::atlas::block_irregularity::block_irregularity;
|
||||
use crate::atlas::district_mix::{compute_district_mix, population_tier};
|
||||
use crate::seed::{SeedChain, SeedDomain};
|
||||
use crate::simulation::generator::{
|
||||
BlockPlacement, BlockSkeleton, CityGenerationContext, ComplexityTier, DistrictId,
|
||||
DistrictLayoutMode, DistrictSkeleton, DistrictType, MultiBlockReservation, PoliticalArchetype,
|
||||
BlockPlacement, BlockSkeleton, CityGenerationContext, ComplexityTier, DistrictLayoutMode,
|
||||
DistrictType, MultiBlockReservation, PoliticalArchetype, QuarterId, QuarterSkeleton,
|
||||
ReservationFunction, ReservationId, SettingType, WorldTier, ZoningType,
|
||||
};
|
||||
|
||||
@@ -31,23 +31,23 @@ use crate::simulation::generator::{
|
||||
// Public API
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Generate a Phase 1 [`DistrictSkeleton`] from a city's generation context.
|
||||
/// Generate a Phase 1 [`QuarterSkeleton`] from a city's generation context.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `context`: Build-time city context (archetype, world tier, orientation…).
|
||||
/// - `population`: Raw population count from atlas_city_names.
|
||||
/// - `economic_role`: Economic role string (one of the 10 canonical values).
|
||||
/// - `district_id`: Content-addressable identifier for this district.
|
||||
/// - `quarter_id`: Content-addressable identifier for this district.
|
||||
/// - `founding_age_years`: Years since founding — controls block irregularity.
|
||||
/// - `chain`: This district's position in the deterministic seed tree (D-224 SeedChain).
|
||||
pub fn generate_skeleton(
|
||||
pub fn generate_quarter_skeleton(
|
||||
context: &CityGenerationContext,
|
||||
population: i64,
|
||||
economic_role: &str,
|
||||
district_id: DistrictId,
|
||||
quarter_id: QuarterId,
|
||||
founding_age_years: u32,
|
||||
chain: SeedChain,
|
||||
) -> DistrictSkeleton {
|
||||
) -> QuarterSkeleton {
|
||||
// ── 1. SettingType ────────────────────────────────────────────────────
|
||||
// Pass through the surrounding_biome from context — it already encodes
|
||||
// the planet/station/wilderness classification established at atlas time.
|
||||
@@ -103,11 +103,11 @@ pub fn generate_skeleton(
|
||||
// Reserved blocks carry their own z_levels count.
|
||||
let z_levels: u8 = 1;
|
||||
|
||||
DistrictSkeleton {
|
||||
district_id,
|
||||
QuarterSkeleton {
|
||||
quarter_id,
|
||||
seed: chain.seed(),
|
||||
district_type: district_type_from_mix(&primary_district_type),
|
||||
context: String::new(), // stub — DistrictContext = String
|
||||
quarter_type: district_type_from_mix(&primary_district_type),
|
||||
context: String::new(), // stub — QuarterContext = String
|
||||
world_tier: context.world_tier.clone(),
|
||||
complexity,
|
||||
setting,
|
||||
@@ -242,7 +242,7 @@ fn derive_layout_mode(
|
||||
/// Generate 4×4 organic block placements seeded deterministically (D-010).
|
||||
///
|
||||
/// Uses a seeded LCG; offset range controlled by `irregularity` (0.05–1.0)
|
||||
/// scaled to the ±16 sim tile maximum from `block_irregularity::max_offset_sim_tiles`.
|
||||
/// scaled to the ±16 subtile maximum from `block_irregularity::max_offset_sim_tiles`.
|
||||
fn organic_placements(irregularity: f32, chain: SeedChain) -> [[BlockPlacement; 4]; 4] {
|
||||
let max_offset = (irregularity * 16.0) as i16;
|
||||
// id = 0: one placement pass per district. Sibling separation comes from the
|
||||
@@ -292,7 +292,7 @@ fn zoning_for_district(dt: &DistrictType) -> ZoningType {
|
||||
}
|
||||
}
|
||||
|
||||
/// Map the primary district type to the DistrictType field on DistrictSkeleton.
|
||||
/// Map the primary district type to the DistrictType field on QuarterSkeleton.
|
||||
fn district_type_from_mix(primary: &DistrictType) -> DistrictType {
|
||||
primary.clone()
|
||||
}
|
||||
@@ -437,14 +437,15 @@ mod tests {
|
||||
fn setting_station_passthrough() {
|
||||
let mut ctx = make_context(PoliticalArchetype::Commission, WorldTier::Regional);
|
||||
ctx.surrounding_biome = SettingType::Station;
|
||||
let sk = generate_skeleton(&ctx, 500_000, "institutional", 1, 200, SeedChain::root(42));
|
||||
let sk =
|
||||
generate_quarter_skeleton(&ctx, 500_000, "institutional", 1, 200, SeedChain::root(42));
|
||||
assert!(matches!(sk.setting, SettingType::Station));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn setting_urban_for_city_on_planet() {
|
||||
let ctx = make_context(PoliticalArchetype::Commission, WorldTier::Regional);
|
||||
let sk = generate_skeleton(&ctx, 500_000, "financial", 1, 200, SeedChain::root(42));
|
||||
let sk = generate_quarter_skeleton(&ctx, 500_000, "financial", 1, 200, SeedChain::root(42));
|
||||
assert!(matches!(sk.setting, SettingType::Urban));
|
||||
}
|
||||
|
||||
@@ -452,14 +453,15 @@ mod tests {
|
||||
fn complexity_epicenter_high_pop_is_full() {
|
||||
let ctx = make_context(PoliticalArchetype::Commission, WorldTier::Epicenter);
|
||||
// 10M pop → pop_tier = 1 → Full on Epicenter
|
||||
let sk = generate_skeleton(&ctx, 10_000_000, "financial", 1, 200, SeedChain::root(42));
|
||||
let sk =
|
||||
generate_quarter_skeleton(&ctx, 10_000_000, "financial", 1, 200, SeedChain::root(42));
|
||||
assert_eq!(sk.complexity, ComplexityTier::Full);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complexity_waypoint_tiny_pop_is_empty() {
|
||||
let ctx = make_context(PoliticalArchetype::Pioneer, WorldTier::Waypoint);
|
||||
let sk = generate_skeleton(&ctx, 1_000, "residential", 1, 50, SeedChain::root(42));
|
||||
let sk = generate_quarter_skeleton(&ctx, 1_000, "residential", 1, 50, SeedChain::root(42));
|
||||
assert_eq!(sk.complexity, ComplexityTier::Empty);
|
||||
}
|
||||
|
||||
@@ -467,7 +469,7 @@ mod tests {
|
||||
fn complexity_backwater_low_pop_is_moderate() {
|
||||
let ctx = make_context(PoliticalArchetype::Pioneer, WorldTier::Backwater);
|
||||
// 50_000 pop → pop_tier = 0 → Moderate on Backwater (D-218: not budget-capped)
|
||||
let sk = generate_skeleton(&ctx, 50_000, "residential", 1, 50, SeedChain::root(42));
|
||||
let sk = generate_quarter_skeleton(&ctx, 50_000, "residential", 1, 50, SeedChain::root(42));
|
||||
assert_eq!(sk.complexity, ComplexityTier::Moderate);
|
||||
}
|
||||
|
||||
@@ -475,7 +477,8 @@ mod tests {
|
||||
fn complexity_backwater_high_pop_is_full() {
|
||||
let ctx = make_context(PoliticalArchetype::Pioneer, WorldTier::Backwater);
|
||||
// 10M pop → pop_tier = 1 → Full on Backwater (D-218: not budget-capped)
|
||||
let sk = generate_skeleton(&ctx, 10_000_000, "residential", 1, 50, SeedChain::root(42));
|
||||
let sk =
|
||||
generate_quarter_skeleton(&ctx, 10_000_000, "residential", 1, 50, SeedChain::root(42));
|
||||
assert_eq!(sk.complexity, ComplexityTier::Full);
|
||||
}
|
||||
|
||||
@@ -483,28 +486,31 @@ mod tests {
|
||||
fn complexity_passage_low_pop_is_minimal() {
|
||||
let ctx = make_context(PoliticalArchetype::Commission, WorldTier::Passage);
|
||||
// 50_000 pop → pop_tier = 0 → Minimal on Passage (transit stop, budget-capped)
|
||||
let sk = generate_skeleton(&ctx, 50_000, "transit_hub", 1, 100, SeedChain::root(42));
|
||||
let sk =
|
||||
generate_quarter_skeleton(&ctx, 50_000, "transit_hub", 1, 100, SeedChain::root(42));
|
||||
assert_eq!(sk.complexity, ComplexityTier::Minimal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_commission_is_grid() {
|
||||
let ctx = make_context(PoliticalArchetype::Commission, WorldTier::Regional);
|
||||
let sk = generate_skeleton(&ctx, 500_000, "institutional", 1, 100, SeedChain::root(99));
|
||||
let sk =
|
||||
generate_quarter_skeleton(&ctx, 500_000, "institutional", 1, 100, SeedChain::root(99));
|
||||
assert!(matches!(sk.layout_mode, DistrictLayoutMode::Grid));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_pioneer_is_organic() {
|
||||
let ctx = make_context(PoliticalArchetype::Pioneer, WorldTier::Regional);
|
||||
let sk = generate_skeleton(&ctx, 500_000, "residential", 1, 400, SeedChain::root(99));
|
||||
let sk =
|
||||
generate_quarter_skeleton(&ctx, 500_000, "residential", 1, 400, SeedChain::root(99));
|
||||
assert!(matches!(sk.layout_mode, DistrictLayoutMode::Organic { .. }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_grid_is_fully_populated() {
|
||||
let ctx = make_context(PoliticalArchetype::Commission, WorldTier::Regional);
|
||||
let sk = generate_skeleton(&ctx, 500_000, "financial", 1, 200, SeedChain::root(42));
|
||||
let sk = generate_quarter_skeleton(&ctx, 500_000, "financial", 1, 200, SeedChain::root(42));
|
||||
// All 16 blocks must have valid positions.
|
||||
for row in 0..4 {
|
||||
for col in 0..4 {
|
||||
@@ -519,7 +525,7 @@ mod tests {
|
||||
fn no_reservations_for_small_city() {
|
||||
let ctx = make_context(PoliticalArchetype::Pioneer, WorldTier::Backwater);
|
||||
// pop_tier 0, not transit_hub → no reservations.
|
||||
let sk = generate_skeleton(&ctx, 80_000, "residential", 1, 50, SeedChain::root(42));
|
||||
let sk = generate_quarter_skeleton(&ctx, 80_000, "residential", 1, 50, SeedChain::root(42));
|
||||
assert!(sk.reservations.is_empty());
|
||||
}
|
||||
|
||||
@@ -527,7 +533,8 @@ mod tests {
|
||||
fn park_reservation_for_large_city() {
|
||||
let ctx = make_context(PoliticalArchetype::Commission, WorldTier::Epicenter);
|
||||
// 100M pop → pop_tier 2 → park reservation.
|
||||
let sk = generate_skeleton(&ctx, 100_000_000, "financial", 1, 300, SeedChain::root(42));
|
||||
let sk =
|
||||
generate_quarter_skeleton(&ctx, 100_000_000, "financial", 1, 300, SeedChain::root(42));
|
||||
let has_park = sk
|
||||
.reservations
|
||||
.iter()
|
||||
@@ -539,7 +546,8 @@ mod tests {
|
||||
fn transit_terminal_for_transit_hub_role() {
|
||||
let ctx = make_context(PoliticalArchetype::Commission, WorldTier::Regional);
|
||||
// pop_tier 0 but transit_hub → terminal reservation.
|
||||
let sk = generate_skeleton(&ctx, 80_000, "transit_hub", 1, 200, SeedChain::root(42));
|
||||
let sk =
|
||||
generate_quarter_skeleton(&ctx, 80_000, "transit_hub", 1, 200, SeedChain::root(42));
|
||||
let has_terminal = sk
|
||||
.reservations
|
||||
.iter()
|
||||
@@ -551,7 +559,8 @@ mod tests {
|
||||
fn reserved_blocks_linked_in_grid() {
|
||||
let ctx = make_context(PoliticalArchetype::Commission, WorldTier::Epicenter);
|
||||
// 100M pop → park at (1,2),(1,3),(2,2),(2,3) with reservation id 1.
|
||||
let sk = generate_skeleton(&ctx, 100_000_000, "financial", 1, 300, SeedChain::root(42));
|
||||
let sk =
|
||||
generate_quarter_skeleton(&ctx, 100_000_000, "financial", 1, 300, SeedChain::root(42));
|
||||
// All park blocks must reference the park reservation (id=1).
|
||||
for &(row, col) in &[(1u8, 2u8), (1, 3), (2, 2), (2, 3)] {
|
||||
let b = &sk.blocks[row as usize][col as usize];
|
||||
@@ -565,7 +574,7 @@ mod tests {
|
||||
#[test]
|
||||
fn determinism_same_seed_same_output() {
|
||||
let ctx = make_context(PoliticalArchetype::Industrial, WorldTier::Regional);
|
||||
let sk1 = generate_skeleton(
|
||||
let sk1 = generate_quarter_skeleton(
|
||||
&ctx,
|
||||
2_000_000,
|
||||
"manufacturing",
|
||||
@@ -573,7 +582,7 @@ mod tests {
|
||||
250,
|
||||
SeedChain::root(12345),
|
||||
);
|
||||
let sk2 = generate_skeleton(
|
||||
let sk2 = generate_quarter_skeleton(
|
||||
&ctx,
|
||||
2_000_000,
|
||||
"manufacturing",
|
||||
|
||||
Reference in New Issue
Block a user