Last active
November 14, 2022 09:41
-
-
Save xmichael446/edf37525445635d1b7d475df3e30ad33 to your computer and use it in GitHub Desktop.
Fish simulation in rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{thread, time::Duration}; | |
use std::fmt::Formatter; | |
use rand::Rng; | |
const INITIAL_FISH_AMOUNT: u32 = 20; | |
const LIFETIME_CONSTRAINTS: (u32, u32) = (10, 50); | |
#[derive(PartialEq, Clone)] | |
enum Gender { | |
Male, | |
Female, | |
Other, | |
} | |
#[derive(Clone)] | |
struct Fish { | |
name: String, | |
gender: Gender, | |
age: u32, | |
lifetime: u32, | |
mother: Option<Box<Fish>>, | |
father: Option<Box<Fish>>, | |
} | |
struct Aquarium { | |
fish: Vec<Fish>, | |
} | |
struct Logger {} | |
impl Logger { | |
fn collision(&self, first: &Fish, second: &Fish) { | |
println!("------------- COLLISION -------------"); | |
print!("{first}\n{second}"); | |
println!("------------- COLLISION -------------"); | |
} | |
fn birth(&self, fish: &Fish) { | |
println!("------------- BIRTH -------------"); | |
print!("{fish}"); | |
println!("------------- BIRTH -------------"); | |
} | |
fn death(&self, fish: &Fish) { | |
println!("------------- DEATH -------------"); | |
print!("{fish}"); | |
println!("------------- DEATH -------------"); | |
} | |
} | |
impl Fish { | |
pub fn new(name: String, gender: Gender, lifetime: u32, mother: Option<Box<Fish>>, father: Option<Box<Fish>>) -> Self { | |
Fish { name, gender, lifetime, father, mother, age: 0 } | |
} | |
fn can_marry(&self, other: &Fish) -> bool { | |
self.gender != other.gender | |
} | |
fn is_male(&self) -> bool { | |
self.gender == Gender::Male | |
} | |
fn is_female(&self) -> bool { | |
self.gender == Gender::Female | |
} | |
fn should_die(&self) -> bool { | |
self.age == self.lifetime | |
} | |
fn increment_age(&mut self) { | |
self.age += 1 | |
} | |
} | |
impl std::fmt::Display for Fish { | |
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | |
write!(f, "name: {}\nage: {}\nlifetime: {}\n", self.name, self.age, self.lifetime) | |
} | |
} | |
fn take<T>(v: &mut Vec<T>, index: usize) -> Option<T> { | |
if v.get(index).is_none() { | |
None | |
} else { | |
Some(v.swap_remove(index)) | |
} | |
} | |
impl Aquarium { | |
fn generate_fish(&self, father: Option<Box<Fish>>, mother: Option<Box<Fish>>) -> Fish { | |
let g: u32 = rand::thread_rng().gen_range(0..2); | |
let gender = match g { | |
0 => Gender::Male, | |
1 => Gender::Female, | |
_ => Gender::Other | |
}; | |
let name = match gender { | |
Gender::Male => String::from("Michael"), | |
Gender::Female => String::from("Qizi"), | |
Gender::Other => String::from("how the hell?") | |
}; | |
let (start, stop) = LIFETIME_CONSTRAINTS; | |
let lifetime = rand::thread_rng().gen_range(start..stop); | |
let f = Fish::new(name, gender, lifetime, father, mother); | |
return f; | |
} | |
fn fill(&mut self, amount: u32) { | |
for _ in 0..amount { | |
self.fish.push(self.generate_fish(None, None)); | |
} | |
} | |
fn get_random(&self) -> Fish { | |
let i = rand::thread_rng().gen_range(0..self.fish.len()); | |
take(&mut self.fish.clone(), i).unwrap() | |
} | |
} | |
fn main() { | |
let mut aquarium = Aquarium { fish: vec![] }; | |
aquarium.fill(INITIAL_FISH_AMOUNT); | |
let logger = Logger {}; | |
let mut collisions: Vec<u32> = Vec::new(); | |
let mut iteration: u32 = 0; | |
loop { | |
for _ in 1..6 { | |
let n: u32 = rand::thread_rng().gen_range(1..6) + iteration; | |
collisions.push(n); | |
} | |
collisions.sort_by(|a, b| b.cmp(a)); | |
for c in collisions.iter() { | |
if c < &iteration { break; } | |
if c != &iteration || c < &iteration { continue; } | |
let f1 = aquarium.get_random(); | |
let f2 = aquarium.get_random(); | |
logger.collision(&f1, &f2); | |
if !f1.can_marry(&f2) { continue; } | |
let father: Box<Fish> = if f1.is_male() { Box::new(f1.clone()) } else { Box::new(f2.clone()) }; | |
let mother: Box<Fish> = if f1.is_female() { Box::new(f1.clone()) } else { Box::new(f2.clone()) }; | |
let new_fish = aquarium.generate_fish(Some(father), Some(mother)); | |
aquarium.fish.push(new_fish.clone()); | |
logger.birth(&new_fish); | |
} | |
for i in 0..aquarium.fish.len() { | |
aquarium.fish[i].increment_age(); | |
if aquarium.fish[i].should_die() { | |
logger.death(&aquarium.fish[i].clone()); | |
} | |
} | |
aquarium.fish.retain(|f| {!f.should_die()}); | |
iteration += 1; | |
thread::sleep(Duration::from_millis(2000)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment