From 1f49f710683533d337b5e23d4386d7daf64cbf3d Mon Sep 17 00:00:00 2001 From: Lars Martens Date: Thu, 12 Dec 2024 21:30:15 +0100 Subject: [PATCH] Solve 12.1 --- src/bin/04.rs | 13 +------ src/bin/10.rs | 11 +----- src/bin/12.rs | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 21 ++++++++++++ 4 files changed, 118 insertions(+), 22 deletions(-) create mode 100644 src/bin/12.rs diff --git a/src/bin/04.rs b/src/bin/04.rs index 1aae2b5..33ec3dd 100644 --- a/src/bin/04.rs +++ b/src/bin/04.rs @@ -56,7 +56,7 @@ fn check_x_mas(start: IVec2, field: &Field) -> usize { } fn count_xmas_at(start: IVec2, field: &Field) -> usize { - DIRECTIONS + DIRECTIONS8 .iter() .filter(|&&dir| check_xmas(start, dir, field)) .count() @@ -69,17 +69,6 @@ fn check_xmas(start: IVec2, direction: IVec2, field: &Field) -> bool { && field.get(start + direction * 3) == 'S' } -const DIRECTIONS: [IVec2; 8] = [ - IVec2::new(1, 0), - IVec2::new(1, 1), - IVec2::new(0, 1), - IVec2::new(-1, 1), - IVec2::new(-1, 0), - IVec2::new(-1, -1), - IVec2::new(0, -1), - IVec2::new(1, -1), -]; - struct Field { data: Vec>, } diff --git a/src/bin/10.rs b/src/bin/10.rs index a0f6fa4..20e3aec 100644 --- a/src/bin/10.rs +++ b/src/bin/10.rs @@ -22,15 +22,6 @@ fn part2(input: &str) -> usize { map.trailheads().map(|t| map.distinct_trails(t)).sum() } -fn directions() -> [IVec2; 4] { - [ - IVec2::new(1, 0), - IVec2::new(-1, 0), - IVec2::new(0, 1), - IVec2::new(0, -1), - ] -} - #[derive(Debug)] struct Map { height: HashMap, @@ -67,7 +58,7 @@ impl Map { } fn climb_up(&self, from: IVec2, from_height: i64) -> Vec { - directions() + DIRECTIONS4 .into_iter() .filter_map(|dir| { let pos = from + dir; diff --git a/src/bin/12.rs b/src/bin/12.rs new file mode 100644 index 0000000..93dcbd5 --- /dev/null +++ b/src/bin/12.rs @@ -0,0 +1,95 @@ +use aoc::*; +use glam::IVec2; +use std::collections::{HashMap, HashSet}; +use std::iter; + +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); + 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 parse_regions(input: &str) -> Vec { + let mut map = parse_map(input); + let mut regions = Vec::new(); + loop { + let Some((&start_pos, &plant)) = map.iter().next() else { + break; + }; + let mut visited = HashSet::new(); + let mut region = Vec::new(); + let mut check = vec![start_pos]; + let mut perimeter = 0; + while let Some(next) = check.pop() { + if visited.contains(&next) { + continue; + } + visited.insert(next); + let Some(&p) = map.get(&next) else { continue }; + if p != plant { + continue; + } + + region.push(next); + map.remove(&next); + + // Adjust perimeter + let empty_sides = DIRECTIONS4 + .into_iter() + .map(|dir| dir + next) + .filter(|pos| !region.contains(pos)) + .count(); + let taken_sides = 4 - empty_sides; + perimeter = perimeter + empty_sides - taken_sides; + + let neighbors = DIRECTIONS4.into_iter().map(|dir| dir + next); + check.extend(neighbors); + } + regions.push(Region { + _plant: plant, + fields: region, + perimeter, + }); + } + regions +} + +#[derive(Debug)] +struct Region { + _plant: char, + fields: Vec, + perimeter: usize, +} + +impl Region { + fn area(&self) -> usize { + self.fields.len() + } + + fn fence_cost(&self) -> usize { + self.perimeter * self.area() + } +} + +fn parse_map(input: &str) -> HashMap { + // TODO Reading a grid with coordinates should be a helper function. + input + .lines() + .enumerate() + .flat_map(|(y, line)| line.chars().enumerate().zip(iter::repeat(y))) + .map(|((x, c), y)| { + let pos = IVec2::new(x as i32, y as i32); + (pos, c) + }) + .collect() +} diff --git a/src/lib.rs b/src/lib.rs index 9d7408b..2520767 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ //! This library contains useful helper functions that may be useful in several problems. +use glam::IVec2; use std::{ fmt::{Debug, Display}, ops::{Div, Mul, Rem}, @@ -106,3 +107,23 @@ macro_rules! assert_example { ) }; } + +/// 4 directions. Start pointing right and go CCW. +pub const DIRECTIONS4: [IVec2; 4] = [ + IVec2::new(1, 0), + IVec2::new(0, 1), + IVec2::new(-1, 0), + IVec2::new(0, -1), +]; + +/// 8 directions. Start pointing right and go CCW. +pub const DIRECTIONS8: [IVec2; 8] = [ + IVec2::new(1, 0), + IVec2::new(1, 1), + IVec2::new(0, 1), + IVec2::new(-1, 1), + IVec2::new(-1, 0), + IVec2::new(-1, -1), + IVec2::new(0, -1), + IVec2::new(1, -1), +];