generated from janezicmatej/aoc-template
solution: day 5
This commit is contained in:
parent
0000010044
commit
00000110da
|
@ -0,0 +1,33 @@
|
|||
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
|
|
@ -0,0 +1,158 @@
|
|||
use std::{cmp::min, str::FromStr};
|
||||
|
||||
use aoc::parsers::to_vec;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Mapping {
|
||||
destination: u64,
|
||||
source: u64,
|
||||
range: u64,
|
||||
}
|
||||
|
||||
struct ParseMappingError;
|
||||
|
||||
impl FromStr for Mapping {
|
||||
type Err = ParseMappingError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let nums: Vec<u64> = to_vec(s, ' ');
|
||||
|
||||
Ok(Self {
|
||||
destination: nums[0],
|
||||
source: nums[1],
|
||||
range: nums[2],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Mapping {
|
||||
fn contains(&self, n: u64) -> bool {
|
||||
n >= self.source && n < self.source + self.range
|
||||
}
|
||||
|
||||
fn contains_any(&self, s: u64, r: u64) -> bool {
|
||||
s < self.source + self.range && s + r > self.source
|
||||
}
|
||||
|
||||
fn map(&self, n: u64) -> u64 {
|
||||
debug_assert!(self.contains(n));
|
||||
let shift = n - self.source;
|
||||
self.destination + shift
|
||||
}
|
||||
|
||||
fn map_range(&self, s: u64, r: u64) -> ((u64, u64), Vec<(u64, u64)>) {
|
||||
debug_assert!(self.contains_any(s, r));
|
||||
let shift = {
|
||||
if self.contains(s) {
|
||||
s - self.source
|
||||
} else {
|
||||
0
|
||||
}
|
||||
};
|
||||
let neg_shift = {
|
||||
if self.contains(s) {
|
||||
0
|
||||
} else {
|
||||
self.source - s
|
||||
}
|
||||
};
|
||||
let dest_start = self.destination + shift;
|
||||
let dest_range = min(r - neg_shift, self.range - shift);
|
||||
let mut rest = Vec::new();
|
||||
|
||||
if !self.contains(s) {
|
||||
rest.push((s, self.source - s));
|
||||
}
|
||||
|
||||
if r - neg_shift > dest_range {
|
||||
rest.push((self.source + self.range, r - dest_range))
|
||||
}
|
||||
|
||||
((dest_start, dest_range), rest)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_map(maps: &str) -> Vec<Vec<Mapping>> {
|
||||
let mut res = Vec::new();
|
||||
|
||||
for mapper in maps.split("\n\n") {
|
||||
res.push(
|
||||
mapper
|
||||
.lines()
|
||||
.skip(1)
|
||||
.filter_map(|m| m.parse().ok())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn part_one(input: &str) -> Option<u64> {
|
||||
let (first, rest) = input.split_once("\n\n").unwrap();
|
||||
let maps = parse_map(rest);
|
||||
let seeds = to_vec::<u64, _>(first.strip_prefix("seeds: ").unwrap(), ' ');
|
||||
|
||||
let mut m = u64::MAX;
|
||||
|
||||
for seed in seeds.iter() {
|
||||
let mut s = *seed;
|
||||
'maps: for map in maps.iter() {
|
||||
for inner in map.iter() {
|
||||
if inner.contains(s) {
|
||||
s = inner.map(s);
|
||||
continue 'maps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m = min(m, s)
|
||||
}
|
||||
|
||||
Some(m)
|
||||
}
|
||||
|
||||
pub fn part_two(input: &str) -> Option<u64> {
|
||||
let (first, rest) = input.split_once("\n\n").unwrap();
|
||||
let maps = parse_map(rest);
|
||||
let seeds = to_vec::<u64, _>(first.strip_prefix("seeds: ").unwrap(), ' ');
|
||||
let mut seeds_ranges: Vec<_> = Vec::new();
|
||||
for s in seeds.chunks(2) {
|
||||
seeds_ranges.push((s[0], s[1]))
|
||||
}
|
||||
|
||||
for mapping in maps.iter() {
|
||||
let mut new_ranges = Vec::new();
|
||||
|
||||
'queue: while let Some((s, r)) = seeds_ranges.pop() {
|
||||
for map in mapping {
|
||||
if map.contains_any(s, r) {
|
||||
let (rng, rest) = map.map_range(s, r);
|
||||
new_ranges.push(rng);
|
||||
seeds_ranges.extend_from_slice(&rest);
|
||||
continue 'queue;
|
||||
}
|
||||
}
|
||||
|
||||
new_ranges.push((s, r));
|
||||
}
|
||||
|
||||
seeds_ranges = new_ranges;
|
||||
}
|
||||
|
||||
seeds_ranges.iter().map(|(x, _)| *x).min()
|
||||
}
|
||||
|
||||
aoc::solution!(5);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_part_one() {
|
||||
assert_eq!(part_one(&aoc::template::read_file("examples", 5)), Some(35));
|
||||
}
|
||||
#[test]
|
||||
fn test_part_two() {
|
||||
assert_eq!(part_two(&aoc::template::read_file("examples", 5)), Some(46));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue