From 49262fba4a3a4b060d37f64624189b146d63b012 Mon Sep 17 00:00:00 2001 From: Sebastian Tobie Date: Sun, 15 Dec 2024 13:22:03 +0100 Subject: [PATCH] solved part 1 of day 14 of 2024 --- Cargo.lock | 14 ++ Cargo.toml | 2 + Makefile | 15 ++ examples/2024/14.txt | 12 + rustfmt.toml | 17 ++ src/bin/2024/14.rs | 126 ++++++++++ src/coordinate_systems/kartesian/direction.rs | 5 +- .../kartesian/external_traits.rs | 142 ++++++++++++ src/coordinate_systems/kartesian/map.rs | 42 +++- src/coordinate_systems/kartesian/mod.rs | 217 ++++++++++-------- src/coordinate_systems/kartesian/test.rs | 183 ++++++++------- src/coordinate_systems/kartesian/traits.rs | 43 ++++ src/strings.rs | 5 +- 13 files changed, 639 insertions(+), 184 deletions(-) create mode 100644 Makefile create mode 100644 examples/2024/14.txt create mode 100644 rustfmt.toml create mode 100644 src/bin/2024/14.rs create mode 100644 src/coordinate_systems/kartesian/external_traits.rs create mode 100644 src/coordinate_systems/kartesian/traits.rs diff --git a/Cargo.lock b/Cargo.lock index 8437ddf..fc7b8b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,8 +7,10 @@ name = "advent-of-code" version = "0.1.0" dependencies = [ "advent-of-code-macros", + "log", "num", "regex", + "thousands", ] [[package]] @@ -35,6 +37,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "memchr" version = "2.7.4" @@ -172,6 +180,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thousands" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" + [[package]] name = "unicode-ident" version = "1.0.14" diff --git a/Cargo.toml b/Cargo.toml index d54fbbf..b93db3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -310,6 +310,8 @@ name = "advent_of_code" [dependencies] num="0.4.*" +log="0.4.*" +thousands="0.2.*" [dependencies.advent-of-code-macros] path = "macros" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9736bc9 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +CARGO:=cargo +CARGO_OPTS:=-q +TARGET_DIR:=debug + +fmt: + @$(CARGO) fmt 2>/dev/null + +%: fmt + @$(CARGO) build $(CARGO_OPTS) --bin $@ + @timeout --preserve-status -v 60 ./target/$(TARGET_DIR)/$@ + +Makefile: + exit + +all: 202{3,4}-{01..25} \ No newline at end of file diff --git a/examples/2024/14.txt b/examples/2024/14.txt new file mode 100644 index 0000000..72a324a --- /dev/null +++ b/examples/2024/14.txt @@ -0,0 +1,12 @@ +p=0,4 v=3,-3 +p=6,3 v=-1,-3 +p=10,3 v=-1,2 +p=2,0 v=2,-1 +p=0,0 v=1,3 +p=3,0 v=-2,-2 +p=7,6 v=-1,-3 +p=3,0 v=-1,-2 +p=9,3 v=2,3 +p=7,3 v=-1,2 +p=2,4 v=2,-3 +p=9,5 v=-3,-3 \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..63b0868 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,17 @@ +array_width = 0 +binop_separator= "Back" +brace_style="SameLineWhere" +chain_width = 240 +fn_params_layout = "Tall" +force_explicit_abi = true +hard_tabs = false +imports_layout = "Vertical" +match_block_trailing_comma = true +max_width = 240 +merge_derives = true +newline_style = "Unix" +remove_nested_parens = true +reorder_imports = true +reorder_modules = true +single_line_if_else_max_width = 0 +tab_spaces = 4 diff --git a/src/bin/2024/14.rs b/src/bin/2024/14.rs new file mode 100644 index 0000000..25b0460 --- /dev/null +++ b/src/bin/2024/14.rs @@ -0,0 +1,126 @@ +use advent_of_code::{ + strings::{convert_to_array, parsenumber}, + Kartesian, Velocity, KD, +}; +#[allow(unused_imports)] +use advent_of_code_macros::{include_data, include_example}; + +include_data!(DATA 2024 14); + +fn parse_robot(line: &str) -> (Kartesian, Velocity) { + let mut dir = KD::None; + let mut x = 0; + let mut y = 0; + let mut position = Kartesian::default(); + for part in line.splitn(2, ' ') { + match part.get(0..2).unwrap_or("") { + "p=" => { + let (y, x) = part.get(2..).unwrap().split_once(',').unwrap(); + position.x = parsenumber(x); + position.y = parsenumber(y); + }, + "v=" => { + let (ys, xs) = part.get(2..).unwrap().split_once(',').unwrap(); + x = parsenumber(xs); + y = parsenumber(ys); + dir = if xs.get(0..1).unwrap() == "-" && x != 0 { + dir.up() + } else if x > 0 { + dir.down() + } else { + dir + }; + dir = if ys.get(0..1).unwrap() == "-" && y != 0 { + dir.left() + } else if x > 0 { + dir.right() + } else { + dir + }; + }, + _ => {}, + } + } + + (position, Velocity::new(x, y, dir)) +} + +fn get_end_start(v: u32) -> (u32, u32) { + match v % 2 { + 0 => (v / 2, v / 2), + 1 => ((v - 1) / 2 - 1, (v + 1) / 2), + _ => unreachable!(), + } +} + +fn calc_safety(coords: Vec>, space: Kartesian) -> (u32, u32, u32, u32) { + let mut robots = (0, 0, 0, 0); + let (x_end, x_start) = get_end_start(space.x); + let (y_end, y_start) = get_end_start(space.y); + for robot in coords { + if robot.x <= x_end && robot.y <= y_end { + robots.0 += 1; + } else if robot.x <= x_end && robot.y >= y_start { + robots.1 += 1 + } else if robot.x >= x_start && robot.y <= y_end { + robots.2 += 1 + } else if robot.x >= x_start && robot.y >= y_start { + robots.3 += 1 + } else { + println!("Robot outside of quarts {}:", robot); + println!("1. {}..={}:{}..={}", 0, x_end, 0, y_end); + println!("2. {}..={}:{}..={}", 0, x_end, y_start, space.y - 1); + println!("3. {}..={}:{}..={}", x_start, space.x - 1, 0, y_end); + println!("4. {}..={}:{}..={}", x_start, space.x - 1, y_start, space.y - 1); + } + } + println!("Robot in quarts: {}, {}, {}, {}", robots.0, robots.1, robots.2, robots.3); + robots +} + +fn calc_final(r: (u32, u32, u32, u32)) -> u32 { + r.0 * r.1 * r.2 * r.3 +} + +fn main() { + const SPACE: Kartesian = Kartesian::new(103, 101); + + let mut target_coords = Vec::new(); + let robots = convert_to_array::<_, _, '\n'>(DATA, parse_robot); + for (mut position, velocity) in robots { + for _i in 0..100 { + position = position.wrapping_move_velocity(velocity, SPACE); + } + target_coords.push(position); + } + println!("{:?}", target_coords); + println!("Safety Factor: {}", calc_final(calc_safety(target_coords, SPACE))); +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_start_end() { + assert_eq!(get_end_start(7), (2, 4)) + } + #[test] + fn test_safety() { + let positions = vec![ + Kartesian { x: 5, y: 3 }, + Kartesian { x: 4, y: 5 }, + Kartesian { x: 0, y: 9 }, + Kartesian { x: 5, y: 4 }, + Kartesian { x: 6, y: 1 }, + Kartesian { x: 3, y: 1 }, + Kartesian { x: 0, y: 6 }, + Kartesian { x: 3, y: 2 }, + Kartesian { x: 2, y: 0 }, + Kartesian { x: 0, y: 6 }, + Kartesian { x: 5, y: 4 }, + Kartesian { x: 6, y: 6 }, + ]; + assert_eq!(calc_safety(positions, Kartesian::new(7, 11)), (1, 3, 4, 1)); + } +} diff --git a/src/coordinate_systems/kartesian/direction.rs b/src/coordinate_systems/kartesian/direction.rs index f79733f..b504448 100644 --- a/src/coordinate_systems/kartesian/direction.rs +++ b/src/coordinate_systems/kartesian/direction.rs @@ -3,13 +3,14 @@ use std::fmt::Display; use super::{Kartesian, KartesianIterator}; use num::*; -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] pub enum KartesianDirection { + #[default] + None, TopLeft, Top, TopRight, Left, - None, Right, BottomLeft, Bottom, diff --git a/src/coordinate_systems/kartesian/external_traits.rs b/src/coordinate_systems/kartesian/external_traits.rs new file mode 100644 index 0000000..3c90d20 --- /dev/null +++ b/src/coordinate_systems/kartesian/external_traits.rs @@ -0,0 +1,142 @@ +use super::{Kartesian, KartesianDirection, KartesianIterator}; +use super::{Map, Velocity}; +use num::*; +use std::{fmt::Display, ops::*}; + +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 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; + } +} + +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 + } +} + +impl Display for Map { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for row in self.data.iter() { + for v in row.iter() { + v.fmt(f)? + } + for _ in row.len()..=self.maximum.y { + T::default().fmt(f)? + } + println!() + } + for _ in self.data.len()..=self.maximum.x { + for _ in 0..self.maximum.y { + T::default().fmt(f)? + } + println!() + } + Ok(()) + } +} + +impl Display for Velocity { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self.direction { + KartesianDirection::None => "⏺", + KartesianDirection::TopLeft => "↖", + KartesianDirection::Top => "↑", + KartesianDirection::TopRight => "↗", + KartesianDirection::Left => "←", + KartesianDirection::Right => "→", + KartesianDirection::BottomLeft => "↙", + KartesianDirection::Bottom => "↓", + KartesianDirection::BottomRight => "↘", + })?; + self.speed.fmt(f)?; + Ok(()) + } +} diff --git a/src/coordinate_systems/kartesian/map.rs b/src/coordinate_systems/kartesian/map.rs index a848e35..0bcd555 100644 --- a/src/coordinate_systems/kartesian/map.rs +++ b/src/coordinate_systems/kartesian/map.rs @@ -1,14 +1,14 @@ 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 +/// 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>, +pub struct Map { + pub(super) maximum: Kartesian, + pub(super) data: Vec>, } -impl Map { +impl Map { /// creates an empty Map pub fn empty(length: usize, height: usize) -> Self { Self { @@ -16,6 +16,7 @@ impl Map { maximum: Kartesian::new(height, length), } } + /// returns true if coordinates are outside of bounds #[inline] fn outside(&self, coord: Kartesian) -> bool { @@ -25,7 +26,7 @@ impl Map { /// 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{ + pub unsafe fn get_unsafe(&self, coord: Kartesian) -> T { if self.outside(coord) { panic!("Coordinates out of bounds: {} >= {}", coord, self.maximum) } @@ -33,7 +34,7 @@ impl Map { } } -impl Map { +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 { @@ -49,6 +50,29 @@ impl Map { } } + /// 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 { @@ -63,7 +87,7 @@ impl Map { } pub fn set(&mut self, coord: Kartesian, value: T) -> T { - if coord.x >= self.maximum.x || coord.y >= self.maximum.y { + if self.outside(coord) { panic!("Coordinates outside of bounds: {} >= {}", coord, self.maximum) } if self.data.len() < coord.x + 1 { @@ -99,7 +123,7 @@ impl Map { } } -impl From>> for Map { +impl From>> for Map { fn from(value: Vec>) -> Self { Map { data: value.clone(), diff --git a/src/coordinate_systems/kartesian/mod.rs b/src/coordinate_systems/kartesian/mod.rs index ecda19e..aaa66f8 100644 --- a/src/coordinate_systems/kartesian/mod.rs +++ b/src/coordinate_systems/kartesian/mod.rs @@ -1,20 +1,27 @@ use log::debug; -use num::*; +use num::{traits::*, *}; use std::{ fmt::{Debug, Display}, - ops::*, + ops::Rem, }; pub mod direction; +pub mod external_traits; pub mod map; pub mod maximum; mod test; +pub mod traits; pub use direction::*; pub use map::*; pub use maximum::*; +pub use traits::*; pub type KD = KartesianDirection; +pub trait ToCoords: Copy { + fn to_coords(self) -> Kartesian; +} + #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Kartesian where @@ -24,42 +31,58 @@ where 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 ToCoords for Kartesian { + fn to_coords(self) -> Kartesian { + Kartesian { x: self.x as usize, y: self.y as usize } + } +} + +impl ToCoords for Kartesian { + fn to_coords(self) -> Kartesian { + Kartesian { x: self.x as usize, y: self.y as usize } + } +} + +impl ToCoords for Kartesian { + fn to_coords(self) -> Kartesian { + Kartesian { x: self.x as usize, y: self.y as usize } + } +} + +impl ToCoords for Kartesian { + fn to_coords(self) -> Kartesian { + Kartesian { x: self.x as usize, y: self.y as usize } + } +} + +impl ToCoords for Kartesian { + fn to_coords(self) -> Kartesian { + Kartesian { x: self.x as usize, y: self.y as usize } + } +} + +impl ToCoords for Kartesian { + fn to_coords(self) -> Kartesian { + Kartesian { x: self.x, y: self.y } + } +} + +fn wrap + Copy + MaximumValue + Display, const FACTOR: u32>(v: T, max: T) -> T { + if v < max { + v + } else if v < max * T::from(FACTOR) { + v % max + } else { + max - (T::MAX - v) + } +} + impl Kartesian { pub fn get_value(self, map: &Vec>) -> Option { if map.len() > self.x { @@ -72,7 +95,7 @@ impl Kartesian { } } -impl Kartesian { +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) { @@ -181,32 +204,72 @@ impl Kartesi } } -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 Kartesian { + pub fn move_velocity(self, velocity: Velocity, max: Kartesian) -> Option> { + if velocity.direction == KD::None { + return Some(self); } + Some(Kartesian { + x: match velocity.direction { + KD::Left | KD::Right => self.x, + KD::TopLeft | KD::Top | KD::TopRight => match self.x.checked_sub(&velocity.speed.x) { + None => return None, + Some(x) => x, + }, + KD::BottomLeft | KD::Bottom | KD::BottomRight => { + let x = self.x + velocity.speed.x; + if x >= max.x { + return None; + } + x + }, + _ => unreachable!(), + }, + y: match velocity.direction { + KD::Top | KD::Bottom => self.y, + KD::TopLeft | KD::Left | KD::BottomLeft => match self.y.checked_sub(&velocity.speed.y) { + None => return None, + Some(y) => y, + }, + KD::TopRight | KD::Right | KD::BottomRight => { + let y = self.y + velocity.speed.y; + if y >= max.y { + return None; + } + y + }, + _ => unreachable!(), + }, + }) } } -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; +impl + Copy> Kartesian { + pub fn wrapping_move_velocity(self, velocity: Velocity, max: Kartesian) -> Kartesian { + Kartesian { + x: match velocity.direction { + KartesianDirection::TopLeft | KartesianDirection::Top | KartesianDirection::TopRight => { + if self.x < velocity.speed.x { + max.x - (velocity.speed.x - self.x) + } else { + self.x - velocity.speed.x + } + }, + KartesianDirection::Left | KartesianDirection::None | KartesianDirection::Right => self.x, + KartesianDirection::BottomLeft | KartesianDirection::Bottom | KartesianDirection::BottomRight => (self.x + velocity.speed.x) % max.x, + }, + y: match velocity.direction { + KartesianDirection::TopLeft | KartesianDirection::Left | KartesianDirection::BottomLeft => { + if self.y < velocity.speed.y { + max.y - (velocity.speed.y - self.y) + } else { + self.y - velocity.speed.y + } + }, + KartesianDirection::Top | KartesianDirection::None | KartesianDirection::Bottom => self.y, + KartesianDirection::TopRight | KartesianDirection::Right | KartesianDirection::BottomRight => (self.y + velocity.speed.y) % max.y, + }, + } } } @@ -217,42 +280,14 @@ pub struct KartesianIterator { straight: bool, } -impl Iterator for KartesianIterator { - type Item = KartesianDirection; +#[derive(Debug, Default, Clone, Copy)] +pub struct Velocity { + speed: Kartesian, + direction: 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 +impl Velocity { + pub fn new(x: T, y: T, dir: KartesianDirection) -> Self { + Velocity { speed: Kartesian { x, y }, direction: dir } } } diff --git a/src/coordinate_systems/kartesian/test.rs b/src/coordinate_systems/kartesian/test.rs index c62e33b..11afaf5 100644 --- a/src/coordinate_systems/kartesian/test.rs +++ b/src/coordinate_systems/kartesian/test.rs @@ -1,87 +1,110 @@ #[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 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 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 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 +#[test] +fn 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); +} + +#[test] +fn moving_wrapping() { + /* + let max: Kartesian = Kartesian::new(10, 10); + let mut pos = Kartesian::new(0, 0); + let velocity = Velocity::new(1, 1, KartesianDirection::BottomRight); + pos = pos.wrapping_move_velocity(velocity, max); + assert_eq!(pos, Kartesian::new(1, 1)); + for _ in 1..10 { + pos = pos.wrapping_move_velocity(velocity, max); + } + assert_eq!(pos, Kartesian::new(0, 0)); + */ + let max = Kartesian::::new(7, 11); + assert_eq!(Kartesian::new(2, 0).wrapping_move_velocity(Velocity::new(1, 3, KartesianDirection::TopLeft), max), Kartesian::new(1, 9)); + assert_eq!(Kartesian::new(4, 2).wrapping_move_velocity(Velocity::new(3, 2, KartesianDirection::TopRight), max), Kartesian::new(1, 4)) +} + +#[test] +fn test_wrap() { + assert_eq!(wrap::(11, 11), 0) +} diff --git a/src/coordinate_systems/kartesian/traits.rs b/src/coordinate_systems/kartesian/traits.rs new file mode 100644 index 0000000..80f6b58 --- /dev/null +++ b/src/coordinate_systems/kartesian/traits.rs @@ -0,0 +1,43 @@ +use num::*; + +macro_rules! predefined_const { + ($trait_name:ident, $const:ident, $t:ty) => { + impl $trait_name for $t { + const $const: $t = <$t>::$const; + } + }; +} + +pub trait CheckedBasicMath: CheckedAdd + CheckedSub {} +impl CheckedBasicMath for T {} + +pub trait MaximumValue { + const MAX: Self; +} +predefined_const!(MaximumValue, MAX, u8); +predefined_const!(MaximumValue, MAX, u16); +predefined_const!(MaximumValue, MAX, u32); +predefined_const!(MaximumValue, MAX, u64); +predefined_const!(MaximumValue, MAX, u128); +predefined_const!(MaximumValue, MAX, usize); +predefined_const!(MaximumValue, MAX, i8); +predefined_const!(MaximumValue, MAX, i16); +predefined_const!(MaximumValue, MAX, i32); +predefined_const!(MaximumValue, MAX, i64); +predefined_const!(MaximumValue, MAX, i128); +predefined_const!(MaximumValue, MAX, isize); +pub trait MinimumValue { + const MIN: Self; +} +predefined_const!(MinimumValue, MIN, u8); +predefined_const!(MinimumValue, MIN, u16); +predefined_const!(MinimumValue, MIN, u32); +predefined_const!(MinimumValue, MIN, u64); +predefined_const!(MinimumValue, MIN, u128); +predefined_const!(MinimumValue, MIN, usize); +predefined_const!(MinimumValue, MIN, i8); +predefined_const!(MinimumValue, MIN, i16); +predefined_const!(MinimumValue, MIN, i32); +predefined_const!(MinimumValue, MIN, i64); +predefined_const!(MinimumValue, MIN, i128); +predefined_const!(MinimumValue, MIN, isize); diff --git a/src/strings.rs b/src/strings.rs index 9f50e08..507c499 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -4,7 +4,7 @@ use std::ops::AddAssign; #[inline] pub fn char_to_num>(c: char) -> T { match c { - '1' => T::from(1), + '1' => T::one(), '2' => T::from(2), '3' => T::from(3), '4' => T::from(4), @@ -13,7 +13,8 @@ pub fn char_to_num>(c: char) -> T { '7' => T::from(7), '8' => T::from(8), '9' => T::from(9), - '0' => T::from(0), + '0' => T::zero(), + '-' => T::zero(), _ => unreachable!(), } }