소스 검색

Refactor and cleanup

Johann Woelper 8 년 전
부모
커밋
5bfb32a31a
1개의 변경된 파일161개의 추가작업 그리고 95개의 파일을 삭제
  1. 161 95
      server/src/main.rs

+ 161 - 95
server/src/main.rs

@@ -1,6 +1,8 @@
 use std::time::{SystemTime};
 use rand::Rng;
-
+use std::fs::File;
+use std::path::Path;
+use std::fs;
 
 #[macro_use]
 extern crate serde_derive;
@@ -13,26 +15,36 @@ extern crate serde_json;
 /*
 UNITS
     mass = kilogram
-    time = sec
+    time = 1 day
     distance = meter
-    speed = meter / tick (s)
+    speed = meter / day
 */
 
 // Time constants
-const TICK: i32 = 1;
-const SECOND: i32 = TICK;
-const MINUTE: i32 = SECOND*60;
-const HOUR: i32 = MINUTE*60;
-const DAY: i32 = HOUR*24;
-const MONTH: i32 = DAY*30;
-const YEAR: i32 = MONTH*12;
+const SECOND: f32 = MINUTE/60.0;
+const MINUTE: f32 = HOUR/60.0;
+const HOUR: f32 = DAY/24.0;
+const DAY: f32 = 1.0;
+const MONTH: f32 = DAY*30.0;
+const YEAR: f32 = MONTH*12.0;
 // weight constants
 const KG: f32 = 1.0;
 const TON: f32 = KG*1000.0;
 
 
-// Diet types a lifeform could have
+
+
 #[derive(Serialize, Deserialize, Debug)]
+struct Config {
+    biome: Biome,
+    lifeforms: Vec<Lifeform>,
+    simtime: f32,
+    simsteps: f32
+}
+
+
+// Diet types a lifeform could have
+#[derive(Serialize, Deserialize, Debug, Clone)]
 enum Diets {
     Carnivore,
     Herbivore,
@@ -41,33 +53,22 @@ enum Diets {
 }
 
 // The types of lifeforms that may exist
-#[derive(Serialize, Deserialize, Debug)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
 enum LifeformKind {
     Fauna,
     Flora,
 }
 
-#[derive(Serialize, Deserialize, Debug)]
-struct Biome {
-    water: f32,
-    biomass: f32,
-    lifeforms: Vec<Lifeform>,
-    bounds: Vec<f32> //left, top, right, bottom boundaries
+#[derive(Serialize, Deserialize, Debug, Clone)]
+struct Rect {
+    x: f32,
+    y: f32,
+    width: f32,
+    height: f32
 }
 
-    fn move_random(lf: &mut Lifeform, bounds: &Vec<f32>) {
-        let mut rng = rand::thread_rng();
-        let rx = rng.gen_range::<f32>(-1.0, 1.0);
-        let rz = rng.gen_range::<f32>(-1.0, 1.0);
-        lf.position[0] += rx*lf.speed;
-        lf.position[2] += rz*lf.speed;
 
-        if lf.position[0] > bounds[2] {lf.position[0] = bounds[2]}; // x > right bound
-        if lf.position[2] > bounds[1] {lf.position[2] = bounds[1]}; // z > upper bound
-        if lf.position[0] < bounds[0] {lf.position[0] = bounds[0]}; // x < left bound
-        if lf.position[2] < bounds[3] {lf.position[2] = bounds[3]}; // z < lower bound
 
-    }
 
 /*
 Biome - a container for lifeforms.
@@ -75,51 +76,62 @@ Ideally, I wanted to have next to no logic here, but I realized my lifeforms nee
 for example to re-deposit their weight back on death, to query for food, etc. I'd like to pass this to a 
 lifeform so it can access it and modify it.
 */
+#[derive(Serialize, Deserialize, Debug, Clone)]
+struct Biome {
+    water: f32,
+    biomass: f32,
+    lifeforms: Vec<Lifeform>,
+    rect: Rect
+}
+
+    
+
 impl Biome {
-    fn tick(&mut self){
+    fn tick(&mut self, timescale: f32){
 
         for mut lifeform in &mut self.lifeforms {
             if lifeform.alive {
-                self.water -= lifeform.water_intake;
-                lifeform.mass += lifeform.nutrient_intake;
-                lifeform.age += 1;
+                if self.water > 0.0 {
+                    self.water -= lifeform.water_intake * timescale as f32;
+                }
+                lifeform.mass += lifeform.nutrient_intake * timescale as f32;
+                lifeform.age += 1.0 * timescale;
                 if lifeform.age > lifeform.maxage {
                     lifeform.alive = false;
-                    println!("Died: {:?}", lifeform);
+                    //println!("Died: {:?}", lifeform);
                 }
 
 
-                move_random(&mut lifeform, &self.bounds);
+                move_random(&mut lifeform, &self.rect, timescale);
             } else {
+                // fuck, we're dead
                 self.biomass += lifeform.mass;
                 lifeform.mass = 0.0;
             }
 
-            //lifeform.tick(self);
-            /*
-            if i could do this, i could handle most of the logic in Lifeform which I
-            would prefer, but "cannot borrow `*self` as mutable more than once at a time"
-            */
-
     }
     
     }
 
 }
 
-#[derive(Serialize, Deserialize, Debug)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
 struct Lifeform {
     name: String,           //just for fun
     mass: f32,              //how much it weights
-    age: i32,               //age in ticks
-    maxage: i32,            //maximum age
+    mass_starve: f32,       //at this mass, starvation begins
+    digestive_capacity: f32,//a food "buffer"; stomach or tree trunk
+    digestive_content: f32, //how much the digestive buffer can store
+    age: f32,               //age in ticks
+    maxage: f32,            //maximum age
     water_intake: f32,      //how much water it consumes per tick
     nutrient_intake: f32,   //how much food it consumes per tick
     diet: Diets,            //the type of stuff it eats
     kind: LifeformKind,     //the kind of lifeform it is
     alive: bool,            //whether it lives or not
     position: Vec<f32>,     //where it hangs out
-    speed: f32,             //how fast it can move (or not)
+    speed: f32,             //how fast it can move (or not),
+    ocurrence_per_sq_km: f32//distribution
 }
 
 
@@ -131,17 +143,22 @@ impl Lifeform {
     i would like to be able to pass the biome to the lifeform as a reference to that
     it could interact with it.
     */
-    fn tick(&mut self, biome: &mut Biome){
+    // fn tick(&mut self, biome: &mut Biome){
 
-    }
+    // }
 }
 
 impl Default for Lifeform {
+
+
     fn default() -> Lifeform {
         Lifeform {
             name: "Generic Plant".to_string(),
             mass: 1.0,
-            age: 0,
+            mass_starve: 0.0,
+            digestive_capacity: 0.0,
+            digestive_content: 0.0,
+            age: 0.0,
             water_intake: 1.0/DAY as f32,
             nutrient_intake: 1.0/DAY as f32,
             diet: Diets::Herbivore,
@@ -150,72 +167,121 @@ impl Default for Lifeform {
             alive: true,
             position: vec![0.0, 0.0, 0.0],
             speed: 0.0,
+            ocurrence_per_sq_km: 1.0
         }
     }
 }
 
-fn main() {
-    let start = SystemTime::now();
-    println!("{:?}", start);
 
-    let mut biome = Biome {water: 1000.0, lifeforms: Vec::new(), biomass: TON, bounds: vec![0.0, 100.0, 100.0, 0.0]};
+fn move_random(lf: &mut Lifeform, rect: &Rect, timescale: f32) {
+        let mut rng = rand::thread_rng();
+        let rx = rng.gen_range::<f32>(-1.0, 1.0);
+        let rz = rng.gen_range::<f32>(-1.0, 1.0);
+        lf.position[0] += (rx * lf.speed) * timescale as f32;
+        lf.position[2] += (rz * lf.speed) * timescale as f32;
+        // where is clamp
+        if lf.position[0] > rect.width+rect.x {lf.position[0] = rect.width+rect.x}; // x > right bound
+        if lf.position[2] > rect.height+rect.y {lf.position[2] = rect.height+rect.y}; // z > upper bound
+        if lf.position[0] < rect.x {lf.position[0] = rect.x}; // x < left bound
+        if lf.position[2] < rect.y {lf.position[2] = rect.y}; // z < lower bound
+
+    }
+
+
 
+fn sim() {
 
     // add some trees
-    for _i in 1..400 {
-        let mut rng = rand::thread_rng();
-        let age = rng.gen_range::<i32>(1*MONTH, 10*YEAR);
-        let maxage = rng.gen_range::<i32>(5*YEAR, 50*YEAR);
-        let mass = rng.gen_range::<f32>(50.0, 6.0*TON);
-        let water_intake = rng.gen_range::<f32>(50.0, 150.0)/DAY as f32;
-        let mut tree = Lifeform {
-            name: "Tree".to_string(),
-            age: age,
-            maxage: maxage,
-            mass: mass,
-            water_intake: water_intake,
-            diet: Diets::Photovore,
-            alive: true,
-            kind: LifeformKind::Flora,
-            ..Default::default()
-            };
+    let mut rng_tree = rand::thread_rng();
+    let tree = Lifeform {
+        name: "Tree".to_string(),
+        age: rng_tree.gen_range::<f32>(1.0*MONTH, 10.0*YEAR),
+        maxage: rng_tree.gen_range::<f32>(5.0*YEAR, 50.0*YEAR),
+        mass: rng_tree.gen_range::<f32>(50.0, 6.0*TON),
+        water_intake: rng_tree.gen_range::<f32>(50.0, 150.0)/DAY,
+        diet: Diets::Photovore,
+        alive: true,
+        kind: LifeformKind::Flora,
+        ..Default::default()
+        };
 
-        biome.lifeforms.push(tree);
-    }
 
     // add deer
-    for _i in 1..10 {
-        let mut rng = rand::thread_rng();
-        let age = rng.gen_range::<i32>(1*MONTH, 5*YEAR);
-        let maxage = rng.gen_range::<i32>(1*YEAR, 5*YEAR);
-        let mass = rng.gen_range::<f32>(4.0, 17.0);
-        let water_intake = rng.gen_range::<f32>(0.5, 1.0)/DAY as f32;
-        let speed = rng.gen_range::<f32>(0.0/HOUR as f32, 10000.0/HOUR as f32) as f32;
+    let mut rng_deer = rand::thread_rng();
+    let deer = Lifeform {
+        name: "Deer".to_string(),
+        kind: LifeformKind::Fauna,
+        age: rng_deer.gen_range::<f32>(1.0*MONTH, 5.0*YEAR),
+        maxage: rng_deer.gen_range::<f32>(2.0*YEAR, 6.0*YEAR),
+        mass: rng_deer.gen_range::<f32>(4.0, 17.0),
+        water_intake: rng_deer.gen_range::<f32>(0.5, 1.0)/DAY,
+        speed: rng_deer.gen_range::<f32>(0.0, 10000.0/HOUR),
+        digestive_capacity: 2.0,
+        mass_starve: 5.0,
+        ocurrence_per_sq_km: 15.0,
+        ..Default::default()};
+
+
+    let gen_config = false;
+
+    if gen_config {
+        let config_rect = Rect {x: 0.0, y: 0.0, width: 100.0, height: 100.0};
+    
+        let config_biome = Biome {water: 1000.0, lifeforms: Vec::new(), biomass: TON, rect: config_rect};
+        let mut config_lifeforms = Vec::new();
+        config_lifeforms.push(deer);
+        config_lifeforms.push(tree);
+
+        let config = Config {biome: config_biome, lifeforms: config_lifeforms, simtime: 1000.0, simsteps: 1.0};
+        let serialized_config = serde_json::to_string_pretty(&config).unwrap();
         
-        let mut deer = Lifeform {
-            name: "Deer".to_string(),
-            kind: LifeformKind::Fauna,
-            age: age,
-            maxage: maxage,
-            mass: mass,
-            water_intake: water_intake,
-            speed: speed,
-            ..Default::default()};
-        biome.lifeforms.push(deer);
+        fs::write("config.json", serialized_config).expect("Unable to write config file");
     }
+    
+    
+    //biome.lifeforms.push(deer);
+    //biome.lifeforms.push(tree);
+
+    // let deserialized: Plant = serde_json::from_str(&serialized).unwrap();
+    //println!("deserialized = {:?}", deserialized);
+
+
+    // Load config file
+    let json_config_path = Path::new("config.json");
+    let config_file = File::open(json_config_path).expect("config file not found");
+    let deserialized_config: Config = serde_json::from_reader(config_file).expect("error while reading json config");
+    // println!("{:?}", deserialized_config);
+
 
+    let mut loaded_biome = deserialized_config.biome;
 
+    for lf in deserialized_config.lifeforms {
+
+        let sq_km = (loaded_biome.rect.width*loaded_biome.rect.width)/1000000.0;
+        let num_instances = sq_km * lf.ocurrence_per_sq_km;
+        println!("\nInstantiating from {:?} {:?} times", lf.name, num_instances);
+        for _i in 0..num_instances as i32 {
+            let mut instance = lf.clone();
+            loaded_biome.lifeforms.push(instance);
+        }
     
 
-    let simtime: i32 = 5*HOUR;
+    }
 
-    for _i in 1..simtime {
-        biome.tick();
+    //biome.lifeforms.push(tree);
+    println!("running {:?} days for {:?} lifeforms", deserialized_config.simtime * deserialized_config.simsteps, loaded_biome.lifeforms.len());
+    for _i in 1..deserialized_config.simtime as i32 {
+        loaded_biome.tick(deserialized_config.simsteps);
     }
 
-    let serialized = serde_json::to_string(&biome).unwrap();
-    println!("serialized = {}", serialized);
+    let serialized = serde_json::to_string(&loaded_biome).unwrap();
+    //println!("serialized = {}", serialized);
+    fs::write("sim.json", serialized).expect("Unable to write file");
+}
 
-    //let deserialized: Plant = serde_json::from_str(&serialized).unwrap();
-    //println!("deserialized = {:?}", deserialized);
+
+fn main() {
+    //let start = SystemTime::now();
+    println!("Starting simulation");
+    sim();
 }