Cache the edge calculations

This commit is contained in:
Quentin Boyer 2025-12-10 01:33:07 +01:00
parent 8662ab104f
commit a8ee7f78f6

View file

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