From 715904ca2be4c068a391214128a3679e629fd9ea Mon Sep 17 00:00:00 2001 From: Matej Focko Date: Tue, 5 Dec 2023 08:34:27 +0100 Subject: [PATCH] day(05): add solution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit “brute-force me up inside” Signed-off-by: Matej Focko --- samples/day05.txt | 33 ++++++++++++ src/bin/day05.rs | 129 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 samples/day05.txt create mode 100644 src/bin/day05.rs diff --git a/samples/day05.txt b/samples/day05.txt new file mode 100644 index 0000000..f756727 --- /dev/null +++ b/samples/day05.txt @@ -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 diff --git a/src/bin/day05.rs b/src/bin/day05.rs new file mode 100644 index 0000000..5a05a58 --- /dev/null +++ b/src/bin/day05.rs @@ -0,0 +1,129 @@ +use rayon::prelude::*; +use std::str::FromStr; + +use aoc_2023::*; + +type Output1 = i64; +type Output2 = Output1; + +#[derive(Debug, Clone, Copy)] +struct AlmanacRange { + destination: i64, + source: i64, + length: i64, +} + +impl FromStr for AlmanacRange { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + let nums: Vec = parse_ws_separated(s); + Ok(AlmanacRange { + destination: nums[0], + source: nums[1], + length: nums[2], + }) + } +} + +impl AlmanacRange { + fn upper_bound(&self) -> i64 { + self.source + self.length + } + + fn has(&self, key: i64) -> bool { + key >= self.source && key < self.upper_bound() + } + + fn map(&self, key: i64) -> Option { + if !self.has(key) { + return None; + } + + Some(self.destination + (key - self.source)) + } + + fn maps_to(&self) -> (i64, i64) { + (self.destination, self.destination + self.length) + } + + fn overlaps(&self, start: i64, length: i64) -> bool { + (start < self.source || self.has(start)) + && (start + length >= self.upper_bound() || self.has(start + length)) + } +} + +struct Mapping { + ranges: Vec, +} + +impl FromStr for Mapping { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + let lines = s.lines().skip(1); + let ranges = lines.map(|l| l.parse().unwrap()).collect(); + Ok(Mapping { ranges }) + } +} + +impl Mapping { + fn map(&self, key: i64) -> i64 { + self.ranges + .iter() + .find(|r| r.has(key)) + .and_then(|r| r.map(key)) + .unwrap_or(key) + } +} + +struct Day05 { + seeds: Vec, + mappings: Vec, +} +impl Solution for Day05 { + fn new>(pathname: P) -> Self { + let lines = file_to_string(pathname); + let mut segments = lines.split("\n\n"); + + let seeds = parse_ws_separated(segments.next().unwrap().split(':').nth(1).unwrap()); + + let mappings = segments.map(|m| m.parse().unwrap()).collect(); + + Self { seeds, mappings } + } + + fn part_1(&mut self) -> Output1 { + self.seeds + .iter() + .map(|s| self.mappings.iter().fold(*s, |key, m| m.map(key))) + .min() + .unwrap() + } + + fn part_2(&mut self) -> Output2 { + let indices = (0..self.seeds.len()) + .map(|i| 2 * i) + .take_while(|i| *i < self.seeds.len() - 1) + .collect_vec(); + + indices + .par_iter() + .flat_map(|i| { + let start = self.seeds[*i]; + let length = self.seeds[i + 1]; + + (start..start + length) + .into_par_iter() + .map(|j| self.mappings.iter().fold(j, |key, m| m.map(key))) + }) + .min() + .unwrap() + } +} + +fn main() -> Result<()> { + Day05::main() +} + +test_sample!(day_05, Day05, 35, 46);