day(05): add solution
“brute-force me up inside” Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
e58483770f
commit
715904ca2b
2 changed files with 162 additions and 0 deletions
33
samples/day05.txt
Normal file
33
samples/day05.txt
Normal file
|
@ -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
|
129
src/bin/day05.rs
Normal file
129
src/bin/day05.rs
Normal file
|
@ -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<Self, Self::Err> {
|
||||||
|
let nums: Vec<i64> = 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<i64> {
|
||||||
|
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<AlmanacRange>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Mapping {
|
||||||
|
type Err = &'static str;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
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<i64>,
|
||||||
|
mappings: Vec<Mapping>,
|
||||||
|
}
|
||||||
|
impl Solution<Output1, Output2> for Day05 {
|
||||||
|
fn new<P: AsRef<Path>>(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);
|
Loading…
Reference in a new issue