diff --git a/server/src/atlas/attractor_matching.rs b/server/src/atlas/attractor_matching.rs index 232bd2f5f..8fe664ad3 100644 --- a/server/src/atlas/attractor_matching.rs +++ b/server/src/atlas/attractor_matching.rs @@ -99,7 +99,11 @@ fn cell_score( let row = role_row(&city.economic_role); let col = attractor_col(&attractor.attractor_type); let weight = matrix.weights[row][col]; - let cost_factor = if terrain_cost > 0.0 { 1.0 / terrain_cost } else { 1.0 }; + let cost_factor = if terrain_cost > 0.0 { + 1.0 / terrain_cost + } else { + 1.0 + }; weight * attractor.strength * cost_factor } @@ -213,11 +217,7 @@ fn hungarian(cost: &[Vec]) -> Vec { /// Minimum pixel separation between synthetic attractor positions. const MIN_SPACING: u16 = 15; -fn synthetic_attractor( - placed: &[CityPlacement], - grid_w: u32, - grid_h: u32, -) -> GeographicAttractor { +fn synthetic_attractor(placed: &[CityPlacement], grid_w: u32, grid_h: u32) -> GeographicAttractor { // Place at grid center as default, then walk until spacing is satisfied. let mut row = (grid_h / 2) as u16; let mut col = (grid_w / 4) as u16; @@ -326,9 +326,7 @@ pub fn match_cities( .iter() .enumerate() .filter(|(i, c)| { - !tier_a_indices.contains(i) - && c.population >= 50_000 - && c.population < 1_000_000 + !tier_a_indices.contains(i) && c.population >= 50_000 && c.population < 1_000_000 }) .map(|(i, _)| i) .collect(); @@ -450,12 +448,12 @@ pub fn founding_orientation( coastal_facing: u16, ) -> FoundingOrientation { match attractor_type { - AttractorType::RiverMouth | AttractorType::CoastalAccess => { - FoundingOrientation::Coastal { facing_degrees: coastal_facing } - } - AttractorType::RiverCrossing => { - FoundingOrientation::RiverAligned { bearing_degrees: river_bearing } - } + AttractorType::RiverMouth | AttractorType::CoastalAccess => FoundingOrientation::Coastal { + facing_degrees: coastal_facing, + }, + AttractorType::RiverCrossing => FoundingOrientation::RiverAligned { + bearing_degrees: river_bearing, + }, AttractorType::ValleyFloor => FoundingOrientation::TerrainFollowing, AttractorType::PlainCenter => { if matches!(territorial_status, TerritorialStatus::CommissionControlled) { @@ -480,11 +478,17 @@ mod tests { use crate::simulation::generator::{CompatibilityMatrix, GeographicAttractor}; fn uniform_matrix() -> CompatibilityMatrix { - CompatibilityMatrix { weights: [[1.0; 7]; 10] } + CompatibilityMatrix { + weights: [[1.0; 7]; 10], + } } fn make_attractor(row: u16, col: u16, at: AttractorType, strength: f32) -> GeographicAttractor { - GeographicAttractor { position: (row, col), attractor_type: at, strength } + GeographicAttractor { + position: (row, col), + attractor_type: at, + strength, + } } fn make_city(id: u64, class: SettlementClass, pop: i64) -> CityRecord { @@ -517,7 +521,7 @@ mod tests { make_city(2, SettlementClass::PopulationBudget, 200_000), ]; let attractors = vec![ - make_attractor(5, 5, AttractorType::RiverMouth, 0.9), // best + make_attractor(5, 5, AttractorType::RiverMouth, 0.9), // best make_attractor(10, 10, AttractorType::ValleyFloor, 0.4), // second ]; let matrix = uniform_matrix(); @@ -597,7 +601,12 @@ mod tests { use crate::simulation::generator::TerritorialStatus; let status = TerritorialStatus::FrontierUnclaimed; let o = founding_orientation(&AttractorType::RiverMouth, &status, 90, 270); - assert!(matches!(o, FoundingOrientation::Coastal { facing_degrees: 270 })); + assert!(matches!( + o, + FoundingOrientation::Coastal { + facing_degrees: 270 + } + )); let o2 = founding_orientation( &AttractorType::PlainCenter, @@ -607,12 +616,7 @@ mod tests { ); assert!(matches!(o2, FoundingOrientation::Cardinal)); - let o3 = founding_orientation( - &AttractorType::ValleyFloor, - &status, - 0, - 0, - ); + let o3 = founding_orientation(&AttractorType::ValleyFloor, &status, 0, 0); assert!(matches!(o3, FoundingOrientation::TerrainFollowing)); } } diff --git a/server/src/atlas/block_irregularity.rs b/server/src/atlas/block_irregularity.rs index b81279c01..f7efdfc09 100644 --- a/server/src/atlas/block_irregularity.rs +++ b/server/src/atlas/block_irregularity.rs @@ -74,21 +74,25 @@ mod tests { fn pioneer_more_irregular_than_commission() { let pioneer = block_irregularity(400, &PoliticalArchetype::Pioneer); let commission = block_irregularity(400, &PoliticalArchetype::Commission); - assert!(pioneer > commission, - "Pioneer ({pioneer}) should be more irregular than Commission ({commission})"); + assert!( + pioneer > commission, + "Pioneer ({pioneer}) should be more irregular than Commission ({commission})" + ); } #[test] fn age_increases_irregularity() { let young = block_irregularity(50, &PoliticalArchetype::Industrial); let old = block_irregularity(800, &PoliticalArchetype::Industrial); - assert!(old > young, - "Older settlement ({old}) should be more irregular than young ({young})"); + assert!( + old > young, + "Older settlement ({old}) should be more irregular than young ({young})" + ); } #[test] fn max_offset_scales_with_irregularity() { - assert_eq!(max_offset_sim_tiles(0.05), 0); // 0.05 × 16 = 0.8 → 0 + assert_eq!(max_offset_sim_tiles(0.05), 0); // 0.05 × 16 = 0.8 → 0 assert_eq!(max_offset_sim_tiles(1.0), 16); assert_eq!(max_offset_sim_tiles(0.5), 8); } @@ -105,7 +109,11 @@ mod tests { ]; for a in &archetypes { let v = block_irregularity(300, a); - assert!(v >= 0.05 && v <= 1.0, "archetype {:?} gave {v} out of [0.05, 1.0]", a); + assert!( + v >= 0.05 && v <= 1.0, + "archetype {:?} gave {v} out of [0.05, 1.0]", + a + ); } } } diff --git a/server/src/atlas/body_world_state.rs b/server/src/atlas/body_world_state.rs index 58f901bdc..f1068668d 100644 --- a/server/src/atlas/body_world_state.rs +++ b/server/src/atlas/body_world_state.rs @@ -236,8 +236,14 @@ mod tests { cache.get("A", 100); // Insert D to trigger eviction; B (tick 2) is now LRU, not A (tick 100). cache.insert(make_state("D", 4)); - assert!(cache.contains("A"), "A was recently accessed — must survive"); - assert!(!cache.contains("B"), "B had oldest access time — should be evicted"); + assert!( + cache.contains("A"), + "A was recently accessed — must survive" + ); + assert!( + !cache.contains("B"), + "B had oldest access time — should be evicted" + ); } #[test] diff --git a/server/src/atlas/district_mix.rs b/server/src/atlas/district_mix.rs index 1735de70c..28b42fc00 100644 --- a/server/src/atlas/district_mix.rs +++ b/server/src/atlas/district_mix.rs @@ -246,12 +246,15 @@ struct LcgRng { impl LcgRng { fn new(seed: u64) -> Self { - Self { state: seed.wrapping_add(1) } + Self { + state: seed.wrapping_add(1), + } } fn next_u64(&mut self) -> u64 { // LCG parameters from Knuth - self.state = self.state + self.state = self + .state .wrapping_mul(6364136223846793005) .wrapping_add(1442695040888963407); self.state @@ -273,10 +276,10 @@ mod tests { #[test] fn population_tier_values() { assert_eq!(population_tier(0), 0); - assert_eq!(population_tier(50_000), 0); // 0.05M → log10 < 0 → tier 0 - assert_eq!(population_tier(1_000_000), 0); // 1M → log10(1) = 0 → tier 0 - assert_eq!(population_tier(10_000_000), 1); // 10M → log10(10) = 1 → tier 1 - assert_eq!(population_tier(100_000_000), 2); // 100M → tier 2 + assert_eq!(population_tier(50_000), 0); // 0.05M → log10 < 0 → tier 0 + assert_eq!(population_tier(1_000_000), 0); // 1M → log10(1) = 0 → tier 0 + assert_eq!(population_tier(10_000_000), 1); // 10M → log10(10) = 1 → tier 1 + assert_eq!(population_tier(100_000_000), 2); // 100M → tier 2 assert_eq!(population_tier(1_000_000_000_000), 5); // capped at 5 } @@ -304,41 +307,81 @@ mod tests { 6, 7, ); - let transit = mix.districts.iter().filter(|d| matches!(d, DistrictType::Transit)).count(); - let commercial = mix.districts.iter().filter(|d| matches!(d, DistrictType::Commercial)).count(); - let residential = mix.districts.iter().filter(|d| matches!(d, DistrictType::Residential)).count(); + let transit = mix + .districts + .iter() + .filter(|d| matches!(d, DistrictType::Transit)) + .count(); + let commercial = mix + .districts + .iter() + .filter(|d| matches!(d, DistrictType::Commercial)) + .count(); + let residential = mix + .districts + .iter() + .filter(|d| matches!(d, DistrictType::Residential)) + .count(); assert!(transit >= 1, "transit guarantee not met: {transit}"); - assert!(commercial >= 1, "commercial guarantee not met: {commercial}"); - assert!(residential >= 2, "residential guarantee not met: {residential}"); + assert!( + commercial >= 1, + "commercial guarantee not met: {commercial}" + ); + assert!( + residential >= 2, + "residential guarantee not met: {residential}" + ); } #[test] fn determinism_same_seed() { - let mix1 = compute_district_mix(5_000_000, "financial", &PoliticalArchetype::Commission, 6, 99); - let mix2 = compute_district_mix(5_000_000, "financial", &PoliticalArchetype::Commission, 6, 99); + let mix1 = compute_district_mix( + 5_000_000, + "financial", + &PoliticalArchetype::Commission, + 6, + 99, + ); + let mix2 = compute_district_mix( + 5_000_000, + "financial", + &PoliticalArchetype::Commission, + 6, + 99, + ); assert_eq!(mix1, mix2, "same inputs must produce identical output"); } #[test] fn different_archetypes_produce_different_mixes() { - let mix_corp = compute_district_mix(5_000_000, "financial", &PoliticalArchetype::Corporate, 8, 42); - let mix_pioneer = compute_district_mix(5_000_000, "financial", &PoliticalArchetype::Pioneer, 8, 42); + let mix_corp = compute_district_mix( + 5_000_000, + "financial", + &PoliticalArchetype::Corporate, + 8, + 42, + ); + let mix_pioneer = + compute_district_mix(5_000_000, "financial", &PoliticalArchetype::Pioneer, 8, 42); // Should differ in at least one district type count. - assert_ne!(mix_corp.districts, mix_pioneer.districts, - "Corporate and Pioneer archetypes should produce different district mixes"); + assert_ne!( + mix_corp.districts, mix_pioneer.districts, + "Corporate and Pioneer archetypes should produce different district mixes" + ); } #[test] fn military_archetype_has_administrative() { - let mix = compute_district_mix( - 2_000_000, - "military", - &PoliticalArchetype::Military, - 8, - 10, + let mix = compute_district_mix(2_000_000, "military", &PoliticalArchetype::Military, 8, 10); + let admin = mix + .districts + .iter() + .filter(|d| matches!(d, DistrictType::Administrative)) + .count(); + assert!( + admin >= 1, + "military archetype should have Administrative districts" ); - let admin = mix.districts.iter().filter(|d| matches!(d, DistrictType::Administrative)).count(); - assert!(admin >= 1, "military archetype should have Administrative districts"); } #[test] @@ -352,8 +395,15 @@ mod tests { 0, ); for dt in &DIST_COLS { - let present = mix.districts.iter().any(|d| std::mem::discriminant(d) == std::mem::discriminant(dt)); - assert!(present, "DistrictType {:?} never appeared in 50-district mix", dt); + let present = mix + .districts + .iter() + .any(|d| std::mem::discriminant(d) == std::mem::discriminant(dt)); + assert!( + present, + "DistrictType {:?} never appeared in 50-district mix", + dt + ); } } } diff --git a/server/src/atlas/drainage.rs b/server/src/atlas/drainage.rs index 5bb5e580b..1e198efcd 100644 --- a/server/src/atlas/drainage.rs +++ b/server/src/atlas/drainage.rs @@ -397,9 +397,7 @@ fn merge_small_basins( let n_basins = sizes.len(); // Stop if within target range and all basins are large enough. - if n_basins <= max_count - && sizes.values().all(|&s| s as f64 / n as f64 >= min_frac) - { + if n_basins <= max_count && sizes.values().all(|&s| s as f64 / n as f64 >= min_frac) { break; } if n_basins <= min_count { @@ -407,10 +405,7 @@ fn merge_small_basins( } // Find the smallest basin. - let (&smallest_id, &smallest_size) = sizes - .iter() - .min_by_key(|(_, &s)| s) - .unwrap(); + let (&smallest_id, &smallest_size) = sizes.iter().min_by_key(|(_, &s)| s).unwrap(); if n_basins <= max_count && smallest_size as f64 / n as f64 >= min_frac { break; @@ -533,10 +528,8 @@ fn build_basins(labels: &[i32], w: usize, h: usize) -> Vec { // Sort boundary by angle from centroid for a coherent polygon. if !boundary.is_empty() { - let cr = boundary.iter().map(|&(r, _)| r as f32).sum::() - / boundary.len() as f32; - let cc = boundary.iter().map(|&(_, c)| c as f32).sum::() - / boundary.len() as f32; + let cr = boundary.iter().map(|&(r, _)| r as f32).sum::() / boundary.len() as f32; + let cc = boundary.iter().map(|&(_, c)| c as f32).sum::() / boundary.len() as f32; boundary.sort_by(|&(r1, c1), &(r2, c2)| { let a1 = (r1 as f32 - cr).atan2(c1 as f32 - cc); let a2 = (r2 as f32 - cr).atan2(c2 as f32 - cc); @@ -644,8 +637,7 @@ mod tests { let r1 = analyze(&elev, 64, 32, 0.3); let r2 = analyze(&elev, 64, 32, 0.3); assert_eq!( - r1.river_network.river_cells, - r2.river_network.river_cells, + r1.river_network.river_cells, r2.river_network.river_cells, "River cells must be deterministic" ); assert_eq!( diff --git a/server/src/atlas/gen_queue.rs b/server/src/atlas/gen_queue.rs index 5ab27afaf..fdfaa1d74 100644 --- a/server/src/atlas/gen_queue.rs +++ b/server/src/atlas/gen_queue.rs @@ -55,7 +55,10 @@ pub enum GenWorkItem { /// Generate a Phase 1 DistrictSkeleton for this city. GenerateSkeleton { city_id: u64 }, /// Pre-fill a chunk in an existing district. - FillChunk { district_id: u64, block_pos: (u32, u32) }, + FillChunk { + district_id: u64, + block_pos: (u32, u32), + }, } impl GenWorkItem { @@ -75,11 +78,21 @@ impl GenWorkItem { /// Sent back to the main thread when a work item finishes (D-206). #[derive(Debug)] pub enum GenCompletion { - BodyAnalyzed { body_id: String }, - SkeletonGenerated { city_id: u64 }, - ChunkFilled { district_id: u64, block_pos: (u32, u32) }, + BodyAnalyzed { + body_id: String, + }, + SkeletonGenerated { + city_id: u64, + }, + ChunkFilled { + district_id: u64, + block_pos: (u32, u32), + }, /// Work item failed — body_id or city_id for logging. - Failed { item: GenWorkItem, reason: String }, + Failed { + item: GenWorkItem, + reason: String, + }, } // --------------------------------------------------------------------------- @@ -114,11 +127,7 @@ pub struct GenerationQueue { impl std::fmt::Debug for GenerationQueue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let pending_len = self - .pending - .lock() - .map(|p| p.len()) - .unwrap_or(0); + let pending_len = self.pending.lock().map(|p| p.len()).unwrap_or(0); f.debug_struct("GenerationQueue") .field("pending_count", &pending_len) .finish() @@ -168,9 +177,7 @@ impl GenerationQueue { drop(in_flight); // Check pending list. let pending = self.pending.lock().unwrap(); - if pending.iter().any(|q| { - q.item.body_id() == Some(body_id) - }) { + if pending.iter().any(|q| q.item.body_id() == Some(body_id)) { return; } drop(pending); @@ -216,10 +223,7 @@ impl GenerationQueue { // Mark body as in-flight. if let Some(body_id) = item.body_id() { - self.in_flight - .lock() - .unwrap() - .insert(body_id.to_string()); + self.in_flight.lock().unwrap().insert(body_id.to_string()); } let tx = self.completion_tx.clone(); @@ -261,18 +265,19 @@ impl Default for GenerationQueue { /// immediate success to allow the queue infrastructure to be tested independently. fn run_work_item(item: &GenWorkItem) -> GenCompletion { match item { - GenWorkItem::AnalyzeBody { body_id } => { - GenCompletion::BodyAnalyzed { body_id: body_id.clone() } - } + GenWorkItem::AnalyzeBody { body_id } => GenCompletion::BodyAnalyzed { + body_id: body_id.clone(), + }, GenWorkItem::GenerateSkeleton { city_id } => { GenCompletion::SkeletonGenerated { city_id: *city_id } } - GenWorkItem::FillChunk { district_id, block_pos } => { - GenCompletion::ChunkFilled { - district_id: *district_id, - block_pos: *block_pos, - } - } + GenWorkItem::FillChunk { + district_id, + block_pos, + } => GenCompletion::ChunkFilled { + district_id: *district_id, + block_pos: *block_pos, + }, } } @@ -293,7 +298,9 @@ mod tests { fn submit_and_drain() { let q = make_queue(); q.submit( - GenWorkItem::AnalyzeBody { body_id: "TestBody".to_string() }, + GenWorkItem::AnalyzeBody { + body_id: "TestBody".to_string(), + }, GenPriority::Medium, ); // Give Rayon time to complete the (stub) task. @@ -311,11 +318,15 @@ mod tests { let q = make_queue(); // Submit the same body twice before it can complete. q.submit( - GenWorkItem::AnalyzeBody { body_id: "Dup".to_string() }, + GenWorkItem::AnalyzeBody { + body_id: "Dup".to_string(), + }, GenPriority::Low, ); q.submit( - GenWorkItem::AnalyzeBody { body_id: "Dup".to_string() }, + GenWorkItem::AnalyzeBody { + body_id: "Dup".to_string(), + }, GenPriority::Low, ); std::thread::sleep(Duration::from_millis(50)); @@ -329,9 +340,18 @@ mod tests { // Submit three items rapidly; Immediate should be dispatched first. let q = make_queue(); // Using GenerateSkeleton (no dedup logic) to test ordering directly. - q.submit(GenWorkItem::GenerateSkeleton { city_id: 1 }, GenPriority::Low); - q.submit(GenWorkItem::GenerateSkeleton { city_id: 2 }, GenPriority::Immediate); - q.submit(GenWorkItem::GenerateSkeleton { city_id: 3 }, GenPriority::Medium); + q.submit( + GenWorkItem::GenerateSkeleton { city_id: 1 }, + GenPriority::Low, + ); + q.submit( + GenWorkItem::GenerateSkeleton { city_id: 2 }, + GenPriority::Immediate, + ); + q.submit( + GenWorkItem::GenerateSkeleton { city_id: 3 }, + GenPriority::Medium, + ); std::thread::sleep(Duration::from_millis(100)); let completions = q.drain_completions(); assert_eq!(completions.len(), 3); @@ -348,7 +368,10 @@ mod tests { fn pending_count_decreases_after_completion() { let q = make_queue(); q.submit( - GenWorkItem::FillChunk { district_id: 99, block_pos: (0, 0) }, + GenWorkItem::FillChunk { + district_id: 99, + block_pos: (0, 0), + }, GenPriority::High, ); std::thread::sleep(Duration::from_millis(50)); diff --git a/server/src/atlas/heightmap.rs b/server/src/atlas/heightmap.rs index fd0e6ea0d..01bc28685 100644 --- a/server/src/atlas/heightmap.rs +++ b/server/src/atlas/heightmap.rs @@ -139,9 +139,7 @@ mod tests { } fn insert_heightmap(conn: &Connection, body_id: &str, w: u32, h: u32, sea_level: f32) { - let floats: Vec = (0..(w * h)) - .map(|i| i as f32 / (w * h) as f32) - .collect(); + let floats: Vec = (0..(w * h)).map(|i| i as f32 / (w * h) as f32).collect(); let bytes: &[u8] = bytemuck::cast_slice(&floats); conn.execute( "INSERT INTO atlas_body_heightmaps (body_id, width, height, data, sea_level) diff --git a/server/src/atlas/skeleton_gen.rs b/server/src/atlas/skeleton_gen.rs index 896a8bebf..50237f50b 100644 --- a/server/src/atlas/skeleton_gen.rs +++ b/server/src/atlas/skeleton_gen.rs @@ -21,10 +21,9 @@ use crate::atlas::block_irregularity::block_irregularity; use crate::atlas::district_mix::{compute_district_mix, population_tier}; use crate::simulation::generator::{ - BlockPlacement, BlockSkeleton, ComplexityTier, DistrictId, DistrictLayoutMode, - DistrictSkeleton, DistrictType, MultiBlockReservation, PoliticalArchetype, + BlockPlacement, BlockSkeleton, CityGenerationContext, ComplexityTier, DistrictId, + DistrictLayoutMode, DistrictSkeleton, DistrictType, MultiBlockReservation, PoliticalArchetype, ReservationFunction, ReservationId, SettingType, WorldTier, ZoningType, - CityGenerationContext, }; // --------------------------------------------------------------------------- @@ -76,8 +75,7 @@ pub fn generate_skeleton( let reservations = derive_reservations(tier, economic_role, seed); // Build the reservation lookup: block position → reservation id. - let mut block_reservation: [[Option; 4]; 4] = - [[None, None, None, None]; 4]; + let mut block_reservation: [[Option; 4]; 4] = [[None, None, None, None]; 4]; for (idx, res) in reservations.iter().enumerate() { let rid = idx as u64 + 1; // 1-based stable id within this district for &(row, col) in &res.blocks { @@ -92,7 +90,10 @@ pub fn generate_skeleton( // ── Build 4×4 block grid ────────────────────────────────────────────── // Flat district-mix list is already in deterministic order; assign // row-major (row 0 col 0 → row 0 col 3 → row 1 col 0 …). - let primary_district_type = mix.districts.first().cloned() + let primary_district_type = mix + .districts + .first() + .cloned() .unwrap_or(DistrictType::MixedUse); let blocks = build_block_grid(&mix.districts, &block_reservation, &primary_district_type); @@ -190,10 +191,18 @@ fn derive_complexity(world_tier: &WorldTier, pop_tier: u8, population: i64) -> C match world_tier { WorldTier::Epicenter | WorldTier::Regional => { - if pop_tier >= 1 { ComplexityTier::Full } else { ComplexityTier::Moderate } + if pop_tier >= 1 { + ComplexityTier::Full + } else { + ComplexityTier::Moderate + } } WorldTier::Backwater | WorldTier::Passage => { - if pop_tier >= 1 { ComplexityTier::Moderate } else { ComplexityTier::Minimal } + if pop_tier >= 1 { + ComplexityTier::Moderate + } else { + ComplexityTier::Minimal + } } WorldTier::Waypoint => ComplexityTier::Minimal, } @@ -245,7 +254,7 @@ fn organic_placements(irregularity: f32, seed: u64) -> [[BlockPlacement; 4]; 4] let raw_x = (lcg.next_u32() % (2 * max_offset as u32 + 1)) as i16 - max_offset; let raw_y = (lcg.next_u32() % (2 * max_offset as u32 + 1)) as i16 - max_offset; let rot = (lcg.next_u32() % 4) as u8; // 0–3 (15° increments, max 45°) - // Street width 7500–20000 bps proportional to irregularity. + // Street width 7500–20000 bps proportional to irregularity. let width_range = 12_500u32; // 20000 - 7500 let width = 7_500u32 + (lcg.next_u32() % (width_range + 1)); *item = BlockPlacement { @@ -256,9 +265,7 @@ fn organic_placements(irregularity: f32, seed: u64) -> [[BlockPlacement; 4]; 4] } // Safety: BlockPlacement is Copy-able; reshape flat array to [[_; 4]; 4]. - core::array::from_fn(|row| { - core::array::from_fn(|col| flat[row * 4 + col].clone()) - }) + core::array::from_fn(|row| core::array::from_fn(|col| flat[row * 4 + col].clone())) } // --------------------------------------------------------------------------- @@ -311,9 +318,9 @@ fn build_block_grid( position: (row as u8, col as u8), zoning, reservation, - chunk_layout: String::new(), // stub + chunk_layout: String::new(), // stub hosted_sites: Vec::new(), - era: String::new(), // stub + era: String::new(), // stub era_modifications: Vec::new(), era_cause: None, density_pct: density, @@ -349,7 +356,11 @@ fn density_for_zoning(zoning: &ZoningType) -> u8 { /// /// Phase 1 produces skeleton-only reservations — floor_zones and vertical_corridors /// are deferred to Phase 2. -fn derive_reservations(pop_tier: u8, economic_role: &str, _seed: u64) -> Vec { +fn derive_reservations( + pop_tier: u8, + economic_role: &str, + _seed: u64, +) -> Vec { let mut out = Vec::new(); // Park: large cities need open space. @@ -398,11 +409,14 @@ struct SkeletonLcg { impl SkeletonLcg { fn new(seed: u64) -> Self { // Mix seed to avoid degenerate state at 0. - Self { state: seed.wrapping_add(0x9e37_79b9_7f4a_7c15) } + Self { + state: seed.wrapping_add(0x9e37_79b9_7f4a_7c15), + } } fn next_u64(&mut self) -> u64 { - self.state = self.state + self.state = self + .state .wrapping_mul(6364136223846793005) .wrapping_add(1442695040888963407); self.state @@ -516,7 +530,9 @@ mod tests { 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, 42); - let has_park = sk.reservations.iter() + let has_park = sk + .reservations + .iter() .any(|r| matches!(r.function, ReservationFunction::Park)); assert!(has_park); } @@ -526,7 +542,9 @@ mod tests { 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, 42); - let has_terminal = sk.reservations.iter() + let has_terminal = sk + .reservations + .iter() .any(|r| matches!(r.function, ReservationFunction::Terminal)); assert!(has_terminal); } @@ -539,7 +557,10 @@ mod tests { // 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]; - assert!(b.reservation.is_some(), "block ({row},{col}) should be reserved"); + assert!( + b.reservation.is_some(), + "block ({row},{col}) should be reserved" + ); } } @@ -553,7 +574,10 @@ mod tests { for col in 0..4 { assert_eq!(sk1.blocks[row][col].zoning, sk2.blocks[row][col].zoning); assert_eq!(sk1.blocks[row][col].position, sk2.blocks[row][col].position); - assert_eq!(sk1.blocks[row][col].density_pct, sk2.blocks[row][col].density_pct); + assert_eq!( + sk1.blocks[row][col].density_pct, + sk2.blocks[row][col].density_pct + ); } } assert_eq!(sk1.reservations.len(), sk2.reservations.len()); diff --git a/server/src/atlas/tile_condition.rs b/server/src/atlas/tile_condition.rs index e5faa850f..7645f7449 100644 --- a/server/src/atlas/tile_condition.rs +++ b/server/src/atlas/tile_condition.rs @@ -147,8 +147,11 @@ mod tests { fn era_floor_decay_enforces_cracked_minimum() { // Prosperous district in an EconomicDisruption-era block — still Cracked. let cond = tile_condition(0.90, Some(&EraCause::EconomicDisruption)); - assert_eq!(cond, TileCondition::Cracked, - "EconomicDisruption floor must prevent Intact/Worn"); + assert_eq!( + cond, + TileCondition::Cracked, + "EconomicDisruption floor must prevent Intact/Worn" + ); } #[test] @@ -162,8 +165,11 @@ mod tests { fn era_floor_does_not_improve_condition() { // EconomicDisruption floor = Cracked; Broken score stays Broken. let cond = tile_condition(0.10, Some(&EraCause::EconomicDisruption)); - assert_eq!(cond, TileCondition::Broken, - "Era floor must not improve condition below score-derived value"); + assert_eq!( + cond, + TileCondition::Broken, + "Era floor must not improve condition below score-derived value" + ); } #[test] diff --git a/server/src/simulation/name_index.rs b/server/src/simulation/name_index.rs index b0e9c2dda..07cd26fde 100644 --- a/server/src/simulation/name_index.rs +++ b/server/src/simulation/name_index.rs @@ -144,9 +144,8 @@ fn collect_names(conn: &Connection) -> rusqlite::Result> { // Star systems — include both system_name and proper_name as separate patterns // so "Van Maanen's Star" and "GJ 35" both trigger if used in dialogue. { - let mut stmt = conn.prepare( - "SELECT system_id, system_name, proper_name FROM star_systems", - )?; + let mut stmt = + conn.prepare("SELECT system_id, system_name, proper_name FROM star_systems")?; let rows = stmt.query_map([], |row| { Ok(( row.get::<_, String>(0)?,