use super::Kartesian; /// Rust implementation of an Map. The Zeropoint is Topleft /// The Rows in the data are not nessesaryly in the specifed length, should values be missing, then there are functions that returns #[derive(Debug, Clone)] pub struct Map { pub(super) maximum: Kartesian, pub(super) data: Vec>, } impl Map { /// creates an empty Map pub fn empty(length: usize, height: usize) -> Self { Self { data: Vec::new(), maximum: Kartesian::new(height, length), } } pub fn size(&self) -> Kartesian { self.maximum } /// returns true if coordinates are outside of bounds #[inline] fn outside(&self, coord: Kartesian) -> bool { coord.x >= self.maximum.x || coord.y >= self.maximum.y } /// Unsafe Version of the get or get_wrapping functions. /// It does not check against an missing value and panics if its out of bounds. #[inline] pub unsafe fn get_unsafe(&self, coord: Kartesian) -> T { if self.outside(coord) { panic!("Coordinates out of bounds: {} >= {}", coord, self.maximum) } self.data[coord.x][coord.y] } } impl Map { /// Returns an Option Containing the value. /// Returns None if out of bounds or not yet set. pub fn get(&self, coord: Kartesian) -> Option { if self.outside(coord) { return None; } if coord.x >= self.data.len() { Some(T::default()) } else if coord.y >= self.data[coord.x].len() { Some(T::default()) } else { Some(self.data[coord.x][coord.y]) } } /// Replaces unset and default values with pub fn replace_default(&mut self, new_value: T) { for row in self.data.iter_mut() { *row = row .iter() .map(|c| { if *c == T::default() { new_value } else { *c } }) .collect(); if row.len() < self.maximum.y { row.resize(self.maximum.y, new_value); } } if self.data.len() < self.maximum.x { let full_row = vec![new_value; self.maximum.y]; self.data.resize(self.maximum.x, full_row); } } /// Returns the value of in the map. #[inline] pub fn wrapping_get(&self, coord: Kartesian) -> T { let modded = coord % self.maximum; if modded.x >= self.data.len() { T::default() } else if modded.y >= self.data[modded.x].len() { T::default() } else { self.data[modded.x][modded.y] } } pub fn set(&mut self, coord: Kartesian, value: T) -> T { if self.outside(coord) { panic!("Coordinates outside of bounds: {} >= {}", coord, self.maximum) } if self.data.len() < coord.x + 1 { self.data.resize(coord.x + 1, Vec::new()); } if self.data[coord.x].len() < coord.y + 1 { self.data[coord.x].resize(coord.y + 1, T::default()); } let oldvalue = self.data[coord.x][coord.y]; self.data[coord.x][coord.y] = value; oldvalue } pub fn extend_left(&mut self, amount: usize) { for line in self.data.iter_mut() { for _ in 0..amount { line.insert(0, T::default()); } } self.maximum.y += amount; } pub fn extend_right(&mut self, amount: usize) { self.maximum.y += amount; } pub fn extend_up(&mut self, amount: usize) { for _ in 0..amount { self.data.insert(0, Vec::new()); } self.maximum.x += amount } pub fn extend_down(&mut self, amount: usize) { self.maximum.x += amount } } impl From>> for Map { fn from(value: Vec>) -> Self { Map { data: value.clone(), maximum: Kartesian::new(value.len(), value.iter().map(|line| line.len()).max().unwrap_or(0)), } } }