Add N-dimensional position code

This commit is contained in:
Joshua Coles 2023-03-04 12:53:12 +00:00
parent 14b5cb4679
commit 1c49bf92c8
3 changed files with 102 additions and 0 deletions

View File

@ -1,3 +1,5 @@
#![feature(array_zip)]
use std::path::PathBuf; use std::path::PathBuf;
use rand::prelude::*; use rand::prelude::*;

View File

@ -6,6 +6,7 @@ use serde::{Serialize, Deserialize, Serializer};
pub mod walker; pub mod walker;
pub mod storage; pub mod storage;
pub mod model; pub mod model;
pub mod nd;
pub trait GriddedPosition: Add<Output=Self> + Serialize + Clone { pub trait GriddedPosition: Add<Output=Self> + Serialize + Clone {
fn zero() -> Self; fn zero() -> Self;

99
src/system/nd.rs Normal file
View File

@ -0,0 +1,99 @@
use std::ops::Add;
use rand::Rng;
use serde::{Serialize, Serializer};
use serde::ser::SerializeMap;
use crate::system::GriddedPosition;
use crate::system::storage::Storage;
pub struct NDVectorStorage<const DIM: usize> {
backing: Vec<bool>,
grid_size: u32,
}
impl<const DIM: usize> Storage<NDPosition<DIM>> for NDVectorStorage<DIM> {
fn at(&self, position: &NDPosition<DIM>) -> bool {
return self.backing[position.linear_index(self.grid_size)];
}
fn deposit(&mut self, position: &NDPosition<DIM>) {
self.backing[position.linear_index(self.grid_size)] = true;
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NDPosition<const DIM: usize>([i32; DIM]);
impl<const DIM: usize> NDPosition<DIM> {
pub fn in_direction(direction: usize, value: i32) -> Self {
let mut arr = [0; DIM];
arr[direction] = value;
NDPosition(arr)
}
}
impl<const DIM: usize> Add for NDPosition<DIM> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0.zip(rhs.0).map(|(a, b)| a + b))
}
}
impl<const DIM: usize> Serialize for NDPosition<DIM> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
let mut map = serializer.serialize_map(Some(DIM))?;
for (i, v) in self.0.iter().enumerate() {
map.serialize_entry(&format!("r{}", i), v)?;
}
map.end()
}
}
impl<const DIM: usize> GriddedPosition for NDPosition<DIM> {
fn zero() -> Self {
NDPosition([0; DIM])
}
fn spawn<R: Rng>(rng: &mut R, radius: f32) -> Self {
let mut a: [f32; DIM] = [0f32; DIM];
let mut b: [i32; DIM] = [0i32; DIM];
for i in 0..DIM {
a[i] = rng.gen_range(0f32..1f32);
}
let norm = a.iter().sum::<f32>()
.sqrt();
for i in 0..DIM {
a[i] = a[i] / norm;
b[i] = a[i] as i32;
}
return Self(b)
}
fn abs(&self) -> f32 {
let a: i32 = self.0.iter()
.map(|r| r.pow(2))
.sum();
(a as f32).powf(0.5)
}
fn neighbours(&self) -> Vec<Self> {
let a = (0..DIM).into_iter();
return a.flat_map(|direction| [
self.clone() + NDPosition::in_direction(direction, 1),
self.clone() + NDPosition::in_direction(direction, -1),
]).collect();
}
fn linear_index(&self, grid_size: u32) -> usize {
self.0.iter()
.enumerate()
.map(|(i, v)| (grid_size.pow(i as u32) as usize) * (v + ((grid_size / 2) as i32)) as usize)
.sum()
}
}