Commits vergleichen
Keine gemeinsamen Commits. „6fafca3b6bda6776b4f2324d37d2f9ec0843e311“ und „78327e8658366e000509f536ca8c0501775db136“ haben vollständig unterschiedliche Historien.
6fafca3b6b
...
78327e8658
36 geänderte Dateien mit 666 neuen und 1892 gelöschten Zeilen
14
Cargo.lock
generiert
14
Cargo.lock
generiert
|
@ -7,10 +7,8 @@ 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]]
|
||||||
|
@ -37,12 +35,6 @@ 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"
|
||||||
|
@ -180,12 +172,6 @@ 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,8 +310,6 @@ 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
15
Makefile
|
@ -1,15 +0,0 @@
|
||||||
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 +0,0 @@
|
||||||
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))
|
|
|
@ -1,12 +0,0 @@
|
||||||
............
|
|
||||||
........0...
|
|
||||||
.....0......
|
|
||||||
.......0....
|
|
||||||
....0.......
|
|
||||||
......A.....
|
|
||||||
............
|
|
||||||
............
|
|
||||||
........A...
|
|
||||||
.........A..
|
|
||||||
............
|
|
||||||
............
|
|
|
@ -1 +0,0 @@
|
||||||
125 17
|
|
|
@ -1 +0,0 @@
|
||||||
12c.txt
|
|
|
@ -1,4 +0,0 @@
|
||||||
AAAA
|
|
||||||
BBCD
|
|
||||||
BBCC
|
|
||||||
EEEC
|
|
|
@ -1,5 +0,0 @@
|
||||||
OOOOO
|
|
||||||
OXOXO
|
|
||||||
OOOOO
|
|
||||||
OXOXO
|
|
||||||
OOOOO
|
|
|
@ -1,10 +0,0 @@
|
||||||
RRRRIICCFF
|
|
||||||
RRRRIICCCF
|
|
||||||
VVRRRCCFFF
|
|
||||||
VVRCCCJFFF
|
|
||||||
VVVVCJJCFE
|
|
||||||
VVIVCCJJEE
|
|
||||||
VVIIICJJEE
|
|
||||||
MIIIIIJJEE
|
|
||||||
MIIISIJEEE
|
|
||||||
MMMISSJEEE
|
|
|
@ -1,5 +0,0 @@
|
||||||
EEEEE
|
|
||||||
EXXXX
|
|
||||||
EEEEE
|
|
||||||
EXXXX
|
|
||||||
EEEEE
|
|
|
@ -1,6 +0,0 @@
|
||||||
AAAAAA
|
|
||||||
AAABBA
|
|
||||||
AAABBA
|
|
||||||
ABBAAA
|
|
||||||
ABBAAA
|
|
||||||
AAAAAA
|
|
|
@ -1,12 +0,0 @@
|
||||||
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,7 +22,11 @@ struct IncludeData {
|
||||||
|
|
||||||
impl Default for IncludeData {
|
impl Default for IncludeData {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
IncludeData { var: VAR_NAME.into(), year: None, day: None }
|
IncludeData {
|
||||||
|
var: VAR_NAME.into(),
|
||||||
|
year: None,
|
||||||
|
day: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +37,14 @@ 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(span, format!("Failed to get sourcetext for {}:{}-{}:{}", start.line, start.column, end.line, end.column,)))
|
Err(Error::new(
|
||||||
},
|
span,
|
||||||
|
format!(
|
||||||
|
"Failed to get sourcetext for {}:{}-{}:{}",
|
||||||
|
start.line, start.column, end.line, end.column,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +73,7 @@ fn canonicalize(dir: &str, input: IncludeData) -> Option<String> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,12 +113,15 @@ 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!("Failed to get the year({:?}) or day({:?}) falling back to default", input.year, input.day);
|
comment = format!(
|
||||||
|
"Failed to get the year({:?}) or day({:?}) falling back to default",
|
||||||
|
input.year, input.day
|
||||||
|
);
|
||||||
}
|
}
|
||||||
quote! {
|
quote! {
|
||||||
#[doc = #comment]
|
#[doc = #comment]
|
||||||
|
@ -135,12 +148,15 @@ 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!("Failed to get the year({:?}) or day({:?}) falling back to default", input.year, input.day);
|
comment = format!(
|
||||||
|
"Failed to get the year({:?}) or day({:?}) falling back to default",
|
||||||
|
input.year, input.day
|
||||||
|
);
|
||||||
}
|
}
|
||||||
quote! {
|
quote! {
|
||||||
#[doc = #comment]
|
#[doc = #comment]
|
||||||
|
|
17
rustfmt.toml
17
rustfmt.toml
|
@ -1,17 +0,0 @@
|
||||||
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,7 +42,11 @@ impl Round {
|
||||||
ok
|
ok
|
||||||
}
|
}
|
||||||
fn power(&self) -> u64 {
|
fn power(&self) -> u64 {
|
||||||
let mut sack = Sack { reds: 0, greens: 0, blues: 0 };
|
let mut sack = Sack {
|
||||||
|
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
|
||||||
|
@ -66,7 +70,11 @@ 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 { red: 0, green: 0, blue: 0 };
|
let mut take = Take {
|
||||||
|
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());
|
||||||
|
@ -88,7 +96,11 @@ 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 { reds: 12, greens: 13, blues: 14 };
|
let sack = Sack {
|
||||||
|
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,7 +7,10 @@ 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,13 +18,23 @@ 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 { x: value.0.x, y: value.0.y, dir: value.1 }
|
DirectionalKartesian {
|
||||||
|
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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,15 +62,19 @@ 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!("Guard is on coordinate {}:{}", position.0.x + 1, position.0.y + 1);
|
debug!(
|
||||||
|
"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().into(), maximum) {
|
position.0 = match position.0.checked_add_max(position.1.vector(), 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] != '#' {
|
||||||
|
@ -68,26 +82,33 @@ fn get_path(map: Table) -> Vec<DirectionalKartesian<i32>> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
position.0 -= position.1.vector();
|
position.0 -= position.1.vector();
|
||||||
debug!("Guard turned right on {}:{}", position.0.x + 1, position.0.y + 1);
|
debug!(
|
||||||
|
"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::<_, _, '\n'>(input, line_to_char);
|
let map = convert_to_array(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(_path: Vec<DirectionalKartesian<i32>>, _start_point: DirectionalKartesian<i32>) -> bool {
|
fn is_looping(
|
||||||
|
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::<_, _, '\n'>(input, line_to_char);
|
let map = convert_to_array(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();
|
||||||
|
@ -102,7 +123,10 @@ 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.0.checked_add_max(currentpoint.1.vector(), maximum) {
|
currentpoint.0 = match currentpoint
|
||||||
|
.0
|
||||||
|
.checked_add_max(currentpoint.1.vector(), maximum)
|
||||||
|
{
|
||||||
None => break,
|
None => break,
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
};
|
};
|
||||||
|
@ -121,8 +145,14 @@ fn solver2(input: &str) -> usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Guard left the space after walking through {} distinct positions", solver1(DATA));
|
println!(
|
||||||
println!("There are {} positions that are good for loops", solver2(DATA));
|
"Guard left the space after walking through {} distinct positions",
|
||||||
|
solver1(DATA)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"There are {} positions that are good for loops",
|
||||||
|
solver2(DATA)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -19,14 +19,27 @@ enum Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operation {
|
impl Operation {
|
||||||
fn op<T: Integer + Add + Mul + Pow<u32, Output = T> + std::ops::DivAssign + AddAssign + From<u32> + Copy>(self, a: T, b: T) -> T {
|
fn op<
|
||||||
|
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
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +47,10 @@ 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 {
|
||||||
|
@ -71,11 +87,7 @@ 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 [
|
for i in [Operation::Add, Operation::Concat, Operation::Multiply] {
|
||||||
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);
|
||||||
|
@ -134,56 +146,32 @@ mod test {
|
||||||
for c in [
|
for c in [
|
||||||
(
|
(
|
||||||
190,
|
190,
|
||||||
Vec::from([
|
Vec::from([10, 19]),
|
||||||
10, 19,
|
|
||||||
]),
|
|
||||||
Vec::from([Operation::Multiply]),
|
Vec::from([Operation::Multiply]),
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
3267,
|
3267,
|
||||||
Vec::from([
|
Vec::from([81, 40, 27]),
|
||||||
81, 40, 27,
|
Vec::from([Operation::Add, Operation::Multiply]),
|
||||||
]),
|
|
||||||
Vec::from([
|
|
||||||
Operation::Add,
|
|
||||||
Operation::Multiply,
|
|
||||||
]),
|
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
3267,
|
3267,
|
||||||
Vec::from([
|
Vec::from([81, 40, 27]),
|
||||||
81, 40, 27,
|
Vec::from([Operation::Multiply, Operation::Add]),
|
||||||
]),
|
|
||||||
Vec::from([
|
|
||||||
Operation::Multiply,
|
|
||||||
Operation::Add,
|
|
||||||
]),
|
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
292,
|
292,
|
||||||
Vec::from([
|
Vec::from([11, 6, 16, 20]),
|
||||||
11, 6, 16, 20,
|
Vec::from([Operation::Add, Operation::Multiply, Operation::Add]),
|
||||||
]),
|
|
||||||
Vec::from([
|
|
||||||
Operation::Add,
|
|
||||||
Operation::Multiply,
|
|
||||||
Operation::Add,
|
|
||||||
]),
|
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
292,
|
292,
|
||||||
Vec::from([
|
Vec::from([11, 6, 16, 20]),
|
||||||
11, 6, 16, 20,
|
Vec::from([Operation::Add, Operation::Multiply, Operation::Multiply]),
|
||||||
]),
|
|
||||||
Vec::from([
|
|
||||||
Operation::Add,
|
|
||||||
Operation::Multiply,
|
|
||||||
Operation::Multiply,
|
|
||||||
]),
|
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
] {
|
] {
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
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,8 +136,14 @@ 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!("Checksum for the blockcompacted disk is: {}", cksum);
|
println!(
|
||||||
|
"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!("Checksum for the filecompacted disk is: {}", cksum,);
|
println!(
|
||||||
|
"Checksum for the filecompacted disk is: {}",
|
||||||
|
cksum,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,193 +0,0 @@
|
||||||
#![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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,307 +0,0 @@
|
||||||
#![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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
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,7 +60,4 @@ 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 };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
502
src/coordinate_systems/kartesian.rs
Normale Datei
502
src/coordinate_systems/kartesian.rs
Normale Datei
|
@ -0,0 +1,502 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,153 +0,0 @@
|
||||||
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(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,142 +0,0 @@
|
||||||
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(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
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)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
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() }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,293 +0,0 @@
|
||||||
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 }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
#[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)
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
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,7 +1,4 @@
|
||||||
use std::{
|
use std::ops::{Add, AddAssign, DivAssign, Sub, SubAssign};
|
||||||
ops::DivAssign,
|
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
|
||||||
|
|
||||||
use num::*;
|
use num::*;
|
||||||
|
|
||||||
|
@ -34,8 +31,8 @@ pub fn matrix(zero: bool, diag: bool, non_diag: bool) -> Vec<(i32, i32)> {
|
||||||
d
|
d
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn numberlength_base<T: Integer + DivAssign + From<u32> + Copy, const BASE: u32>(n: T) -> u32 {
|
pub fn numberlength<T: Integer + DivAssign + From<u32> + Copy>(n: T) -> u32 {
|
||||||
let divider = T::from(BASE);
|
let divider = T::from(10);
|
||||||
let mut num = n;
|
let mut num = n;
|
||||||
let mut length = 0;
|
let mut length = 0;
|
||||||
loop {
|
loop {
|
||||||
|
@ -46,22 +43,3 @@ pub fn numberlength_base<T: Integer + DivAssign + From<u32> + Copy, const BASE:
|
||||||
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::one(),
|
'1' => T::from(1),
|
||||||
'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,13 +13,14 @@ 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::zero(),
|
'0' => T::from(0),
|
||||||
'-' => T::zero(),
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parsenumber<T: Integer + From<u32> + Pow<u32, Output = T> + AddAssign + Copy>(input: &str) -> T {
|
pub fn parsenumber<T: Integer + From<u32> + Pow<u32, Output = T> + AddAssign + Copy>(
|
||||||
|
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);
|
||||||
|
@ -51,60 +52,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 {
|
||||||
|
@ -112,20 +113,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 {
|
||||||
|
@ -133,16 +134,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;
|
||||||
},
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,5 +156,10 @@ 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.trim().split(S).map(str::trim_ascii).map(func).collect()
|
input
|
||||||
|
.trim()
|
||||||
|
.split(S)
|
||||||
|
.map(str::trim_ascii)
|
||||||
|
.map(func)
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
Laden …
Tabelle hinzufügen
In neuem Issue referenzieren