diff --git a/src/coordinate_systems/kartesian.rs b/src/coordinate_systems/kartesian.rs deleted file mode 100644 index aa3954f..0000000 --- a/src/coordinate_systems/kartesian.rs +++ /dev/null @@ -1,517 +0,0 @@ -use log::debug; -use num::*; -use std::{ - fmt::{Debug, Display}, - ops::*, -}; - -pub type KD = KartesianDirection; - -pub trait MaximumFromMap { - fn maximum(map: &Vec>) -> Kartesian; -} - -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Kartesian -where - T: Integer, -{ - pub x: T, - pub y: T, -} - -impl Add for Kartesian { - fn add(self, rhs: Self) -> Self::Output { - Kartesian { x: self.x + rhs.x, y: self.y + rhs.y } - } - - type Output = Kartesian; -} - -impl AddAssign for Kartesian { - fn add_assign(&mut self, rhs: Self) { - self.x += rhs.x; - self.y += rhs.y; - } -} - -impl Sub for Kartesian { - fn sub(self, rhs: Self) -> Self::Output { - Kartesian { x: self.x - rhs.x, y: self.y - rhs.y } - } - - type Output = Kartesian; -} - -impl MaximumFromMap for Kartesian { - fn maximum(map: &Vec>) -> Kartesian { - Kartesian { - x: map.len().to_u32().unwrap(), - y: map[0].len().to_u32().unwrap(), - } - } -} - -impl MaximumFromMap for Kartesian { - fn maximum(map: &Vec>) -> Kartesian { - Kartesian { - x: map.len().to_u64().unwrap(), - y: map[0].len().to_u64().unwrap(), - } - } -} - -impl MaximumFromMap for Kartesian { - fn maximum(map: &Vec>) -> Kartesian { - Kartesian { - x: map.len().to_u128().unwrap(), - y: map[0].len().to_u128().unwrap(), - } - } -} - -impl MaximumFromMap for Kartesian { - fn maximum(map: &Vec>) -> Kartesian { - Kartesian { x: map.len(), y: map[0].len() } - } -} - -impl SubAssign for Kartesian { - fn sub_assign(&mut self, rhs: Self) { - self.x -= rhs.x; - self.y -= rhs.y; - } -} - -impl Kartesian { - pub const fn new(x: T, y: T) -> Self { - Self { x: x, y: y } - } -} - -impl Kartesian { - pub fn get_value(self, map: &Vec>) -> Option { - if map.len() > self.x { - if map[self.x].len() > self.y { - return Some(map[self.x][self.y]); - } - } - - None - } -} - -impl Kartesian { - pub fn checked_add_max(self, rhs: Kartesian, max: Kartesian) -> Option> { - let mut new = Kartesian::default(); - new.x = match self.x.checked_add(&rhs.x) { - None => return None, - Some(x) => { - if x < T::default() || x >= max.x { - return None; - } - x - }, - }; - new.y = match self.y.checked_add(&rhs.y) { - None => return None, - Some(y) => { - if y < T::default() || y >= max.y { - return None; - } - y - }, - }; - Some(new) - } - pub fn checked_sub(self, rhs: Kartesian) -> Option> { - let mut new = Kartesian::default(); - new.x = match self.x.checked_sub(&rhs.x) { - None => return None, - Some(x) => x, - }; - new.y = match self.y.checked_sub(&rhs.y) { - None => return None, - Some(y) => y, - }; - Some(new) - } - - pub fn diff(self, rhs: Kartesian) -> (Kartesian, KartesianDirection) { - let mut relative = Kartesian::::default(); - let mut dir = KartesianDirection::None; - debug!("{:?} <> {:?}", self.x, rhs.x); - if self.x < rhs.x { - dir = dir.down(); - relative.x = rhs.x - self.x; - } else if self.x > rhs.x { - dir = dir.up(); - relative.x = self.x - rhs.x; - } - debug!("{:?} <> {:?}", self.x, rhs.x); - if self.y < rhs.y { - dir = dir.right(); - relative.y = rhs.y - self.y; - } else if self.y > rhs.y { - dir = dir.left(); - relative.y = self.y - rhs.y; - } - (relative, dir) - } - - #[inline] - pub fn move_dir(self, vector: Kartesian, dir: KartesianDirection) -> Option> { - let mut new = self; - match dir { - KartesianDirection::TopLeft | KartesianDirection::Top | KartesianDirection::TopRight => { - new.x = match new.x.checked_sub(&vector.x) { - None => return None, - Some(d) => d, - } - }, - KartesianDirection::BottomLeft | KartesianDirection::Bottom | KartesianDirection::BottomRight => { - new.x = match new.x.checked_add(&vector.x) { - None => return None, - Some(d) => d, - } - }, - _ => {}, - } - match dir { - KartesianDirection::TopLeft | KartesianDirection::Left | KartesianDirection::BottomLeft => { - new.y = match new.y.checked_sub(&vector.y) { - None => return None, - Some(d) => d, - } - }, - KartesianDirection::TopRight | KartesianDirection::Right | KartesianDirection::BottomRight => { - new.y = match new.y.checked_add(&vector.y) { - None => return None, - Some(d) => d, - } - }, - _ => {}, - } - Some(new) - } - - #[inline] - pub fn move_dir_max(self, vector: Kartesian, dir: KartesianDirection, max: Kartesian) -> Option> { - match self.move_dir(vector, dir) { - None => None, - Some(new) => { - if new.x < max.x && new.y < max.y { - Some(new) - } else { - None - } - }, - } - } -} - -impl Display for Kartesian { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!("{}:{}", self.x, self.y)) - } -} - -impl Div for Kartesian { - type Output = Kartesian; - fn div(self, rhs: T) -> Self::Output { - Kartesian { - x: self.x.div_ceil(&rhs), - y: self.y.div_ceil(&rhs), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum KartesianDirection { - TopLeft, - Top, - TopRight, - Left, - None, - Right, - BottomLeft, - Bottom, - BottomRight, -} - -impl KartesianDirection { - pub fn vector(self) -> Kartesian { - Kartesian { - x: match self { - Self::Left | Self::None | Self::Right => T::zero(), - _ => T::one(), - }, - y: match self { - Self::Top | Self::None | Self::Bottom => T::zero(), - _ => T::one(), - }, - } - } - - #[inline] - pub fn vector_abs>(self) -> Kartesian { - self.vector() - } - - pub fn clockwise(self, diagonal: bool) -> Self { - match (self, diagonal) { - (Self::TopLeft, _) => Self::Top, - (Self::Top, true) => Self::TopRight, - (Self::Top, false) => Self::Right, - (Self::TopRight, _) => Self::Right, - (Self::Right, true) => Self::BottomRight, - (Self::Right, false) => Self::Bottom, - (Self::BottomRight, _) => Self::Bottom, - (Self::Bottom, true) => Self::BottomLeft, - (Self::Bottom, false) => Self::Left, - (Self::BottomLeft, _) => Self::Left, - (Self::Left, true) => Self::TopLeft, - (Self::Left, false) => Self::Top, - (Self::None, _) => Self::None, - } - } - - pub fn anticlockwise(self, diagonal: bool) -> Self { - match (self, diagonal) { - (Self::TopLeft, _) => Self::Left, - (Self::Left, true) => Self::BottomLeft, - (Self::Left, false) => Self::Bottom, - (Self::BottomLeft, _) => Self::Bottom, - (Self::Bottom, true) => Self::BottomRight, - (Self::Bottom, false) => Self::Right, - (Self::BottomRight, _) => Self::Right, - (Self::Right, true) => Self::TopRight, - (Self::Right, false) => Self::Top, - (Self::TopRight, _) => Self::Top, - (Self::Top, true) => Self::TopLeft, - (Self::Top, false) => Self::Left, - (Self::None, _) => Self::None, - } - } - - pub fn up(self) -> Self { - match self { - Self::Top | Self::TopLeft | Self::TopRight => self, - Self::Left => Self::TopLeft, - Self::None => Self::Top, - Self::Right => Self::TopRight, - Self::BottomLeft => Self::Left, - Self::Bottom => Self::None, - Self::BottomRight => Self::Right, - } - } - pub fn down(self) -> Self { - match self { - Self::Bottom | Self::BottomLeft | Self::BottomRight => self, - Self::TopLeft => Self::Left, - Self::Top => Self::None, - Self::TopRight => Self::Right, - Self::Left => Self::BottomLeft, - Self::None => Self::Bottom, - Self::Right => Self::BottomRight, - } - } - pub fn left(self) -> Self { - match self { - Self::TopLeft | Self::Left | Self::BottomLeft => self, - Self::Top => Self::TopLeft, - Self::None => Self::Left, - Self::Bottom => Self::BottomLeft, - Self::TopRight => Self::Top, - Self::Right => Self::None, - Self::BottomRight => Self::Bottom, - } - } - pub fn right(self) -> Self { - match self { - Self::TopRight | Self::Right | Self::BottomRight => self, - Self::Top => Self::TopRight, - Self::None => Self::Right, - Self::Bottom => Self::BottomRight, - Self::TopLeft => Self::Top, - Self::Left => Self::None, - Self::BottomLeft => Self::Bottom, - } - } - pub fn neg(self) -> Self { - match self { - Self::TopLeft => Self::BottomRight, - Self::Top => Self::Bottom, - Self::TopRight => Self::BottomLeft, - Self::Left => Self::Right, - Self::None => Self::None, - Self::Right => Self::Left, - Self::BottomLeft => Self::TopRight, - Self::Bottom => Self::Top, - Self::BottomRight => Self::TopLeft, - } - } - - pub fn iter(none: bool, diagonal: bool, straight: bool) -> KartesianIterator { - KartesianIterator { - i: 0, - none, - diagonal, - straight, - } - } -} - -impl Display for KartesianDirection { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let _ = match *self { - Self::Top | Self::TopLeft | Self::TopRight => f.write_str("top"), - Self::Bottom | Self::BottomLeft | Self::BottomRight => f.write_str("bottom"), - Self::None => return f.write_str("none"), - _ => std::fmt::Result::Ok(()), - }; - let _ = match *self { - Self::TopLeft | Self::Left | Self::BottomLeft => f.write_str("left"), - Self::TopRight | Self::Right | Self::BottomRight => f.write_str("right"), - _ => std::fmt::Result::Ok(()), - }; - std::fmt::Result::Ok(()) - } -} - -pub struct KartesianIterator { - i: u8, - diagonal: bool, - none: bool, - straight: bool, -} - -impl Iterator for KartesianIterator { - type Item = KartesianDirection; - - fn next(&mut self) -> Option { - let mut i = self.i; - if self.straight { - if i < 4 { - self.i += 1; - } - match i { - 0 => return Some(KartesianDirection::Right), - 1 => return Some(KartesianDirection::Bottom), - 2 => return Some(KartesianDirection::Left), - 3 => return Some(KartesianDirection::Top), - _ => i -= 4, - } - } - if self.none { - if i == 0 { - self.i += 1; - return Some(KartesianDirection::None); - } - i -= 1; - } - if self.diagonal { - if i < 4 { - self.i += 1; - } - match i { - 0 => return Some(KartesianDirection::TopLeft), - 1 => return Some(KartesianDirection::TopRight), - 2 => return Some(KartesianDirection::BottomLeft), - 3 => return Some(KartesianDirection::BottomRight), - _ => {}, - } - } - None - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_clockwise() { - let mut current = KartesianDirection::Top; - let clock = [ - KartesianDirection::Top, - KartesianDirection::TopRight, - KartesianDirection::Right, - KartesianDirection::BottomRight, - KartesianDirection::Bottom, - KartesianDirection::BottomLeft, - KartesianDirection::Left, - KartesianDirection::TopLeft, - ]; - for hand in clock { - assert_eq!(current, hand); - current = current.clockwise(true); - } - } - #[test] - fn test_anticlockwise() { - let mut current = KartesianDirection::Top; - let clock = [ - KartesianDirection::Top, - KartesianDirection::TopLeft, - KartesianDirection::Left, - KartesianDirection::BottomLeft, - KartesianDirection::Bottom, - KartesianDirection::BottomRight, - KartesianDirection::Right, - KartesianDirection::TopRight, - ]; - for hand in clock { - assert_eq!(current, hand); - current = current.anticlockwise(true); - } - } - - #[test] - fn test_kartesian_iter() { - let test: Vec<_> = [ - KartesianDirection::Right, - KartesianDirection::Top, - KartesianDirection::Left, - KartesianDirection::Bottom, - KartesianDirection::None, - KartesianDirection::TopLeft, - KartesianDirection::TopRight, - KartesianDirection::BottomLeft, - KartesianDirection::BottomRight, - ] - .into(); - let i: Vec<_> = KartesianDirection::iter(true, true, true).collect(); - assert_eq!(i, test); - let test: Vec<_> = [ - KartesianDirection::Right, - KartesianDirection::Top, - KartesianDirection::Left, - KartesianDirection::Bottom, - KartesianDirection::TopLeft, - KartesianDirection::TopRight, - KartesianDirection::BottomLeft, - KartesianDirection::BottomRight, - ] - .into(); - let i: Vec<_> = KartesianDirection::iter(false, true, true).collect(); - assert_eq!(i, test); - } - - #[test] - fn test_diff_dir() { - const START: Kartesian = Kartesian::new(1, 1); - // Top Group - assert_eq!(KartesianDirection::TopLeft, START.diff(Kartesian::new(0, 0)).1); - assert_eq!(KartesianDirection::Top, START.diff(Kartesian::new(0, 1)).1); - assert_eq!(KartesianDirection::TopRight, START.diff(Kartesian::new(0, 2)).1); - // Same Line - assert_eq!(KartesianDirection::Left, START.diff(Kartesian::new(1, 0)).1); - assert_eq!(KartesianDirection::None, START.diff(Kartesian::new(1, 1)).1); - assert_eq!(KartesianDirection::Right, START.diff(Kartesian::new(1, 2)).1); - // Below/Bottom Line - assert_eq!(KartesianDirection::BottomLeft, START.diff(Kartesian::new(2, 0)).1); - assert_eq!(KartesianDirection::Bottom, START.diff(Kartesian::new(2, 1)).1); - assert_eq!(KartesianDirection::BottomRight, START.diff(Kartesian::new(2, 2)).1); - } -} diff --git a/src/coordinate_systems/kartesian/direction.rs b/src/coordinate_systems/kartesian/direction.rs new file mode 100644 index 0000000..f79733f --- /dev/null +++ b/src/coordinate_systems/kartesian/direction.rs @@ -0,0 +1,152 @@ +use std::fmt::Display; + +use super::{Kartesian, KartesianIterator}; +use num::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum KartesianDirection { + TopLeft, + Top, + TopRight, + Left, + None, + Right, + BottomLeft, + Bottom, + BottomRight, +} + +impl KartesianDirection { + pub fn vector(self) -> Kartesian { + Kartesian { + x: match self { + Self::Left | Self::None | Self::Right => T::zero(), + _ => T::one(), + }, + y: match self { + Self::Top | Self::None | Self::Bottom => T::zero(), + _ => T::one(), + }, + } + } + + #[inline] + pub fn vector_abs>(self) -> Kartesian { + self.vector() + } + + pub fn clockwise(self, diagonal: bool) -> Self { + match (self, diagonal) { + (Self::TopLeft, _) => Self::Top, + (Self::Top, true) => Self::TopRight, + (Self::Top, false) => Self::Right, + (Self::TopRight, _) => Self::Right, + (Self::Right, true) => Self::BottomRight, + (Self::Right, false) => Self::Bottom, + (Self::BottomRight, _) => Self::Bottom, + (Self::Bottom, true) => Self::BottomLeft, + (Self::Bottom, false) => Self::Left, + (Self::BottomLeft, _) => Self::Left, + (Self::Left, true) => Self::TopLeft, + (Self::Left, false) => Self::Top, + (Self::None, _) => Self::None, + } + } + + pub fn anticlockwise(self, diagonal: bool) -> Self { + match (self, diagonal) { + (Self::TopLeft, _) => Self::Left, + (Self::Left, true) => Self::BottomLeft, + (Self::Left, false) => Self::Bottom, + (Self::BottomLeft, _) => Self::Bottom, + (Self::Bottom, true) => Self::BottomRight, + (Self::Bottom, false) => Self::Right, + (Self::BottomRight, _) => Self::Right, + (Self::Right, true) => Self::TopRight, + (Self::Right, false) => Self::Top, + (Self::TopRight, _) => Self::Top, + (Self::Top, true) => Self::TopLeft, + (Self::Top, false) => Self::Left, + (Self::None, _) => Self::None, + } + } + + pub fn up(self) -> Self { + match self { + Self::Top | Self::TopLeft | Self::TopRight => self, + Self::Left => Self::TopLeft, + Self::None => Self::Top, + Self::Right => Self::TopRight, + Self::BottomLeft => Self::Left, + Self::Bottom => Self::None, + Self::BottomRight => Self::Right, + } + } + pub fn down(self) -> Self { + match self { + Self::Bottom | Self::BottomLeft | Self::BottomRight => self, + Self::TopLeft => Self::Left, + Self::Top => Self::None, + Self::TopRight => Self::Right, + Self::Left => Self::BottomLeft, + Self::None => Self::Bottom, + Self::Right => Self::BottomRight, + } + } + pub fn left(self) -> Self { + match self { + Self::TopLeft | Self::Left | Self::BottomLeft => self, + Self::Top => Self::TopLeft, + Self::None => Self::Left, + Self::Bottom => Self::BottomLeft, + Self::TopRight => Self::Top, + Self::Right => Self::None, + Self::BottomRight => Self::Bottom, + } + } + pub fn right(self) -> Self { + match self { + Self::TopRight | Self::Right | Self::BottomRight => self, + Self::Top => Self::TopRight, + Self::None => Self::Right, + Self::Bottom => Self::BottomRight, + Self::TopLeft => Self::Top, + Self::Left => Self::None, + Self::BottomLeft => Self::Bottom, + } + } + pub fn neg(self) -> Self { + match self { + Self::TopLeft => Self::BottomRight, + Self::Top => Self::Bottom, + Self::TopRight => Self::BottomLeft, + Self::Left => Self::Right, + Self::None => Self::None, + Self::Right => Self::Left, + Self::BottomLeft => Self::TopRight, + Self::Bottom => Self::Top, + Self::BottomRight => Self::TopLeft, + } + } + + pub fn iter(none: bool, diagonal: bool, straight: bool) -> KartesianIterator { + KartesianIterator { i: 0, none, diagonal, straight } + } +} + +impl Display for KartesianDirection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let _ = match *self { + Self::Top | Self::TopLeft | Self::TopRight => f.write_str("top"), + Self::Bottom | Self::BottomLeft | Self::BottomRight => f.write_str("bottom"), + Self::None => return f.write_str("none"), + _ => std::fmt::Result::Ok(()), + }; + let _ = match *self { + Self::TopLeft | Self::Left | Self::BottomLeft => f.write_str("left"), + Self::TopRight | Self::Right | Self::BottomRight => f.write_str("right"), + _ => std::fmt::Result::Ok(()), + }; + std::fmt::Result::Ok(()) + } +} diff --git a/src/coordinate_systems/kartesian/map.rs b/src/coordinate_systems/kartesian/map.rs new file mode 100644 index 0000000..a848e35 --- /dev/null +++ b/src/coordinate_systems/kartesian/map.rs @@ -0,0 +1,109 @@ +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 { + maximum: Kartesian, + 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), + } + } + /// 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]) + } + } + + /// 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 coord.x >= self.maximum.x || coord.y >= self.maximum.y { + 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)), + } + } +} diff --git a/src/coordinate_systems/kartesian/maximum.rs b/src/coordinate_systems/kartesian/maximum.rs new file mode 100644 index 0000000..16b7162 --- /dev/null +++ b/src/coordinate_systems/kartesian/maximum.rs @@ -0,0 +1,39 @@ +use super::Kartesian; +use num::*; + +pub trait MaximumFromMap { + fn maximum(map: &Vec>) -> Kartesian; +} + +impl MaximumFromMap for Kartesian { + fn maximum(map: &Vec>) -> Kartesian { + Kartesian { + x: map.len().to_u32().unwrap(), + y: map[0].len().to_u32().unwrap(), + } + } +} + +impl MaximumFromMap for Kartesian { + fn maximum(map: &Vec>) -> Kartesian { + Kartesian { + x: map.len().to_u64().unwrap(), + y: map[0].len().to_u64().unwrap(), + } + } +} + +impl MaximumFromMap for Kartesian { + fn maximum(map: &Vec>) -> Kartesian { + Kartesian { + x: map.len().to_u128().unwrap(), + y: map[0].len().to_u128().unwrap(), + } + } +} + +impl MaximumFromMap for Kartesian { + fn maximum(map: &Vec>) -> Kartesian { + Kartesian { x: map.len(), y: map[0].len() } + } +} diff --git a/src/coordinate_systems/kartesian/mod.rs b/src/coordinate_systems/kartesian/mod.rs new file mode 100644 index 0000000..ecda19e --- /dev/null +++ b/src/coordinate_systems/kartesian/mod.rs @@ -0,0 +1,258 @@ +use log::debug; +use num::*; +use std::{ + fmt::{Debug, Display}, + ops::*, +}; + +pub mod direction; +pub mod map; +pub mod maximum; +mod test; +pub use direction::*; +pub use map::*; +pub use maximum::*; + +pub type KD = KartesianDirection; + +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Kartesian +where + T: Integer, +{ + pub x: T, + pub y: T, +} + +impl Add for Kartesian { + fn add(self, rhs: Self) -> Self::Output { + Kartesian { x: self.x + rhs.x, y: self.y + rhs.y } + } + + type Output = Kartesian; +} + +impl AddAssign for Kartesian { + fn add_assign(&mut self, rhs: Self) { + self.x += rhs.x; + self.y += rhs.y; + } +} + +impl Sub for Kartesian { + fn sub(self, rhs: Self) -> Self::Output { + Kartesian { x: self.x - rhs.x, y: self.y - rhs.y } + } + + type Output = Kartesian; +} + +impl SubAssign for Kartesian { + fn sub_assign(&mut self, rhs: Self) { + self.x -= rhs.x; + self.y -= rhs.y; + } +} + +impl Kartesian { + pub const fn new(x: T, y: T) -> Self { + Self { x: x, y: y } + } +} + +impl Kartesian { + pub fn get_value(self, map: &Vec>) -> Option { + if map.len() > self.x { + if map[self.x].len() > self.y { + return Some(map[self.x][self.y]); + } + } + + None + } +} + +impl Kartesian { + pub fn checked_add_max(self, rhs: Kartesian, max: Kartesian) -> Option> { + let mut new = Kartesian::default(); + new.x = match self.x.checked_add(&rhs.x) { + None => return None, + Some(x) => { + if x < T::default() || x >= max.x { + return None; + } + x + }, + }; + new.y = match self.y.checked_add(&rhs.y) { + None => return None, + Some(y) => { + if y < T::default() || y >= max.y { + return None; + } + y + }, + }; + Some(new) + } + pub fn checked_sub(self, rhs: Kartesian) -> Option> { + let mut new = Kartesian::default(); + new.x = match self.x.checked_sub(&rhs.x) { + None => return None, + Some(x) => x, + }; + new.y = match self.y.checked_sub(&rhs.y) { + None => return None, + Some(y) => y, + }; + Some(new) + } + + pub fn diff(self, rhs: Kartesian) -> (Kartesian, KartesianDirection) { + let mut relative = Kartesian::::default(); + let mut dir = KartesianDirection::None; + debug!("{:?} <> {:?}", self.x, rhs.x); + if self.x < rhs.x { + dir = dir.down(); + relative.x = rhs.x - self.x; + } else if self.x > rhs.x { + dir = dir.up(); + relative.x = self.x - rhs.x; + } + debug!("{:?} <> {:?}", self.x, rhs.x); + if self.y < rhs.y { + dir = dir.right(); + relative.y = rhs.y - self.y; + } else if self.y > rhs.y { + dir = dir.left(); + relative.y = self.y - rhs.y; + } + (relative, dir) + } + + #[inline] + pub fn move_dir(self, vector: Kartesian, dir: KartesianDirection) -> Option> { + let mut new = self; + match dir { + KartesianDirection::TopLeft | KartesianDirection::Top | KartesianDirection::TopRight => { + new.x = match new.x.checked_sub(&vector.x) { + None => return None, + Some(d) => d, + } + }, + KartesianDirection::BottomLeft | KartesianDirection::Bottom | KartesianDirection::BottomRight => { + new.x = match new.x.checked_add(&vector.x) { + None => return None, + Some(d) => d, + } + }, + _ => {}, + } + match dir { + KartesianDirection::TopLeft | KartesianDirection::Left | KartesianDirection::BottomLeft => { + new.y = match new.y.checked_sub(&vector.y) { + None => return None, + Some(d) => d, + } + }, + KartesianDirection::TopRight | KartesianDirection::Right | KartesianDirection::BottomRight => { + new.y = match new.y.checked_add(&vector.y) { + None => return None, + Some(d) => d, + } + }, + _ => {}, + } + Some(new) + } + + #[inline] + pub fn move_dir_max(self, vector: Kartesian, dir: KartesianDirection, max: Kartesian) -> Option> { + match self.move_dir(vector, dir) { + None => None, + Some(new) => { + if new.x < max.x && new.y < max.y { + Some(new) + } else { + None + } + }, + } + } +} + +impl Display for Kartesian { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{}:{}", self.x, self.y)) + } +} + +impl Div for Kartesian { + type Output = Kartesian; + fn div(self, rhs: T) -> Self::Output { + Kartesian { + x: self.x.div_ceil(&rhs), + y: self.y.div_ceil(&rhs), + } + } +} + +impl Rem for Kartesian { + type Output = Self; + fn rem(self, rhs: Self) -> Self { + Kartesian { x: self.x % rhs.x, y: self.y % rhs.y } + } +} +impl RemAssign for Kartesian { + fn rem_assign(&mut self, rhs: Self) { + self.x %= rhs.x; + self.y %= rhs.y; + } +} + +pub struct KartesianIterator { + i: u8, + diagonal: bool, + none: bool, + straight: bool, +} + +impl Iterator for KartesianIterator { + type Item = KartesianDirection; + + fn next(&mut self) -> Option { + let mut i = self.i; + if self.straight { + if i < 4 { + self.i += 1; + } + match i { + 0 => return Some(KartesianDirection::Right), + 1 => return Some(KartesianDirection::Bottom), + 2 => return Some(KartesianDirection::Left), + 3 => return Some(KartesianDirection::Top), + _ => i -= 4, + } + } + if self.none { + if i == 0 { + self.i += 1; + return Some(KartesianDirection::None); + } + i -= 1; + } + if self.diagonal { + if i < 4 { + self.i += 1; + } + match i { + 0 => return Some(KartesianDirection::TopLeft), + 1 => return Some(KartesianDirection::TopRight), + 2 => return Some(KartesianDirection::BottomLeft), + 3 => return Some(KartesianDirection::BottomRight), + _ => {}, + } + } + None + } +} diff --git a/src/coordinate_systems/kartesian/test.rs b/src/coordinate_systems/kartesian/test.rs new file mode 100644 index 0000000..c62e33b --- /dev/null +++ b/src/coordinate_systems/kartesian/test.rs @@ -0,0 +1,87 @@ +#[cfg(test)] +use super::*; + + #[test] + fn test_clockwise() { + let mut current = KartesianDirection::Top; + let clock = [ + KartesianDirection::Top, + KartesianDirection::TopRight, + KartesianDirection::Right, + KartesianDirection::BottomRight, + KartesianDirection::Bottom, + KartesianDirection::BottomLeft, + KartesianDirection::Left, + KartesianDirection::TopLeft, + ]; + for hand in clock { + assert_eq!(current, hand); + current = current.clockwise(true); + } + } + #[test] + fn test_anticlockwise() { + let mut current = KartesianDirection::Top; + let clock = [ + KartesianDirection::Top, + KartesianDirection::TopLeft, + KartesianDirection::Left, + KartesianDirection::BottomLeft, + KartesianDirection::Bottom, + KartesianDirection::BottomRight, + KartesianDirection::Right, + KartesianDirection::TopRight, + ]; + for hand in clock { + assert_eq!(current, hand); + current = current.anticlockwise(true); + } + } + + #[test] + fn test_kartesian_iter() { + let test: Vec<_> = [ + KartesianDirection::Right, + KartesianDirection::Top, + KartesianDirection::Left, + KartesianDirection::Bottom, + KartesianDirection::None, + KartesianDirection::TopLeft, + KartesianDirection::TopRight, + KartesianDirection::BottomLeft, + KartesianDirection::BottomRight, + ] + .into(); + let i: Vec<_> = KartesianDirection::iter(true, true, true).collect(); + assert_eq!(i, test); + let test: Vec<_> = [ + KartesianDirection::Right, + KartesianDirection::Top, + KartesianDirection::Left, + KartesianDirection::Bottom, + KartesianDirection::TopLeft, + KartesianDirection::TopRight, + KartesianDirection::BottomLeft, + KartesianDirection::BottomRight, + ] + .into(); + let i: Vec<_> = KartesianDirection::iter(false, true, true).collect(); + assert_eq!(i, test); + } + + #[test] + fn test_diff_dir() { + const START: Kartesian = Kartesian::new(1, 1); + // Top Group + assert_eq!(KartesianDirection::TopLeft, START.diff(Kartesian::new(0, 0)).1); + assert_eq!(KartesianDirection::Top, START.diff(Kartesian::new(0, 1)).1); + assert_eq!(KartesianDirection::TopRight, START.diff(Kartesian::new(0, 2)).1); + // Same Line + assert_eq!(KartesianDirection::Left, START.diff(Kartesian::new(1, 0)).1); + assert_eq!(KartesianDirection::None, START.diff(Kartesian::new(1, 1)).1); + assert_eq!(KartesianDirection::Right, START.diff(Kartesian::new(1, 2)).1); + // Below/Bottom Line + assert_eq!(KartesianDirection::BottomLeft, START.diff(Kartesian::new(2, 0)).1); + assert_eq!(KartesianDirection::Bottom, START.diff(Kartesian::new(2, 1)).1); + assert_eq!(KartesianDirection::BottomRight, START.diff(Kartesian::new(2, 2)).1); + } \ No newline at end of file