From 95e328ea1fdbc80b4fc0bd7c95ea172d62929df7 Mon Sep 17 00:00:00 2001 From: Joshua Coles Date: Thu, 2 Mar 2023 16:44:19 +0000 Subject: [PATCH] Some refactor to allow for other entry points --- src/main.rs | 133 +----------------------------------------- src/system/mod.rs | 1 + src/system/model.rs | 136 +++++++++++++++++++++++++++++++++++++++++++ src/system/walker.rs | 8 +-- 4 files changed, 143 insertions(+), 135 deletions(-) create mode 100644 src/system/model.rs diff --git a/src/main.rs b/src/main.rs index 3c66dd9..329f2ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,140 +13,11 @@ use system::storage::{Storage, VectorStorage}; use num_integer::Integer; use rand::rngs::SmallRng; use crate::system::{DIM, Position}; - -struct DLASystem { - rng: SmallRng, - - storage: S, - walker: W, - - stick_probability: f32, - max_particles: usize, - - running: bool, - - particles: Vec, - active_particle: Option, - - add_ratio: f32, - add_circle: f32, - kill_ratio: f32, - kill_circle: f32, - cluster_radius: f32, -} - -impl DLASystem { - fn new(seed: u64, max_particles: usize, stick_probability: f32) -> DLASystem { - let mut sys: DLASystem = DLASystem { - rng: SmallRng::seed_from_u64(seed), - stick_probability, - max_particles, - running: true, - - storage: VectorStorage::new(1600, 2), - walker: LocalRandomWalker, - particles: vec![], - active_particle: None, - - add_ratio: 1.2, - kill_ratio: 1.7, - - add_circle: 10.0, - kill_circle: 20.0, - cluster_radius: 0.0, - }; - - sys.deposit(&Position(0, 0)); - - sys - } - - fn update(&mut self) { - if self.active_particle.is_some() { - self.move_particle(); - } else if self.particles.len() < self.max_particles { - self.spawn_particle(); - } else { - self.running = false; - } - } - - fn move_particle(&mut self) { - let current_position = &self - .active_particle - .clone() - .expect("No active particle"); - - if self.check_stick(current_position) { - self.deposit(current_position); - self.active_particle = None; - return; - } - - let next_position = self.walker.walk(&mut self.rng, current_position); - let distance = next_position.abs(); - - if distance > self.kill_circle { - self.active_particle = None; - } else if !self.storage.at(&next_position) { - self.active_particle.replace(next_position); - } - } - - fn check_stick(&mut self, position: &Position) -> bool { - for direction in 0..DIM { - for sign in [-1, 1] { - let neighbour = position.clone() + Position::in_direction(direction, sign); - if self.storage.at(&neighbour) && self.rng.gen_range(0.0f32..1.0) < self.stick_probability { - return true; - } - } - } - - return false; - } - - fn spawn_particle(&mut self) { - let theta = self.rng.gen_range(0f32..1.0); - let (x, y) = (self.add_circle * theta.cos(), self.add_circle * theta.sin()); - let position = Position(x.round() as i32, y.round() as i32); - - if !self.storage.at(&position) { - self.active_particle = Some(position); - } - } - - fn deposit(&mut self, p0: &Position) { - self.particles.push(p0.clone()); - self.storage.deposit(p0); - - let distance = p0.abs(); - if distance > self.cluster_radius { - self.cluster_radius = distance; - - let new_add_circle = (self.cluster_radius * self.add_ratio).max(self.cluster_radius + 5.0); - if self.add_circle < new_add_circle { - self.add_circle = new_add_circle; - self.kill_circle = self.kill_ratio * self.add_circle; - } - } - } - - fn export_data(&self) -> io::Result<()> { - let mut file = File::create("out.csv")?; - writeln!(&mut file, "x, y")?; - - for particle in &self.particles { - writeln!(&mut file, "{}, {}", particle.0, particle.1)?; - } - - Ok(()) - } -} +use crate::system::model::DLASystem; fn main() { use rand::{SeedableRng, thread_rng}; - let mut sys: DLASystem = DLASystem::::new(1, 1000, 1.0); + let mut sys = DLASystem::::new(1, 1000, 1.0); while sys.running { sys.update(); diff --git a/src/system/mod.rs b/src/system/mod.rs index b285a56..ad7a5f9 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -2,6 +2,7 @@ use std::ops::Add; pub mod walker; pub mod storage; +pub mod model; pub const DIM: u32 = 2; diff --git a/src/system/model.rs b/src/system/model.rs new file mode 100644 index 0000000..98dc69d --- /dev/null +++ b/src/system/model.rs @@ -0,0 +1,136 @@ +use std::fs::File; +use std::io::Write; +use std::io; +use rand::prelude::*; +use crate::system::{DIM, Position}; +use crate::system::storage::{Storage, VectorStorage}; +use crate::system::walker::{LocalRandomWalker, Walker}; + +pub struct DLASystem> { + rng: R, + storage: S, + walker: W, + + stick_probability: f32, + max_particles: usize, + + pub running: bool, + + particles: Vec, + active_particle: Option, + + add_ratio: f32, + add_circle: f32, + kill_ratio: f32, + kill_circle: f32, + cluster_radius: f32, +} + +impl> DLASystem { + pub fn new(seed: u64, max_particles: usize, stick_probability: f32) -> DLASystem { + let mut sys: DLASystem = DLASystem { + rng: SmallRng::seed_from_u64(seed), + stick_probability, + max_particles, + running: true, + + storage: VectorStorage::new(1600, 2), + walker: LocalRandomWalker, + particles: vec![], + active_particle: None, + + add_ratio: 1.2, + kill_ratio: 1.7, + + add_circle: 10.0, + kill_circle: 20.0, + cluster_radius: 0.0, + }; + + sys.deposit(&Position(0, 0)); + + sys + } + + pub fn update(&mut self) { + if self.active_particle.is_some() { + self.move_particle(); + } else if self.particles.len() < self.max_particles { + self.spawn_particle(); + } else { + self.running = false; + } + } + + fn move_particle(&mut self) { + let current_position = &self + .active_particle + .clone() + .expect("No active particle"); + + if self.check_stick(current_position) { + self.deposit(current_position); + self.active_particle = None; + return; + } + + let next_position = self.walker.walk(&mut self.rng, current_position); + let distance = next_position.abs(); + + if distance > self.kill_circle { + self.active_particle = None; + } else if !self.storage.at(&next_position) { + self.active_particle.replace(next_position); + } + } + + fn check_stick(&mut self, position: &Position) -> bool { + for direction in 0..DIM { + for sign in [-1, 1] { + let neighbour = position.clone() + Position::in_direction(direction, sign); + if self.storage.at(&neighbour) && self.rng.gen_range(0.0f32..1.0) < self.stick_probability { + return true; + } + } + } + + return false; + } + + fn spawn_particle(&mut self) { + let theta = self.rng.gen_range(0f32..1.0); + let (x, y) = (self.add_circle * theta.cos(), self.add_circle * theta.sin()); + let position = Position(x.round() as i32, y.round() as i32); + + if !self.storage.at(&position) { + self.active_particle = Some(position); + } + } + + fn deposit(&mut self, p0: &Position) { + self.particles.push(p0.clone()); + self.storage.deposit(p0); + + let distance = p0.abs(); + if distance > self.cluster_radius { + self.cluster_radius = distance; + + let new_add_circle = (self.cluster_radius * self.add_ratio).max(self.cluster_radius + 5.0); + if self.add_circle < new_add_circle { + self.add_circle = new_add_circle; + self.kill_circle = self.kill_ratio * self.add_circle; + } + } + } + + pub fn export_data(&self) -> io::Result<()> { + let mut file = File::create("out.csv")?; + writeln!(&mut file, "x, y")?; + + for particle in &self.particles { + writeln!(&mut file, "{}, {}", particle.0, particle.1)?; + } + + Ok(()) + } +} diff --git a/src/system/walker.rs b/src/system/walker.rs index 70c1bf5..6cde562 100644 --- a/src/system/walker.rs +++ b/src/system/walker.rs @@ -2,14 +2,14 @@ use num_integer::Integer; use rand::prelude::{Rng, SmallRng}; use crate::system::{DIM, Position}; -pub trait Walker { - fn walk(&self, rng: &mut SmallRng, position: &Position) -> Position; +pub trait Walker { + fn walk(&self, rng: &mut R, position: &Position) -> Position; } pub struct LocalRandomWalker; -impl Walker for LocalRandomWalker { - fn walk(&self, rng: &mut SmallRng, position: &Position) -> Position { +impl Walker for LocalRandomWalker { + fn walk(&self, rng: &mut R, position: &Position) -> Position { let (dim, sign) = rng.gen_range(0u32..(DIM * 2)).div_rem(&DIM); let sign = if sign == 0 { -1 } else { 1 }; let offset = Position::in_direction(dim, sign);