Compare commits
No commits in common. "9a10cf7c47c39bec3e67a04da091805297a1fa30" and "cb7e8465a2342048f0d10c73834dfa3bb6a7e03f" have entirely different histories.
9a10cf7c47
...
cb7e8465a2
17 changed files with 341 additions and 1264 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1 @@
|
|||
/target
|
||||
/real_puzzel_input/*
|
||||
!/real_puzzel_input/.gitkeep
|
||||
|
|
60
\
Normal file
60
\
Normal file
|
@ -0,0 +1,60 @@
|
|||
use std::{fs, io, path::Path, process::ExitCode};
|
||||
|
||||
use advent_of_code_2023::{cli::AppCliArguments, solutions};
|
||||
use clap::Parser;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let args = AppCliArguments::parse();
|
||||
let solution = solve_given(&args);
|
||||
match solution {
|
||||
Ok(found_solution) => {
|
||||
println!("{}", found_solution);
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
Err(error) => {
|
||||
eprintln!("{}", error);
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn solve_given(args: &AppCliArguments) -> Result<String, CouldNotSolveError> {
|
||||
let all_solutions = solutions::create_solutions();
|
||||
|
||||
let found_task = {
|
||||
let day: u32 = args.day().into();
|
||||
let task: u32 = args.task().into();
|
||||
let found_day = all_solutions
|
||||
.get(day.saturating_sub(1) as usize)
|
||||
.ok_or_else(|| CouldNotSolveError::DayNotFound(day))?;
|
||||
found_day
|
||||
.get(task.saturating_sub(1) as usize)
|
||||
.ok_or_else(|| CouldNotSolveError::TaskNotFound { day, task })
|
||||
}?;
|
||||
|
||||
let solved = (found_task)(args.input());
|
||||
Ok(solved)
|
||||
}
|
||||
|
||||
fn try_read_from_file_if_demanded(args: &AppCliArguments) -> io::Result<String> {
|
||||
let content = if args.read_as_file() {
|
||||
let path = Path::new(args.input());
|
||||
let input_as_file = fs::read_to_string(path)?;
|
||||
input_as_file
|
||||
} else {
|
||||
args.input().to_string()
|
||||
};
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Error)]
|
||||
enum CouldNotSolveError {
|
||||
#[error("There is no solution for the day {0}")]
|
||||
DayNotFound(u32),
|
||||
#[error("There is not solution for task {task} under the day {day}")]
|
||||
TaskNotFound { day: u32, task: u32 },
|
||||
#[error("Could not read puzzel input from the given file\n {0}")]
|
||||
CouldNotReadFromFile(#[from] io::Error),
|
||||
}
|
451
output.txt
451
output.txt
|
@ -1,451 +0,0 @@
|
|||
Compiling advent_of_code_2023 v0.1.0 (/home/nice_graphic/Code/AdventOfCode/advent_of_code_2023_in_rust)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.74s
|
||||
Running `target/debug/advent_of_code_2023 -d 5 -t 2 -r real_puzzel_input/day5_real.txt`
|
||||
[src/solutions/day5/task2.rs:42:5] ¤t_branches = [
|
||||
SeedRange {
|
||||
start: 1742065688,
|
||||
end: 1750102221,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2567370277,
|
||||
end: 2599723683,
|
||||
},
|
||||
]
|
||||
[src/solutions/day5/task2.rs:42:5] ¤t_branches = [
|
||||
SeedRange {
|
||||
start: 0,
|
||||
end: 8416624,
|
||||
},
|
||||
SeedRange {
|
||||
start: 266989853,
|
||||
end: 274550609,
|
||||
},
|
||||
SeedRange {
|
||||
start: 300866774,
|
||||
end: 317512630,
|
||||
},
|
||||
SeedRange {
|
||||
start: 358218184,
|
||||
end: 372723591,
|
||||
},
|
||||
SeedRange {
|
||||
start: 380891048,
|
||||
end: 442413628,
|
||||
},
|
||||
SeedRange {
|
||||
start: 515244023,
|
||||
end: 557308930,
|
||||
},
|
||||
SeedRange {
|
||||
start: 683066098,
|
||||
end: 684855124,
|
||||
},
|
||||
SeedRange {
|
||||
start: 807721029,
|
||||
end: 832371103,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1194459751,
|
||||
end: 1203805997,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1468004524,
|
||||
end: 1485692688,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1543990204,
|
||||
end: 1544270679,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2018290756,
|
||||
end: 2019801469,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2019801470,
|
||||
end: 2042706893,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2115385660,
|
||||
end: 2129003835,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2129003836,
|
||||
end: 2211102547,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2392979056,
|
||||
end: 2408003322,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2607311497,
|
||||
end: 2674349508,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2746561268,
|
||||
end: 2747062564,
|
||||
},
|
||||
]
|
||||
[src/solutions/day5/task2.rs:42:5] ¤t_branches = [
|
||||
SeedRange {
|
||||
start: 58753428,
|
||||
end: 65411093,
|
||||
},
|
||||
SeedRange {
|
||||
start: 100997493,
|
||||
end: 137201535,
|
||||
},
|
||||
SeedRange {
|
||||
start: 157986927,
|
||||
end: 199863499,
|
||||
},
|
||||
SeedRange {
|
||||
start: 204313376,
|
||||
end: 218545188,
|
||||
},
|
||||
SeedRange {
|
||||
start: 332621358,
|
||||
end: 372723591,
|
||||
},
|
||||
SeedRange {
|
||||
start: 426571448,
|
||||
end: 467405784,
|
||||
},
|
||||
SeedRange {
|
||||
start: 495575122,
|
||||
end: 511974002,
|
||||
},
|
||||
SeedRange {
|
||||
start: 743910440,
|
||||
end: 759938333,
|
||||
},
|
||||
SeedRange {
|
||||
start: 759938334,
|
||||
end: 760087643,
|
||||
},
|
||||
SeedRange {
|
||||
start: 793045073,
|
||||
end: 807721028,
|
||||
},
|
||||
SeedRange {
|
||||
start: 867655257,
|
||||
end: 896123052,
|
||||
},
|
||||
SeedRange {
|
||||
start: 896123053,
|
||||
end: 973947275,
|
||||
},
|
||||
SeedRange {
|
||||
start: 973947276,
|
||||
end: 993981548,
|
||||
},
|
||||
SeedRange {
|
||||
start: 993981549,
|
||||
end: 1002343672,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1055927934,
|
||||
end: 1095728907,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1095728908,
|
||||
end: 1119175102,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1154854138,
|
||||
end: 1180635906,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1238423661,
|
||||
end: 1248511724,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1512990961,
|
||||
end: 1523584140,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1534040686,
|
||||
end: 1546302601,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1803258673,
|
||||
end: 1809841397,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1809841398,
|
||||
end: 1841935458,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1856531115,
|
||||
end: 1913738155,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2018290756,
|
||||
end: 2028995369,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2674349509,
|
||||
end: 2681453545,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2738910873,
|
||||
end: 2744209881,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2747062565,
|
||||
end: 2783941215,
|
||||
},
|
||||
]
|
||||
[src/solutions/day5/task2.rs:42:5] ¤t_branches = [
|
||||
SeedRange {
|
||||
start: 475181169,
|
||||
end: 490368072,
|
||||
},
|
||||
SeedRange {
|
||||
start: 836186785,
|
||||
end: 843842518,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2734840928,
|
||||
end: 2738910872,
|
||||
},
|
||||
]
|
||||
[src/solutions/day5/task2.rs:42:5] ¤t_branches = [
|
||||
SeedRange {
|
||||
start: 244009039,
|
||||
end: 254933582,
|
||||
},
|
||||
SeedRange {
|
||||
start: 305477485,
|
||||
end: 329774690,
|
||||
},
|
||||
SeedRange {
|
||||
start: 442413629,
|
||||
end: 458180769,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1260160771,
|
||||
end: 1272797031,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1272797032,
|
||||
end: 1286745099,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1769136092,
|
||||
end: 1817580770,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1941952815,
|
||||
end: 1959258660,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2941559481,
|
||||
end: 2963703887,
|
||||
},
|
||||
SeedRange {
|
||||
start: 3338671715,
|
||||
end: 3392340230,
|
||||
},
|
||||
]
|
||||
[src/solutions/day5/task2.rs:42:5] ¤t_branches = [
|
||||
SeedRange {
|
||||
start: 332621358,
|
||||
end: 351714897,
|
||||
},
|
||||
SeedRange {
|
||||
start: 372723592,
|
||||
end: 390393835,
|
||||
},
|
||||
SeedRange {
|
||||
start: 426571448,
|
||||
end: 467405784,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1203805998,
|
||||
end: 1248511724,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1512990961,
|
||||
end: 1523584140,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1628354042,
|
||||
end: 1634087664,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2089724509,
|
||||
end: 2193360445,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2333003205,
|
||||
end: 2348927163,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2919622420,
|
||||
end: 2941559480,
|
||||
},
|
||||
SeedRange {
|
||||
start: 3241659967,
|
||||
end: 3257744758,
|
||||
},
|
||||
]
|
||||
[src/solutions/day5/task2.rs:42:5] ¤t_branches = [
|
||||
SeedRange {
|
||||
start: 137201536,
|
||||
end: 157986926,
|
||||
},
|
||||
SeedRange {
|
||||
start: 218545189,
|
||||
end: 220477638,
|
||||
},
|
||||
SeedRange {
|
||||
start: 600713965,
|
||||
end: 665397099,
|
||||
},
|
||||
SeedRange {
|
||||
start: 832371104,
|
||||
end: 836186784,
|
||||
},
|
||||
SeedRange {
|
||||
start: 843842519,
|
||||
end: 867655256,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1119175103,
|
||||
end: 1138382174,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1491903136,
|
||||
end: 1499334672,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1523584141,
|
||||
end: 1543990203,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2281428417,
|
||||
end: 2289569154,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2492935748,
|
||||
end: 2514211768,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2562030648,
|
||||
end: 2567370276,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2744209882,
|
||||
end: 2758197105,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2961556571,
|
||||
end: 2970025309,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2970025310,
|
||||
end: 2975037528,
|
||||
},
|
||||
SeedRange {
|
||||
start: 3055485859,
|
||||
end: 3060533366,
|
||||
},
|
||||
SeedRange {
|
||||
start: 3336845004,
|
||||
end: 3337449016,
|
||||
},
|
||||
]
|
||||
[src/solutions/day5/task2.rs:42:5] ¤t_branches = [
|
||||
SeedRange {
|
||||
start: 372723592,
|
||||
end: 390393835,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1203805998,
|
||||
end: 1230926691,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1230926692,
|
||||
end: 1234898502,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1450460003,
|
||||
end: 1468004523,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1546302602,
|
||||
end: 1600730425,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1628354042,
|
||||
end: 1634087664,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1644303246,
|
||||
end: 1684446508,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1702371352,
|
||||
end: 1750102221,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1899676495,
|
||||
end: 1926978899,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1950759356,
|
||||
end: 1994459585,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2089724509,
|
||||
end: 2193360445,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2172619534,
|
||||
end: 2188333609,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2333003205,
|
||||
end: 2348927163,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2567370277,
|
||||
end: 2607311496,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2885502549,
|
||||
end: 2941559480,
|
||||
},
|
||||
SeedRange {
|
||||
start: 3241659967,
|
||||
end: 3257744758,
|
||||
},
|
||||
]
|
||||
[src/solutions/day5/task2.rs:42:5] ¤t_branches = [
|
||||
SeedRange {
|
||||
start: 1672236638,
|
||||
end: 1707764533,
|
||||
},
|
||||
SeedRange {
|
||||
start: 2064249380,
|
||||
end: 2073429343,
|
||||
},
|
||||
]
|
||||
[src/solutions/day5/task2.rs:42:5] ¤t_branches = [
|
||||
SeedRange {
|
||||
start: 688038520,
|
||||
end: 693497941,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1485692689,
|
||||
end: 1491903135,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1750102222,
|
||||
end: 1755861445,
|
||||
},
|
||||
SeedRange {
|
||||
start: 1775334238,
|
||||
end: 1803258672,
|
||||
},
|
||||
]
|
|
@ -1,70 +0,0 @@
|
|||
pub trait AdventIterator: Iterator {
|
||||
fn into_chunks<const N: usize>(self) -> impl Iterator<Item = Chunck<N, Self::Item>>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
in_chunks::<N, Self::Item>(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> AdventIterator for I where I: Iterator {}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Chunck<const N: usize, T> {
|
||||
Next([T; N]),
|
||||
Rest(Vec<T>),
|
||||
}
|
||||
|
||||
pub fn in_chunks<const N: usize, T>(
|
||||
mut iterator: impl Iterator<Item = T>,
|
||||
) -> impl Iterator<Item = Chunck<N, T>> {
|
||||
let mut buffer = Vec::new();
|
||||
let mut done = false;
|
||||
std::iter::from_fn(move || {
|
||||
if done {
|
||||
return None;
|
||||
}
|
||||
for _ in 0..N {
|
||||
match iterator.next() {
|
||||
Some(to_push) => buffer.push(to_push),
|
||||
None => {
|
||||
done = true;
|
||||
return if buffer.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Chunck::Rest(std::mem::take(&mut buffer)))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
let array: [T; N] = std::mem::take(&mut buffer)
|
||||
.try_into()
|
||||
.unwrap_or_else(|_| panic!("Buffer must have the same size as the N ({})", N));
|
||||
Some(Chunck::Next(array))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod testing {
|
||||
use crate::iterations::{in_chunks, Chunck};
|
||||
|
||||
#[test]
|
||||
fn should_split_chunks() {
|
||||
fn assert_case<const N: usize>(input: Vec<u32>, expected: Vec<Chunck<N, u32>>) {
|
||||
let actual: Vec<Chunck<N, u32>> = in_chunks::<N, u32>(input.into_iter()).collect();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
assert_case::<2>(vec![2], vec![Chunck::Rest(vec![2])]);
|
||||
assert_case::<2>(vec![], vec![]);
|
||||
assert_case::<2>(vec![2, 2], vec![Chunck::Next([2, 2])]);
|
||||
assert_case::<2>(
|
||||
vec![1, 2, 3],
|
||||
vec![Chunck::Next([1, 2]), Chunck::Rest(vec![3])],
|
||||
);
|
||||
assert_case::<1>(
|
||||
vec![1, 2, 3],
|
||||
vec![Chunck::Next([1]), Chunck::Next([2]), Chunck::Next([3])],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
pub mod cli;
|
||||
pub mod constants;
|
||||
pub mod iterations;
|
||||
pub mod parsing_utils;
|
||||
pub mod sequences;
|
||||
pub mod solutions;
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
pub fn is_sorted<T>(shoube_be_sorted: &[T]) -> bool
|
||||
where
|
||||
T: PartialOrd + Ord + Clone + PartialEq + Eq,
|
||||
{
|
||||
let mut sorted: Vec<T> = shoube_be_sorted.into_iter().cloned().collect();
|
||||
sorted.sort();
|
||||
sorted.as_slice().eq(shoube_be_sorted)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod testing {
|
||||
|
||||
#[test]
|
||||
fn should_detect_if_is_sorted() {
|
||||
fn assert_case(input: &[u32], expected: bool) {
|
||||
let actual = super::is_sorted(input);
|
||||
assert_eq!(expected, actual, "Input {:#?}", input);
|
||||
}
|
||||
|
||||
assert_case(&[1, 2], true);
|
||||
assert_case(&[2, 1, 2], false);
|
||||
assert_case(&[2, 1], false);
|
||||
assert_case(&[1], true);
|
||||
assert_case(&[], true);
|
||||
}
|
||||
}
|
|
@ -2,11 +2,11 @@ pub mod day5;
|
|||
|
||||
pub fn create_solutions() -> Vec<Vec<fn(&str) -> String>> {
|
||||
vec![
|
||||
vec![not_implemented_yet],
|
||||
vec![not_implemented_yet, not_implemented_yet],
|
||||
vec![not_implemented_yet, not_implemented_yet],
|
||||
vec![not_implemented_yet, not_implemented_yet],
|
||||
vec![not_implemented_yet, not_implemented_yet],
|
||||
vec![day5::solve_task_1, day5::solve_task_2],
|
||||
vec![day5::solve_task_1, not_implemented_yet],
|
||||
vec![not_implemented_yet, not_implemented_yet],
|
||||
vec![not_implemented_yet, not_implemented_yet],
|
||||
vec![not_implemented_yet, not_implemented_yet],
|
||||
|
|
|
@ -1,234 +1,36 @@
|
|||
use item_mapping::{ItemMapping, MappedRange};
|
||||
use seed_range::SeedRange;
|
||||
use mapping_layer::MappingLayer;
|
||||
|
||||
mod item_mapping;
|
||||
mod mapping_layer;
|
||||
mod parsing;
|
||||
mod seed_range;
|
||||
type UnsignedNumber = u128;
|
||||
|
||||
mod range_mapping;
|
||||
pub fn solve_task_1(input: &str) -> String {
|
||||
let (seeds, mapping_layers) = parsing::parse(input);
|
||||
let min = min_location_from_given_single_seeds(&seeds, &mapping_layers);
|
||||
min.to_string()
|
||||
let _parsed = parsing::parse(input);
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn min_location_from_given_single_seeds(
|
||||
seeds: &[UnsignedNumber],
|
||||
layers: &[Vec<ItemMapping>],
|
||||
) -> UnsignedNumber {
|
||||
let mut min = UnsignedNumber::MAX;
|
||||
for next_seed in seeds {
|
||||
let mut current_seed = *next_seed;
|
||||
for next_layer in layers {
|
||||
for next_mapping in next_layer {
|
||||
match next_mapping.map_point(current_seed) {
|
||||
Some(found_mapping) => {
|
||||
current_seed = found_mapping;
|
||||
break;
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
min = current_seed.min(min);
|
||||
}
|
||||
min
|
||||
}
|
||||
|
||||
pub fn solve_task_2(input: &str) -> String {
|
||||
let (starting_from, mappings) = {
|
||||
let (single_seeds, mappings) = parsing::parse(input);
|
||||
let seed_ranges = combine_single_to_ranges_for_seeds(&single_seeds);
|
||||
(seed_ranges, mappings)
|
||||
};
|
||||
let mut min = UnsignedNumber::MAX;
|
||||
|
||||
for next_start in starting_from {
|
||||
let min_of_last_round = go_through_all_rounds_for_one_starting_seed(next_start, &mappings);
|
||||
min = min_of_last_round.min(min);
|
||||
}
|
||||
|
||||
min.to_string()
|
||||
}
|
||||
|
||||
fn go_through_all_rounds_for_one_starting_seed(
|
||||
starting_from: SeedRange,
|
||||
all_rounds: &[Vec<ItemMapping>],
|
||||
) -> UnsignedNumber {
|
||||
let mut for_next_round: Vec<SeedRange> = vec![starting_from];
|
||||
|
||||
for next_round in all_rounds {
|
||||
let mut add_to_next_round = Vec::new();
|
||||
for next_seed_range in for_next_round {
|
||||
let new_ones = simulate_one_round_on_one_seed_range(next_seed_range, next_round);
|
||||
add_to_next_round.extend(new_ones);
|
||||
}
|
||||
for_next_round = add_to_next_round;
|
||||
}
|
||||
|
||||
for_next_round
|
||||
.into_iter()
|
||||
.map(|seed_range| seed_range.start())
|
||||
.min()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn simulate_one_round_on_one_seed_range(
|
||||
seed_range: SeedRange,
|
||||
rounds_mapping: &[ItemMapping],
|
||||
) -> Vec<SeedRange> {
|
||||
let (mut to_map, mut mapped_ranges): (Vec<SeedRange>, Vec<SeedRange>) =
|
||||
(vec![seed_range], Vec::new());
|
||||
while let Some(next_to_map) = to_map.pop() {
|
||||
let mut found_a_mapping = false;
|
||||
for next_mapping in rounds_mapping {
|
||||
match next_mapping.map_range(next_to_map) {
|
||||
MappedRange::Outside => (),
|
||||
MappedRange::Within(mapped) => {
|
||||
mapped_ranges.push(mapped);
|
||||
found_a_mapping = true;
|
||||
break;
|
||||
}
|
||||
MappedRange::PartiallyWithin { outside, mapped } => {
|
||||
mapped_ranges.push(mapped);
|
||||
to_map.push(outside);
|
||||
found_a_mapping = true;
|
||||
break;
|
||||
}
|
||||
MappedRange::FromBothSidePartiallyWithin {
|
||||
outside: (left, right),
|
||||
mapped,
|
||||
} => {
|
||||
mapped_ranges.push(mapped);
|
||||
to_map.push(left);
|
||||
to_map.push(right);
|
||||
found_a_mapping = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found_a_mapping {
|
||||
mapped_ranges.push(next_to_map);
|
||||
}
|
||||
}
|
||||
|
||||
mapped_ranges
|
||||
}
|
||||
|
||||
fn combine_single_to_ranges_for_seeds(single_seeds: &[UnsignedNumber]) -> Vec<SeedRange> {
|
||||
assert!(single_seeds.len() % 2 == 0);
|
||||
single_seeds
|
||||
.chunks(2)
|
||||
.into_iter()
|
||||
.map(|array| match array {
|
||||
[start, end] => {
|
||||
let start = *start;
|
||||
let range = end - 1;
|
||||
let end = start + range;
|
||||
SeedRange::new(start, end)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect()
|
||||
fn location_of_one_point(seeds: u32, layers: &[MappingLayer]) -> u32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod testing {
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::solutions::day5::{
|
||||
combine_single_to_ranges_for_seeds, item_mapping::ItemMapping, parsing,
|
||||
seed_range::SeedRange, simulate_one_round_on_one_seed_range, solve_task_2,
|
||||
};
|
||||
|
||||
use super::solve_task_1;
|
||||
const EXAMPLE_INPUT: &str = include_str!("day5/day_example_input.txt");
|
||||
use super::*;
|
||||
|
||||
// Seed 79, soil 81, fertilizer 81, water 81, light 74, temperature 78, humidity 78, location 82.
|
||||
// Seed 14, soil 14, fertilizer 53, water 49, light 42, temperature 42, humidity 43, location 43.
|
||||
// Seed 55, soil 57, fertilizer 57, water 53, light 46, temperature 82, humidity 82, location 86.
|
||||
// Seed 13, soil 13, fertilizer 52, water 41, light 34, temperature 34, humidity 35, location 35.
|
||||
#[test]
|
||||
fn should_solve_task_1() {
|
||||
let actual = solve_task_1(EXAMPLE_INPUT);
|
||||
let expected = "35";
|
||||
assert_eq!(expected, actual)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_combine_single_to_ranges_for_seeds() {
|
||||
let (single_seeds, _) = parsing::parse(EXAMPLE_INPUT);
|
||||
let actual = combine_single_to_ranges_for_seeds(&single_seeds);
|
||||
let expected = vec![SeedRange::new(79, 92), SeedRange::new(55, 67)];
|
||||
assert_eq!(expected, actual)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_solve_task2() {
|
||||
let actual = solve_task_2(EXAMPLE_INPUT);
|
||||
let expected = "46";
|
||||
assert_eq!(expected, actual)
|
||||
}
|
||||
|
||||
fn create_first_round_of_example() -> Vec<ItemMapping> {
|
||||
vec![
|
||||
ItemMapping::from_str("50 98 2").unwrap(),
|
||||
ItemMapping::from_str("52 50 48").unwrap(),
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_simulate_one_round_on_one_seed_range() {
|
||||
fn assert_case(
|
||||
seed_range: SeedRange,
|
||||
rounds_mapping: &[ItemMapping],
|
||||
mut expected: Vec<SeedRange>,
|
||||
) {
|
||||
let mut actual = simulate_one_round_on_one_seed_range(seed_range, rounds_mapping);
|
||||
actual.sort();
|
||||
expected.sort();
|
||||
assert_eq!(
|
||||
expected, actual,
|
||||
"Given range: {:?}\nGiven mapping: {:?}",
|
||||
seed_range, rounds_mapping
|
||||
);
|
||||
fn name() {
|
||||
fn assert_case(seeds: u32, layer: &[MappingLayer], expected: u32) {
|
||||
let actual = location_of_one_point(seeds, layer);
|
||||
assert_eq!(expected, actual, "Given seeds: {}", seeds);
|
||||
}
|
||||
let example = create_first_round_of_example();
|
||||
assert_case(SeedRange::new(0, 4), &example, vec![SeedRange::new(0, 4)]);
|
||||
assert_case(
|
||||
SeedRange::new(100, 110),
|
||||
&example,
|
||||
vec![SeedRange::new(100, 110)],
|
||||
);
|
||||
assert_case(
|
||||
SeedRange::new(98, 99),
|
||||
&example,
|
||||
vec![SeedRange::new(50, 51)],
|
||||
);
|
||||
assert_case(
|
||||
SeedRange::new(98, 110),
|
||||
&example,
|
||||
vec![SeedRange::new(50, 51), SeedRange::new(100, 110)],
|
||||
);
|
||||
assert_case(
|
||||
SeedRange::new(90, 110),
|
||||
&example,
|
||||
vec![
|
||||
SeedRange::new(92, 99),
|
||||
SeedRange::new(50, 51),
|
||||
SeedRange::new(100, 110),
|
||||
],
|
||||
);
|
||||
assert_case(
|
||||
SeedRange::new(70, 98),
|
||||
&example,
|
||||
vec![SeedRange::new(72, 99), SeedRange::new(50, 50)],
|
||||
);
|
||||
assert_case(
|
||||
SeedRange::new(40, 110),
|
||||
&example,
|
||||
vec![
|
||||
SeedRange::new(40, 49),
|
||||
SeedRange::new(52, 99),
|
||||
SeedRange::new(50, 51),
|
||||
SeedRange::new(100, 110),
|
||||
],
|
||||
);
|
||||
let input = parsing::parse(include_str!("day5/day5_example_input.txt"));
|
||||
let layers = &input.1;
|
||||
assert_case(79, layers, 82);
|
||||
assert_case(14, layers, 43);
|
||||
assert_case(55, layers, 86);
|
||||
assert_case(13, layers, 35);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,273 +0,0 @@
|
|||
use std::{str::FromStr};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use super::{seed_range::SeedRange, UnsignedNumber};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct ItemMapping {
|
||||
source_range: SeedRange,
|
||||
target: UnsignedNumber,
|
||||
range: UnsignedNumber,
|
||||
}
|
||||
|
||||
impl ItemMapping {
|
||||
|
||||
fn offset_mapping(&self, to_map: UnsignedNumber) -> UnsignedNumber {
|
||||
assert!(to_map >= self.source_range.start());
|
||||
let difference = to_map - self.source_range.start();
|
||||
self.target + difference
|
||||
}
|
||||
|
||||
pub fn map_range(&self, to_map: SeedRange) -> MappedRange {
|
||||
let start = self.source_range.start();
|
||||
let end = self.source_range.end();
|
||||
// xxxxxx => to_map
|
||||
// yyyyyy => self
|
||||
|
||||
// -------xxxxxx
|
||||
// yyyyyy-------
|
||||
if to_map.start() > end ||
|
||||
// xxxxxxx---------
|
||||
// ----------yyyyyy
|
||||
to_map.end() < start {
|
||||
MappedRange::Outside
|
||||
} else if to_map.start() < start && to_map.end() <= end {
|
||||
// xxxxxxx----
|
||||
// ----yyyyyyy
|
||||
let outside_start = to_map.start();
|
||||
let outside_end = start.saturating_sub(1);
|
||||
let outside = SeedRange::new(outside_start, outside_end);
|
||||
|
||||
let mapped_start = self.target;
|
||||
let mapped_end = self.offset_mapping(to_map.end());
|
||||
let mapped = SeedRange::new(mapped_start, mapped_end);
|
||||
MappedRange::PartiallyWithin { outside, mapped }
|
||||
} else if to_map.start() >= start && to_map.end() > end {
|
||||
// yyyyyy----
|
||||
// ----xxxxxx
|
||||
let outside_start = end + 1;
|
||||
let outside_end = to_map.end();
|
||||
let outside = SeedRange::new(outside_start, outside_end);
|
||||
|
||||
let mapped_start = self.offset_mapping(to_map.start());
|
||||
let mapped_end = self.offset_mapping(outside_start - 1);
|
||||
let mapped = SeedRange::new(mapped_start, mapped_end);
|
||||
MappedRange::PartiallyWithin { outside, mapped }
|
||||
|
||||
} else if to_map.start() < start && to_map.end() > end {
|
||||
|
||||
// -----yyy----
|
||||
// ----xxxxxx
|
||||
let left = {
|
||||
let left_start = to_map.start();
|
||||
let left_end = start - 1;
|
||||
SeedRange::new(left_start, left_end)
|
||||
};
|
||||
let right = {
|
||||
let right_start = end + 1;
|
||||
let right_end = to_map.end();
|
||||
SeedRange::new(right_start, right_end)
|
||||
};
|
||||
let mapped = {
|
||||
let mapped_start = self.target;
|
||||
let mapped_end = self.offset_mapping(end);
|
||||
SeedRange::new(mapped_start, mapped_end)
|
||||
};
|
||||
MappedRange::FromBothSidePartiallyWithin { outside: (left, right), mapped }
|
||||
} else {
|
||||
// ----yyyyyy----
|
||||
// -----xxxx-----
|
||||
let mapped_start = self.offset_mapping(to_map.start());
|
||||
let mapped_end = self.offset_mapping(to_map.end());
|
||||
let mapped = SeedRange::new(mapped_start, mapped_end);
|
||||
MappedRange::Within(mapped)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_point(&self, to_map: UnsignedNumber) -> Option<UnsignedNumber> {
|
||||
let source_range = self.source_range;
|
||||
let start = source_range.start();
|
||||
let end = source_range.end(); if start <= to_map && end >= to_map {
|
||||
let mapped = self.offset_mapping(to_map);
|
||||
Some(mapped)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum MappedRange {
|
||||
Outside,
|
||||
Within(SeedRange),
|
||||
PartiallyWithin {
|
||||
outside: SeedRange,
|
||||
mapped: SeedRange,
|
||||
},
|
||||
FromBothSidePartiallyWithin {
|
||||
outside: (SeedRange, SeedRange),
|
||||
mapped: SeedRange,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, PartialEq, Eq)]
|
||||
#[error("Item mapping must be exactly 3 numbers")]
|
||||
pub struct InvalidStrItemMapping;
|
||||
|
||||
impl FromStr for ItemMapping {
|
||||
type Err = InvalidStrItemMapping;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut splitted = s.split_whitespace().take(3).map(|to_parse| {
|
||||
to_parse
|
||||
.parse::<UnsignedNumber>()
|
||||
.map_err(|_| InvalidStrItemMapping)
|
||||
});
|
||||
match (splitted.next(), splitted.next(), splitted.next()) {
|
||||
(Some(Ok(target)), Some(Ok(source)), Some(Ok(range))) => {
|
||||
let inclusive_range = range.saturating_sub(1);
|
||||
let end = source + inclusive_range;
|
||||
let source_range = SeedRange::new(source, end);
|
||||
let parsed_self = Self {
|
||||
source_range,
|
||||
target,
|
||||
range,
|
||||
};
|
||||
Ok(parsed_self)
|
||||
}
|
||||
(_, _, _) => Err(InvalidStrItemMapping),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod testing {
|
||||
use crate::solutions::day5::{
|
||||
item_mapping::{InvalidStrItemMapping, ItemMapping, MappedRange},
|
||||
seed_range::SeedRange,
|
||||
UnsignedNumber,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn from_str_item_mapping() {
|
||||
fn assert_case(input: &str, expected: Result<ItemMapping, InvalidStrItemMapping>) {
|
||||
let actual = input.parse();
|
||||
assert_eq!(expected, actual, "Input: {}", input);
|
||||
}
|
||||
assert_case(
|
||||
"20 10 22",
|
||||
Ok(ItemMapping {
|
||||
source_range: SeedRange::new(10, 31),
|
||||
target: 20,
|
||||
range: 22,
|
||||
}),
|
||||
);
|
||||
assert_case(
|
||||
"50 98 2",
|
||||
Ok(ItemMapping {
|
||||
source_range: SeedRange::new(98, 99),
|
||||
target: 50,
|
||||
range: 2,
|
||||
}),
|
||||
);
|
||||
assert_case(
|
||||
"52 50 48",
|
||||
Ok(ItemMapping {
|
||||
source_range: SeedRange::new(50, 97),
|
||||
target: 52,
|
||||
range: 48,
|
||||
}),
|
||||
);
|
||||
assert_case("a 10 22", Err(InvalidStrItemMapping));
|
||||
assert_case("10 10", Err(InvalidStrItemMapping));
|
||||
}
|
||||
#[test]
|
||||
fn should_map_point() {
|
||||
fn assert_case(point: UnsignedNumber, input: &str, expected: Option<UnsignedNumber>) {
|
||||
let mapping: ItemMapping = input.parse().unwrap();
|
||||
let actual = mapping.map_point(point);
|
||||
|
||||
assert_eq!(
|
||||
expected, actual,
|
||||
"Point: {:?}\nMaping: {:?}",
|
||||
point, mapping
|
||||
);
|
||||
}
|
||||
|
||||
assert_case(2, "4 2 2", Some(4));
|
||||
assert_case(0, "4 2 2", None);
|
||||
assert_case(4, "4 2 2", None);
|
||||
assert_case(79, "52 50 48", Some(81));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_map_ranges() {
|
||||
fn assert_case(given: SeedRange, mapping: ItemMapping, expected: MappedRange) {
|
||||
let actual = mapping.map_range(given);
|
||||
assert_eq!(
|
||||
expected, actual,
|
||||
"Given: {:?}\nMapping: {:?}",
|
||||
given, mapping
|
||||
);
|
||||
}
|
||||
let example_mapping = ItemMapping {
|
||||
source_range: SeedRange::new(98, 99),
|
||||
target: 50,
|
||||
range: 2,
|
||||
};
|
||||
|
||||
assert_case(
|
||||
SeedRange::new(95, 97),
|
||||
example_mapping.clone(),
|
||||
MappedRange::Outside,
|
||||
);
|
||||
assert_case(
|
||||
SeedRange::new(100, 120),
|
||||
example_mapping.clone(),
|
||||
MappedRange::Outside,
|
||||
);
|
||||
assert_case(
|
||||
SeedRange::new(98, 99),
|
||||
example_mapping.clone(),
|
||||
MappedRange::Within(SeedRange::new(50, 51)),
|
||||
);
|
||||
let greater_example_mapping = ItemMapping {
|
||||
source_range: SeedRange::new(50, 97),
|
||||
target: 52,
|
||||
range: 48,
|
||||
};
|
||||
assert_case(
|
||||
SeedRange::new(40, 80),
|
||||
greater_example_mapping.clone(),
|
||||
MappedRange::PartiallyWithin {
|
||||
outside: SeedRange::new(40, 49),
|
||||
mapped: SeedRange::new(52, 82),
|
||||
},
|
||||
);
|
||||
assert_case(
|
||||
SeedRange::new(80, 100),
|
||||
greater_example_mapping.clone(),
|
||||
MappedRange::PartiallyWithin {
|
||||
outside: SeedRange::new(98, 100),
|
||||
mapped: SeedRange::new(82, 99),
|
||||
},
|
||||
);
|
||||
assert_case(
|
||||
SeedRange::new(30, 100),
|
||||
greater_example_mapping.clone(),
|
||||
MappedRange::FromBothSidePartiallyWithin {
|
||||
outside: (SeedRange::new(30, 49), SeedRange::new(98, 100)),
|
||||
mapped: SeedRange::new(52, 99),
|
||||
},
|
||||
);
|
||||
assert_case(
|
||||
SeedRange::new(96, 102),
|
||||
example_mapping.clone(),
|
||||
MappedRange::FromBothSidePartiallyWithin {
|
||||
outside: (SeedRange::new(96, 97), SeedRange::new(100, 102)),
|
||||
mapped: SeedRange::new(50, 51),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
19
src/solutions/day5/mapping_layer.rs
Normal file
19
src/solutions/day5/mapping_layer.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use derive_more::derive;
|
||||
|
||||
use super::range_mapping::RangeMapping;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MappingLayer {
|
||||
label: String,
|
||||
ranges: Vec<RangeMapping>,
|
||||
}
|
||||
|
||||
impl MappingLayer {
|
||||
pub fn new(label: impl Into<String>, mut ranges: Vec<RangeMapping>) -> Self {
|
||||
ranges.sort_by_key(|element| element.source());
|
||||
Self {
|
||||
label: label.into(),
|
||||
ranges,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +1,45 @@
|
|||
use crate::parsing_utils;
|
||||
use crate::{parsing_utils, solutions::day5::range_mapping::RangeMapping};
|
||||
|
||||
use super::{item_mapping::ItemMapping, UnsignedNumber};
|
||||
use super::mapping_layer::MappingLayer;
|
||||
|
||||
pub fn parse(input: &str) -> (Vec<UnsignedNumber>, Vec<Vec<ItemMapping>>) {
|
||||
pub fn parse(input: &str) -> (Vec<u32>, Vec<MappingLayer>) {
|
||||
fn parse_one_layer(lines: Vec<&str>) -> MappingLayer {
|
||||
const ALREADY_GOT_MAPPING_NAME: usize = 1;
|
||||
let mapping_name = *lines.first().unwrap();
|
||||
let mut mappings = Vec::new();
|
||||
|
||||
for next_line in lines.into_iter().skip(ALREADY_GOT_MAPPING_NAME) {
|
||||
let next_mapping: RangeMapping = next_line.parse().unwrap();
|
||||
mappings.push(next_mapping);
|
||||
}
|
||||
|
||||
MappingLayer::new(mapping_name.to_string(), mappings)
|
||||
}
|
||||
let mut blocks = parsing_utils::blocks_of_lines_seperated_by_empty_lines(input);
|
||||
let seeds = {
|
||||
let first_block = blocks.next().unwrap();
|
||||
let first_line = first_block.first().unwrap();
|
||||
first_line
|
||||
.strip_prefix("seeds:")
|
||||
.unwrap()
|
||||
.split_whitespace()
|
||||
.map(|not_parsed| not_parsed.parse::<UnsignedNumber>().unwrap())
|
||||
.collect()
|
||||
};
|
||||
let first_block = blocks.next().unwrap();
|
||||
|
||||
let mappings: Vec<Vec<ItemMapping>> = blocks
|
||||
.map(|lines| {
|
||||
lines
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
.map(|to_parse| to_parse.parse::<ItemMapping>().unwrap())
|
||||
.collect()
|
||||
})
|
||||
assert!(first_block.len() == 1);
|
||||
let seeds = first_block
|
||||
.first()
|
||||
.unwrap()
|
||||
.trim_start_matches("seeds: ")
|
||||
.split(" ")
|
||||
.map(|to_number| to_number.parse().unwrap())
|
||||
.collect();
|
||||
let mappings = blocks.into_iter().map(parse_one_layer).collect();
|
||||
|
||||
(seeds, mappings)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod testing {
|
||||
|
||||
#[test]
|
||||
fn should_parse() {
|
||||
let input = include_str!("day_example_input.txt");
|
||||
fn parse_input_day5() {
|
||||
let input = include_str!("day5_example_input.txt");
|
||||
let actual = super::parse(input);
|
||||
insta::assert_debug_snapshot!(actual);
|
||||
let expected_seeds: Vec<u32> = vec![79, 14, 55, 13];
|
||||
assert_eq!(expected_seeds, actual.0);
|
||||
insta::assert_debug_snapshot!(actual.1);
|
||||
}
|
||||
}
|
||||
|
|
76
src/solutions/day5/range_mapping.rs
Normal file
76
src/solutions/day5/range_mapping.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct RangeMapping {
|
||||
source: u32,
|
||||
target: u32,
|
||||
range: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ParseErrorRangeMapping {
|
||||
#[error("Needs to have at least 3 numbers")]
|
||||
LessThan3Numbers,
|
||||
#[error("Every item must be a valid unsigned number")]
|
||||
InvalidFormatForNumbers,
|
||||
}
|
||||
impl FromStr for RangeMapping {
|
||||
type Err = ParseErrorRangeMapping;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut numbers_as_3 = s.split(" ").take(3).map(|unparsed| {
|
||||
unparsed
|
||||
.parse::<u32>()
|
||||
.map_err(|_| ParseErrorRangeMapping::InvalidFormatForNumbers)
|
||||
});
|
||||
let (target, source, range) = (
|
||||
numbers_as_3
|
||||
.next()
|
||||
.ok_or(ParseErrorRangeMapping::LessThan3Numbers)??,
|
||||
numbers_as_3
|
||||
.next()
|
||||
.ok_or(ParseErrorRangeMapping::LessThan3Numbers)??,
|
||||
numbers_as_3
|
||||
.next()
|
||||
.ok_or(ParseErrorRangeMapping::LessThan3Numbers)??,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
target,
|
||||
source,
|
||||
range,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl RangeMapping {
|
||||
pub fn source(&self) -> u32 {
|
||||
self.source
|
||||
}
|
||||
|
||||
pub fn target(&self) -> u32 {
|
||||
self.target
|
||||
}
|
||||
|
||||
pub fn range(&self) -> u32 {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod testing {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_from_line() {
|
||||
const INPUT: &str = "50 98 2";
|
||||
let expected = RangeMapping {
|
||||
source: 98,
|
||||
target: 50,
|
||||
range: 2,
|
||||
};
|
||||
let actual: RangeMapping = INPUT.parse().unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
use super::UnsignedNumber;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
|
||||
pub struct SeedRange {
|
||||
start: UnsignedNumber,
|
||||
end: UnsignedNumber,
|
||||
}
|
||||
|
||||
impl SeedRange {
|
||||
pub fn new(start: UnsignedNumber, end: UnsignedNumber) -> Self {
|
||||
assert!(end >= start);
|
||||
Self { start, end }
|
||||
}
|
||||
|
||||
pub fn start(&self) -> UnsignedNumber {
|
||||
self.start
|
||||
}
|
||||
|
||||
pub fn end(&self) -> UnsignedNumber {
|
||||
self.end
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
source: src/solutions/day5/parsing.rs
|
||||
expression: actual.1
|
||||
---
|
||||
[
|
||||
MappingLayer {
|
||||
label: "seed-to-soil map:",
|
||||
ranges: [
|
||||
RangeMapping {
|
||||
source: 50,
|
||||
target: 52,
|
||||
range: 48,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 98,
|
||||
target: 50,
|
||||
range: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
MappingLayer {
|
||||
label: "soil-to-fertilizer map:",
|
||||
ranges: [
|
||||
RangeMapping {
|
||||
source: 0,
|
||||
target: 39,
|
||||
range: 15,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 15,
|
||||
target: 0,
|
||||
range: 37,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 52,
|
||||
target: 37,
|
||||
range: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
MappingLayer {
|
||||
label: "fertilizer-to-water map:",
|
||||
ranges: [
|
||||
RangeMapping {
|
||||
source: 0,
|
||||
target: 42,
|
||||
range: 7,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 7,
|
||||
target: 57,
|
||||
range: 4,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 11,
|
||||
target: 0,
|
||||
range: 42,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 53,
|
||||
target: 49,
|
||||
range: 8,
|
||||
},
|
||||
],
|
||||
},
|
||||
MappingLayer {
|
||||
label: "water-to-light map:",
|
||||
ranges: [
|
||||
RangeMapping {
|
||||
source: 18,
|
||||
target: 88,
|
||||
range: 7,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 25,
|
||||
target: 18,
|
||||
range: 70,
|
||||
},
|
||||
],
|
||||
},
|
||||
MappingLayer {
|
||||
label: "light-to-temperature map:",
|
||||
ranges: [
|
||||
RangeMapping {
|
||||
source: 45,
|
||||
target: 81,
|
||||
range: 19,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 64,
|
||||
target: 68,
|
||||
range: 13,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 77,
|
||||
target: 45,
|
||||
range: 23,
|
||||
},
|
||||
],
|
||||
},
|
||||
MappingLayer {
|
||||
label: "temperature-to-humidity map:",
|
||||
ranges: [
|
||||
RangeMapping {
|
||||
source: 0,
|
||||
target: 1,
|
||||
range: 69,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 69,
|
||||
target: 0,
|
||||
range: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
MappingLayer {
|
||||
label: "humidity-to-location map:",
|
||||
ranges: [
|
||||
RangeMapping {
|
||||
source: 56,
|
||||
target: 60,
|
||||
range: 37,
|
||||
},
|
||||
RangeMapping {
|
||||
source: 93,
|
||||
target: 56,
|
||||
range: 4,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
|
@ -1,172 +0,0 @@
|
|||
---
|
||||
source: src/solutions/day5/parsing.rs
|
||||
expression: actual
|
||||
---
|
||||
(
|
||||
[
|
||||
79,
|
||||
14,
|
||||
55,
|
||||
13,
|
||||
],
|
||||
[
|
||||
[
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 98,
|
||||
end: 99,
|
||||
},
|
||||
target: 50,
|
||||
range: 2,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 50,
|
||||
end: 97,
|
||||
},
|
||||
target: 52,
|
||||
range: 48,
|
||||
},
|
||||
],
|
||||
[
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 15,
|
||||
end: 51,
|
||||
},
|
||||
target: 0,
|
||||
range: 37,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 52,
|
||||
end: 53,
|
||||
},
|
||||
target: 37,
|
||||
range: 2,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 0,
|
||||
end: 14,
|
||||
},
|
||||
target: 39,
|
||||
range: 15,
|
||||
},
|
||||
],
|
||||
[
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 53,
|
||||
end: 60,
|
||||
},
|
||||
target: 49,
|
||||
range: 8,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 11,
|
||||
end: 52,
|
||||
},
|
||||
target: 0,
|
||||
range: 42,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 0,
|
||||
end: 6,
|
||||
},
|
||||
target: 42,
|
||||
range: 7,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 7,
|
||||
end: 10,
|
||||
},
|
||||
target: 57,
|
||||
range: 4,
|
||||
},
|
||||
],
|
||||
[
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 18,
|
||||
end: 24,
|
||||
},
|
||||
target: 88,
|
||||
range: 7,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 25,
|
||||
end: 94,
|
||||
},
|
||||
target: 18,
|
||||
range: 70,
|
||||
},
|
||||
],
|
||||
[
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 77,
|
||||
end: 99,
|
||||
},
|
||||
target: 45,
|
||||
range: 23,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 45,
|
||||
end: 63,
|
||||
},
|
||||
target: 81,
|
||||
range: 19,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 64,
|
||||
end: 76,
|
||||
},
|
||||
target: 68,
|
||||
range: 13,
|
||||
},
|
||||
],
|
||||
[
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 69,
|
||||
end: 69,
|
||||
},
|
||||
target: 0,
|
||||
range: 1,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 0,
|
||||
end: 68,
|
||||
},
|
||||
target: 1,
|
||||
range: 69,
|
||||
},
|
||||
],
|
||||
[
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 56,
|
||||
end: 92,
|
||||
},
|
||||
target: 60,
|
||||
range: 37,
|
||||
},
|
||||
ItemMapping {
|
||||
source_range: SeedRange {
|
||||
start: 93,
|
||||
end: 96,
|
||||
},
|
||||
target: 56,
|
||||
range: 4,
|
||||
},
|
||||
],
|
||||
],
|
||||
)
|
Loading…
Add table
Reference in a new issue