diff --git a/src/bin/12.rs b/src/bin/12.rs index 93dcbd5..5f7f90c 100644 --- a/src/bin/12.rs +++ b/src/bin/12.rs @@ -1,5 +1,6 @@ use aoc::*; use glam::IVec2; +use itertools::Itertools; use std::collections::{HashMap, HashSet}; use std::iter; @@ -8,15 +9,19 @@ const INPUT: &str = include_str!("../../input/12"); fn main() { assert_example!(part1, "12-test", 140); println!("Part 1: {}", part1(INPUT)); - assert_example!(part2, "12-test", 0); + assert_example!(part2, "12-test", 80); println!("Part 2: {}", part2(INPUT)); } fn part1(input: &str) -> usize { parse_regions(input).iter().map(Region::fence_cost).sum() } -fn part2(_input: &str) -> usize { - 0 + +fn part2(input: &str) -> usize { + parse_regions(input) + .iter() + .map(Region::bulk_fence_cost) + .sum() } fn parse_regions(input: &str) -> Vec { @@ -79,10 +84,51 @@ impl Region { fn fence_cost(&self) -> usize { self.perimeter * self.area() } + + fn bulk_fence_cost(&self) -> usize { + self.corners() * self.area() + } + + /// Detect corners by moving a 2x2 window over the region and checking the shape. + /// A region has as many corners as edges. + fn corners(&self) -> usize { + let min = self.fields.iter().fold(IVec2::ZERO, |acc, &x| acc.min(x)) - IVec2::ONE; + let max = self.fields.iter().fold(IVec2::ZERO, |acc, &x| acc.max(x)); + + let clockwise = [ + IVec2::ZERO, + IVec2::new(1, 0), + IVec2::new(1, 1), + IVec2::new(0, 1), + ]; + + let mut corners = 0; + + for y in min.y..=max.y { + for x in min.x..=max.x { + let p = IVec2::new(x, y); + let pattern = clockwise + .iter() + .map(|dir| p + dir) + .map(|p| self.fields.contains(&p)) + .collect_vec(); + let count = pattern.iter().filter(|b| **b).count(); + match count { + 0 | 4 => (), + 1 | 3 => corners += 1, + 2 if pattern == [true, false, true, false] => corners += 2, + 2 if pattern == [false, true, false, true] => corners += 2, + 2 => (), + other => unreachable!("should not have {other} elements when checking corners"), + } + } + } + + corners + } } fn parse_map(input: &str) -> HashMap { - // TODO Reading a grid with coordinates should be a helper function. input .lines() .enumerate()