use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum PlanetaryBody {
Earth,
Moon,
Mars,
Europa,
Titan,
Ceres,
OrbitalHabitat,
}
impl PlanetaryBody {
pub fn solar_flux_fraction(&self) -> f64 {
match self {
Self::Earth => 1.0,
Self::Moon => 1.0, Self::Mars => 0.43, Self::Europa => 0.037, Self::Titan => 0.011, Self::Ceres => 0.13, Self::OrbitalHabitat => 1.0,
}
}
pub fn gravity_fraction(&self) -> f64 {
match self {
Self::Earth => 1.0,
Self::Moon => 0.166,
Self::Mars => 0.38,
Self::Europa => 0.134,
Self::Titan => 0.138,
Self::Ceres => 0.029,
Self::OrbitalHabitat => 0.0, }
}
pub fn solar_viable(&self) -> bool {
self.solar_flux_fraction() > 0.1
}
pub fn has_atmosphere(&self) -> bool {
matches!(self, Self::Earth | Self::Mars | Self::Titan)
}
pub fn light_delay_to_earth_secs(&self) -> f64 {
match self {
Self::Earth => 0.0,
Self::Moon => 1.28,
Self::Mars => 750.0, Self::Europa => 2592.0, Self::Titan => 4758.0, Self::Ceres => 1380.0, Self::OrbitalHabitat => 0.01, }
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Earth => "Earth",
Self::Moon => "Moon",
Self::Mars => "Mars",
Self::Europa => "Europa",
Self::Titan => "Titan",
Self::Ceres => "Ceres",
Self::OrbitalHabitat => "OrbitalHabitat",
}
}
pub fn from_str(s: &str) -> Option<Self> {
match s {
"Earth" => Some(Self::Earth),
"Moon" => Some(Self::Moon),
"Mars" => Some(Self::Mars),
"Europa" => Some(Self::Europa),
"Titan" => Some(Self::Titan),
"Ceres" => Some(Self::Ceres),
"OrbitalHabitat" | "Orbital" => Some(Self::OrbitalHabitat),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ColonyPhase {
Planning,
Dependent,
Developing,
SelfSufficient,
Exporting,
Collapsed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColonyStatus {
pub body: PlanetaryBody,
pub name: String,
pub phase: ColonyPhase,
pub population: u32,
pub founded_tick: u32,
pub self_sufficiency: f64,
pub infrastructure: f64,
pub mean_phi: f64,
pub resources: ResourceManifest,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ResourceManifest {
pub food_kg: f64,
pub water_kg: f64,
pub oxygen_kg: f64,
pub nitrogen_kg: f64,
pub power_kw: f64,
pub energy_stored_kwh: f64,
pub iron_kg: f64,
pub silicon_kg: f64,
pub aluminum_kg: f64,
pub carbon_kg: f64,
pub rare_earth_kg: f64,
pub hydrocarbons_kg: f64,
pub regolith_processed_kg: f64,
}
impl ResourceManifest {
pub fn abundance_profile(body: PlanetaryBody) -> Self {
match body {
PlanetaryBody::Earth => Self {
food_kg: 1.0,
water_kg: 1.0,
oxygen_kg: 1.0,
nitrogen_kg: 1.0,
power_kw: 1.0,
energy_stored_kwh: 1.0,
iron_kg: 1.0,
silicon_kg: 1.0,
aluminum_kg: 1.0,
carbon_kg: 1.0,
rare_earth_kg: 1.0,
hydrocarbons_kg: 0.0,
regolith_processed_kg: 0.0,
},
PlanetaryBody::Moon => Self {
food_kg: 0.0,
water_kg: 0.1,
oxygen_kg: 0.3,
nitrogen_kg: 0.0,
power_kw: 1.0,
energy_stored_kwh: 0.5,
iron_kg: 0.4,
silicon_kg: 0.6,
aluminum_kg: 0.5,
carbon_kg: 0.01,
rare_earth_kg: 0.2,
hydrocarbons_kg: 0.0,
regolith_processed_kg: 0.8,
},
PlanetaryBody::Mars => Self {
food_kg: 0.0,
water_kg: 0.3,
oxygen_kg: 0.2,
nitrogen_kg: 0.05,
power_kw: 0.43,
energy_stored_kwh: 0.3,
iron_kg: 0.7,
silicon_kg: 0.5,
aluminum_kg: 0.4,
carbon_kg: 0.3,
rare_earth_kg: 0.3,
hydrocarbons_kg: 0.0,
regolith_processed_kg: 0.6,
},
PlanetaryBody::Europa => Self {
food_kg: 0.0,
water_kg: 10.0,
oxygen_kg: 5.0,
nitrogen_kg: 0.0,
power_kw: 0.0,
energy_stored_kwh: 0.0, iron_kg: 0.05,
silicon_kg: 0.02,
aluminum_kg: 0.02,
carbon_kg: 0.01,
rare_earth_kg: 0.01,
hydrocarbons_kg: 0.0,
regolith_processed_kg: 0.1,
},
PlanetaryBody::Titan => Self {
food_kg: 0.0,
water_kg: 5.0,
oxygen_kg: 2.0,
nitrogen_kg: 10.0,
power_kw: 0.0,
energy_stored_kwh: 0.0, iron_kg: 0.0,
silicon_kg: 0.0,
aluminum_kg: 0.0,
carbon_kg: 10.0,
rare_earth_kg: 0.0,
hydrocarbons_kg: 100.0,
regolith_processed_kg: 0.3,
},
PlanetaryBody::Ceres => Self {
food_kg: 0.0,
water_kg: 3.0,
oxygen_kg: 1.0,
nitrogen_kg: 0.1,
power_kw: 0.13,
energy_stored_kwh: 0.1,
iron_kg: 0.5,
silicon_kg: 0.4,
aluminum_kg: 0.3,
carbon_kg: 0.5,
rare_earth_kg: 0.4,
hydrocarbons_kg: 0.0,
regolith_processed_kg: 0.7,
},
PlanetaryBody::OrbitalHabitat => Self {
food_kg: 0.0,
water_kg: 0.0,
oxygen_kg: 0.0,
nitrogen_kg: 0.0,
power_kw: 1.0,
energy_stored_kwh: 0.5,
iron_kg: 0.0,
silicon_kg: 0.0,
aluminum_kg: 0.0,
carbon_kg: 0.0,
rare_earth_kg: 0.0,
hydrocarbons_kg: 0.0,
regolith_processed_kg: 0.0,
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_planetary_body_roundtrip() {
for body in [
PlanetaryBody::Earth,
PlanetaryBody::Europa,
PlanetaryBody::Titan,
] {
assert_eq!(PlanetaryBody::from_str(body.as_str()), Some(body));
}
}
#[test]
fn test_solar_viability() {
assert!(PlanetaryBody::Earth.solar_viable());
assert!(PlanetaryBody::Mars.solar_viable());
assert!(!PlanetaryBody::Europa.solar_viable());
assert!(!PlanetaryBody::Titan.solar_viable());
}
#[test]
fn test_titan_has_atmosphere() {
assert!(PlanetaryBody::Titan.has_atmosphere());
assert!(!PlanetaryBody::Europa.has_atmosphere());
assert!(!PlanetaryBody::Moon.has_atmosphere());
}
#[test]
fn test_abundance_profiles_differ() {
let titan = ResourceManifest::abundance_profile(PlanetaryBody::Titan);
let europa = ResourceManifest::abundance_profile(PlanetaryBody::Europa);
assert!(titan.carbon_kg > europa.carbon_kg);
assert!(europa.water_kg > titan.water_kg);
assert!(titan.iron_kg < 0.1);
}
}