From 5f70c0666cb37d2cc19aca84b49435cf78650ef0 Mon Sep 17 00:00:00 2001 From: Lars Martens Date: Tue, 5 Dec 2023 12:08:13 +0100 Subject: [PATCH] Solve day 5 part 1 --- input/05-test | 33 +++++++++++++ src/bin/05.rs | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 input/05-test create mode 100644 src/bin/05.rs diff --git a/input/05-test b/input/05-test new file mode 100644 index 0000000..bd902a4 --- /dev/null +++ b/input/05-test @@ -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 \ No newline at end of file diff --git a/src/bin/05.rs b/src/bin/05.rs new file mode 100644 index 0000000..65506f5 --- /dev/null +++ b/src/bin/05.rs @@ -0,0 +1,126 @@ +use itertools::Itertools; + +const INPUT: &str = include_str!("../../input/05"); +const TEST_INPUT: &str = include_str!("../../input/05-test"); + +fn main() { + assert_eq!(part1(TEST_INPUT), 35); + println!("Part 1: {}", part1(INPUT)); + assert_eq!(part2(TEST_INPUT), 46); + println!("Part 2: {}", part2(INPUT)); +} + +fn part1(input: &str) -> u64 { + let garden = Garden::parse(input); + garden + .simple_seeds + .iter() + .copied() + .map(|seed| garden.map(seed)) + .min() + .unwrap() +} + +fn part2(input: &str) -> u64 { + 0 +} + +#[derive(Debug)] +struct Garden { + simple_seeds: Vec, + seed_ranges: Vec, + maps: Vec, +} + +impl Garden { + fn parse(input: &str) -> Self { + let mut blocks = input.split("\n\n"); + let seeds = blocks.next().unwrap().strip_prefix("seeds: ").unwrap(); + let maps = blocks.map(Map::parse).collect(); + + let simple_seeds = parse_ws_numbers(seeds); + let seed_ranges = simple_seeds + .iter() + .copied() + .tuples() + .map(|(start, length)| SeedRange { start, length }) + .collect(); + + Self { + simple_seeds, + seed_ranges, + maps, + } + } + + /// Look up n in every map. + fn map(&self, mut n: u64) -> u64 { + for map in &self.maps { + n = map.map(n); + } + n + } +} + +#[derive(Debug)] +struct SeedRange { + start: u64, + length: u64, +} + +#[derive(Debug)] +struct Map { + ranges: Vec, +} + +impl Map { + fn map(&self, n: u64) -> u64 { + for range in &self.ranges { + if let Some(mapped) = range.map(n) { + return mapped; + } + } + + n + } + + fn parse(block: &str) -> Self { + let lines = block.lines().skip(1); + let ranges = lines.map(MappedRange::parse).collect(); + Self { ranges } + } +} + +#[derive(Debug)] +struct MappedRange { + destination: u64, + source: u64, + length: u64, +} + +impl MappedRange { + fn map(&self, n: u64) -> Option { + let source_start = self.source; + let source_end = source_start + self.length; + if (source_start..source_end).contains(&n) { + Some(n - source_start + self.destination) + } else { + None + } + } + + fn parse(line: &str) -> Self { + let [destination, source, length] = parse_ws_numbers(line).try_into().unwrap(); + Self { + destination, + source, + length, + } + } +} + +fn parse_ws_numbers(s: &str) -> Vec { + s.split_ascii_whitespace() + .map(|s| s.parse().unwrap()) + .collect() +}