solved part 1 of day 14 of 2024
Dieser Commit ist enthalten in:
Ursprung
6236636fc9
Commit
49262fba4a
13 geänderte Dateien mit 639 neuen und 184 gelöschten Zeilen
14
Cargo.lock
generiert
14
Cargo.lock
generiert
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
15
Makefile
Normale Datei
15
Makefile
Normale Datei
|
@ -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}
|
12
examples/2024/14.txt
Normale Datei
12
examples/2024/14.txt
Normale Datei
|
@ -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
|
17
rustfmt.toml
Normale Datei
17
rustfmt.toml
Normale Datei
|
@ -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
|
126
src/bin/2024/14.rs
Normale Datei
126
src/bin/2024/14.rs
Normale Datei
|
@ -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<u32>, Velocity<u32>) {
|
||||
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<Kartesian<u32>>, space: Kartesian<u32>) -> (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<u32> = 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));
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
142
src/coordinate_systems/kartesian/external_traits.rs
Normale Datei
142
src/coordinate_systems/kartesian/external_traits.rs
Normale Datei
|
@ -0,0 +1,142 @@
|
|||
use super::{Kartesian, KartesianDirection, KartesianIterator};
|
||||
use super::{Map, Velocity};
|
||||
use num::*;
|
||||
use std::{fmt::Display, ops::*};
|
||||
|
||||
impl<T: Integer> Add for Kartesian<T> {
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Kartesian { x: self.x + rhs.x, y: self.y + rhs.y }
|
||||
}
|
||||
|
||||
type Output = Kartesian<T>;
|
||||
}
|
||||
|
||||
impl<T: Integer + AddAssign> AddAssign for Kartesian<T> {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.x += rhs.x;
|
||||
self.y += rhs.y;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Integer> Sub for Kartesian<T> {
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Kartesian { x: self.x - rhs.x, y: self.y - rhs.y }
|
||||
}
|
||||
|
||||
type Output = Kartesian<T>;
|
||||
}
|
||||
|
||||
impl<T: Integer + SubAssign> SubAssign for Kartesian<T> {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
self.x -= rhs.x;
|
||||
self.y -= rhs.y;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Integer + Display + Copy> Display for Kartesian<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("{}:{}", self.x, self.y))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Integer + Copy> Div<T> for Kartesian<T> {
|
||||
type Output = Kartesian<T>;
|
||||
fn div(self, rhs: T) -> Self::Output {
|
||||
Kartesian {
|
||||
x: self.x.div_ceil(&rhs),
|
||||
y: self.y.div_ceil(&rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Integer + Rem> Rem for Kartesian<T> {
|
||||
type Output = Self;
|
||||
fn rem(self, rhs: Self) -> Self {
|
||||
Kartesian { x: self.x % rhs.x, y: self.y % rhs.y }
|
||||
}
|
||||
}
|
||||
impl<T: Integer + RemAssign> RemAssign for Kartesian<T> {
|
||||
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<Self::Item> {
|
||||
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<T: Display + Copy + Default> Display for Map<T> {
|
||||
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<T: Integer + Display + Unsigned + Copy> Display for Velocity<T> {
|
||||
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(())
|
||||
}
|
||||
}
|
|
@ -3,12 +3,12 @@ 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<T: Clone+Copy> {
|
||||
maximum: Kartesian<usize>,
|
||||
data: Vec<Vec<T>>,
|
||||
pub struct Map<T: Clone + Copy> {
|
||||
pub(super) maximum: Kartesian<usize>,
|
||||
pub(super) data: Vec<Vec<T>>,
|
||||
}
|
||||
|
||||
impl<T: Clone+Copy> Map<T> {
|
||||
impl<T: Clone + Copy> Map<T> {
|
||||
/// creates an empty Map
|
||||
pub fn empty(length: usize, height: usize) -> Self {
|
||||
Self {
|
||||
|
@ -16,6 +16,7 @@ impl<T: Clone+Copy> Map<T> {
|
|||
maximum: Kartesian::new(height, length),
|
||||
}
|
||||
}
|
||||
|
||||
/// returns true if coordinates are outside of bounds
|
||||
#[inline]
|
||||
fn outside(&self, coord: Kartesian<usize>) -> bool {
|
||||
|
@ -25,7 +26,7 @@ impl<T: Clone+Copy> Map<T> {
|
|||
/// 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<usize>) ->T{
|
||||
pub unsafe fn get_unsafe(&self, coord: Kartesian<usize>) -> T {
|
||||
if self.outside(coord) {
|
||||
panic!("Coordinates out of bounds: {} >= {}", coord, self.maximum)
|
||||
}
|
||||
|
@ -33,7 +34,7 @@ impl<T: Clone+Copy> Map<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy +Copy+ Default> Map<T> {
|
||||
impl<T: Copy + Copy + Default + PartialEq> Map<T> {
|
||||
/// Returns an Option Containing the value.
|
||||
/// Returns None if out of bounds or not yet set.
|
||||
pub fn get(&self, coord: Kartesian<usize>) -> Option<T> {
|
||||
|
@ -49,6 +50,29 @@ impl<T: Copy +Copy+ Default> Map<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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<usize>) -> T {
|
||||
|
@ -63,7 +87,7 @@ impl<T: Copy +Copy+ Default> Map<T> {
|
|||
}
|
||||
|
||||
pub fn set(&mut self, coord: Kartesian<usize>, 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<T: Copy +Copy+ Default> Map<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Clone+Copy> From<Vec<Vec<T>>> for Map<T> {
|
||||
impl<T: Clone + Copy> From<Vec<Vec<T>>> for Map<T> {
|
||||
fn from(value: Vec<Vec<T>>) -> Self {
|
||||
Map {
|
||||
data: value.clone(),
|
||||
|
|
|
@ -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<usize>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Kartesian<T>
|
||||
where
|
||||
|
@ -24,42 +31,58 @@ where
|
|||
pub y: T,
|
||||
}
|
||||
|
||||
impl<T: Integer> Add for Kartesian<T> {
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Kartesian { x: self.x + rhs.x, y: self.y + rhs.y }
|
||||
}
|
||||
|
||||
type Output = Kartesian<T>;
|
||||
}
|
||||
|
||||
impl<T: Integer + AddAssign> AddAssign for Kartesian<T> {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.x += rhs.x;
|
||||
self.y += rhs.y;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Integer> Sub for Kartesian<T> {
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Kartesian { x: self.x - rhs.x, y: self.y - rhs.y }
|
||||
}
|
||||
|
||||
type Output = Kartesian<T>;
|
||||
}
|
||||
|
||||
impl<T: Integer + SubAssign> SubAssign for Kartesian<T> {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
self.x -= rhs.x;
|
||||
self.y -= rhs.y;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Integer> Kartesian<T> {
|
||||
pub const fn new(x: T, y: T) -> Self {
|
||||
Self { x: x, y: y }
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCoords for Kartesian<u8> {
|
||||
fn to_coords(self) -> Kartesian<usize> {
|
||||
Kartesian { x: self.x as usize, y: self.y as usize }
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCoords for Kartesian<u16> {
|
||||
fn to_coords(self) -> Kartesian<usize> {
|
||||
Kartesian { x: self.x as usize, y: self.y as usize }
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCoords for Kartesian<u32> {
|
||||
fn to_coords(self) -> Kartesian<usize> {
|
||||
Kartesian { x: self.x as usize, y: self.y as usize }
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCoords for Kartesian<u64> {
|
||||
fn to_coords(self) -> Kartesian<usize> {
|
||||
Kartesian { x: self.x as usize, y: self.y as usize }
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCoords for Kartesian<u128> {
|
||||
fn to_coords(self) -> Kartesian<usize> {
|
||||
Kartesian { x: self.x as usize, y: self.y as usize }
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCoords for Kartesian<usize> {
|
||||
fn to_coords(self) -> Kartesian<usize> {
|
||||
Kartesian { x: self.x, y: self.y }
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap<T: Integer + Rem + MaximumValue + From<u32> + 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<usize> {
|
||||
pub fn get_value<T: Copy>(self, map: &Vec<Vec<T>>) -> Option<T> {
|
||||
if map.len() > self.x {
|
||||
|
@ -72,7 +95,7 @@ impl Kartesian<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Integer + Eq + Debug + CheckedAdd + CheckedSub + Default + Copy> Kartesian<T> {
|
||||
impl<T: Integer + Eq + Debug + CheckedBasicMath + Default + Copy> Kartesian<T> {
|
||||
pub fn checked_add_max(self, rhs: Kartesian<T>, max: Kartesian<T>) -> Option<Kartesian<T>> {
|
||||
let mut new = Kartesian::default();
|
||||
new.x = match self.x.checked_add(&rhs.x) {
|
||||
|
@ -181,32 +204,72 @@ impl<T: Integer + Eq + Debug + CheckedAdd + CheckedSub + Default + Copy> Kartesi
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Integer + Display + Copy> Display for Kartesian<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("{}:{}", self.x, self.y))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Integer + Copy> Div<T> for Kartesian<T> {
|
||||
type Output = Kartesian<T>;
|
||||
fn div(self, rhs: T) -> Self::Output {
|
||||
Kartesian {
|
||||
x: self.x.div_ceil(&rhs),
|
||||
y: self.y.div_ceil(&rhs),
|
||||
impl<T: Integer + Unsigned + CheckedBasicMath> Kartesian<T> {
|
||||
pub fn move_velocity(self, velocity: Velocity<T>, max: Kartesian<T>) -> Option<Kartesian<T>> {
|
||||
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<T: Integer + Rem> Rem for Kartesian<T> {
|
||||
type Output = Self;
|
||||
fn rem(self, rhs: Self) -> Self {
|
||||
Kartesian { x: self.x % rhs.x, y: self.y % rhs.y }
|
||||
}
|
||||
}
|
||||
impl<T: Integer + RemAssign> RemAssign for Kartesian<T> {
|
||||
fn rem_assign(&mut self, rhs: Self) {
|
||||
self.x %= rhs.x;
|
||||
self.y %= rhs.y;
|
||||
impl<T: Integer + Display + Unsigned + WrappingAdd + WrappingSub + MaximumValue + From<u32> + Copy> Kartesian<T> {
|
||||
pub fn wrapping_move_velocity(self, velocity: Velocity<T>, max: Kartesian<T>) -> Kartesian<T> {
|
||||
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<T: Integer + Unsigned> {
|
||||
speed: Kartesian<T>,
|
||||
direction: KartesianDirection,
|
||||
}
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
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<T: Integer + Unsigned> Velocity<T> {
|
||||
pub fn new(x: T, y: T, dir: KartesianDirection) -> Self {
|
||||
Velocity { speed: Kartesian { x, y }, direction: dir }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<u8> = 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 diff_dir() {
|
||||
const START: Kartesian<u8> = 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<u32> = 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::<u32>::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::<u32, 10>(11, 11), 0)
|
||||
}
|
||||
|
|
43
src/coordinate_systems/kartesian/traits.rs
Normale Datei
43
src/coordinate_systems/kartesian/traits.rs
Normale Datei
|
@ -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<T: CheckedAdd + CheckedSub> 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);
|
|
@ -4,7 +4,7 @@ use std::ops::AddAssign;
|
|||
#[inline]
|
||||
pub fn char_to_num<T: Integer + From<u32>>(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<T: Integer + From<u32>>(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!(),
|
||||
}
|
||||
}
|
||||
|
|
Laden …
Tabelle hinzufügen
In neuem Issue referenzieren