diff --git a/server/src/bin/generate_corporations/main.rs b/server/src/bin/generate_corporations/main.rs index acf7ef73a..d927d72e5 100644 --- a/server/src/bin/generate_corporations/main.rs +++ b/server/src/bin/generate_corporations/main.rs @@ -17,7 +17,7 @@ //! cargo run --bin generate_corporations -- --seed 42 --min-corps 5000 //! ``` -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet}; use std::path::PathBuf; use std::process; @@ -246,11 +246,7 @@ fn load_locations(conn: &Connection) -> Vec { }) }) .unwrap(); - for row in body_rows { - if let Ok(loc) = row { - locations.push(loc); - } - } + locations.extend(body_rows.flatten()); // Stations with population let mut stmt = conn @@ -275,11 +271,7 @@ fn load_locations(conn: &Connection) -> Vec { }) }) .unwrap(); - for row in station_rows { - if let Ok(loc) = row { - locations.push(loc); - } - } + locations.extend(station_rows.flatten()); locations } @@ -305,7 +297,7 @@ fn load_existing_corps(conn: &Connection) -> Vec { .collect() } -fn load_commodity_ids(conn: &Connection) -> HashSet { +fn load_commodity_ids(conn: &Connection) -> BTreeSet { let mut stmt = conn .prepare("SELECT commodity_id FROM commodities") .unwrap(); @@ -469,7 +461,7 @@ fn assign_brands( } // Pick 1-4 brands weighted by relevance to the lore archetype's commodities - let all_commodities: HashSet<&str> = lore_arch + let all_commodities: BTreeSet<&str> = lore_arch .primary_commodities .iter() .chain(lore_arch.secondary_commodities.iter()) @@ -530,9 +522,9 @@ fn make_corp_id(name: &str) -> String { // --------------------------------------------------------------------------- struct CoverageReport { - commodity_coverage: HashMap, + commodity_coverage: BTreeMap, uncovered_commodities: Vec, - system_coverage: HashMap, + system_coverage: BTreeMap, uncovered_systems: Vec, total_generated: usize, } @@ -540,17 +532,17 @@ struct CoverageReport { fn validate_coverage( generated: &BTreeMap, lore_archetypes: &BTreeMap, - commodity_ids: &HashSet, + commodity_ids: &BTreeSet, conn: &Connection, ) -> CoverageReport { // Track which commodities have at least one producer - let mut commodity_coverage: HashMap = HashMap::new(); + let mut commodity_coverage: BTreeMap = BTreeMap::new(); for cid in commodity_ids { commodity_coverage.insert(cid.clone(), 0); } // Track system presence - let mut system_coverage: HashMap = HashMap::new(); + let mut system_coverage: BTreeMap = BTreeMap::new(); for corp in generated.values() { // Count commodity coverage from lore archetype @@ -593,22 +585,19 @@ fn validate_coverage( // Also check body-level population since system_economy only has 10 systems > 100K // but 146 bodies > 100K - let mut body_systems: HashSet = HashSet::new(); let mut stmt2 = conn .prepare( "SELECT DISTINCT system_id FROM bodies WHERE inhabited = 1 AND population > 100000", ) .unwrap(); - for row in stmt2 + let body_systems: BTreeSet = stmt2 .query_map([], |row| row.get::<_, String>(0)) .unwrap() .filter_map(|r| r.ok()) - { - body_systems.insert(row); - } + .collect(); - let mut all_high_pop: HashSet = high_pop_systems.into_iter().collect(); + let mut all_high_pop: BTreeSet = high_pop_systems.into_iter().collect(); all_high_pop.extend(body_systems); let uncovered_systems: Vec = all_high_pop @@ -634,7 +623,7 @@ fn validate_coverage( fn fill_coverage_gaps( generated: &mut BTreeMap, lore_archetypes: &BTreeMap, - commodity_ids: &HashSet, + commodity_ids: &BTreeSet, conn: &Connection, rng: &mut ChaCha8Rng, ) { @@ -679,21 +668,16 @@ fn fill_coverage_gaps( let name = names::generate_name(rng, §or, &lore.category); let corp_id = make_corp_id(&name); - if !generated.contains_key(&corp_id) { - generated.insert( - corp_id, - GeneratedCorp { - proper_name: name, - lore_archetype: lore_id.to_string(), - behavioral_archetype: behavioral, - location_id: loc_id, - location_type: loc_type, - system_id: sys_id.clone(), - geographic_sector: sector, - brands: vec![], - }, - ); - } + generated.entry(corp_id).or_insert_with(|| GeneratedCorp { + proper_name: name, + lore_archetype: lore_id.to_string(), + behavioral_archetype: behavioral, + location_id: loc_id, + location_type: loc_type, + system_id: sys_id.clone(), + geographic_sector: sector, + brands: vec![], + }); } } @@ -757,41 +741,31 @@ fn fill_coverage_gaps( for _ in current_count..3 { let n = names::generate_name(rng, sector, &lore.category); let cid = make_corp_id(&n); - if !generated.contains_key(&cid) { - generated.insert( - cid, - GeneratedCorp { - proper_name: n, - lore_archetype: arch_id.to_string(), - behavioral_archetype: pick_behavioral_archetype( - rng, - &lore.behavioral_affinity, - ), - location_id: loc_id.clone(), - location_type: "body".to_string(), - system_id: sys_id.clone(), - geographic_sector: sector.to_string(), - brands: vec![], - }, - ); - } + generated.entry(cid).or_insert_with(|| GeneratedCorp { + proper_name: n, + lore_archetype: arch_id.to_string(), + behavioral_archetype: pick_behavioral_archetype( + rng, + &lore.behavioral_affinity, + ), + location_id: loc_id.clone(), + location_type: "body".to_string(), + system_id: sys_id.clone(), + geographic_sector: sector.to_string(), + brands: vec![], + }); } - if !generated.contains_key(&corp_id) { - generated.insert( - corp_id, - GeneratedCorp { - proper_name: name, - lore_archetype: arch_id.to_string(), - behavioral_archetype: behavioral, - location_id: loc_id, - location_type: "body".to_string(), - system_id: sys_id, - geographic_sector: sector.to_string(), - brands: vec![], - }, - ); - } + generated.entry(corp_id).or_insert_with(|| GeneratedCorp { + proper_name: name, + lore_archetype: arch_id.to_string(), + behavioral_archetype: behavioral, + location_id: loc_id, + location_type: "body".to_string(), + system_id: sys_id, + geographic_sector: sector.to_string(), + brands: vec![], + }); } } } @@ -983,7 +957,7 @@ fn main() { report.system_coverage.len() ); - let mut by_sector: HashMap = HashMap::new(); + let mut by_sector: BTreeMap = BTreeMap::new(); for corp in generated.values() { *by_sector.entry(corp.geographic_sector.clone()).or_insert(0) += 1; }