diff --git a/src/bin/day9.rs b/src/bin/day9.rs index 79e3b4c..8c4af39 100644 --- a/src/bin/day9.rs +++ b/src/bin/day9.rs @@ -1,5 +1,6 @@ use std::{ collections::{HashMap, HashSet}, + hash::Hash, ops::RangeInclusive, time::Instant, }; @@ -183,11 +184,27 @@ impl Polygon { } } +struct InsertGuard<'a, K, V>(K, V, &'a mut HashMap) +where + K: Hash + Eq + Copy, + V: Copy; + +impl<'a, K, V> Drop for InsertGuard<'a, K, V> +where + K: Hash + Eq + Copy, + V: Copy, +{ + fn drop(&mut self) { + self.2.insert(self.0, self.1); + } +} + fn horizontal_edges_contained( poly: &Polygon, a: Point2, b: Point2, cache: &mut HashMap, + edge_cache: &mut HashMap<(u64, (u64, u64)), bool>, ) -> bool { assert_ne!(a.x, b.x); @@ -206,6 +223,13 @@ fn horizontal_edges_contained( }; for &y in y_values { + let key = (y, (min_x, max_x)); + if let Some(&v) = edge_cache.get(&key) { + return v; + } + + let guard = InsertGuard(key, false, edge_cache); + // Left corner if !contains(Point2 { x: min_x, y }) { @@ -241,6 +265,9 @@ fn horizontal_edges_contained( if !contains(Point2 { x: max_x - 1, y }) { return false; } + + std::mem::forget(guard); + edge_cache.insert(key, true); } true @@ -251,6 +278,7 @@ fn vertical_edges_contain( a: Point2, b: Point2, cache: &mut HashMap, + edge_cache: &mut HashMap<(u64, (u64, u64)), bool>, ) -> bool { assert_ne!(a.y, b.y); @@ -269,6 +297,13 @@ fn vertical_edges_contain( }; for &x in x_values { + let key = (x, (min_y, max_y)); + if let Some(&v) = edge_cache.get(&key) { + return v; + } + + let guard = InsertGuard(key, false, edge_cache); + // Bottom corner if !contains(Point2 { x, y: min_y }) { @@ -304,6 +339,9 @@ fn vertical_edges_contain( if !contains(Point2 { x, y: max_y - 1 }) { return false; } + + std::mem::forget(guard); + edge_cache.insert(key, true); } true @@ -316,6 +354,8 @@ pub fn part2(input: Parsed) { let mut max_area = 0; let mut contains_cache = HashMap::new(); + let mut h_edge_cache = HashMap::new(); + let mut v_edge_cache = HashMap::new(); for (ia, &a) in poly.points().iter().enumerate() { for &b in poly.points().iter().skip(ia + 1) { @@ -327,11 +367,15 @@ pub fn part2(input: Parsed) { assert!(area > 1); - if a.x != b.x && !horizontal_edges_contained(&poly, a, b, &mut contains_cache) { + if a.x != b.x + && !horizontal_edges_contained(&poly, a, b, &mut contains_cache, &mut h_edge_cache) + { continue; } - if a.y != b.y && !vertical_edges_contain(&poly, a, b, &mut contains_cache) { + if a.y != b.y + && !vertical_edges_contain(&poly, a, b, &mut contains_cache, &mut v_edge_cache) + { continue; }