Commits vergleichen
7 Commits
4f32ca95cf
...
bd97c2e422
Autor | SHA1 | Datum | |
---|---|---|---|
bd97c2e422 | |||
20ad63acaf | |||
dec9308b2f | |||
194e904ccc | |||
ed43974f0f | |||
2bbf7c86f6 | |||
855772e976 |
13 geänderte Dateien mit 785 neuen und 42 gelöschten Zeilen
80
Cargo.lock
generiert
80
Cargo.lock
generiert
|
@ -7,6 +7,7 @@ name = "advent-of-code"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"advent-of-code-macros",
|
"advent-of-code-macros",
|
||||||
|
"num",
|
||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -28,12 +29,91 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.92"
|
version = "1.0.92"
|
||||||
|
|
|
@ -309,6 +309,7 @@ path = "src/bin/2024/25.rs"
|
||||||
name = "advent_of_code"
|
name = "advent_of_code"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
num="0.4.*"
|
||||||
|
|
||||||
[dependencies.advent-of-code-macros]
|
[dependencies.advent-of-code-macros]
|
||||||
path = "macros"
|
path = "macros"
|
||||||
|
|
9
examples/2024/07.txt
Normale Datei
9
examples/2024/07.txt
Normale Datei
|
@ -0,0 +1,9 @@
|
||||||
|
190: 10 19
|
||||||
|
3267: 81 40 27
|
||||||
|
83: 17 5
|
||||||
|
156: 15 6
|
||||||
|
7290: 6 8 6 15
|
||||||
|
161011: 16 10 13
|
||||||
|
192: 17 8 14
|
||||||
|
21037: 9 7 18 13
|
||||||
|
292: 11 6 16 20
|
|
@ -1,6 +1,6 @@
|
||||||
use advent_of_code::strings::{get_numbers, get_string_numbers};
|
use advent_of_code::strings::{get_numbers, get_string_numbers};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use advent_of_code_macros::{include_data, include_example};
|
use advent_of_code::{include_data, include_example};
|
||||||
|
|
||||||
include_data!(DATAa 2023 01a);
|
include_data!(DATAa 2023 01a);
|
||||||
include_data!(DATAb 2023 01b);
|
include_data!(DATAb 2023 01b);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use advent_of_code::strings::parsenumber;
|
use advent_of_code::strings::parsenumber;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use advent_of_code_macros::{include_data, include_example};
|
use advent_of_code::{include_data, include_example};
|
||||||
|
|
||||||
include_example!(DATA 2023 02);
|
include_example!(DATA 2023 02);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use advent_of_code::strings::{parsenumber, splitspace};
|
use advent_of_code::strings::{convert_to_array, parsenumber, splitspace};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use advent_of_code_macros::{include_data, include_example};
|
use advent_of_code::{include_data, include_example};
|
||||||
|
|
||||||
include_data!(DATA 2024 01);
|
include_data!(DATA 2024 01);
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ fn similarity(leftlist: &Vec<u32>, rightlist: &Vec<u32>) -> u32 {
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut leftlist = Vec::<u32>::with_capacity(1000);
|
let mut leftlist = Vec::<u32>::with_capacity(1000);
|
||||||
let mut rightlist = Vec::<u32>::with_capacity(1000);
|
let mut rightlist = Vec::<u32>::with_capacity(1000);
|
||||||
for (left, right) in DATA.split("\n").map(splitspace) {
|
for (left, right) in convert_to_array::<_, _, '\n'>(DATA, splitspace) {
|
||||||
leftlist.push(parsenumber(left));
|
leftlist.push(parsenumber(left));
|
||||||
rightlist.push(parsenumber(right));
|
rightlist.push(parsenumber(right));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use advent_of_code::strings::parsenumber;
|
use advent_of_code::strings::{convert_to_array, parsenumber};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use advent_of_code_macros::{include_data, include_example};
|
use advent_of_code::{include_data, include_example};
|
||||||
|
|
||||||
include_data!(DATA 2024 02);
|
include_data!(DATA 2024 02);
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ fn safe(record: Vec<u32>) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let numbers = DATA.split('\n').map(get_numbers);
|
let numbers = convert_to_array::<_,_,'\n'>(DATA, get_numbers);
|
||||||
let mut safe_reports = 0;
|
let mut safe_reports = 0;
|
||||||
let mut safe_with_dampener = 0;
|
let mut safe_with_dampener = 0;
|
||||||
for report in numbers {
|
for report in numbers {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use advent_of_code::strings::parsenumber;
|
use advent_of_code::strings::parsenumber;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use advent_of_code_macros::{include_data, include_example};
|
use advent_of_code::{include_data, include_example};
|
||||||
use regex::{Captures, Regex};
|
use regex::{Captures, Regex};
|
||||||
|
|
||||||
include_data!(DATA 2024 03);
|
include_data!(DATA 2024 03);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use advent_of_code_macros::{include_data, include_example};
|
use advent_of_code::{include_data, include_example};
|
||||||
|
|
||||||
include_data!(DATA 2024 04);
|
include_data!(DATA 2024 04);
|
||||||
|
|
||||||
|
|
173
src/bin/2024/06.rs
Normale Datei
173
src/bin/2024/06.rs
Normale Datei
|
@ -0,0 +1,173 @@
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use advent_of_code::{
|
||||||
|
include_data, include_example,
|
||||||
|
strings::{convert_to_array, line_to_char},
|
||||||
|
KartesianDirection,
|
||||||
|
};
|
||||||
|
use advent_of_code::{Kartesian, Table};
|
||||||
|
use log::debug;
|
||||||
|
use num::Integer;
|
||||||
|
|
||||||
|
include_data!(DATA 2024 06);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
struct DirectionalKartesian<T: Integer> {
|
||||||
|
x: T,
|
||||||
|
y: T,
|
||||||
|
dir: KartesianDirection,
|
||||||
|
}
|
||||||
|
impl<T: Integer> From<(Kartesian<T>, KartesianDirection)> for DirectionalKartesian<T> {
|
||||||
|
fn from(value: (Kartesian<T>, KartesianDirection)) -> Self {
|
||||||
|
DirectionalKartesian {
|
||||||
|
x: value.0.x,
|
||||||
|
y: value.0.y,
|
||||||
|
dir: value.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Integer + Copy> Into<(Kartesian<T>, KartesianDirection)> for &DirectionalKartesian<T> {
|
||||||
|
fn into(self) -> (Kartesian<T>, KartesianDirection) {
|
||||||
|
(
|
||||||
|
Kartesian {
|
||||||
|
x: self.x,
|
||||||
|
y: self.y,
|
||||||
|
},
|
||||||
|
self.dir,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Integer> DirectionalKartesian<T> {
|
||||||
|
fn kartesian(self) -> Kartesian<T> {
|
||||||
|
Kartesian::new(self.x, self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_guard(map: Table) -> Kartesian<i32> {
|
||||||
|
let mut position = Kartesian::default();
|
||||||
|
for line in map {
|
||||||
|
for char in line {
|
||||||
|
if char == '^' {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
position.y += 1;
|
||||||
|
}
|
||||||
|
position.y = 0;
|
||||||
|
position.x += 1;
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_path(map: Table) -> Vec<DirectionalKartesian<i32>> {
|
||||||
|
let mut position = (find_guard(map.clone()), KartesianDirection::Top);
|
||||||
|
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
|
||||||
|
);
|
||||||
|
let mut passed = Vec::new();
|
||||||
|
passed.push(position.into());
|
||||||
|
loop {
|
||||||
|
position.0 = match position.0.checked_add_max(position.1.vector(), maximum) {
|
||||||
|
None => {
|
||||||
|
debug!("Guard left the space after {} steps", passed.len());
|
||||||
|
return passed;
|
||||||
|
}
|
||||||
|
Some(pos) => pos,
|
||||||
|
};
|
||||||
|
if map[position.0.x as usize][position.0.y as usize] != '#' {
|
||||||
|
passed.push(position.into());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
position.0 -= position.1.vector();
|
||||||
|
debug!(
|
||||||
|
"Guard turned right on {}:{}",
|
||||||
|
position.0.x + 1,
|
||||||
|
position.0.y + 1
|
||||||
|
);
|
||||||
|
position.1 = position.1.clockwise(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solver1(input: &str) -> usize {
|
||||||
|
let map = convert_to_array(input, line_to_char);
|
||||||
|
let mut path = get_path(map);
|
||||||
|
path.sort();
|
||||||
|
path.dedup_by_key(|p| (p.x, p.y));
|
||||||
|
path.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_looping(
|
||||||
|
path: Vec<DirectionalKartesian<i32>>,
|
||||||
|
start_point: DirectionalKartesian<i32>,
|
||||||
|
) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables, unused_mut)]
|
||||||
|
fn solver2(input: &str) -> usize {
|
||||||
|
let map = convert_to_array(input, line_to_char);
|
||||||
|
let maximum = Kartesian::new(map.len() as i32, map[0].len() as i32);
|
||||||
|
let mut path = get_path(map.clone());
|
||||||
|
let mut p = path.iter();
|
||||||
|
let mut looppoints = Vec::new();
|
||||||
|
let startpoint = p.next().unwrap().kartesian();
|
||||||
|
|
||||||
|
let mut currentpoint: (Kartesian<i32>, KartesianDirection);
|
||||||
|
for point in p {
|
||||||
|
if point.kartesian() == startpoint {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
currentpoint = point.into();
|
||||||
|
currentpoint.1 = currentpoint.1.clockwise(false);
|
||||||
|
loop {
|
||||||
|
currentpoint.0 = match currentpoint
|
||||||
|
.0
|
||||||
|
.checked_add_max(currentpoint.1.vector(), maximum)
|
||||||
|
{
|
||||||
|
None => break,
|
||||||
|
Some(p) => p,
|
||||||
|
};
|
||||||
|
if path.contains(¤tpoint.into()) {
|
||||||
|
looppoints.push(point.kartesian());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if map[currentpoint.0.x as usize][currentpoint.0.y as usize] == '#' {
|
||||||
|
currentpoint.0 -= currentpoint.1.vector();
|
||||||
|
currentpoint.1 = currentpoint.1.clockwise(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
looppoints.dedup();
|
||||||
|
looppoints.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!(
|
||||||
|
"Guard left the space after walking through {} distinct positions",
|
||||||
|
solver1(DATA)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"There are {} positions that are good for loops",
|
||||||
|
solver2(DATA)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
include_example!(EXAMPLE 2024 06);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_solution_1() {
|
||||||
|
assert_eq!(solver1(EXAMPLE), 41);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_solution_2() {
|
||||||
|
assert_eq!(solver2(EXAMPLE), 6);
|
||||||
|
}
|
||||||
|
}
|
181
src/bin/2024/07.rs
Normale Datei
181
src/bin/2024/07.rs
Normale Datei
|
@ -0,0 +1,181 @@
|
||||||
|
#![cfg_attr(debug_assertions, allow(unused_imports))]
|
||||||
|
use std::ops::{Add, AddAssign, BitXor, Mul};
|
||||||
|
|
||||||
|
use advent_of_code::{
|
||||||
|
numberlength,
|
||||||
|
strings::{convert_to_array, parsenumber},
|
||||||
|
};
|
||||||
|
use advent_of_code_macros::{include_data, include_example};
|
||||||
|
use log::*;
|
||||||
|
use num::{pow::Pow, Integer};
|
||||||
|
|
||||||
|
include_data!(DATA 2024 07);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum Operation {
|
||||||
|
Add,
|
||||||
|
Multiply,
|
||||||
|
Concat,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
match self {
|
||||||
|
Operation::Add => a + b,
|
||||||
|
Operation::Multiply => a * b,
|
||||||
|
Operation::Concat => {
|
||||||
|
let ta = a * T::from(10).pow(numberlength(b));
|
||||||
|
ta + b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_data(line: &str) -> (u64, Vec<u64>) {
|
||||||
|
let (result, numbers) = line.split_once(':').unwrap();
|
||||||
|
|
||||||
|
(
|
||||||
|
parsenumber(result.trim()),
|
||||||
|
Vec::from(convert_to_array::<_, _, ' '>(numbers, parsenumber)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_equation(result: u64, numbers: Vec<u64>, ops: Vec<Operation>) -> bool {
|
||||||
|
let mut numberiter = numbers.iter();
|
||||||
|
let mut opiter = ops.iter();
|
||||||
|
let mut calcresult = numberiter.next().unwrap().clone();
|
||||||
|
let mut next_number;
|
||||||
|
debug_assert!(numbers.len() - 1 == ops.len());
|
||||||
|
loop {
|
||||||
|
next_number = numberiter.next().cloned();
|
||||||
|
if next_number.is_none() {
|
||||||
|
return calcresult == result;
|
||||||
|
}
|
||||||
|
calcresult = opiter.next().unwrap().op(calcresult, next_number.unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ops(len: usize, conf: usize) -> Vec<Operation> {
|
||||||
|
let mut shift = 0;
|
||||||
|
let mut ops = Vec::with_capacity(len);
|
||||||
|
loop {
|
||||||
|
match (conf & (0b1 << shift)) >> shift {
|
||||||
|
0 => ops.push(Operation::Add),
|
||||||
|
1 => ops.push(Operation::Multiply),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
shift += 1;
|
||||||
|
if ops.len() == len {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ops
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ops_with_concat(len: u32) -> Vec<Vec<Operation>> {
|
||||||
|
let mut ops = Vec::with_capacity(3u64.saturating_pow(len) as usize);
|
||||||
|
for i in [Operation::Add, Operation::Concat, Operation::Multiply] {
|
||||||
|
if len > 1 {
|
||||||
|
for mut oplist in get_ops_with_concat(len - 1) {
|
||||||
|
oplist.insert(0, i);
|
||||||
|
ops.push(oplist);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ops.push(vec![i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ops
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn pow2(i: usize) -> usize {
|
||||||
|
2_u64.pow(i as u32) as usize - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solution1(data: Vec<(u64, Vec<u64>)>) -> u64 {
|
||||||
|
let mut output = 0;
|
||||||
|
for line in data {
|
||||||
|
for i in 0..=pow2(line.1.len()) {
|
||||||
|
if test_equation(line.0, line.1.clone(), get_ops(line.1.len() - 1, i)) {
|
||||||
|
output += line.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solution2(data: Vec<(u64, Vec<u64>)>) -> u128 {
|
||||||
|
let mut output = 0;
|
||||||
|
for line in data {
|
||||||
|
for ops in get_ops_with_concat((line.1.len() - 1) as u32) {
|
||||||
|
if test_equation(line.0, line.1.clone(), ops) {
|
||||||
|
output += line.0 as u128;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let data = convert_to_array::<_, _, '\n'>(DATA, get_data);
|
||||||
|
println!("Found Calibration Total: {}", solution1(data.clone()));
|
||||||
|
println!("Calibration total with Concat: {}", solution2(data.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_equation() {
|
||||||
|
for c in [
|
||||||
|
(
|
||||||
|
190,
|
||||||
|
Vec::from([10, 19]),
|
||||||
|
Vec::from([Operation::Multiply]),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
3267,
|
||||||
|
Vec::from([81, 40, 27]),
|
||||||
|
Vec::from([Operation::Add, Operation::Multiply]),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
3267,
|
||||||
|
Vec::from([81, 40, 27]),
|
||||||
|
Vec::from([Operation::Multiply, Operation::Add]),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
292,
|
||||||
|
Vec::from([11, 6, 16, 20]),
|
||||||
|
Vec::from([Operation::Add, Operation::Multiply, Operation::Add]),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
292,
|
||||||
|
Vec::from([11, 6, 16, 20]),
|
||||||
|
Vec::from([Operation::Add, Operation::Multiply, Operation::Multiply]),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
] {
|
||||||
|
assert_eq!(test_equation(c.0, c.1.into(), c.2.into()), c.3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
280
src/lib.rs
280
src/lib.rs
|
@ -1 +1,281 @@
|
||||||
|
use std::ops::{Add, AddAssign, DivAssign, Sub, SubAssign};
|
||||||
|
|
||||||
|
use num::*;
|
||||||
|
|
||||||
pub mod strings;
|
pub mod strings;
|
||||||
|
pub use advent_of_code_macros::*;
|
||||||
|
|
||||||
|
pub type Table = Vec<Vec<char>>;
|
||||||
|
|
||||||
|
pub fn matrix(zero: bool, diag: bool, non_diag: bool) -> Vec<(i32, i32)> {
|
||||||
|
const MIN: i32 = -1;
|
||||||
|
const MAX: i32 = 1;
|
||||||
|
let mut d = Vec::new();
|
||||||
|
for i in MIN..=MAX {
|
||||||
|
for j in MIN..=MAX {
|
||||||
|
let ia = i.abs();
|
||||||
|
let ja = j.abs();
|
||||||
|
if zero && i == 0 && j == 0 {
|
||||||
|
d.push((i, j));
|
||||||
|
}
|
||||||
|
if diag && ia == 1 && ja == 1 {
|
||||||
|
d.push((i, j));
|
||||||
|
}
|
||||||
|
if non_diag && ia != ja && ia + ja == 1 {
|
||||||
|
d.push((i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
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<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 + 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Euclidian<T>
|
||||||
|
where
|
||||||
|
T: Integer,
|
||||||
|
{
|
||||||
|
pub x: T,
|
||||||
|
pub y: T,
|
||||||
|
pub z: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Integer> Add for Euclidian<T> {
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Euclidian {
|
||||||
|
x: self.x + rhs.x,
|
||||||
|
y: self.y + rhs.y,
|
||||||
|
z: self.z + rhs.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Output = Euclidian<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Integer + AddAssign> AddAssign for Euclidian<T> {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.x += rhs.x;
|
||||||
|
self.y += rhs.y;
|
||||||
|
self.z += rhs.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Integer> Sub for Euclidian<T> {
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Euclidian {
|
||||||
|
x: self.x - rhs.x,
|
||||||
|
y: self.y - rhs.y,
|
||||||
|
z: self.z - rhs.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Output = Euclidian<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Integer + SubAssign> SubAssign for Euclidian<T> {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.x -= rhs.x;
|
||||||
|
self.y -= rhs.y;
|
||||||
|
self.z -= rhs.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Integer> Euclidian<T> {
|
||||||
|
pub const fn new(x: T, y: T, z: T) -> Self {
|
||||||
|
Self { x: x, y: y, z: z }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<T: Signed + Integer + Zero + From<i8>>(self) -> Kartesian<T> {
|
||||||
|
const BELOW: i8 = -1;
|
||||||
|
const ON: i8 = 0;
|
||||||
|
const UPPER: i8 = 1;
|
||||||
|
Kartesian::<T> {
|
||||||
|
x: match self {
|
||||||
|
Self::TopLeft | Self::Top | Self::TopRight => BELOW.into(),
|
||||||
|
Self::Left | Self::None | Self::Right => ON.into(),
|
||||||
|
Self::BottomLeft | Self::Bottom | Self::BottomRight => UPPER.into(),
|
||||||
|
},
|
||||||
|
y: match self {
|
||||||
|
Self::TopLeft | Self::Left | Self::BottomLeft => BELOW.into(),
|
||||||
|
Self::Top | Self::None | Self::Bottom => ON.into(),
|
||||||
|
Self::TopRight | Self::Right | Self::BottomRight => UPPER.into(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clockwise(self, diagonal: bool) -> KartesianDirection {
|
||||||
|
match (self, diagonal) {
|
||||||
|
(KartesianDirection::TopLeft, _) => Self::Top,
|
||||||
|
(KartesianDirection::Top, true) => Self::TopRight,
|
||||||
|
(KartesianDirection::Top, false) => Self::Right,
|
||||||
|
(KartesianDirection::TopRight, _) => Self::Right,
|
||||||
|
(KartesianDirection::Left, true) => Self::TopLeft,
|
||||||
|
(KartesianDirection::Left, false) => Self::Top,
|
||||||
|
(KartesianDirection::None, _) => Self::None,
|
||||||
|
(KartesianDirection::Right, true) => Self::BottomRight,
|
||||||
|
(KartesianDirection::Right, false) => Self::Bottom,
|
||||||
|
(KartesianDirection::BottomLeft, _) => Self::Left,
|
||||||
|
(KartesianDirection::Bottom, true) => Self::BottomLeft,
|
||||||
|
(KartesianDirection::Bottom, false) => Self::Left,
|
||||||
|
(KartesianDirection::BottomRight, _) => Self::Bottom,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn anticlockwise(self, diagonal: bool) -> KartesianDirection {
|
||||||
|
match (self, diagonal) {
|
||||||
|
(KartesianDirection::TopLeft, _) => Self::Left,
|
||||||
|
(KartesianDirection::Top, true) => Self::TopLeft,
|
||||||
|
(KartesianDirection::Top, false) => Self::Left,
|
||||||
|
(KartesianDirection::TopRight, _) => Self::Top,
|
||||||
|
(KartesianDirection::Left, true) => Self::BottomLeft,
|
||||||
|
(KartesianDirection::Left, false) => Self::Bottom,
|
||||||
|
(KartesianDirection::None, _) => Self::None,
|
||||||
|
(KartesianDirection::Right, true) => Self::TopRight,
|
||||||
|
(KartesianDirection::Right, false) => Self::Top,
|
||||||
|
(KartesianDirection::BottomLeft, _) => Self::Bottom,
|
||||||
|
(KartesianDirection::Bottom, true) => Self::BottomRight,
|
||||||
|
(KartesianDirection::Bottom, false) => Self::Right,
|
||||||
|
(KartesianDirection::BottomRight, _) => Self::Right,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn numberlength<T: Integer + DivAssign + From<u32> + Copy>(n: T) -> u32 {
|
||||||
|
let divider = T::from(10);
|
||||||
|
let mut num = n;
|
||||||
|
let mut length = 0;
|
||||||
|
loop {
|
||||||
|
if num < divider {
|
||||||
|
return length + 1;
|
||||||
|
}
|
||||||
|
num /= divider;
|
||||||
|
length += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,51 +1,56 @@
|
||||||
const MAXMUL: u32 = 100000;
|
use num::{pow::Pow, Integer};
|
||||||
|
use std::ops::AddAssign;
|
||||||
|
|
||||||
pub fn splitspace(input: &str) -> (&str, &str) {
|
pub fn splitspace(input: &str) -> (&str, &str) {
|
||||||
let mut output = input.split_ascii_whitespace();
|
let mut output = input.split_ascii_whitespace();
|
||||||
(output.next().unwrap(), output.next().unwrap())
|
(output.next().unwrap().trim(), output.next().unwrap().trim())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parsenumber(input: &str) -> u32 {
|
pub fn parsenumber<T: Integer + From<u32> + Pow<u32, Output = T> + AddAssign + Copy>(
|
||||||
let mut output = 0;
|
input: &str,
|
||||||
let mut mul = 1;
|
) -> T {
|
||||||
|
const MAX_POWER: u32 = 32;
|
||||||
|
let base = T::from(10);
|
||||||
|
let mut output: T = T::from(0);
|
||||||
|
let mut mul: u32 = 0;
|
||||||
for c in input.chars().rev() {
|
for c in input.chars().rev() {
|
||||||
let i: u32 = match c {
|
let i: T = match c {
|
||||||
'1' => 1,
|
'1' => T::from(1),
|
||||||
'2' => 2,
|
'2' => T::from(2),
|
||||||
'3' => 3,
|
'3' => T::from(3),
|
||||||
'4' => 4,
|
'4' => T::from(4),
|
||||||
'5' => 5,
|
'5' => T::from(5),
|
||||||
'6' => 6,
|
'6' => T::from(6),
|
||||||
'7' => 7,
|
'7' => T::from(7),
|
||||||
'8' => 8,
|
'8' => T::from(8),
|
||||||
'9' => 9,
|
'9' => T::from(9),
|
||||||
'0' => 0,
|
'0' => T::from(0),
|
||||||
_ => 0,
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
if mul > MAXMUL {
|
if mul > MAX_POWER {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
output += i * mul;
|
output += i * base.pow(mul);
|
||||||
mul *= 10;
|
mul += 1;
|
||||||
}
|
}
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_numbers(input: &str) -> Vec<u32> {
|
pub fn get_numbers<T: Integer + From<u32>>(input: &str) -> Vec<T> {
|
||||||
let mut numbers = Vec::new();
|
let mut numbers = Vec::new();
|
||||||
for char in input.chars() {
|
for char in input.chars() {
|
||||||
match char {
|
match char {
|
||||||
'1' => numbers.push(1),
|
'1' => numbers.push(T::from(1)),
|
||||||
'2' => numbers.push(2),
|
'2' => numbers.push(T::from(2)),
|
||||||
'3' => numbers.push(3),
|
'3' => numbers.push(T::from(3)),
|
||||||
'4' => numbers.push(4),
|
'4' => numbers.push(T::from(4)),
|
||||||
'5' => numbers.push(5),
|
'5' => numbers.push(T::from(5)),
|
||||||
'6' => numbers.push(6),
|
'6' => numbers.push(T::from(6)),
|
||||||
'7' => numbers.push(7),
|
'7' => numbers.push(T::from(7)),
|
||||||
'8' => numbers.push(8),
|
'8' => numbers.push(T::from(8)),
|
||||||
'9' => numbers.push(9),
|
'9' => numbers.push(T::from(9)),
|
||||||
'0' => numbers.push(0),
|
'0' => numbers.push(T::from(0)),
|
||||||
_ => {}
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
numbers
|
numbers
|
||||||
|
@ -156,3 +161,17 @@ pub fn get_string_numbers(input: &str) -> Vec<u32> {
|
||||||
}
|
}
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn line_to_char(line: &str) -> Vec<char> {
|
||||||
|
Vec::from_iter(line.chars())
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
Laden …
Tabelle hinzufügen
In neuem Issue referenzieren