1
0
Fork 0
This commit is contained in:
Lars Martens 2024-12-14 15:16:56 +01:00
parent 44f9b238f7
commit 271d764144
Signed by: haselkern
GPG key ID: B5CF1F363C179AD4

View file

@ -1,5 +1,6 @@
use aoc::*; use aoc::*;
use glam::IVec2; use glam::IVec2;
use itertools::Itertools;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::iter; use std::iter;
@ -8,15 +9,19 @@ const INPUT: &str = include_str!("../../input/12");
fn main() { fn main() {
assert_example!(part1, "12-test", 140); assert_example!(part1, "12-test", 140);
println!("Part 1: {}", part1(INPUT)); println!("Part 1: {}", part1(INPUT));
assert_example!(part2, "12-test", 0); assert_example!(part2, "12-test", 80);
println!("Part 2: {}", part2(INPUT)); println!("Part 2: {}", part2(INPUT));
} }
fn part1(input: &str) -> usize { fn part1(input: &str) -> usize {
parse_regions(input).iter().map(Region::fence_cost).sum() 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<Region> { fn parse_regions(input: &str) -> Vec<Region> {
@ -79,10 +84,51 @@ impl Region {
fn fence_cost(&self) -> usize { fn fence_cost(&self) -> usize {
self.perimeter * self.area() 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<IVec2, char> { fn parse_map(input: &str) -> HashMap<IVec2, char> {
// TODO Reading a grid with coordinates should be a helper function.
input input
.lines() .lines()
.enumerate() .enumerate()