From 6d73fba8d0182fdbef4f1b914265f66f55c3abe6 Mon Sep 17 00:00:00 2001 From: spectre Date: Fri, 8 Dec 2023 00:39:22 +0100 Subject: [PATCH] day05 part 2 --- aoc2023/src/day05.rs | 123 ++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 12 ++++- 2 files changed, 126 insertions(+), 9 deletions(-) diff --git a/aoc2023/src/day05.rs b/aoc2023/src/day05.rs index 202aedf..f29af25 100644 --- a/aoc2023/src/day05.rs +++ b/aoc2023/src/day05.rs @@ -1,4 +1,5 @@ -use std::fmt::Debug; +use std::cmp::{max, min}; +use std::fmt::{Debug, Display, Formatter}; use shared::{Solution, Answer}; pub struct Day05; @@ -8,22 +9,22 @@ impl Solution for Day05 { let blocks: Vec<&str> = input.split("\n\n") .collect(); - let seeds: Vec = blocks[0].split(" ") + let seeds: Vec = blocks[0].split(" ") .skip(1) - .map(|x| x.parse::().unwrap()) + .map(|x| x.parse::().unwrap()) .collect(); - let rules: Vec>> = blocks.iter() + let rules: Vec>> = blocks.iter() .skip(1) .map(|rule_block| rule_block.split("\n") .skip(1) .map(|rule| rule.split(" ").map( |y| - y.parse::().unwrap()).collect() + y.parse::().unwrap()).collect() ).collect() ).collect(); - let final_seeds: Vec = seeds.iter() + let final_seeds: Vec = seeds.iter() .map(|seed| { let mut res = seed.clone(); @@ -37,12 +38,59 @@ impl Solution for Day05 { Answer::from(final_seeds.iter().min().unwrap().clone()) } + fn part_2(&self, input: &str) -> Answer { - todo!() + let blocks: Vec<&str> = input.split("\n\n") + .collect(); + + let mut seeds: Vec = blocks[0].split(" ") + .skip(1) + .collect::>() + .chunks(2) + .map(|x| SeedRange::from_seeds(x[0].parse::().unwrap(), x[1].parse::().unwrap())) + .collect(); + + let rule_blocks: Vec> = blocks.iter() + .skip(1) + .map( + |block| block.split("\n").skip(1).map( + |line| { + let l: Vec<&str> = line.split(" ").collect(); + Rule::from_rules(l[0].parse::().unwrap(), l[1].parse::().unwrap(), l[2].parse::().unwrap()) + } + ).collect() + ).collect(); + + + for rule_blk in &rule_blocks { + let mut ranges_to_check: Vec = seeds.clone(); + let mut next_ranges: Vec = vec![]; + let mut ranges_done: Vec = vec![]; + + for rule in rule_blk { + for range in ranges_to_check { + match rule.apply(&range) { + None => next_ranges.push(range), + Some((None, mid, None)) => ranges_done.push(mid), + Some((Some(first), mid, None)) => { next_ranges.push(first); ranges_done.push(mid) }, + Some((None, mid, Some(last))) => { next_ranges.push(last); ranges_done.push(mid) }, + Some((Some(first), mid, Some(last))) => { next_ranges.push(first); next_ranges.push(last); ranges_done.push(mid) } + } + } + ranges_to_check = next_ranges; + next_ranges = vec![]; + } + + seeds = [ranges_to_check, ranges_done].concat(); + } + + let result = seeds.iter().min_by_key(|x| x.start).unwrap().start; + + Answer::from(result) } } -fn map(seed: u64, rules: &Vec>) -> u64 { +fn map(seed: i64, rules: &Vec>) -> i64 { for rule in rules { let dest = rule[0]; let source = rule[1]; @@ -54,3 +102,62 @@ fn map(seed: u64, rules: &Vec>) -> u64 { } seed } + +#[derive(Clone, Debug)] +struct SeedRange { + start: i64, + end: i64, +} + +impl SeedRange { + fn new(start: i64, end: i64) -> SeedRange { + SeedRange {start, end} + } + + fn from_seeds(start: i64, range: i64) -> SeedRange { + SeedRange {start, end: start + range - 1} + } +} + +impl Display for SeedRange { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}..{}", self.start, self.end) + } +} + +#[derive(Clone, Debug)] +struct Rule { + start: i64, + end: i64, + offset: i64, +} + +impl Rule { + fn new(start: i64, end: i64, offset: i64) -> Rule { + Rule {start, end, offset} + } + + fn from_rules(dest: i64, source: i64, range: i64) -> Rule { + Rule {start: source, end: source + range - 1, offset: (dest - source) as i64} + } + + fn apply(&self, seeds: &SeedRange) -> Option<(Option, SeedRange, Option)> { + if (self.start <= seeds.end && self.end >= seeds.start) { + Some( + ( + if self.start > seeds.start { Some(SeedRange::new(seeds.start, self.start - 1)) } else { None }, + SeedRange::new(max(self.start, seeds.start) + self.offset, min(self.end, seeds.end) + self.offset), + if self.end < seeds.end { Some(SeedRange::new(self.end + 1, seeds.end)) } else { None }, + ) + ) + } + else { None } + } +} + +impl Display for Rule { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}..{}: {}", self.start, self.end, self.offset) + } +} + diff --git a/src/main.rs b/src/main.rs index 582e5be..8216fe0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,9 +4,19 @@ mod load_data; use aoc2023; use load_data::load; +use std::time::Instant; + fn main() { + let now = Instant::now(); + let Ok(data) = load(2023, 5) else { return; }; - print!("{}", aoc2023::day05::Day05.part_1(&data)); + let result = aoc2023::day05::Day05.part_2(&data); + + let elapsed = now.elapsed(); + + println!("{}", result); + + println!("{:?}", elapsed); } \ No newline at end of file