From 1a82e611018d891232554ef2a08e508cc4f4c92a Mon Sep 17 00:00:00 2001 From: Connor Slade Date: Tue, 10 Dec 2024 00:45:25 -0500 Subject: [PATCH] [2024] Cleanup day 10 --- aoc_2024/src/day_07.rs | 4 +-- aoc_2024/src/day_10.rs | 74 +++++++++++++----------------------------- common/src/misc.rs | 1 - 3 files changed, 25 insertions(+), 54 deletions(-) diff --git a/aoc_2024/src/day_07.rs b/aoc_2024/src/day_07.rs index ac3a626..04f47b6 100644 --- a/aoc_2024/src/day_07.rs +++ b/aoc_2024/src/day_07.rs @@ -17,7 +17,7 @@ fn solve(input: &str, part_b: bool) -> u64 { // For part a, we check if its valid using `is_valid` with part_b = false, // because an equation that is valid for part a is must be valid for part b, // we can get a small speedup by only doing the more intense part_b = true - // check if needed. + // check if needed. problem .cases .into_iter() @@ -85,7 +85,7 @@ impl TestCase { } // Increments the leftmost operation, carrying if it exceeds 1 for - // part a or 2 for part b. + // part a or 2 for part b. for op in ops.iter_mut() { *op += 1; if *op <= (1 + part_b as usize) { diff --git a/aoc_2024/src/day_10.rs b/aoc_2024/src/day_10.rs index e6d232e..d604bde 100644 --- a/aoc_2024/src/day_10.rs +++ b/aoc_2024/src/day_10.rs @@ -7,21 +7,18 @@ use nd_vec::Vec2; solution!("Hoof It", 10); fn part_a(input: &str) -> Answer { - let map = Map::parse(input); - map.trailheads() - .into_iter() - .map(|x| map.score(x)) - .sum::() - .into() + solve(input, false).into() } fn part_b(input: &str) -> Answer { + solve(input, true).into() +} + +fn solve(input: &str, part_b: bool) -> usize { let map = Map::parse(input); map.trailheads() - .into_iter() - .map(|x| map.rating(x)) + .map(|x| map.score(x, !part_b)) .sum::() - .into() } struct Map { @@ -34,15 +31,17 @@ impl Map { Self { board } } - fn trailheads(&self) -> Vec> { + // Find the coordinates of all 0s + fn trailheads(&self) -> impl Iterator> + use<'_> { self.board .iter() .filter(|(_, &tile)| tile == 0) .map(|(pos, _)| pos) - .collect() } - fn score(&self, pos: Vec2) -> usize { + // Simple BFS for pathfinding, where we don't avoid going to already + // explored tiles if on part B. + fn score(&self, pos: Vec2, no_repeats: bool) -> usize { let mut queue = VecDeque::new(); let mut seen = HashSet::new(); @@ -52,49 +51,22 @@ impl Map { let mut score = 0; while let Some(pos) = queue.pop_front() { let value = *self.board.get(pos).unwrap(); - if value == 9 { - score += 1; - } - - for dir in Direction::ALL { - if let Some(next) = dir.try_advance(pos) { - if self.board.contains(next) - && *self.board.get(next).unwrap() == value + 1 - && seen.insert(next) - { - queue.push_back(next); - } - } - } + score += (value == 9) as usize; + + queue.extend( + Direction::ALL + .iter() + .filter_map(|&dir| dir.try_advance(pos)) + .filter(|&next| { + self.board.contains(next) + && *self.board.get(next).unwrap() == value + 1 + && (!no_repeats || seen.insert(next)) + }), + ); } score } - - fn rating(&self, pos: Vec2) -> usize { - fn inner(board: &Matrix, pos: Vec2, mut seen: HashSet>) -> usize { - let value = *board.get(pos).unwrap(); - if value == 9 { - return 1; - } - - let mut sum = 0; - for dir in Direction::ALL { - if let Some(next) = dir.try_advance(pos) { - if board.contains(next) - && *board.get(next).unwrap() == value + 1 - && seen.insert(next) - { - sum += inner(board, next, seen.clone()); - } - } - } - - sum - } - - inner(&self.board, pos, HashSet::new()) - } } #[cfg(test)] diff --git a/common/src/misc.rs b/common/src/misc.rs index f15e765..fe626cc 100644 --- a/common/src/misc.rs +++ b/common/src/misc.rs @@ -11,4 +11,3 @@ pub fn load_raw(year: u16, day: u32) -> io::Result { let file = format!("data/{year}/{:02}.txt", day); fs::read_to_string(file) } -