From 94466c7f1b0e5df55cd6cbaa281fb4a5bc5a2528 Mon Sep 17 00:00:00 2001 From: Rene Luria Date: Thu, 5 May 2022 14:33:52 +0200 Subject: [PATCH] propagate each human consecutively --- src/main.rs | 2 +- src/population.rs | 96 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index b0186ea..b6aed33 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,7 @@ fn main() { let mut counter: u32 = 0; loop { counter += 1; - stats = population.propagate(); + stats = population.propagate_new(); //population.display(); println!( "Normal: {} Infecteds: {} Immunes: {} Deads: {}", diff --git a/src/population.rs b/src/population.rs index f9600f6..864e0d3 100644 --- a/src/population.rs +++ b/src/population.rs @@ -259,6 +259,84 @@ impl Population { // print!("\n"); // } // } + + pub fn propagate_new(&mut self) -> [i32; 4] { + let mut stats: [i32; 4] = [0, 0, 0, 0]; + let mut humans_n_plus_1: Vec = Vec::with_capacity(self.humans.len()); + + for human in self.humans.iter() { + let mut neighbors: Vec<&Human> = Vec::with_capacity(8); + if human.present_state == State::Normal { + let possible = [ + (human.x - 1, human.y - 1), (human.x, human.y - 1), (human.x + 1, human.y - 1), + (human.x - 1, human.y) , (human.x + 1, human.y), + (human.x - 1, human.y + 1), (human.x, human.y + 1), (human.x + 1, human.y + 1), + ]; + for neigh_coords in possible.iter() { + let neigh_idx = point_to_index(neigh_coords.0, neigh_coords.1, self.width, self.height); + match neigh_idx { + Some(x) => neighbors.push(&self.humans[x]), + None => {}, + } + } + } + let new_human = evolve(human, neighbors, self.plague.infection_rate, self.plague.curing_rate, self.plague.death_rate); + match human.present_state { + State::Normal => { stats[0] += 1; } + State::Infected => { stats[1] += 1; } + State::Immune => { stats[2] += 1; } + State::Dead => { stats[3] += 1; } + } + humans_n_plus_1.push(new_human); + } + + self.humans = humans_n_plus_1; + stats + } +} + +fn evolve(human: &Human, neighbors: Vec<&Human>, infection_rate: i32, curing_rate: i32, death_rate: i32) -> Human { + let mut new_human = human.clone(); + match human.present_state { + State::Normal => { + new_human.present_state = infect_by_neighbors(neighbors, infection_rate); + } + State::Infected => { + new_human.present_state = die_or_cure(curing_rate, death_rate); + } + State::Immune => {} + State::Dead => {} + } + new_human +} + +fn infect_by_neighbors(neighbors: Vec<&Human>, infection_rate: i32) -> State { + for neighbor in neighbors.iter() { + if neighbor.present_state == State::Infected { + if roll(infection_rate) { + return State::Infected; + } + } + } + State::Normal +} + +fn die_or_cure(curing_rate: i32, death_rate: i32) -> State { + if roll(curing_rate) { + State::Immune + } else if roll(death_rate) { + State::Dead + } else { + State::Infected + } +} + +fn point_to_index(x: i32, y: i32, width: i32, height: i32) -> Option { + if (x >= 0) && (x < width) && (y >= 0) && (y < height) { + Some(human_idx(x, y, width)) + } else { + None + } } pub fn roll(probability: i32) -> bool { @@ -446,7 +524,7 @@ mod tests { assert_eq!(stats.infected, 100, "everybody should be infected"); // kill every one - propagate_stats = population.propagate(); + propagate_stats = population.propagate_new(); stats = humans_stats(&population.humans); println!("propate_stats: {:?}", propagate_stats); assert_eq!(propagate_stats, [0, 100, 0, 0]); @@ -456,7 +534,7 @@ mod tests { assert_eq!(stats.dead, 100); for _x in 0..100 { - propagate_stats = population.propagate(); + propagate_stats = population.propagate_new(); stats = humans_stats(&population.humans); println!("propate_stats: {:?}", propagate_stats); assert_eq!(propagate_stats, [0, 0, 0, 100]); @@ -527,7 +605,7 @@ mod tests { assert_eq!(stats.normal, 8); // kill every one - propagate_stats = population.propagate(); + propagate_stats = population.propagate_new(); stats = humans_stats(&population.humans); println!("propate_stats: {:?}", propagate_stats); assert_eq!(propagate_stats, [8, 1, 0, 0]); @@ -537,7 +615,7 @@ mod tests { assert_eq!(stats.dead, 0); for _x in 0..100 { - propagate_stats = population.propagate(); + propagate_stats = population.propagate_new(); stats = humans_stats(&population.humans); println!("propate_stats: {:?}", propagate_stats); assert_eq!(propagate_stats, [0, 9, 0, 0]); @@ -608,7 +686,7 @@ mod tests { assert_eq!(stats.normal, 8); // infect every one - propagate_stats = population.propagate(); + propagate_stats = population.propagate_new(); stats = humans_stats(&population.humans); println!("propate_stats: {:?}", propagate_stats); println!("population: {:?}", stats); @@ -619,7 +697,7 @@ mod tests { assert_eq!(stats.dead, 0); // cure every one - propagate_stats = population.propagate(); + propagate_stats = population.propagate_new(); stats = humans_stats(&population.humans); println!("propate_stats: {:?}", propagate_stats); println!("population: {:?}", stats); @@ -631,7 +709,7 @@ mod tests { // then for _x in 0..100 { - propagate_stats = population.propagate(); + propagate_stats = population.propagate_new(); stats = humans_stats(&population.humans); println!("propate_stats: {:?}", propagate_stats); println!("population: {:?}", stats); @@ -658,7 +736,7 @@ mod tests { assert!(stats_before.infected <= should_be_infected + tolerance, "{} infected, should be less than {}", stats_before.infected, should_be_infected + tolerance); assert!(stats_before.infected >= should_be_infected - tolerance, "{} infected, should be more than {}", stats_before.infected, should_be_infected - tolerance); - population.propagate(); + population.propagate_new(); stats_after = humans_stats(&population.humans); assert_eq!(stats_before.infected, stats_after.infected, "no one should have been infected"); @@ -693,7 +771,7 @@ mod tests { let infected_at_start = stats.infected; let dead_at_start = stats.dead; - let propa_stats: [i32; 4] = population.propagate(); + let propa_stats: [i32; 4] = population.propagate_new(); assert!(propa_stats[3] >= dead_at_start);