use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum WindMode {
Off,
Constant {
force: f32,
},
Stochastic {
seed: u64,
max_force: f32,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LunarLanderConfig {
pub wind_mode: WindMode,
pub gravity: f32,
pub main_engine_power: f32,
pub side_engine_power: f32,
pub initial_random: f32,
pub seed: u64,
pub max_steps: usize,
pub dt: f32,
pub lander_density: f32,
}
impl Default for LunarLanderConfig {
fn default() -> Self {
Self {
wind_mode: WindMode::Off,
gravity: -10.0,
main_engine_power: 13.0,
side_engine_power: 0.6,
initial_random: 1.0,
seed: 0,
max_steps: 1000,
dt: 1.0 / 50.0,
lander_density: 5.0,
}
}
}
impl LunarLanderConfig {
pub fn builder() -> LunarLanderConfigBuilder {
LunarLanderConfigBuilder {
inner: LunarLanderConfig::default(),
}
}
}
#[derive(Debug, Clone)]
pub struct LunarLanderConfigBuilder {
inner: LunarLanderConfig,
}
impl LunarLanderConfigBuilder {
pub fn wind_mode(mut self, mode: WindMode) -> Self {
self.inner.wind_mode = mode;
self
}
pub fn gravity(mut self, g: f32) -> Self {
self.inner.gravity = g;
self
}
pub fn seed(mut self, seed: u64) -> Self {
self.inner.seed = seed;
self
}
pub fn max_steps(mut self, n: usize) -> Self {
self.inner.max_steps = n;
self
}
pub fn main_engine_power(mut self, p: f32) -> Self {
self.inner.main_engine_power = p;
self
}
pub fn build(self) -> LunarLanderConfig {
self.inner
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let cfg = LunarLanderConfig::default();
assert_eq!(cfg.max_steps, 1000);
assert!(matches!(cfg.wind_mode, WindMode::Off));
}
#[test]
fn test_builder() {
let cfg = LunarLanderConfig::builder()
.seed(7)
.wind_mode(WindMode::Constant { force: 2.5 })
.max_steps(500)
.build();
assert_eq!(cfg.seed, 7);
assert_eq!(cfg.max_steps, 500);
assert!(matches!(cfg.wind_mode, WindMode::Constant { .. }));
}
}