use num::*; use std::ops::*; #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)] 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 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) } } #[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 { const BELOW: i8 = -1; const ON: i8 = 0; const UPPER: i8 = 1; Kartesian:: { x: match self { Self::TopLeft | Self::Top | Self::TopRight => BELOW.into(), Self::Left | Self::None | Self::Right => ON.into(), Self::BottomLeft | Self::Bottom | Self::BottomRight => UPPER.into(), }, y: match self { Self::TopLeft | Self::Left | Self::BottomLeft => BELOW.into(), Self::Top | Self::None | Self::Bottom => ON.into(), Self::TopRight | Self::Right | Self::BottomRight => UPPER.into(), }, } } pub fn clockwise(self, diagonal: bool) -> KartesianDirection { match (self, diagonal) { (KartesianDirection::TopLeft, _) => Self::Top, (KartesianDirection::Top, true) => Self::TopRight, (KartesianDirection::Top, false) => Self::Right, (KartesianDirection::TopRight, _) => Self::Right, (KartesianDirection::Left, true) => Self::TopLeft, (KartesianDirection::Left, false) => Self::Top, (KartesianDirection::None, _) => Self::None, (KartesianDirection::Right, true) => Self::BottomRight, (KartesianDirection::Right, false) => Self::Bottom, (KartesianDirection::BottomLeft, _) => Self::Left, (KartesianDirection::Bottom, true) => Self::BottomLeft, (KartesianDirection::Bottom, false) => Self::Left, (KartesianDirection::BottomRight, _) => Self::Bottom, } } pub fn anticlockwise(self, diagonal: bool) -> KartesianDirection { match (self, diagonal) { (KartesianDirection::TopLeft, _) => Self::Left, (KartesianDirection::Top, true) => Self::TopLeft, (KartesianDirection::Top, false) => Self::Left, (KartesianDirection::TopRight, _) => Self::Top, (KartesianDirection::Left, true) => Self::BottomLeft, (KartesianDirection::Left, false) => Self::Bottom, (KartesianDirection::None, _) => Self::None, (KartesianDirection::Right, true) => Self::TopRight, (KartesianDirection::Right, false) => Self::Top, (KartesianDirection::BottomLeft, _) => Self::Bottom, (KartesianDirection::Bottom, true) => Self::BottomRight, (KartesianDirection::Bottom, false) => Self::Right, (KartesianDirection::BottomRight, _) => Self::Right, } } } #[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); } } }