solve year 2023 day 05
This commit is contained in:
@@ -24,4 +24,5 @@ pub mod year2023 {
|
||||
pub mod day02;
|
||||
pub mod day03;
|
||||
pub mod day04;
|
||||
pub mod day05;
|
||||
}
|
||||
|
@@ -99,5 +99,6 @@ fn year2023() -> Vec<Solution> {
|
||||
solution!(year2023, day02),
|
||||
solution!(year2023, day03),
|
||||
solution!(year2023, day04),
|
||||
solution!(year2023, day05),
|
||||
]
|
||||
}
|
||||
|
155
src/year2023/day05.rs
Normal file
155
src/year2023/day05.rs
Normal file
@@ -0,0 +1,155 @@
|
||||
use crate::util::parse::ParseExt;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Map {
|
||||
tuples: Vec<(usize, usize, usize)>,
|
||||
}
|
||||
|
||||
impl Map {
|
||||
// We divide the seed range up into smaller seed ranges:
|
||||
// 1) seed range before map range
|
||||
// 2) seed range after map range
|
||||
// 3) seed range in map range
|
||||
// for the seed range inside the map range we map it and it to the result array
|
||||
// the before and after seed ranges will be saved for the next map where. apply again
|
||||
// rinse and repeat until the ranges are empty
|
||||
fn calc_range(&self, mut ranges: Vec<(usize, usize)>) -> Vec<(usize, usize)> {
|
||||
let mut mapped = vec![];
|
||||
for (dest, source, l) in &self.tuples {
|
||||
let mut todo = vec![];
|
||||
|
||||
while let Some((range_start, range_end)) = ranges.pop() {
|
||||
let before_range = (range_start, range_end.min(*source));
|
||||
if before_range.1 > before_range.0 {
|
||||
todo.push(before_range);
|
||||
}
|
||||
let after_range = ((*source + l).max(range_start), range_end);
|
||||
if after_range.1 > after_range.0 {
|
||||
todo.push(after_range);
|
||||
}
|
||||
let between_range = (range_start.max(*source), (*source + *l).min(range_end));
|
||||
if between_range.1 > between_range.0 {
|
||||
mapped.push((
|
||||
between_range.0 - source + dest,
|
||||
between_range.1 - source + dest,
|
||||
));
|
||||
}
|
||||
}
|
||||
ranges = todo;
|
||||
}
|
||||
mapped.extend(ranges);
|
||||
mapped
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(input: &str) -> (Vec<usize>, Vec<Map>) {
|
||||
let mut chunks = input.split("\n\n");
|
||||
let seeds = chunks
|
||||
.next()
|
||||
.unwrap()
|
||||
.u32s()
|
||||
.map(|v| v as usize)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let maps = chunks
|
||||
.map(|chunk| Map {
|
||||
tuples: chunk
|
||||
.lines()
|
||||
.enumerate()
|
||||
.filter_map(|(idx, line)| {
|
||||
if idx == 0 {
|
||||
return None;
|
||||
}
|
||||
let mut nums = line.u32s();
|
||||
Some((
|
||||
nums.next()? as usize,
|
||||
nums.next()? as usize,
|
||||
nums.next()? as usize,
|
||||
))
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(seeds, maps)
|
||||
}
|
||||
|
||||
pub fn part1(input: &str) -> impl std::fmt::Display {
|
||||
let (mut seeds, maps) = parse(input);
|
||||
|
||||
for seed in seeds.iter_mut() {
|
||||
for map in &maps {
|
||||
for (dest, source, l) in &map.tuples {
|
||||
// if seed is within range map it in-place else leave it
|
||||
if *seed >= *source && *seed < *source + *l {
|
||||
*seed = *seed + *dest - *source;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
seeds.sort();
|
||||
seeds[0]
|
||||
}
|
||||
|
||||
pub fn part2(input: &str) -> impl std::fmt::Display {
|
||||
let (seeds, maps) = parse(input);
|
||||
let seeds = seeds.chunks(2).map(|v| (v[0], v[1]));
|
||||
|
||||
let mut res = seeds
|
||||
.map(|(start, end)| {
|
||||
let mut ranges = maps
|
||||
.iter()
|
||||
.fold(vec![(start, start + end)], |acc, map| map.calc_range(acc));
|
||||
ranges.sort();
|
||||
// We want the lowest, so take lower end of range
|
||||
ranges[0].0
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
res.sort();
|
||||
res[0]
|
||||
}
|
||||
|
||||
static TEST_INPUT: &str = "seeds: 79 14 55 13
|
||||
|
||||
seed-to-soil map:
|
||||
50 98 2
|
||||
52 50 48
|
||||
|
||||
soil-to-fertilizer map:
|
||||
0 15 37
|
||||
37 52 2
|
||||
39 0 15
|
||||
|
||||
fertilizer-to-water map:
|
||||
49 53 8
|
||||
0 11 42
|
||||
42 0 7
|
||||
57 7 4
|
||||
|
||||
water-to-light map:
|
||||
88 18 7
|
||||
18 25 70
|
||||
|
||||
light-to-temperature map:
|
||||
45 77 23
|
||||
81 45 19
|
||||
68 64 13
|
||||
|
||||
temperature-to-humidity map:
|
||||
0 69 1
|
||||
1 0 69
|
||||
|
||||
humidity-to-location map:
|
||||
60 56 37
|
||||
56 93 4";
|
||||
|
||||
#[test]
|
||||
fn test_part1() {
|
||||
assert_eq!("35", part1(TEST_INPUT).to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part2() {
|
||||
assert_eq!("46", part2(TEST_INPUT).to_string())
|
||||
}
|
Reference in New Issue
Block a user