Commits vergleichen
6 Commits
78327e8658
...
6fafca3b6b
Autor | SHA1 | Datum | |
---|---|---|---|
6fafca3b6b | |||
49262fba4a | |||
6236636fc9 | |||
b24a6f52c0 | |||
f3339b38e1 | |||
50f451efd2 |
36 geänderte Dateien mit 1892 neuen und 666 gelöschten Zeilen
14
Cargo.lock
generiert
14
Cargo.lock
generiert
|
@ -7,8 +7,10 @@ name = "advent-of-code"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"advent-of-code-macros",
|
"advent-of-code-macros",
|
||||||
|
"log",
|
||||||
"num",
|
"num",
|
||||||
"regex",
|
"regex",
|
||||||
|
"thousands",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -35,6 +37,12 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
|
@ -172,6 +180,12 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thousands"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
|
|
|
@ -310,6 +310,8 @@ name = "advent_of_code"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num="0.4.*"
|
num="0.4.*"
|
||||||
|
log="0.4.*"
|
||||||
|
thousands="0.2.*"
|
||||||
|
|
||||||
[dependencies.advent-of-code-macros]
|
[dependencies.advent-of-code-macros]
|
||||||
path = "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}
|
1
examples/2024/03.txt
Normale Datei
1
examples/2024/03.txt
Normale Datei
|
@ -0,0 +1 @@
|
||||||
|
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))
|
12
examples/2024/08.txt
Normale Datei
12
examples/2024/08.txt
Normale Datei
|
@ -0,0 +1,12 @@
|
||||||
|
............
|
||||||
|
........0...
|
||||||
|
.....0......
|
||||||
|
.......0....
|
||||||
|
....0.......
|
||||||
|
......A.....
|
||||||
|
............
|
||||||
|
............
|
||||||
|
........A...
|
||||||
|
.........A..
|
||||||
|
............
|
||||||
|
............
|
1
examples/2024/11.txt
Normale Datei
1
examples/2024/11.txt
Normale Datei
|
@ -0,0 +1 @@
|
||||||
|
125 17
|
1
examples/2024/12.txt
Softlink
1
examples/2024/12.txt
Softlink
|
@ -0,0 +1 @@
|
||||||
|
12c.txt
|
4
examples/2024/12a.txt
Normale Datei
4
examples/2024/12a.txt
Normale Datei
|
@ -0,0 +1,4 @@
|
||||||
|
AAAA
|
||||||
|
BBCD
|
||||||
|
BBCC
|
||||||
|
EEEC
|
5
examples/2024/12b.txt
Normale Datei
5
examples/2024/12b.txt
Normale Datei
|
@ -0,0 +1,5 @@
|
||||||
|
OOOOO
|
||||||
|
OXOXO
|
||||||
|
OOOOO
|
||||||
|
OXOXO
|
||||||
|
OOOOO
|
10
examples/2024/12c.txt
Normale Datei
10
examples/2024/12c.txt
Normale Datei
|
@ -0,0 +1,10 @@
|
||||||
|
RRRRIICCFF
|
||||||
|
RRRRIICCCF
|
||||||
|
VVRRRCCFFF
|
||||||
|
VVRCCCJFFF
|
||||||
|
VVVVCJJCFE
|
||||||
|
VVIVCCJJEE
|
||||||
|
VVIIICJJEE
|
||||||
|
MIIIIIJJEE
|
||||||
|
MIIISIJEEE
|
||||||
|
MMMISSJEEE
|
5
examples/2024/12d.txt
Normale Datei
5
examples/2024/12d.txt
Normale Datei
|
@ -0,0 +1,5 @@
|
||||||
|
EEEEE
|
||||||
|
EXXXX
|
||||||
|
EEEEE
|
||||||
|
EXXXX
|
||||||
|
EEEEE
|
6
examples/2024/12f.txt
Normale Datei
6
examples/2024/12f.txt
Normale Datei
|
@ -0,0 +1,6 @@
|
||||||
|
AAAAAA
|
||||||
|
AAABBA
|
||||||
|
AAABBA
|
||||||
|
ABBAAA
|
||||||
|
ABBAAA
|
||||||
|
AAAAAA
|
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
|
|
@ -22,11 +22,7 @@ struct IncludeData {
|
||||||
|
|
||||||
impl Default for IncludeData {
|
impl Default for IncludeData {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
IncludeData {
|
IncludeData { var: VAR_NAME.into(), year: None, day: None }
|
||||||
var: VAR_NAME.into(),
|
|
||||||
year: None,
|
|
||||||
day: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,14 +33,8 @@ fn get_text<T: Spanned>(item: T) -> Result<String> {
|
||||||
None => {
|
None => {
|
||||||
let start = span.start();
|
let start = span.start();
|
||||||
let end = span.end();
|
let end = span.end();
|
||||||
Err(Error::new(
|
Err(Error::new(span, format!("Failed to get sourcetext for {}:{}-{}:{}", start.line, start.column, end.line, end.column,)))
|
||||||
span,
|
},
|
||||||
format!(
|
|
||||||
"Failed to get sourcetext for {}:{}-{}:{}",
|
|
||||||
start.line, start.column, end.line, end.column,
|
|
||||||
),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +63,7 @@ fn canonicalize(dir: &str, input: IncludeData) -> Option<String> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,15 +103,12 @@ pub fn include_data(data: TokenStream) -> TokenStream {
|
||||||
#[doc = #comment]
|
#[doc = #comment]
|
||||||
const #ident: &str = include_str!(#p).trim_ascii();
|
const #ident: &str = include_str!(#p).trim_ascii();
|
||||||
}
|
}
|
||||||
.into()
|
.into();
|
||||||
}
|
},
|
||||||
None => comment = "failed to get data from the paths".into(),
|
None => comment = "failed to get data from the paths".into(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
comment = format!(
|
comment = format!("Failed to get the year({:?}) or day({:?}) falling back to default", input.year, input.day);
|
||||||
"Failed to get the year({:?}) or day({:?}) falling back to default",
|
|
||||||
input.year, input.day
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
quote! {
|
quote! {
|
||||||
#[doc = #comment]
|
#[doc = #comment]
|
||||||
|
@ -148,15 +135,12 @@ pub fn include_example(data: TokenStream) -> TokenStream {
|
||||||
#[doc = #comment]
|
#[doc = #comment]
|
||||||
const #ident: &str = include_str!(#p).trim_ascii();
|
const #ident: &str = include_str!(#p).trim_ascii();
|
||||||
}
|
}
|
||||||
.into()
|
.into();
|
||||||
}
|
},
|
||||||
None => comment = "failed to get data from the path".into(),
|
None => comment = "failed to get data from the path".into(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
comment = format!(
|
comment = format!("Failed to get the year({:?}) or day({:?}) falling back to default", input.year, input.day);
|
||||||
"Failed to get the year({:?}) or day({:?}) falling back to default",
|
|
||||||
input.year, input.day
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
quote! {
|
quote! {
|
||||||
#[doc = #comment]
|
#[doc = #comment]
|
||||||
|
|
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
|
|
@ -42,11 +42,7 @@ impl Round {
|
||||||
ok
|
ok
|
||||||
}
|
}
|
||||||
fn power(&self) -> u64 {
|
fn power(&self) -> u64 {
|
||||||
let mut sack = Sack {
|
let mut sack = Sack { reds: 0, greens: 0, blues: 0 };
|
||||||
reds: 0,
|
|
||||||
greens: 0,
|
|
||||||
blues: 0,
|
|
||||||
};
|
|
||||||
for take in self.takes.clone() {
|
for take in self.takes.clone() {
|
||||||
if take.red > sack.reds {
|
if take.red > sack.reds {
|
||||||
sack.reds = take.red
|
sack.reds = take.red
|
||||||
|
@ -70,11 +66,7 @@ impl From<&str> for Round {
|
||||||
takes: Vec::<Take>::new(),
|
takes: Vec::<Take>::new(),
|
||||||
};
|
};
|
||||||
for taking in value.get(doublecolon + 1..).unwrap().split(";") {
|
for taking in value.get(doublecolon + 1..).unwrap().split(";") {
|
||||||
let mut take = Take {
|
let mut take = Take { red: 0, green: 0, blue: 0 };
|
||||||
red: 0,
|
|
||||||
green: 0,
|
|
||||||
blue: 0,
|
|
||||||
};
|
|
||||||
for color in taking.split(',').map(str::trim) {
|
for color in taking.split(',').map(str::trim) {
|
||||||
let mut i = color.splitn(2, char::is_whitespace);
|
let mut i = color.splitn(2, char::is_whitespace);
|
||||||
let amount = parsenumber(i.next().unwrap());
|
let amount = parsenumber(i.next().unwrap());
|
||||||
|
@ -96,11 +88,7 @@ fn main() {
|
||||||
for game in DATA.split('\n') {
|
for game in DATA.split('\n') {
|
||||||
gamerounds.push(game.into());
|
gamerounds.push(game.into());
|
||||||
}
|
}
|
||||||
let sack = Sack {
|
let sack = Sack { reds: 12, greens: 13, blues: 14 };
|
||||||
reds: 12,
|
|
||||||
greens: 13,
|
|
||||||
blues: 14,
|
|
||||||
};
|
|
||||||
let mut sum = 0;
|
let mut sum = 0;
|
||||||
for round in gamerounds.clone() {
|
for round in gamerounds.clone() {
|
||||||
if round.possible(sack) {
|
if round.possible(sack) {
|
||||||
|
|
|
@ -7,10 +7,7 @@ include_data!(DATA 2024 01);
|
||||||
pub fn splitspace(input: &str) -> (u32, u32) {
|
pub fn splitspace(input: &str) -> (u32, u32) {
|
||||||
println!("{}", input);
|
println!("{}", input);
|
||||||
let mut output = input.split_ascii_whitespace();
|
let mut output = input.split_ascii_whitespace();
|
||||||
(
|
(parsenumber(output.next().unwrap()), parsenumber(output.next().unwrap()))
|
||||||
parsenumber(output.next().unwrap()),
|
|
||||||
parsenumber(output.next().unwrap()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn distance(leftlist: &Vec<u32>, rightlist: &Vec<u32>) -> u32 {
|
fn distance(leftlist: &Vec<u32>, rightlist: &Vec<u32>) -> u32 {
|
||||||
|
|
|
@ -34,8 +34,8 @@ fn main() {
|
||||||
let a = parsenumber::<u32>(capture.name("i").unwrap().as_str());
|
let a = parsenumber::<u32>(capture.name("i").unwrap().as_str());
|
||||||
let b = parsenumber::<u32>(capture.name("j").unwrap().as_str());
|
let b = parsenumber::<u32>(capture.name("j").unwrap().as_str());
|
||||||
sum += a * b
|
sum += a * b
|
||||||
}
|
},
|
||||||
(_, _) => {}
|
(_, _) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("The Cleaned with check output is: {}", sum);
|
println!("The Cleaned with check output is: {}", sum);
|
||||||
|
|
|
@ -18,23 +18,13 @@ struct DirectionalKartesian<T: Integer> {
|
||||||
}
|
}
|
||||||
impl<T: Integer> From<(Kartesian<T>, KartesianDirection)> for DirectionalKartesian<T> {
|
impl<T: Integer> From<(Kartesian<T>, KartesianDirection)> for DirectionalKartesian<T> {
|
||||||
fn from(value: (Kartesian<T>, KartesianDirection)) -> Self {
|
fn from(value: (Kartesian<T>, KartesianDirection)) -> Self {
|
||||||
DirectionalKartesian {
|
DirectionalKartesian { x: value.0.x, y: value.0.y, dir: value.1 }
|
||||||
x: value.0.x,
|
|
||||||
y: value.0.y,
|
|
||||||
dir: value.1,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Integer + Copy> Into<(Kartesian<T>, KartesianDirection)> for &DirectionalKartesian<T> {
|
impl<T: Integer + Copy> Into<(Kartesian<T>, KartesianDirection)> for &DirectionalKartesian<T> {
|
||||||
fn into(self) -> (Kartesian<T>, KartesianDirection) {
|
fn into(self) -> (Kartesian<T>, KartesianDirection) {
|
||||||
(
|
(Kartesian { x: self.x, y: self.y }, self.dir)
|
||||||
Kartesian {
|
|
||||||
x: self.x,
|
|
||||||
y: self.y,
|
|
||||||
},
|
|
||||||
self.dir,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,19 +52,15 @@ fn find_guard(map: Table) -> Kartesian<i32> {
|
||||||
fn get_path(map: Table) -> Vec<DirectionalKartesian<i32>> {
|
fn get_path(map: Table) -> Vec<DirectionalKartesian<i32>> {
|
||||||
let mut position = (find_guard(map.clone()), KartesianDirection::Top);
|
let mut position = (find_guard(map.clone()), KartesianDirection::Top);
|
||||||
let maximum = Kartesian::new(map.len() as i32, map[0].len() as i32);
|
let maximum = Kartesian::new(map.len() as i32, map[0].len() as i32);
|
||||||
debug!(
|
debug!("Guard is on coordinate {}:{}", position.0.x + 1, position.0.y + 1);
|
||||||
"Guard is on coordinate {}:{}",
|
|
||||||
position.0.x + 1,
|
|
||||||
position.0.y + 1
|
|
||||||
);
|
|
||||||
let mut passed = Vec::new();
|
let mut passed = Vec::new();
|
||||||
passed.push(position.into());
|
passed.push(position.into());
|
||||||
loop {
|
loop {
|
||||||
position.0 = match position.0.checked_add_max(position.1.vector(), maximum) {
|
position.0 = match position.0.checked_add_max(position.1.vector().into(), maximum) {
|
||||||
None => {
|
None => {
|
||||||
debug!("Guard left the space after {} steps", passed.len());
|
debug!("Guard left the space after {} steps", passed.len());
|
||||||
return passed;
|
return passed;
|
||||||
}
|
},
|
||||||
Some(pos) => pos,
|
Some(pos) => pos,
|
||||||
};
|
};
|
||||||
if map[position.0.x as usize][position.0.y as usize] != '#' {
|
if map[position.0.x as usize][position.0.y as usize] != '#' {
|
||||||
|
@ -82,33 +68,26 @@ fn get_path(map: Table) -> Vec<DirectionalKartesian<i32>> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
position.0 -= position.1.vector();
|
position.0 -= position.1.vector();
|
||||||
debug!(
|
debug!("Guard turned right on {}:{}", position.0.x + 1, position.0.y + 1);
|
||||||
"Guard turned right on {}:{}",
|
|
||||||
position.0.x + 1,
|
|
||||||
position.0.y + 1
|
|
||||||
);
|
|
||||||
position.1 = position.1.clockwise(false);
|
position.1 = position.1.clockwise(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solver1(input: &str) -> usize {
|
fn solver1(input: &str) -> usize {
|
||||||
let map = convert_to_array(input, line_to_char);
|
let map = convert_to_array::<_, _, '\n'>(input, line_to_char);
|
||||||
let mut path = get_path(map);
|
let mut path = get_path(map);
|
||||||
path.sort();
|
path.sort();
|
||||||
path.dedup_by_key(|p| (p.x, p.y));
|
path.dedup_by_key(|p| (p.x, p.y));
|
||||||
path.len()
|
path.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_looping(
|
fn is_looping(_path: Vec<DirectionalKartesian<i32>>, _start_point: DirectionalKartesian<i32>) -> bool {
|
||||||
path: Vec<DirectionalKartesian<i32>>,
|
|
||||||
start_point: DirectionalKartesian<i32>,
|
|
||||||
) -> bool {
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables, unused_mut)]
|
#[allow(unused_variables, unused_mut)]
|
||||||
fn solver2(input: &str) -> usize {
|
fn solver2(input: &str) -> usize {
|
||||||
let map = convert_to_array(input, line_to_char);
|
let map = convert_to_array::<_, _, '\n'>(input, line_to_char);
|
||||||
let maximum = Kartesian::new(map.len() as i32, map[0].len() as i32);
|
let maximum = Kartesian::new(map.len() as i32, map[0].len() as i32);
|
||||||
let mut path = get_path(map.clone());
|
let mut path = get_path(map.clone());
|
||||||
let mut p = path.iter();
|
let mut p = path.iter();
|
||||||
|
@ -123,10 +102,7 @@ fn solver2(input: &str) -> usize {
|
||||||
currentpoint = point.into();
|
currentpoint = point.into();
|
||||||
currentpoint.1 = currentpoint.1.clockwise(false);
|
currentpoint.1 = currentpoint.1.clockwise(false);
|
||||||
loop {
|
loop {
|
||||||
currentpoint.0 = match currentpoint
|
currentpoint.0 = match currentpoint.0.checked_add_max(currentpoint.1.vector(), maximum) {
|
||||||
.0
|
|
||||||
.checked_add_max(currentpoint.1.vector(), maximum)
|
|
||||||
{
|
|
||||||
None => break,
|
None => break,
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
};
|
};
|
||||||
|
@ -145,14 +121,8 @@ fn solver2(input: &str) -> usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!(
|
println!("Guard left the space after walking through {} distinct positions", solver1(DATA));
|
||||||
"Guard left the space after walking through {} distinct positions",
|
println!("There are {} positions that are good for loops", solver2(DATA));
|
||||||
solver1(DATA)
|
|
||||||
);
|
|
||||||
println!(
|
|
||||||
"There are {} positions that are good for loops",
|
|
||||||
solver2(DATA)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -19,27 +19,14 @@ enum Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operation {
|
impl Operation {
|
||||||
fn op<
|
fn op<T: Integer + Add + Mul + Pow<u32, Output = T> + std::ops::DivAssign + AddAssign + From<u32> + Copy>(self, a: T, b: T) -> T {
|
||||||
T: Integer
|
|
||||||
+ Add
|
|
||||||
+ Mul
|
|
||||||
+ Pow<u32, Output = T>
|
|
||||||
+ std::ops::DivAssign
|
|
||||||
+ AddAssign
|
|
||||||
+ From<u32>
|
|
||||||
+ Copy,
|
|
||||||
>(
|
|
||||||
self,
|
|
||||||
a: T,
|
|
||||||
b: T,
|
|
||||||
) -> T {
|
|
||||||
match self {
|
match self {
|
||||||
Operation::Add => a + b,
|
Operation::Add => a + b,
|
||||||
Operation::Multiply => a * b,
|
Operation::Multiply => a * b,
|
||||||
Operation::Concat => {
|
Operation::Concat => {
|
||||||
let ta = a * T::from(10).pow(numberlength(b));
|
let ta = a * T::from(10).pow(numberlength(b));
|
||||||
ta + b
|
ta + b
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,10 +34,7 @@ impl Operation {
|
||||||
fn get_data(line: &str) -> (u64, Vec<u64>) {
|
fn get_data(line: &str) -> (u64, Vec<u64>) {
|
||||||
let (result, numbers) = line.split_once(':').unwrap();
|
let (result, numbers) = line.split_once(':').unwrap();
|
||||||
|
|
||||||
(
|
(parsenumber(result.trim()), Vec::from(convert_to_array::<_, _, ' '>(numbers, parsenumber)))
|
||||||
parsenumber(result.trim()),
|
|
||||||
Vec::from(convert_to_array::<_, _, ' '>(numbers, parsenumber)),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_equation(result: u64, numbers: Vec<u64>, ops: Vec<Operation>) -> bool {
|
fn test_equation(result: u64, numbers: Vec<u64>, ops: Vec<Operation>) -> bool {
|
||||||
|
@ -87,7 +71,11 @@ fn get_ops(len: usize, conf: usize) -> Vec<Operation> {
|
||||||
|
|
||||||
fn get_ops_with_concat(len: u32) -> Vec<Vec<Operation>> {
|
fn get_ops_with_concat(len: u32) -> Vec<Vec<Operation>> {
|
||||||
let mut ops = Vec::with_capacity(3u64.saturating_pow(len) as usize);
|
let mut ops = Vec::with_capacity(3u64.saturating_pow(len) as usize);
|
||||||
for i in [Operation::Add, Operation::Concat, Operation::Multiply] {
|
for i in [
|
||||||
|
Operation::Add,
|
||||||
|
Operation::Concat,
|
||||||
|
Operation::Multiply,
|
||||||
|
] {
|
||||||
if len > 1 {
|
if len > 1 {
|
||||||
for mut oplist in get_ops_with_concat(len - 1) {
|
for mut oplist in get_ops_with_concat(len - 1) {
|
||||||
oplist.insert(0, i);
|
oplist.insert(0, i);
|
||||||
|
@ -146,32 +134,56 @@ mod test {
|
||||||
for c in [
|
for c in [
|
||||||
(
|
(
|
||||||
190,
|
190,
|
||||||
Vec::from([10, 19]),
|
Vec::from([
|
||||||
|
10, 19,
|
||||||
|
]),
|
||||||
Vec::from([Operation::Multiply]),
|
Vec::from([Operation::Multiply]),
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
3267,
|
3267,
|
||||||
Vec::from([81, 40, 27]),
|
Vec::from([
|
||||||
Vec::from([Operation::Add, Operation::Multiply]),
|
81, 40, 27,
|
||||||
|
]),
|
||||||
|
Vec::from([
|
||||||
|
Operation::Add,
|
||||||
|
Operation::Multiply,
|
||||||
|
]),
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
3267,
|
3267,
|
||||||
Vec::from([81, 40, 27]),
|
Vec::from([
|
||||||
Vec::from([Operation::Multiply, Operation::Add]),
|
81, 40, 27,
|
||||||
|
]),
|
||||||
|
Vec::from([
|
||||||
|
Operation::Multiply,
|
||||||
|
Operation::Add,
|
||||||
|
]),
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
292,
|
292,
|
||||||
Vec::from([11, 6, 16, 20]),
|
Vec::from([
|
||||||
Vec::from([Operation::Add, Operation::Multiply, Operation::Add]),
|
11, 6, 16, 20,
|
||||||
|
]),
|
||||||
|
Vec::from([
|
||||||
|
Operation::Add,
|
||||||
|
Operation::Multiply,
|
||||||
|
Operation::Add,
|
||||||
|
]),
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
292,
|
292,
|
||||||
Vec::from([11, 6, 16, 20]),
|
Vec::from([
|
||||||
Vec::from([Operation::Add, Operation::Multiply, Operation::Multiply]),
|
11, 6, 16, 20,
|
||||||
|
]),
|
||||||
|
Vec::from([
|
||||||
|
Operation::Add,
|
||||||
|
Operation::Multiply,
|
||||||
|
Operation::Multiply,
|
||||||
|
]),
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
] {
|
] {
|
||||||
|
|
120
src/bin/2024/08.rs
Normale Datei
120
src/bin/2024/08.rs
Normale Datei
|
@ -0,0 +1,120 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use advent_of_code::{
|
||||||
|
strings::{convert_to_array, line_to_char},
|
||||||
|
Kartesian, Table,
|
||||||
|
};
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use advent_of_code_macros::{include_data, include_example};
|
||||||
|
use log::*;
|
||||||
|
|
||||||
|
include_data!(DATA 2024 08);
|
||||||
|
|
||||||
|
const EMPTY: char = '.';
|
||||||
|
|
||||||
|
fn get_map(maximum: Kartesian<usize>) -> Vec<Vec<char>> {
|
||||||
|
let mut resomap = Vec::new();
|
||||||
|
let mut m = Vec::new();
|
||||||
|
m.resize(maximum.y, EMPTY);
|
||||||
|
resomap.resize(maximum.x, m);
|
||||||
|
resomap
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_antennas(map: Table) -> HashMap<char, Vec<Kartesian<usize>>> {
|
||||||
|
let mut positions = HashMap::new();
|
||||||
|
let mut x = 0;
|
||||||
|
let mut y;
|
||||||
|
let len = map[0].len();
|
||||||
|
for line in map.clone() {
|
||||||
|
y = 0;
|
||||||
|
for char in line {
|
||||||
|
if char != EMPTY {
|
||||||
|
if !positions.contains_key(&char) {
|
||||||
|
positions.insert(char, Vec::with_capacity(len));
|
||||||
|
}
|
||||||
|
positions.get_mut(&char).unwrap().push(Kartesian::new(x, y));
|
||||||
|
}
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
positions
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_resonance(points: Vec<Kartesian<usize>>, maximum: Kartesian<usize>, harmonic: bool) -> Vec<Kartesian<usize>> {
|
||||||
|
let mut resonances = Vec::new();
|
||||||
|
let mut diff;
|
||||||
|
let mut direction;
|
||||||
|
for outer in points.clone() {
|
||||||
|
for inner in points.clone() {
|
||||||
|
if outer == inner {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(diff, direction) = inner.diff(outer);
|
||||||
|
loop {
|
||||||
|
if let Some(reso) = outer.move_dir(diff, direction) {
|
||||||
|
if reso.x < maximum.x && reso.y < maximum.y {
|
||||||
|
debug!("Found Point: {}", reso);
|
||||||
|
resonances.push(reso);
|
||||||
|
if !harmonic {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resonances
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let map = convert_to_array::<_, _, '\n'>(DATA, line_to_char);
|
||||||
|
let maximum = Kartesian::new(map.len(), map[0].len());
|
||||||
|
let positions = find_antennas(map.clone());
|
||||||
|
let mut tmp;
|
||||||
|
let mut resonating_points = Vec::new();
|
||||||
|
for (group, points) in positions.clone() {
|
||||||
|
tmp = get_resonance(points.clone(), maximum, false);
|
||||||
|
println!("Found {} resonances for {} antennas in group {}", tmp.len(), points.len(), group,);
|
||||||
|
resonating_points.append(&mut tmp);
|
||||||
|
}
|
||||||
|
println!("Found {} points before dedup", resonating_points.len());
|
||||||
|
resonating_points.dedup();
|
||||||
|
println!("{} after simple dedup", resonating_points.len());
|
||||||
|
resonating_points = resonating_points
|
||||||
|
.iter()
|
||||||
|
.filter(|x| {
|
||||||
|
for (group, positions) in positions.clone() {
|
||||||
|
if positions.contains(*x) {
|
||||||
|
println!("Discarded point {} because it is over an point of group {}", *x, group);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
let mut resomap = map.clone();
|
||||||
|
println!("There are {} Resonating points on the map after dedup.", resonating_points.len());
|
||||||
|
if resonating_points.len() != 305 {
|
||||||
|
println!("Wrong solution");
|
||||||
|
}
|
||||||
|
for point in resonating_points {
|
||||||
|
resomap[point.x][point.y] = '~';
|
||||||
|
}
|
||||||
|
for line in 0..resomap.len() {
|
||||||
|
print!("{:02}. ", line + 1);
|
||||||
|
for char in map[line].clone() {
|
||||||
|
print!("{}", char);
|
||||||
|
}
|
||||||
|
print!("|");
|
||||||
|
for char in resomap[line].clone() {
|
||||||
|
print!("{}", char);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
|
@ -136,14 +136,8 @@ fn main() {
|
||||||
let mut file_disk = raw_disk.clone();
|
let mut file_disk = raw_disk.clone();
|
||||||
compact_blocks(&mut block_disk);
|
compact_blocks(&mut block_disk);
|
||||||
let mut cksum = calculate_checksum(block_disk);
|
let mut cksum = calculate_checksum(block_disk);
|
||||||
println!(
|
println!("Checksum for the blockcompacted disk is: {}", cksum);
|
||||||
"Checksum for the blockcompacted disk is: {}",
|
|
||||||
cksum
|
|
||||||
);
|
|
||||||
compact_files(&mut file_disk);
|
compact_files(&mut file_disk);
|
||||||
cksum = calculate_checksum(file_disk);
|
cksum = calculate_checksum(file_disk);
|
||||||
println!(
|
println!("Checksum for the filecompacted disk is: {}", cksum,);
|
||||||
"Checksum for the filecompacted disk is: {}",
|
|
||||||
cksum,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
193
src/bin/2024/11.rs
Normale Datei
193
src/bin/2024/11.rs
Normale Datei
|
@ -0,0 +1,193 @@
|
||||||
|
#![allow(unused)]
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use advent_of_code::{
|
||||||
|
numberlength,
|
||||||
|
strings::{convert_to_array, parsenumber},
|
||||||
|
ExtendedOption,
|
||||||
|
};
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use advent_of_code_macros::{include_data, include_example};
|
||||||
|
use num::Integer;
|
||||||
|
|
||||||
|
include_data!(DATA 2024 11);
|
||||||
|
|
||||||
|
const BILLIONS: u64 = 1000_000_000;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
struct Stone {
|
||||||
|
number: u64,
|
||||||
|
left: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
struct MapSkip {
|
||||||
|
newnumber_a: u64,
|
||||||
|
newnumber_b: u64,
|
||||||
|
skipped_steps: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct StoneCounter {
|
||||||
|
cache: Vec<Stone>,
|
||||||
|
map: HashMap<u64, ExtendedOption<MapSkip>>,
|
||||||
|
stones: u64,
|
||||||
|
start: usize,
|
||||||
|
stones_billions: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StoneCounter {
|
||||||
|
fn new(start_values: Vec<u64>, rounds: usize) -> StoneCounter {
|
||||||
|
let mut cache = Vec::with_capacity(start_values.len());
|
||||||
|
for v in start_values.iter() {
|
||||||
|
cache.push(Stone { number: *v, left: rounds });
|
||||||
|
}
|
||||||
|
StoneCounter {
|
||||||
|
cache: cache,
|
||||||
|
map: HashMap::with_capacity(10_000),
|
||||||
|
stones: 0,
|
||||||
|
start: rounds,
|
||||||
|
stones_billions: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blink(&mut self) -> u64 {
|
||||||
|
let mut stone: Stone;
|
||||||
|
let mut copy: Stone;
|
||||||
|
let (mut next, mut second);
|
||||||
|
while self.cache.len() > 0 {
|
||||||
|
stone = self.cache.pop().unwrap();
|
||||||
|
copy = stone.clone();
|
||||||
|
while stone.left > 0 {
|
||||||
|
if self.map.contains_key(&stone.number) {
|
||||||
|
match self.map.get(&stone.number).unwrap() {
|
||||||
|
ExtendedOption::None => {
|
||||||
|
self.stones += 1;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
ExtendedOption::Some(skip) => {
|
||||||
|
if stone.left < skip.skipped_steps {
|
||||||
|
stone.left = 0
|
||||||
|
} else {
|
||||||
|
stone.left -= skip.skipped_steps;
|
||||||
|
}
|
||||||
|
stone.number = skip.newnumber_a;
|
||||||
|
self.cache.push(Stone { number: skip.newnumber_b, left: stone.left });
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
ExtendedOption::Unset => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if stone.left == 1 {
|
||||||
|
self.map = self
|
||||||
|
.map
|
||||||
|
.iter()
|
||||||
|
.filter_map(|x| {
|
||||||
|
Some(if *x.1 == ExtendedOption::Unset {
|
||||||
|
(*x.0, ExtendedOption::None)
|
||||||
|
} else {
|
||||||
|
(*x.0, *x.1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
self.map.insert(stone.number, ExtendedOption::Unset);
|
||||||
|
}
|
||||||
|
stone.left -= 1;
|
||||||
|
(next, second) = blink(stone.number);
|
||||||
|
match second {
|
||||||
|
None => {
|
||||||
|
self.map.insert(stone.number, ExtendedOption::Unset);
|
||||||
|
stone.number = next;
|
||||||
|
},
|
||||||
|
Some(sec) => {
|
||||||
|
self.map.insert(
|
||||||
|
stone.number,
|
||||||
|
ExtendedOption::Some(MapSkip {
|
||||||
|
newnumber_a: next,
|
||||||
|
newnumber_b: sec,
|
||||||
|
skipped_steps: copy.left - stone.left,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.stones_billions * BILLIONS + self.stones
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn combine_number(p: &[u64]) -> u64 {
|
||||||
|
let mut o = 0;
|
||||||
|
for i in p {
|
||||||
|
o = o * 10 + i;
|
||||||
|
}
|
||||||
|
o
|
||||||
|
}
|
||||||
|
|
||||||
|
fn splitnumber(i: u64) -> (u64, u64) {
|
||||||
|
let len = numberlength(i) as usize;
|
||||||
|
let mut array = Vec::with_capacity(len);
|
||||||
|
let (mut quot, mut remainder);
|
||||||
|
quot = i;
|
||||||
|
loop {
|
||||||
|
(quot, remainder) = quot.div_rem(&10);
|
||||||
|
array.insert(0, remainder);
|
||||||
|
if quot == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let (a, b) = array.split_at(len / 2);
|
||||||
|
(combine_number(a), combine_number(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blink(stone: u64) -> (u64, Option<u64>) {
|
||||||
|
if stone == 0 {
|
||||||
|
(1, None)
|
||||||
|
} else if numberlength(stone) % 2 == 0 {
|
||||||
|
let (stone, t) = splitnumber(stone);
|
||||||
|
(stone, Some(t))
|
||||||
|
} else {
|
||||||
|
(stone * 2024, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let stoneline = convert_to_array::<_, _, ' '>(DATA, parsenumber);
|
||||||
|
let mut counter = StoneCounter::new(stoneline.clone(), 25);
|
||||||
|
let stones = counter.blink();
|
||||||
|
debug_assert!(stones == 235850, "{} != {}", stones, 235850);
|
||||||
|
println!("{:?} Stones after 25 blinks", stones);
|
||||||
|
counter = StoneCounter::new(stoneline, 75);
|
||||||
|
println!("{:?} Stones after 75 blinks", counter.blink());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blink() {
|
||||||
|
let mut res = blink(8);
|
||||||
|
assert_eq!(res, (16192, None));
|
||||||
|
res = blink(res.0);
|
||||||
|
assert_eq!(res, (32772608, None));
|
||||||
|
res = blink(res.0);
|
||||||
|
assert_eq!(res, (3277, Some(2608)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stones() {
|
||||||
|
let testvalues = vec![
|
||||||
|
125, 17,
|
||||||
|
];
|
||||||
|
let mut counter = StoneCounter::new(testvalues.clone(), 6);
|
||||||
|
assert_eq!(counter.blink(), 22);
|
||||||
|
|
||||||
|
counter = StoneCounter::new(testvalues.clone(), 25);
|
||||||
|
assert_eq!(counter.blink(), 55312);
|
||||||
|
}
|
||||||
|
}
|
307
src/bin/2024/12.rs
Normale Datei
307
src/bin/2024/12.rs
Normale Datei
|
@ -0,0 +1,307 @@
|
||||||
|
#![allow(unused)]
|
||||||
|
use std::ops::{Mul, Not};
|
||||||
|
|
||||||
|
use advent_of_code::{strings::convert_to_array, ExtendedOption, Kartesian, KartesianDirection, KartesianIterator, MaximumFromMap, Table, KD};
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use advent_of_code_macros::{include_data, include_example};
|
||||||
|
use log::*;
|
||||||
|
use num::{iter, Integer};
|
||||||
|
|
||||||
|
include_data!(DATA 2024 12);
|
||||||
|
|
||||||
|
type Minimap = Vec<Vec<bool>>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn mul<T: Integer + Mul>(v: (T, T)) -> T {
|
||||||
|
v.0 * v.1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_perimeter_and_area(minimap: &Minimap) -> (u32, u32) {
|
||||||
|
//print_minimap(minimap);
|
||||||
|
let mut rectangle = true;
|
||||||
|
let length = minimap[0].len();
|
||||||
|
for line in minimap.clone() {
|
||||||
|
rectangle = rectangle && line.len() == length && line.iter().all(|x| *x);
|
||||||
|
}
|
||||||
|
if rectangle {
|
||||||
|
let height = minimap.len() as u32;
|
||||||
|
(height * length as u32, 2 * (length as u32 + height))
|
||||||
|
} else {
|
||||||
|
let (mut area, mut perimeter) = (0, 0);
|
||||||
|
for (x, line) in minimap.iter().enumerate() {
|
||||||
|
debug!("Row: {}", x + 1);
|
||||||
|
for (y, cell) in line.iter().cloned().enumerate() {
|
||||||
|
if cell {
|
||||||
|
area += 1;
|
||||||
|
}
|
||||||
|
if cell {
|
||||||
|
if x == 0 {
|
||||||
|
debug!(" Top Border in column {}", y + 1);
|
||||||
|
perimeter += 1;
|
||||||
|
}
|
||||||
|
if x == minimap.len() - 1 {
|
||||||
|
debug!(" Bottom Border");
|
||||||
|
perimeter += 1;
|
||||||
|
}
|
||||||
|
if y == 0 {
|
||||||
|
debug!(" Left border on line {}", x + 1);
|
||||||
|
perimeter += 1
|
||||||
|
}
|
||||||
|
if y == line.len() - 1 {
|
||||||
|
debug!(" Right border on line {}", x + 1);
|
||||||
|
perimeter += 1;
|
||||||
|
}
|
||||||
|
if x != 0 {
|
||||||
|
if minimap[x - 1].len() <= y || minimap[x - 1].len() > y && !minimap[x - 1][y] {
|
||||||
|
debug!(" Top Border on line {} and column {}", x + 1, y + 1);
|
||||||
|
perimeter += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if x != minimap.len() - 1 {
|
||||||
|
if minimap[x + 1].len() <= y || minimap[x + 1].len() > y && !minimap[x + 1][y] {
|
||||||
|
debug!(" Bottom Border on line {} and column {}", x + 1, y + 1);
|
||||||
|
perimeter += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if y != 0 && !minimap[x][y - 1] {
|
||||||
|
debug!(" Left Border on line {} and column {}", x + 1, y + 1);
|
||||||
|
perimeter += 1;
|
||||||
|
}
|
||||||
|
if y != line.len() - 1 && !minimap[x][y + 1] {
|
||||||
|
debug!(" Right Border on line {} and column {}", x + 1, y + 1);
|
||||||
|
perimeter += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug!("Area is {} and perimeter {}", area, perimeter);
|
||||||
|
(area, perimeter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_side(minimap: &Minimap, position: Kartesian<usize>, dir: KD) -> Option<Kartesian<usize>> {
|
||||||
|
match position.move_dir(dir.vector(), dir) {
|
||||||
|
None => None,
|
||||||
|
Some(new) => {
|
||||||
|
if minimap.len() == new.x || minimap[new.x].len() < new.y {
|
||||||
|
return Some(new);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn calc_sides_and_area(minimap: &Minimap) -> (u32, u32) {
|
||||||
|
print_minimap(&minimap);
|
||||||
|
let maximum: Kartesian<usize> = Kartesian::maximum(&minimap);
|
||||||
|
let area = minimap.iter().map(|l| l.iter().filter(|x| **x == true).count()).sum::<usize>() as u32;
|
||||||
|
let mut sides = 0;
|
||||||
|
let mut lines = Vec::with_capacity(minimap.len().max(minimap[0].len()));
|
||||||
|
let mut position = Kartesian::default();
|
||||||
|
let mut innerdir;
|
||||||
|
let mut innerposition;
|
||||||
|
let mut emptys;
|
||||||
|
let mut map;
|
||||||
|
for dir in KD::iter(false, false, true) {
|
||||||
|
map = minimap.clone();
|
||||||
|
innerdir = dir.clockwise(false);
|
||||||
|
loop {
|
||||||
|
emptys = 0;
|
||||||
|
innerposition = position;
|
||||||
|
loop {
|
||||||
|
if innerposition.get_value(&map) == Some(true) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
emptys += 1;
|
||||||
|
innerposition = match innerposition.move_dir_max(innerdir.vector(), innerdir, maximum) {
|
||||||
|
None => break,
|
||||||
|
Some(new) => new,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lines.push(emptys);
|
||||||
|
if let Some(newpos) = position.move_dir_max(dir.vector(), dir, maximum) {
|
||||||
|
position = newpos;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut iter = lines.iter().cloned();
|
||||||
|
let mut last = iter.next().unwrap();
|
||||||
|
for i in iter {
|
||||||
|
if last != i {
|
||||||
|
sides += 1;
|
||||||
|
}
|
||||||
|
last = i;
|
||||||
|
}
|
||||||
|
sides += 1;
|
||||||
|
lines.clear();
|
||||||
|
}
|
||||||
|
println!("Prossesing done, found {} sides with and area of {}", sides, area);
|
||||||
|
(area, sides)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_minimap(map: &Minimap) {
|
||||||
|
for row in map {
|
||||||
|
for column in row {
|
||||||
|
print!(
|
||||||
|
"{}",
|
||||||
|
match column {
|
||||||
|
false => ".",
|
||||||
|
true => "X",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
println!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn move_content_left(minimap: &mut Minimap, columns: usize) {
|
||||||
|
for line in minimap.iter_mut() {
|
||||||
|
for _ in 0..columns {
|
||||||
|
if line.len() == 0 {
|
||||||
|
line.push(false);
|
||||||
|
} else {
|
||||||
|
line.insert(0, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_size(minimap: &mut Minimap, x: usize, y: usize) {
|
||||||
|
if minimap.len() <= x + 1 {
|
||||||
|
let mut minimal_v = Vec::new();
|
||||||
|
minimal_v.resize(y + 1, false);
|
||||||
|
minimap.resize(x + 1, minimal_v);
|
||||||
|
}
|
||||||
|
if minimap[x].len() <= y + 1 {
|
||||||
|
minimap[x].resize(y + 1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_connected_i(position: Kartesian<u32>, minimap: &mut Minimap, visited: &mut Vec<Kartesian<u32>>, max: Kartesian<u32>, map: &Table, plant: char, startpos: &mut Kartesian<u32>) {
|
||||||
|
for direction in KD::iter(false, false, true) {
|
||||||
|
match position.move_dir_max(direction.vector(), direction, max) {
|
||||||
|
None => continue,
|
||||||
|
Some(new) => {
|
||||||
|
if map[new.x as usize][new.y as usize] != plant {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !visited.contains(&new) {
|
||||||
|
visited.push(new);
|
||||||
|
}
|
||||||
|
let (mut diff, dir) = startpos.diff(new);
|
||||||
|
let mut movedir = KD::None;
|
||||||
|
match dir {
|
||||||
|
KD::Left | KD::BottomLeft => {
|
||||||
|
debug!("Moving {} from {}, because {} is {}", dir, startpos, new, dir);
|
||||||
|
*startpos = startpos.move_dir(KD::Left.vector(), KD::Left).unwrap();
|
||||||
|
move_content_left(minimap, diff.y as usize);
|
||||||
|
(diff, _) = startpos.diff(new);
|
||||||
|
},
|
||||||
|
KD::TopLeft => {
|
||||||
|
debug!("Moving {} from {}, because {} is {}", dir, startpos, new, dir);
|
||||||
|
*startpos = startpos.move_dir(KD::TopLeft.vector(), KD::TopLeft).unwrap();
|
||||||
|
minimap.insert(0, Vec::new());
|
||||||
|
move_content_left(minimap, diff.y as usize);
|
||||||
|
(diff, _) = startpos.diff(new);
|
||||||
|
},
|
||||||
|
KD::Top => {
|
||||||
|
debug!("Moving {} from {}, because {} is {}", dir, startpos, new, dir);
|
||||||
|
*startpos = startpos.move_dir(KD::Top.vector(), KD::Top).unwrap();
|
||||||
|
minimap.insert(0, Vec::new());
|
||||||
|
(diff, _) = startpos.diff(new);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
ensure_size(minimap, diff.x as usize, diff.y as usize);
|
||||||
|
if minimap[diff.x as usize][diff.y as usize] {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
minimap[diff.x as usize][diff.y as usize] = true;
|
||||||
|
find_connected_i(new, minimap, visited, max, map, plant, startpos);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_connected<F: Fn(&Minimap) -> (u32, u32) + Copy>(position: Kartesian<u32>, map: &Table, visited: &mut Vec<Kartesian<u32>>, func: F) -> u32 {
|
||||||
|
if visited.contains(&position) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let max = Kartesian::maximum(map);
|
||||||
|
let plant = map[position.x as usize][position.y as usize];
|
||||||
|
let mut fences = 2;
|
||||||
|
let mut newposition = position;
|
||||||
|
let mut startposition = position;
|
||||||
|
let mut minimap = vec![vec![true]];
|
||||||
|
find_connected_i(position, &mut minimap, visited, max, map, plant, &mut startposition);
|
||||||
|
let max_length = minimap.iter().map(|line| line.len()).max().unwrap_or(0);
|
||||||
|
for line in minimap.iter_mut() {
|
||||||
|
if line.len() < max_length {
|
||||||
|
line.resize(max_length, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let price = mul(func(&minimap));
|
||||||
|
debug!("price for region {}: {}", plant, price);
|
||||||
|
price
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_fence_price<F: Fn(&Minimap) -> (u32, u32) + Copy>(map: Table, func: F) -> u32 {
|
||||||
|
let mut visited = Vec::with_capacity(map.len() * map[0].len());
|
||||||
|
let mut fences = 0;
|
||||||
|
let mut position = Kartesian::new(0, 0);
|
||||||
|
for (x, row) in map.iter().enumerate() {
|
||||||
|
for (y, column) in row.iter().enumerate() {
|
||||||
|
position = Kartesian::new(x as u32, y as u32);
|
||||||
|
if !visited.contains(&position) {
|
||||||
|
fences += find_connected(position, &map, &mut visited, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fences
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let map: Table = convert_to_array::<_, _, '\n'>(DATA, |l| l.chars().collect());
|
||||||
|
println!("The Price for the fences is {}", calculate_fence_price(map.clone(), calc_perimeter_and_area));
|
||||||
|
println!("The Price with bulk discount is {}", calculate_fence_price(map, calc_sides_and_area));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
include_example!(MAP_A 2024 12a);
|
||||||
|
include_example!(MAP_B 2024 12b);
|
||||||
|
include_example!(MAP_C 2024 12c);
|
||||||
|
include_example!(MAP_D 2024 12d);
|
||||||
|
include_example!(MAP_E 2024 12f);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fence_a_perimeter() {
|
||||||
|
assert_eq!(calculate_fence_price(convert_to_array::<_, _, '\n'>(MAP_A, |l| l.chars().collect()), calc_perimeter_and_area), 140);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fence_b_perimeter() {
|
||||||
|
assert_eq!(calculate_fence_price(convert_to_array::<_, _, '\n'>(MAP_B, |l| l.chars().collect()), calc_perimeter_and_area), 772);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fence_c_perimeter() {
|
||||||
|
assert_eq!(calculate_fence_price(convert_to_array::<_, _, '\n'>(MAP_C, |l| l.chars().collect()), calc_perimeter_and_area), 1930);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fence_a_sides() {
|
||||||
|
assert_eq!(calculate_fence_price(convert_to_array::<_, _, '\n'>(MAP_A, |l| l.chars().collect()), calc_sides_and_area), 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fence_d_sides() {
|
||||||
|
assert_eq!(calculate_fence_price(convert_to_array::<_, _, '\n'>(MAP_D, |l| l.chars().collect()), calc_sides_and_area), 236);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fence_e_sides() {
|
||||||
|
assert_eq!(calculate_fence_price(convert_to_array::<_, _, '\n'>(MAP_E, |l| l.chars().collect()), calc_sides_and_area), 368);
|
||||||
|
}
|
||||||
|
}
|
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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,4 +60,7 @@ impl<T: Integer> Euclidian<T> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
fn test() {
|
||||||
|
Euclidian { x: 0, y: 0, z: 0 };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,502 +0,0 @@
|
||||||
use num::*;
|
|
||||||
use std::{fmt::Display, ops::*};
|
|
||||||
|
|
||||||
pub trait MaximumFromMap<T: Integer> {
|
|
||||||
fn maximum<U>(map: &Vec<Vec<U>>) -> Kartesian<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
pub struct Kartesian<T>
|
|
||||||
where
|
|
||||||
T: Integer,
|
|
||||||
{
|
|
||||||
pub x: T,
|
|
||||||
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 MaximumFromMap<u32> for Kartesian<u32> {
|
|
||||||
fn maximum<U>(map: &Vec<Vec<U>>) -> Kartesian<u32> {
|
|
||||||
Kartesian {
|
|
||||||
x: map.len().to_u32().unwrap(),
|
|
||||||
y: map[0].len().to_u32().unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaximumFromMap<u64> for Kartesian<u64> {
|
|
||||||
fn maximum<U>(map: &Vec<Vec<U>>) -> Kartesian<u64> {
|
|
||||||
Kartesian {
|
|
||||||
x: map.len().to_u64().unwrap(),
|
|
||||||
y: map[0].len().to_u64().unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaximumFromMap<u128> for Kartesian<u128> {
|
|
||||||
fn maximum<U>(map: &Vec<Vec<U>>) -> Kartesian<u128> {
|
|
||||||
Kartesian {
|
|
||||||
x: map.len().to_u128().unwrap(),
|
|
||||||
y: map[0].len().to_u128().unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaximumFromMap<usize> for Kartesian<usize> {
|
|
||||||
fn maximum<U>(map: &Vec<Vec<U>>) -> Kartesian<usize> {
|
|
||||||
Kartesian { x: map.len(), y: map[0].len() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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<T: Integer + CheckedAdd + CheckedSub + Default> 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) {
|
|
||||||
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<T>) -> Option<Kartesian<T>> {
|
|
||||||
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<T>) -> (Kartesian<T>, KartesianDirection) {
|
|
||||||
let mut k = Kartesian::<T>::default();
|
|
||||||
let mut dir = KartesianDirection::None;
|
|
||||||
k.x = match (self.x.checked_sub(&rhs.x), rhs.x.checked_sub(&self.x)) {
|
|
||||||
(Some(d), _) => {
|
|
||||||
dir = dir.up();
|
|
||||||
d
|
|
||||||
},
|
|
||||||
(_, Some(d)) => {
|
|
||||||
dir = dir.down();
|
|
||||||
d
|
|
||||||
},
|
|
||||||
(None, None) => {
|
|
||||||
unreachable!()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
k.y = match (self.y.checked_sub(&rhs.y), rhs.y.checked_sub(&self.y)) {
|
|
||||||
(Some(d), _) => {
|
|
||||||
dir = dir.left();
|
|
||||||
d
|
|
||||||
},
|
|
||||||
(_, Some(d)) => {
|
|
||||||
dir = dir.right();
|
|
||||||
d
|
|
||||||
},
|
|
||||||
(None, None) => {
|
|
||||||
unreachable!()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
(k, dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn move_dir(self, vector: Kartesian<T>, dir: KartesianDirection) -> Option<Kartesian<T>> {
|
|
||||||
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<T>, dir: KartesianDirection, max: Kartesian<T>) -> Option<Kartesian<T>> {
|
|
||||||
match self.move_dir(vector, dir) {
|
|
||||||
None => None,
|
|
||||||
Some(new) => {
|
|
||||||
if new.x < max.x && new.y < max.y {
|
|
||||||
Some(new)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Integer + Display + From<u8> + Copy> Display for Kartesian<T> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.write_fmt(format_args!("{}:{}", self.x + T::from(1), self.y + T::from(1)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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<i16> {
|
|
||||||
Kartesian {
|
|
||||||
x: match self {
|
|
||||||
Self::TopLeft | Self::Top | Self::TopRight => -1,
|
|
||||||
Self::Left | Self::None | Self::Right => 0,
|
|
||||||
Self::BottomLeft | Self::Bottom | Self::BottomRight => 1,
|
|
||||||
},
|
|
||||||
y: match self {
|
|
||||||
Self::TopLeft | Self::Left | Self::BottomLeft => -1,
|
|
||||||
Self::Top | Self::None | Self::Bottom => 0,
|
|
||||||
Self::TopRight | Self::Right | Self::BottomRight => 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vector_abs<T: Integer + From<u8>>(self) -> Kartesian<T> {
|
|
||||||
Kartesian {
|
|
||||||
x: match self {
|
|
||||||
Self::Left | Self::None | Self::Right => From::from(0),
|
|
||||||
_ => From::from(1),
|
|
||||||
},
|
|
||||||
y: match self {
|
|
||||||
Self::Top | Self::None | Self::Bottom => From::from(0),
|
|
||||||
_ => From::from(1),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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::None,
|
|
||||||
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, nondiagonal: bool) -> KartesianIterator {
|
|
||||||
KartesianIterator {
|
|
||||||
i: 0,
|
|
||||||
none: none,
|
|
||||||
diagonal: diagonal,
|
|
||||||
nondiagonal: nondiagonal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
nondiagonal: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for KartesianIterator {
|
|
||||||
type Item = KartesianDirection;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
let mut i = self.i;
|
|
||||||
if self.nondiagonal {
|
|
||||||
if i < 4 {
|
|
||||||
self.i += 1;
|
|
||||||
}
|
|
||||||
match i {
|
|
||||||
0 => return Some(KartesianDirection::Right),
|
|
||||||
1 => return Some(KartesianDirection::Top),
|
|
||||||
2 => return Some(KartesianDirection::Left),
|
|
||||||
3 => return Some(KartesianDirection::Bottom),
|
|
||||||
_ => 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);
|
|
||||||
}
|
|
||||||
}
|
|
153
src/coordinate_systems/kartesian/direction.rs
Normale Datei
153
src/coordinate_systems/kartesian/direction.rs
Normale Datei
|
@ -0,0 +1,153 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use super::{Kartesian, KartesianIterator};
|
||||||
|
use num::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
|
pub enum KartesianDirection {
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
TopLeft,
|
||||||
|
Top,
|
||||||
|
TopRight,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
BottomLeft,
|
||||||
|
Bottom,
|
||||||
|
BottomRight,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KartesianDirection {
|
||||||
|
pub fn vector<T: Integer>(self) -> Kartesian<T> {
|
||||||
|
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<T: Integer + From<u8>>(self) -> Kartesian<T> {
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
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(())
|
||||||
|
}
|
||||||
|
}
|
133
src/coordinate_systems/kartesian/map.rs
Normale Datei
133
src/coordinate_systems/kartesian/map.rs
Normale Datei
|
@ -0,0 +1,133 @@
|
||||||
|
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> {
|
||||||
|
pub(super) maximum: Kartesian<usize>,
|
||||||
|
pub(super) data: Vec<Vec<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + Copy> Map<T> {
|
||||||
|
/// 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<usize>) -> 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<usize>) -> T {
|
||||||
|
if self.outside(coord) {
|
||||||
|
panic!("Coordinates out of bounds: {} >= {}", coord, self.maximum)
|
||||||
|
}
|
||||||
|
self.data[coord.x][coord.y]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
if self.outside(coord) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if coord.x >= self.data.len() {
|
||||||
|
Some(T::default())
|
||||||
|
} else if coord.y >= self.data[coord.x].len() {
|
||||||
|
Some(T::default())
|
||||||
|
} else {
|
||||||
|
Some(self.data[coord.x][coord.y])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces unset and default values with
|
||||||
|
pub fn replace_default(&mut self, new_value: T) {
|
||||||
|
for row in self.data.iter_mut() {
|
||||||
|
*row = row
|
||||||
|
.iter()
|
||||||
|
.map(|c| {
|
||||||
|
if *c == T::default() {
|
||||||
|
new_value
|
||||||
|
} else {
|
||||||
|
*c
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if row.len() < self.maximum.y {
|
||||||
|
row.resize(self.maximum.y, new_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.data.len() < self.maximum.x {
|
||||||
|
let full_row = vec![new_value; self.maximum.y];
|
||||||
|
self.data.resize(self.maximum.x, full_row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the value of in the map.
|
||||||
|
#[inline]
|
||||||
|
pub fn wrapping_get(&self, coord: Kartesian<usize>) -> 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<usize>, value: T) -> T {
|
||||||
|
if self.outside(coord) {
|
||||||
|
panic!("Coordinates outside of bounds: {} >= {}", coord, self.maximum)
|
||||||
|
}
|
||||||
|
if self.data.len() < coord.x + 1 {
|
||||||
|
self.data.resize(coord.x + 1, Vec::new());
|
||||||
|
}
|
||||||
|
if self.data[coord.x].len() < coord.y + 1 {
|
||||||
|
self.data[coord.x].resize(coord.y + 1, T::default());
|
||||||
|
}
|
||||||
|
let oldvalue = self.data[coord.x][coord.y];
|
||||||
|
self.data[coord.x][coord.y] = value;
|
||||||
|
oldvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend_left(&mut self, amount: usize) {
|
||||||
|
for line in self.data.iter_mut() {
|
||||||
|
for _ in 0..amount {
|
||||||
|
line.insert(0, T::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.maximum.y += amount;
|
||||||
|
}
|
||||||
|
pub fn extend_right(&mut self, amount: usize) {
|
||||||
|
self.maximum.y += amount;
|
||||||
|
}
|
||||||
|
pub fn extend_up(&mut self, amount: usize) {
|
||||||
|
for _ in 0..amount {
|
||||||
|
self.data.insert(0, Vec::new());
|
||||||
|
}
|
||||||
|
self.maximum.x += amount
|
||||||
|
}
|
||||||
|
pub fn extend_down(&mut self, amount: usize) {
|
||||||
|
self.maximum.x += amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + Copy> From<Vec<Vec<T>>> for Map<T> {
|
||||||
|
fn from(value: Vec<Vec<T>>) -> Self {
|
||||||
|
Map {
|
||||||
|
data: value.clone(),
|
||||||
|
maximum: Kartesian::new(value.len(), value.iter().map(|line| line.len()).max().unwrap_or(0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
src/coordinate_systems/kartesian/maximum.rs
Normale Datei
39
src/coordinate_systems/kartesian/maximum.rs
Normale Datei
|
@ -0,0 +1,39 @@
|
||||||
|
use super::Kartesian;
|
||||||
|
use num::*;
|
||||||
|
|
||||||
|
pub trait MaximumFromMap<T: Integer> {
|
||||||
|
fn maximum<U>(map: &Vec<Vec<U>>) -> Kartesian<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaximumFromMap<u32> for Kartesian<u32> {
|
||||||
|
fn maximum<U>(map: &Vec<Vec<U>>) -> Kartesian<u32> {
|
||||||
|
Kartesian {
|
||||||
|
x: map.len().to_u32().unwrap(),
|
||||||
|
y: map[0].len().to_u32().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaximumFromMap<u64> for Kartesian<u64> {
|
||||||
|
fn maximum<U>(map: &Vec<Vec<U>>) -> Kartesian<u64> {
|
||||||
|
Kartesian {
|
||||||
|
x: map.len().to_u64().unwrap(),
|
||||||
|
y: map[0].len().to_u64().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaximumFromMap<u128> for Kartesian<u128> {
|
||||||
|
fn maximum<U>(map: &Vec<Vec<U>>) -> Kartesian<u128> {
|
||||||
|
Kartesian {
|
||||||
|
x: map.len().to_u128().unwrap(),
|
||||||
|
y: map[0].len().to_u128().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaximumFromMap<usize> for Kartesian<usize> {
|
||||||
|
fn maximum<U>(map: &Vec<Vec<U>>) -> Kartesian<usize> {
|
||||||
|
Kartesian { x: map.len(), y: map[0].len() }
|
||||||
|
}
|
||||||
|
}
|
293
src/coordinate_systems/kartesian/mod.rs
Normale Datei
293
src/coordinate_systems/kartesian/mod.rs
Normale Datei
|
@ -0,0 +1,293 @@
|
||||||
|
use log::debug;
|
||||||
|
use num::{traits::*, *};
|
||||||
|
use std::{
|
||||||
|
fmt::{Debug, Display},
|
||||||
|
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
|
||||||
|
T: Integer,
|
||||||
|
{
|
||||||
|
pub x: T,
|
||||||
|
pub y: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
if map[self.x].len() > self.y {
|
||||||
|
return Some(map[self.x][self.y]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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<T>) -> Option<Kartesian<T>> {
|
||||||
|
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<T>) -> (Kartesian<T>, KartesianDirection) {
|
||||||
|
let mut relative = Kartesian::<T>::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<T>, dir: KartesianDirection) -> Option<Kartesian<T>> {
|
||||||
|
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<T>, dir: KartesianDirection, max: Kartesian<T>) -> Option<Kartesian<T>> {
|
||||||
|
match self.move_dir(vector, dir) {
|
||||||
|
None => None,
|
||||||
|
Some(new) => {
|
||||||
|
if new.x < max.x && new.y < max.y {
|
||||||
|
Some(new)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 + 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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KartesianIterator {
|
||||||
|
i: u8,
|
||||||
|
diagonal: bool,
|
||||||
|
none: bool,
|
||||||
|
straight: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
pub struct Velocity<T: Integer + Unsigned> {
|
||||||
|
speed: Kartesian<T>,
|
||||||
|
direction: KartesianDirection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Integer + Unsigned> Velocity<T> {
|
||||||
|
pub fn new(x: T, y: T, dir: KartesianDirection) -> Self {
|
||||||
|
Velocity { speed: Kartesian { x, y }, direction: dir }
|
||||||
|
}
|
||||||
|
}
|
110
src/coordinate_systems/kartesian/test.rs
Normale Datei
110
src/coordinate_systems/kartesian/test.rs
Normale Datei
|
@ -0,0 +1,110 @@
|
||||||
|
#[cfg(test)]
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[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 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 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 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);
|
28
src/lib.rs
28
src/lib.rs
|
@ -1,4 +1,7 @@
|
||||||
use std::ops::{Add, AddAssign, DivAssign, Sub, SubAssign};
|
use std::{
|
||||||
|
ops::DivAssign,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
use num::*;
|
use num::*;
|
||||||
|
|
||||||
|
@ -31,8 +34,8 @@ pub fn matrix(zero: bool, diag: bool, non_diag: bool) -> Vec<(i32, i32)> {
|
||||||
d
|
d
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn numberlength<T: Integer + DivAssign + From<u32> + Copy>(n: T) -> u32 {
|
pub fn numberlength_base<T: Integer + DivAssign + From<u32> + Copy, const BASE: u32>(n: T) -> u32 {
|
||||||
let divider = T::from(10);
|
let divider = T::from(BASE);
|
||||||
let mut num = n;
|
let mut num = n;
|
||||||
let mut length = 0;
|
let mut length = 0;
|
||||||
loop {
|
loop {
|
||||||
|
@ -43,3 +46,22 @@ pub fn numberlength<T: Integer + DivAssign + From<u32> + Copy>(n: T) -> u32 {
|
||||||
length += 1;
|
length += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn numberlength<T: Integer + DivAssign + From<u32> + Copy>(n: T) -> u32 {
|
||||||
|
numberlength_base::<T, 10>(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn time_function<T, F: FnOnce() -> T>(func: F) -> (Duration, T) {
|
||||||
|
let now = Instant::now();
|
||||||
|
let o = func();
|
||||||
|
(now.elapsed(), o)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum ExtendedOption<T> {
|
||||||
|
#[default]
|
||||||
|
Unset,
|
||||||
|
Some(T),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::ops::AddAssign;
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn char_to_num<T: Integer + From<u32>>(c: char) -> T {
|
pub fn char_to_num<T: Integer + From<u32>>(c: char) -> T {
|
||||||
match c {
|
match c {
|
||||||
'1' => T::from(1),
|
'1' => T::one(),
|
||||||
'2' => T::from(2),
|
'2' => T::from(2),
|
||||||
'3' => T::from(3),
|
'3' => T::from(3),
|
||||||
'4' => T::from(4),
|
'4' => T::from(4),
|
||||||
|
@ -13,14 +13,13 @@ pub fn char_to_num<T: Integer + From<u32>>(c: char) -> T {
|
||||||
'7' => T::from(7),
|
'7' => T::from(7),
|
||||||
'8' => T::from(8),
|
'8' => T::from(8),
|
||||||
'9' => T::from(9),
|
'9' => T::from(9),
|
||||||
'0' => T::from(0),
|
'0' => T::zero(),
|
||||||
|
'-' => T::zero(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parsenumber<T: Integer + From<u32> + Pow<u32, Output = T> + AddAssign + Copy>(
|
pub fn parsenumber<T: Integer + From<u32> + Pow<u32, Output = T> + AddAssign + Copy>(input: &str) -> T {
|
||||||
input: &str,
|
|
||||||
) -> T {
|
|
||||||
const MAX_POWER: u32 = 32;
|
const MAX_POWER: u32 = 32;
|
||||||
let base = T::from(10);
|
let base = T::from(10);
|
||||||
let mut output: T = T::from(0);
|
let mut output: T = T::from(0);
|
||||||
|
@ -52,60 +51,60 @@ pub fn get_string_numbers(input: &str) -> Vec<u32> {
|
||||||
"1" => {
|
"1" => {
|
||||||
output.push(1);
|
output.push(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"2" => {
|
"2" => {
|
||||||
output.push(2);
|
output.push(2);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"3" => {
|
"3" => {
|
||||||
output.push(3);
|
output.push(3);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"4" => {
|
"4" => {
|
||||||
output.push(4);
|
output.push(4);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"5" => {
|
"5" => {
|
||||||
output.push(5);
|
output.push(5);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"6" => {
|
"6" => {
|
||||||
output.push(6);
|
output.push(6);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"7" => {
|
"7" => {
|
||||||
output.push(7);
|
output.push(7);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"8" => {
|
"8" => {
|
||||||
output.push(8);
|
output.push(8);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"9" => {
|
"9" => {
|
||||||
output.push(9);
|
output.push(9);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"0" => {
|
"0" => {
|
||||||
output.push(0);
|
output.push(0);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
if (i + 3) <= len {
|
if (i + 3) <= len {
|
||||||
match input.get(i..i + 3).unwrap() {
|
match input.get(i..i + 3).unwrap() {
|
||||||
"one" => {
|
"one" => {
|
||||||
output.push(1);
|
output.push(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"two" => {
|
"two" => {
|
||||||
output.push(2);
|
output.push(2);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"six" => {
|
"six" => {
|
||||||
output.push(6);
|
output.push(6);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
_ => {}
|
_ => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (i + 4) <= len {
|
if (i + 4) <= len {
|
||||||
|
@ -113,20 +112,20 @@ pub fn get_string_numbers(input: &str) -> Vec<u32> {
|
||||||
"four" => {
|
"four" => {
|
||||||
output.push(4);
|
output.push(4);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"five" => {
|
"five" => {
|
||||||
output.push(5);
|
output.push(5);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"nine" => {
|
"nine" => {
|
||||||
output.push(9);
|
output.push(9);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"zero" => {
|
"zero" => {
|
||||||
output.push(0);
|
output.push(0);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
_ => {}
|
_ => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (i + 5) <= len {
|
if (i + 5) <= len {
|
||||||
|
@ -134,16 +133,16 @@ pub fn get_string_numbers(input: &str) -> Vec<u32> {
|
||||||
"three" => {
|
"three" => {
|
||||||
output.push(3);
|
output.push(3);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"seven" => {
|
"seven" => {
|
||||||
output.push(7);
|
output.push(7);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
"eight" => {
|
"eight" => {
|
||||||
output.push(8);
|
output.push(8);
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
_ => {}
|
_ => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,10 +155,5 @@ pub fn line_to_char(line: &str) -> Vec<char> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_to_array<T, F: FnMut(&str) -> T, const S: char>(input: &str, func: F) -> Vec<T> {
|
pub fn convert_to_array<T, F: FnMut(&str) -> T, const S: char>(input: &str, func: F) -> Vec<T> {
|
||||||
input
|
input.trim().split(S).map(str::trim_ascii).map(func).collect()
|
||||||
.trim()
|
|
||||||
.split(S)
|
|
||||||
.map(str::trim_ascii)
|
|
||||||
.map(func)
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
Laden …
Tabelle hinzufügen
In neuem Issue referenzieren