|
@@ -0,0 +1,222 @@
|
|
|
+use std::time::{SystemTime};
|
|
|
+use rand::Rng;
|
|
|
+
|
|
|
+
|
|
|
+#[macro_use]
|
|
|
+extern crate serde_derive;
|
|
|
+
|
|
|
+extern crate rand;
|
|
|
+extern crate serde;
|
|
|
+extern crate serde_json;
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+UNITS
|
|
|
+
|
|
|
+mass = kilogram
|
|
|
+time = sec
|
|
|
+distance = meter
|
|
|
+speed = meter / tick (s)
|
|
|
+
|
|
|
+*/
|
|
|
+
|
|
|
+// 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;
|
|
|
+// weight constants
|
|
|
+const KG: f32 = 1.0;
|
|
|
+const TON: f32 = KG*1000.0;
|
|
|
+
|
|
|
+#[derive(Serialize, Deserialize, Debug)]
|
|
|
+enum Diets {
|
|
|
+ Carnivore,
|
|
|
+ Herbivore,
|
|
|
+ Omnivore,
|
|
|
+ Photovore
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Serialize, Deserialize, Debug)]
|
|
|
+enum LifeformKind {
|
|
|
+ Fauna,
|
|
|
+ Flora,
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Serialize, Deserialize, Debug)]
|
|
|
+struct Biome {
|
|
|
+ width: f32,
|
|
|
+ height: f32,
|
|
|
+ water: f32,
|
|
|
+ biomass: f32,
|
|
|
+ lifeforms: Vec<Lifeform>
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+impl Biome {
|
|
|
+ fn tick(&mut self){
|
|
|
+
|
|
|
+ for lifeform in &mut self.lifeforms {
|
|
|
+ if lifeform.alive {
|
|
|
+ lifeform.tick();
|
|
|
+ self.water -= lifeform.water_intake;
|
|
|
+ } else {
|
|
|
+ self.biomass += lifeform.mass;
|
|
|
+ lifeform.mass = 0.0;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //keep lifeform in bounds
|
|
|
+ //TODO: clamp
|
|
|
+ if lifeform.position[0] < 0.0 {
|
|
|
+ lifeform.position[0] = 0.0;
|
|
|
+ }
|
|
|
+ if lifeform.position[0] > self.width {
|
|
|
+ lifeform.position[0] = self.width;
|
|
|
+ }
|
|
|
+
|
|
|
+ if lifeform.position[2] > self.height {
|
|
|
+ lifeform.position[2] = self.height;
|
|
|
+ }
|
|
|
+ if lifeform.position[2] < 0.0 {
|
|
|
+ lifeform.position[2] = 0.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // fn lf_move(&mut self, mut lf: &Lifeform) {
|
|
|
+
|
|
|
+ // }
|
|
|
+
|
|
|
+ // fn lf_eat(&mut self) {
|
|
|
+ // for lf in self.lifeforms {
|
|
|
+
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Serialize, Deserialize, Debug)]
|
|
|
+struct Lifeform {
|
|
|
+ name: String,
|
|
|
+ mass: f32,
|
|
|
+ age: i32,
|
|
|
+ maxage: i32,
|
|
|
+ water_intake: f32,
|
|
|
+ nutrient_intake: f32,
|
|
|
+ diet: Diets,
|
|
|
+ kind: LifeformKind,
|
|
|
+ alive: bool,
|
|
|
+ position: Vec<f32>,
|
|
|
+ speed: f32,
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// TODO: add position
|
|
|
+impl Lifeform {
|
|
|
+ fn tick(&mut self){
|
|
|
+ if self.alive {
|
|
|
+ self.mass += self.nutrient_intake;
|
|
|
+ self.age += 1;
|
|
|
+ }
|
|
|
+ if self.age > self.maxage {
|
|
|
+ self.alive = false;
|
|
|
+ println!("Died: {:?}", self);
|
|
|
+ }
|
|
|
+ self.move_random();
|
|
|
+ }
|
|
|
+ fn move_random(&mut self) {
|
|
|
+ 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);
|
|
|
+ self.position[0] += rx*self.speed;
|
|
|
+ self.position[2] += rz*self.speed;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl Default for Lifeform {
|
|
|
+ fn default() -> Lifeform {
|
|
|
+ Lifeform {
|
|
|
+ name: "Generic Plant".to_string(),
|
|
|
+ mass: 1.0,
|
|
|
+ age: 0,
|
|
|
+ water_intake: 1.0/DAY as f32,
|
|
|
+ nutrient_intake: 1.0/DAY as f32,
|
|
|
+ diet: Diets::Herbivore,
|
|
|
+ kind: LifeformKind::Flora,
|
|
|
+ maxage: YEAR,
|
|
|
+ alive: true,
|
|
|
+ position: vec![0.0, 0.0, 0.0],
|
|
|
+ speed: 0.0,
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn main() {
|
|
|
+ let start = SystemTime::now();
|
|
|
+ println!("{:?}", start);
|
|
|
+
|
|
|
+ let mut biome = Biome {width: 1000.0, height: 1000.0, water: 1000.0, lifeforms: Vec::new(), biomass: TON};
|
|
|
+
|
|
|
+
|
|
|
+ // 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()
|
|
|
+ };
|
|
|
+
|
|
|
+ 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 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);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ for _i in 1..1000 {
|
|
|
+ biome.tick();
|
|
|
+ }
|
|
|
+
|
|
|
+ let serialized = serde_json::to_string(&biome).unwrap();
|
|
|
+ println!("serialized = {}", serialized);
|
|
|
+
|
|
|
+ //let deserialized: Plant = serde_json::from_str(&serialized).unwrap();
|
|
|
+ //println!("deserialized = {:?}", deserialized);
|
|
|
+}
|