solution: day5 ranges

Squashed commit of the following:

commit 000001603e10102f634c2f4ca7eb310ec72f1863
Author: Matej Janežič <janezic.mj@gmail.com>
Date:   Wed Dec 6 20:47:26 2023 +0100

    day(5): ranges

commit 0000015049
Author: Matej Janežič <janezic.mj@gmail.com>
Date:   Wed Dec 6 18:58:58 2023 +0100

    wip: solve with range type
This commit is contained in:
Matej Janezic 2023-12-06 20:49:10 +01:00
parent 00000140d3
commit 0000015082
Signed by: janezicmatej
GPG Key ID: 4298E230ED37B2C0
1 changed files with 53 additions and 42 deletions

View File

@ -1,17 +1,33 @@
use std::{ use std::{
cmp::{max, min}, cmp::{max, min},
fmt::Debug,
ops::RangeInclusive,
str::FromStr, str::FromStr,
}; };
use aoc::parsers::to_vec; use aoc::parsers::to_vec;
type PairRange = (u64, u64); trait RangeInclusiveExt {
fn overlaps(&self, other: &Self) -> bool;
}
impl<T> RangeInclusiveExt for RangeInclusive<T>
where
T: PartialOrd,
{
fn overlaps(&self, other: &Self) -> bool {
self.contains(other.start()) || self.contains(other.end())
}
}
fn build_range(start: u64, range: u64) -> RangeInclusive<u64> {
start..=(start + range - 1)
}
#[derive(Debug)] #[derive(Debug)]
struct Mapping { struct Mapping {
destination: u64, pub source: RangeInclusive<u64>,
source: u64, pub destination: RangeInclusive<u64>,
range: u64,
} }
struct ParseMappingError; struct ParseMappingError;
@ -22,49 +38,43 @@ impl FromStr for Mapping {
let nums: Vec<u64> = to_vec(s, ' '); let nums: Vec<u64> = to_vec(s, ' ');
Ok(Self { Ok(Self {
destination: nums[0], destination: build_range(nums[0], nums[2]),
source: nums[1], source: build_range(nums[1], nums[2]),
range: nums[2],
}) })
} }
} }
impl Mapping { impl Mapping {
fn contains(&self, n: u64) -> bool {
n >= self.source && n < self.source + self.range
}
fn contains_any(&self, (s, r): PairRange) -> bool {
s < self.source + self.range && s + r > self.source
}
fn map(&self, n: u64) -> u64 { fn map(&self, n: u64) -> u64 {
let shift = n - self.source; let shift = n - self.source.start();
self.destination + shift self.destination.start() + shift
} }
fn split_range(&self, (s, r): PairRange) -> [Option<PairRange>; 3] { fn map_range(&self, r: RangeInclusive<u64>) -> RangeInclusive<u64> {
self.map(*r.start())..=(self.map(*r.end()))
}
fn split_range(&self, r: RangeInclusive<u64>) -> [Option<RangeInclusive<u64>>; 3] {
let mut fences = [ let mut fences = [
s, *r.start(),
s + r, *r.end() + 1,
max(self.source, s), max(*self.source.start(), *r.start()),
min(self.source + self.range, s + r), min(*self.source.end() + 1, *r.end() + 1),
]; ];
fences.sort(); fences.sort();
let mut v = Vec::new(); const ARRAY_REPEAT_VALUE: Option<RangeInclusive<u64>> = None;
let mut v = [ARRAY_REPEAT_VALUE; 3];
for i in 0..3 { for i in 0..3 {
let f = fences[i]; let f = fences[i];
let nf = fences[i + 1]; let nf = fences[i + 1];
if f != nf { if f != nf {
v.push(Some((f, nf - f))) v[i] = Some(f..=(nf - 1))
} else {
v.push(None)
} }
} }
v
v[..3].try_into().unwrap()
} }
} }
@ -95,7 +105,7 @@ pub fn part_one(input: &str) -> Option<u64> {
let mut s = *seed; let mut s = *seed;
'maps: for map in maps.iter() { 'maps: for map in maps.iter() {
for inner in map.iter() { for inner in map.iter() {
if inner.contains(s) { if inner.source.contains(&s) {
s = inner.map(s); s = inner.map(s);
continue 'maps; continue 'maps;
} }
@ -111,22 +121,19 @@ pub fn part_one(input: &str) -> Option<u64> {
pub fn part_two(input: &str) -> Option<u64> { pub fn part_two(input: &str) -> Option<u64> {
let (first, rest) = input.split_once("\n\n").unwrap(); let (first, rest) = input.split_once("\n\n").unwrap();
let maps = parse_map(rest); let maps = parse_map(rest);
let seeds = to_vec::<u64, _>(first.strip_prefix("seeds: ").unwrap(), ' '); let mut seeds_ranges: Vec<_> = to_vec::<u64, _>(first.strip_prefix("seeds: ").unwrap(), ' ')
let mut seeds_ranges: Vec<_> = Vec::new(); .chunks(2)
for s in seeds.chunks(2) { .map(|x| build_range(x[0], x[1]))
seeds_ranges.push((s[0], s[1])) .collect();
}
for mapping in maps.iter() { for mapping in maps.iter() {
let mut new_ranges = Vec::new(); let mut new_ranges = Vec::new();
'queue: while let Some((s, r)) = seeds_ranges.pop() { 'queue: while let Some(rng) = seeds_ranges.pop() {
for map in mapping { for map in mapping {
if map.contains_any((s, r)) { if map.source.overlaps(&rng) {
let [pre, to_map, post] = map.split_range((s, r)); let [pre, to_map, post] = map.split_range(rng);
let to_map = to_map.unwrap(); new_ranges.push(map.map_range(to_map.unwrap()));
let mapped = (map.map(to_map.0), to_map.1);
new_ranges.push(mapped);
for r in [pre, post].into_iter().flatten() { for r in [pre, post].into_iter().flatten() {
seeds_ranges.push(r); seeds_ranges.push(r);
} }
@ -134,13 +141,17 @@ pub fn part_two(input: &str) -> Option<u64> {
} }
} }
new_ranges.push((s, r)); new_ranges.push(rng);
} }
seeds_ranges = new_ranges; seeds_ranges = new_ranges;
} }
seeds_ranges.iter().map(|(x, _)| *x).min() seeds_ranges
.iter()
.map(RangeInclusive::start)
.min()
.copied()
} }
aoc::solution!(5); aoc::solution!(5);