diff --git a/src/system/mod.rs b/src/system/mod.rs index 1da8f5f..2e230fe 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -1,5 +1,6 @@ use std::f32::consts::PI; use std::ops::Add; +use num_integer::Integer; use rand::Rng; use serde::{Serialize, Deserialize, Serializer}; @@ -9,10 +10,12 @@ pub mod model; pub mod nd; pub trait GriddedPosition: Add + Serialize + Clone { + const NEIGHBOURS: u32; + fn zero() -> Self; fn spawn(rng: &mut R, radius: f32) -> Self; fn abs(&self) -> f32; - fn neighbours(&self) -> Vec; + fn neighbour(&self, neighbour_index: u32) -> Self; fn linear_index(&self, grid_size: u32) -> usize; } @@ -37,6 +40,8 @@ impl Add for Position { } impl GriddedPosition for Position { + const NEIGHBOURS: u32 = 4; + fn zero() -> Position { Position { x: 0, y: 0 } } @@ -51,13 +56,12 @@ impl GriddedPosition for Position { ((self.x.pow(2) + self.y.pow(2)) as f32).powf(0.5) } - fn neighbours(&self) -> Vec { - let a = (0..2).into_iter(); + fn neighbour(&self, neighbour_index: u32) -> Self { + let (dim, sign) = neighbour_index.div_rem(&2); + let sign = if sign == 0 { 1 } else { -1 }; + let offset = Position::in_direction(dim, sign); - return a.flat_map(|direction| [ - self.clone() + Position::in_direction(direction, 1), - self.clone() + Position::in_direction(direction, -1), - ]).collect(); + self.clone() + offset } fn linear_index(&self, grid_size: u32) -> usize { diff --git a/src/system/model.rs b/src/system/model.rs index 8041769..ecbdbb0 100644 --- a/src/system/model.rs +++ b/src/system/model.rs @@ -114,8 +114,8 @@ impl, W: Walker

> DLASystem bool { - position.neighbours() - .iter() + (0..P::NEIGHBOURS) + .map(|n| position.neighbour(n)) .any(|neighbour| self.space.at(&neighbour) && self.rng.gen_range(0.0f32..=1.0) < self.stick_probability diff --git a/src/system/nd.rs b/src/system/nd.rs index 654a452..1a84b92 100644 --- a/src/system/nd.rs +++ b/src/system/nd.rs @@ -1,4 +1,5 @@ use std::ops::Add; +use num_integer::Integer; use rand::Rng; use serde::{Serialize, Serializer}; use serde::ser::SerializeMap; @@ -56,6 +57,8 @@ impl Serialize for NDPosition { } impl GriddedPosition for NDPosition { + const NEIGHBOURS: u32 = { 2u32.pow(DIM as u32) } as u32; + fn zero() -> Self { NDPosition([0; DIM]) } @@ -87,13 +90,12 @@ impl GriddedPosition for NDPosition { (a as f32).powf(0.5) } - fn neighbours(&self) -> Vec { - let a = (0..DIM).into_iter(); + fn neighbour(&self, neighbour_index: u32) -> Self { + let (dim, sign) = neighbour_index.div_rem(&(DIM as u32)); + let sign = if sign == 0 { 1 } else { -1 }; + let offset = Self::in_direction(dim as usize, sign); - return a.flat_map(|direction| [ - self.clone() + NDPosition::in_direction(direction, 1), - self.clone() + NDPosition::in_direction(direction, -1), - ]).collect(); + self.clone() + offset } fn linear_index(&self, grid_size: u32) -> usize { diff --git a/src/system/walker.rs b/src/system/walker.rs index af72685..c563dd4 100644 --- a/src/system/walker.rs +++ b/src/system/walker.rs @@ -10,9 +10,7 @@ pub struct LocalRandomWalker; impl Walker for LocalRandomWalker { fn walk(&self, rng: &mut R, position: &Position) -> Position { - let neighbours = position.neighbours(); - let index = rng.gen_range(0..(neighbours.len())); - neighbours[index].clone() + position.neighbour(rng.gen_range(0u32..Position::NEIGHBOURS)) } }