Skip to content

Commit a456e94

Browse files
committed
Year 2024 Day 12
1 parent fce358d commit a456e94

File tree

7 files changed

+173
-0
lines changed

7 files changed

+173
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
8383
| 9 | [Disk Fragmenter](https://adventofcode.com/2024/day/9) | [Source](src/year2024/day09.rs) | 106 |
8484
| 10 | [Hoof It](https://adventofcode.com/2024/day/10) | [Source](src/year2024/day10.rs) | 38 |
8585
| 11 | [Plutonian Pebbles](https://adventofcode.com/2024/day/11) | [Source](src/year2024/day11.rs) | 248 |
86+
| 12 | [Garden Groups](https://adventofcode.com/2024/day/12) | [Source](src/year2024/day12.rs) | 2901 |
8687

8788
## 2023
8889

benches/benchmark.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,4 +303,5 @@ mod year2024 {
303303
benchmark!(year2024, day09);
304304
benchmark!(year2024, day10);
305305
benchmark!(year2024, day11);
306+
benchmark!(year2024, day12);
306307
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,4 +302,5 @@ pub mod year2024 {
302302
pub mod day09;
303303
pub mod day10;
304304
pub mod day11;
305+
pub mod day12;
305306
}

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,5 +372,6 @@ fn year2024() -> Vec<Solution> {
372372
solution!(year2024, day09),
373373
solution!(year2024, day10),
374374
solution!(year2024, day11),
375+
solution!(year2024, day12),
375376
]
376377
}

src/year2024/day12.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//! # Garden Groups
2+
use crate::util::grid::*;
3+
use crate::util::hash::*;
4+
use crate::util::point::*;
5+
use std::collections::VecDeque;
6+
7+
pub fn parse(input: &str) -> Grid<u8> {
8+
Grid::parse(input)
9+
}
10+
11+
pub fn part1(grid: &Grid<u8>) -> i32 {
12+
let mut result = 0;
13+
let mut todo = VecDeque::new();
14+
let mut seen = grid.same_size_with(false);
15+
let mut added = grid.same_size_with(false);
16+
17+
for y in 0..grid.height {
18+
for x in 0..grid.width {
19+
let point = Point::new(x, y);
20+
if seen[point] {
21+
continue;
22+
}
23+
24+
let kind = grid[point];
25+
let mut area = 0;
26+
let mut perm = 0;
27+
28+
todo.push_back(point);
29+
seen[point] = true;
30+
31+
while let Some(point) = todo.pop_front() {
32+
area += 1;
33+
perm += 4;
34+
added[point] = true;
35+
36+
for next in ORTHOGONAL.map(|o| point + o) {
37+
if grid.contains(next) && grid[next] == kind {
38+
if !seen[next] {
39+
seen[next] = true;
40+
todo.push_back(next);
41+
}
42+
if added[next] {
43+
perm -= 2;
44+
}
45+
}
46+
}
47+
}
48+
49+
result += area * perm;
50+
}
51+
}
52+
53+
result
54+
}
55+
56+
pub fn part2(grid: &Grid<u8>) -> u32 {
57+
let mut result = 0;
58+
let mut seen = grid.same_size_with(false);
59+
60+
for y in 0..grid.height {
61+
for x in 0..grid.width {
62+
let point = Point::new(x, y);
63+
if !seen[point] {
64+
result += flood_fill(grid, &mut seen, point);
65+
}
66+
}
67+
}
68+
69+
result
70+
}
71+
72+
fn flood_fill(grid: &Grid<u8>, seen: &mut Grid<bool>, start: Point) -> u32 {
73+
let kind = grid[start];
74+
let mut todo = VecDeque::new();
75+
76+
let mut corner = FastMap::new();
77+
let mut middle = FastMap::new();
78+
79+
let mut size = 0;
80+
81+
todo.push_back(start);
82+
seen[start] = true;
83+
84+
while let Some(point) = todo.pop_front() {
85+
size += 1;
86+
87+
let x = 2 * point.x;
88+
let y = 2 * point.y;
89+
90+
*corner.entry(Point::new(x, y)).or_insert(0) += 1;
91+
*corner.entry(Point::new(x + 2, y)).or_insert(0) += 1;
92+
*corner.entry(Point::new(x, y + 2)).or_insert(0) += 1;
93+
*corner.entry(Point::new(x + 2, y + 2)).or_insert(0) += 1;
94+
95+
*middle.entry(Point::new(x + 1, y)).or_insert(0) += 1;
96+
*middle.entry(Point::new(x, y + 1)).or_insert(0) += 1;
97+
*middle.entry(Point::new(x + 2, y + 1)).or_insert(0) += 1;
98+
*middle.entry(Point::new(x + 1, y + 2)).or_insert(0) += 1;
99+
100+
for next in ORTHOGONAL.map(|o| point + o) {
101+
if grid.contains(next) && grid[next] == kind && !seen[next] {
102+
seen[next] = true;
103+
todo.push_back(next);
104+
}
105+
}
106+
}
107+
108+
corner.retain(|_, v| *v < 4);
109+
middle.retain(|_, v| *v < 2);
110+
let mut sides = 0;
111+
112+
for &point in corner.keys() {
113+
let mut count = 0;
114+
let mut v1 = UP;
115+
let mut v2 = RIGHT;
116+
117+
for _ in 0..4 {
118+
if middle.contains_key(&(point + v1)) && middle.contains_key(&(point + v2)) {
119+
count += 1;
120+
}
121+
v1 = v1.clockwise();
122+
v2 = v2.clockwise();
123+
}
124+
125+
if count == 1 {
126+
sides += 1;
127+
} else if count == 4 {
128+
sides += 2;
129+
}
130+
}
131+
132+
size * sides
133+
}

tests/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,4 +292,5 @@ mod year2024 {
292292
mod day09_test;
293293
mod day10_test;
294294
mod day11_test;
295+
mod day12_test;
295296
}

tests/year2024/day12_test.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use aoc::year2024::day12::*;
2+
3+
const FIRST_EXAMPLE: &str = "\
4+
RRRRIICCFF
5+
RRRRIICCCF
6+
VVRRRCCFFF
7+
VVRCCCJFFF
8+
VVVVCJJCFE
9+
VVIVCCJJEE
10+
VVIIICJJEE
11+
MIIIIIJJEE
12+
MIIISIJEEE
13+
MMMISSJEEE";
14+
15+
const SECOND_EXAMPLE: &str = "\
16+
AAAAAA
17+
AAABBA
18+
AAABBA
19+
ABBAAA
20+
ABBAAA
21+
AAAAAA";
22+
23+
#[test]
24+
fn part1_test() {
25+
let input = parse(FIRST_EXAMPLE);
26+
assert_eq!(part1(&input), 1930);
27+
}
28+
29+
#[test]
30+
fn part2_test() {
31+
let input = parse(FIRST_EXAMPLE);
32+
assert_eq!(part2(&input), 1206);
33+
let input = parse(SECOND_EXAMPLE);
34+
assert_eq!(part2(&input), 368);
35+
}

0 commit comments

Comments
 (0)