From 74dd02b80efb662383a3f2ff45aea29d42fa604c Mon Sep 17 00:00:00 2001 From: Daniel Lin Date: Tue, 10 Dec 2024 02:43:38 -0500 Subject: [PATCH] Day 10: Hoof It --- README.md | 2 +- rs/benches/criterion.rs | 8 +++- rs/src/day10.rs | 100 ++++++++++++++++++++++++++++++++++++++++ rs/src/lib.rs | 1 + rs/src/main.rs | 10 +++- 5 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 rs/src/day10.rs diff --git a/README.md b/README.md index 39a9dbb..133c3e1 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,4 @@ Development occurs in language-specific directories: |[Day7.hs](hs/src/Day7.hs)|[Day7.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day7.kt)|[day7.py](py/aoc2024/day7.py)|[day7.rs](rs/src/day7.rs)| |[Day8.hs](hs/src/Day8.hs)|[Day8.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day8.kt)|[day8.py](py/aoc2024/day8.py)|[day8.rs](rs/src/day8.rs)| |[Day9.hs](hs/src/Day9.hs)|[Day9.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day9.kt)|[day9.py](py/aoc2024/day9.py)|[day9.rs](rs/src/day9.rs)| -|[Day10.hs](hs/src/Day10.hs)|[Day10.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day10.kt)|[day10.py](py/aoc2024/day10.py)|| +|[Day10.hs](hs/src/Day10.hs)|[Day10.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day10.kt)|[day10.py](py/aoc2024/day10.py)|[day10.rs](rs/src/day10.rs)| diff --git a/rs/benches/criterion.rs b/rs/benches/criterion.rs index 01f9911..42bb1ec 100644 --- a/rs/benches/criterion.rs +++ b/rs/benches/criterion.rs @@ -1,4 +1,4 @@ -use aoc2024::{day1, day2, day3, day4, day5, day6, day7, day8, day9}; +use aoc2024::{day1, day10, day2, day3, day4, day5, day6, day7, day8, day9}; use criterion::{black_box, Criterion}; use std::env; use std::fs; @@ -68,6 +68,12 @@ fn aoc2024_bench(c: &mut Criterion) -> io::Result<()> { g.bench_function("part 2", |b| b.iter(|| day9::part2(black_box(&data)))); g.finish(); + let data = get_day_input(10)?; + let mut g = c.benchmark_group("day 10"); + g.bench_function("part 1", |b| b.iter(|| day10::part1(black_box(&data)))); + g.bench_function("part 2", |b| b.iter(|| day10::part2(black_box(&data)))); + g.finish(); + Ok(()) } diff --git a/rs/src/day10.rs b/rs/src/day10.rs new file mode 100644 index 0000000..9d23e6f --- /dev/null +++ b/rs/src/day10.rs @@ -0,0 +1,100 @@ +use std::array; +use std::collections::{BTreeMap, BTreeSet}; + +fn parse(data: &str) -> [BTreeSet<(usize, usize)>; 10] { + let mut elevations = array::from_fn(|_| BTreeSet::new()); + for (y, line) in data.lines().enumerate() { + for (x, c) in line.char_indices() { + if let Some(h) = c.to_digit(10) { + elevations[h as usize].insert((y, x)); + } + } + } + elevations +} + +fn step( + acc: &BTreeMap<(usize, usize), T>, + points: &BTreeSet<(usize, usize)>, + plus: F, +) -> BTreeMap<(usize, usize), T> +where + T: Clone, + F: Fn(&T, &T) -> T, +{ + let mut ret = BTreeMap::new(); + for ((y, x), value) in acc { + for (dy, dx) in [(-1, 0), (0, -1), (0, 1), (1, 0)] { + if let Some(point) = y + .checked_add_signed(dy) + .zip(x.checked_add_signed(dx)) + .filter(|point| points.contains(point)) + { + ret.entry(point) + .and_modify(|e: &mut T| *e = plus(value, e)) + .or_insert_with(|| value.clone()); + } + } + } + ret +} + +pub fn part1(data: &str) -> usize { + let elevations = parse(data); + elevations[1..] + .iter() + .fold( + elevations[0] + .iter() + .map(|point| (*point, [*point].into_iter().collect())) + .collect(), + |acc, points| { + step(&acc, points, |x, y| -> BTreeSet<_> { + x.union(y).copied().collect() + }) + }, + ) + .values() + .map(|value| value.len()) + .sum() +} + +pub fn part2(data: &str) -> usize { + let elevations = parse(data); + elevations[1..] + .iter() + .fold( + elevations[0].iter().map(|point| (*point, 1usize)).collect(), + |acc, points| step(&acc, points, |x, y| x + y), + ) + .values() + .sum() +} + +#[cfg(test)] +mod tests { + use super::*; + use indoc::indoc; + use pretty_assertions::assert_eq; + + static EXAMPLE: &str = indoc! {" + 89010123 + 78121874 + 87430965 + 96549874 + 45678903 + 32019012 + 01329801 + 10456732 + "}; + + #[test] + fn part1_examples() { + assert_eq!(36, part1(EXAMPLE)); + } + + #[test] + fn part2_examples() { + assert_eq!(81, part2(EXAMPLE)); + } +} diff --git a/rs/src/lib.rs b/rs/src/lib.rs index b7940e5..bcca163 100644 --- a/rs/src/lib.rs +++ b/rs/src/lib.rs @@ -1,4 +1,5 @@ pub mod day1; +pub mod day10; pub mod day2; pub mod day3; pub mod day4; diff --git a/rs/src/main.rs b/rs/src/main.rs index eb8f1c2..2157680 100644 --- a/rs/src/main.rs +++ b/rs/src/main.rs @@ -1,5 +1,5 @@ use anyhow::anyhow; -use aoc2024::{day1, day2, day3, day4, day5, day6, day7, day8, day9}; +use aoc2024::{day1, day10, day2, day3, day4, day5, day6, day7, day8, day9}; use std::collections::HashSet; use std::env; use std::fs; @@ -89,5 +89,13 @@ fn main() -> anyhow::Result<()> { println!(); } + if args.is_empty() || args.contains("10") { + println!("Day 10"); + let data = get_day_input(10)?; + println!("{:?}", day10::part1(&data)); + println!("{:?}", day10::part2(&data)); + println!(); + } + Ok(()) }