feat(simulation): quarter street network — typed corridors/access/lattice (#957)

Complete the Layer-4 quarter geometry with the street layer (D-234), replacing
the ChunkLayout/CorridorSpine/AccessPoint String stubs with real types:
- AccessPoint{position,kind} + AccessKind (QuarterEdge/ReservationGate/
  BlockJunction): the quarter's road nodes (from road_entry_directions octants +
  reservation gates), the node set the D-097 audit reads.
- CorridorSpine{from,to,path}: arterial trunk edges, ±45°-snapped polylines
  (D-096 cap). Topology gated by morphology (D-234a): Ribbon (fjord/canyon/
  mountain-pass), HubSpoke (delta/island/enclosed water), Mesh/Prim-MST
  (plains/meander/coastal). A spanning tree over the access nodes.
- ChunkLayout{spacing,offset,rotation_steps}: per-block local ±45° lattice,
  spacing from density, offset/rotation modulated by the D-096 Grid/Organic mode.

Wired into generate_quarter_skeleton (access_points + corridors + per-block
chunk_layout). All integer-deterministic (D-010). 7 new tests.

Remaining D-234 piece: the per-edge waterfront pier/quay rule needs Layer-1
terrain water-adjacency threaded to the skeleton (cross-layer plumbing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-05 23:29:21 +02:00
co-authored by Claude Opus 4.8
parent 728a27e1b4
commit 4c6fe596d1
2 changed files with 403 additions and 15 deletions
+52 -6
View File
@@ -50,10 +50,8 @@ pub type Era = String;
pub type EraModification = String;
/// Landmark slot description within a block. Stub.
pub type LandmarkSlot = String;
/// Chunk layout specification within a block (how the 2×2 chunks are arranged). Stub.
pub type ChunkLayout = String;
/// Corridor spine connecting district access points. Stub.
pub type CorridorSpine = String;
// `ChunkLayout`, `CorridorSpine`, `AccessPoint` are typed street-network structs
// (D-234, #957) — see the "Street-network types" section below.
/// District context — neighboring districts, world position, system. Stub.
pub type QuarterContext = String;
/// Society profile reference (Miri's cultural ingredients). Stub.
@@ -64,8 +62,56 @@ pub type ZoneDefinition = String;
pub type QuarterBoundaries = String;
/// Guarantee audit result — tier-appropriate spatial invariant checks. Stub.
pub type GuaranteeAuditResult = String;
/// District access point (entry/exit to neighboring district). Stub.
pub type AccessPoint = String;
// ---------------------------------------------------------------------------
// Street-network types (D-234, #957)
// ---------------------------------------------------------------------------
/// Where a quarter's street network connects to the outside, to a reservation,
/// or to an interior junction (D-234). These are the nodes the arterial graph
/// spans and the guarantee audit (D-097) reads.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct AccessPoint {
/// Tile-space position within the 512-tile quarter (0511).
pub position: (u16, u16),
pub kind: AccessKind,
}
/// Kind of [`AccessPoint`] (D-234).
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum AccessKind {
/// Road enters the quarter from outside at a compass octant (0=N…7=NW),
/// from `CityGenerationContext.road_entry_directions`.
QuarterEdge { octant: u8 },
/// Gate into a multi-block reservation.
ReservationGate { reservation: ReservationId },
/// Internal junction between blocks.
BlockJunction,
}
/// One arterial spine — a ±45°-snapped edge of the quarter's trunk-road graph
/// (D-234 refined: arterials = least-cost graph over the access nodes). `from`/`to`
/// index into the quarter's `access_points`; `path` is the tile-space polyline
/// (segments axis- or 45°-aligned, D-096 ±45° cap). This node/edge graph is what
/// the guarantee audit (D-097) reads as the trunk topology.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct CorridorSpine {
pub from: u16,
pub to: u16,
pub path: Vec<(u16, u16)>,
}
/// Local street lattice descriptor for one block (D-234 refined: local streets =
/// a ±45° grid lattice within each block, modulated by the D-096 layout mode).
/// A compact parametric form the fill layer rasterizes — not the raster itself.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct ChunkLayout {
/// Street spacing in tiles (the block is divided into spacing-sized cells).
pub spacing: u8,
/// Lattice origin offset in tiles (organic jitter; `(0,0)` for grid).
pub offset: (u8, u8),
/// Rotation in 15° steps (03 ⇒ 045°, the D-096 cap; 0 for grid).
pub rotation_steps: u8,
}
/// Base visual palette for a zone. Stub.
pub type BasePalette = String;
/// Economic modifier on a zone palette. Stub.