Skip to content

Commit 044c971

Browse files
committed
Implement 2024 day 12
1 parent 8308580 commit 044c971

File tree

5 files changed

+141
-0
lines changed

5 files changed

+141
-0
lines changed

2024/src/aoc/days/day12.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import numpy
2+
3+
from . import CombinedRunner
4+
5+
DIRECTIONS = [
6+
(-1, 0),
7+
(1, 0),
8+
(0, -1),
9+
(0, 1),
10+
]
11+
12+
13+
class DayRunner(CombinedRunner):
14+
@classmethod
15+
def run_both(cls, input: str) -> tuple[int, int]:
16+
grid = numpy.array(list(map(list, input.strip().split("\n"))))
17+
18+
score = 0
19+
score2 = 0
20+
21+
for y in range(grid.shape[0]):
22+
for x in range(grid.shape[1]):
23+
if grid[y, x] == ".":
24+
continue
25+
26+
search = grid[y, x]
27+
grid[y, x] = "."
28+
29+
todo = [(y, x)]
30+
cluster = {(y, x)}
31+
32+
def enqueue(y, x):
33+
if grid[y, x] == search:
34+
grid[y, x] = "."
35+
todo.append((y, x))
36+
cluster.add((y, x))
37+
38+
while todo:
39+
cy, cx = todo.pop()
40+
41+
if cx > 0:
42+
enqueue(cy, cx - 1)
43+
if cy > 0:
44+
enqueue(cy - 1, cx)
45+
46+
if cx < grid.shape[1] - 1:
47+
enqueue(cy, cx + 1)
48+
if cy < grid.shape[0] - 1:
49+
enqueue(cy + 1, cx)
50+
51+
side_length = sum(
52+
sum((cy + dy, cx + dx) not in cluster for dy, dx in DIRECTIONS)
53+
for cy, cx in cluster
54+
)
55+
56+
corners = 0
57+
58+
for cy, cx in cluster:
59+
# Outer corners
60+
corners += (cy, cx - 1) not in cluster and (
61+
cy - 1,
62+
cx,
63+
) not in cluster
64+
corners += (cy, cx + 1) not in cluster and (
65+
cy - 1,
66+
cx,
67+
) not in cluster
68+
corners += (cy, cx - 1) not in cluster and (
69+
cy + 1,
70+
cx,
71+
) not in cluster
72+
corners += (cy, cx + 1) not in cluster and (
73+
cy + 1,
74+
cx,
75+
) not in cluster
76+
# Inner corners
77+
corners += (
78+
(cy, cx - 1) in cluster
79+
and (cy - 1, cx) in cluster
80+
and (cy - 1, cx - 1) not in cluster
81+
)
82+
corners += (
83+
(cy, cx + 1) in cluster
84+
and (cy - 1, cx) in cluster
85+
and (cy - 1, cx + 1) not in cluster
86+
)
87+
corners += (
88+
(cy, cx - 1) in cluster
89+
and (cy + 1, cx) in cluster
90+
and (cy + 1, cx - 1) not in cluster
91+
)
92+
corners += (
93+
(cy, cx + 1) in cluster
94+
and (cy + 1, cx) in cluster
95+
and (cy + 1, cx + 1) not in cluster
96+
)
97+
98+
score += side_length * len(cluster)
99+
score2 += corners * len(cluster)
100+
101+
return (score, score2)

2024/tests/samples/12.1.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
AAAA
2+
BBCD
3+
BBCC
4+
EEEC

2024/tests/samples/12.2.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
OOOOO
2+
OXOXO
3+
OOOOO
4+
OXOXO
5+
OOOOO

2024/tests/samples/12.3.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
RRRRIICCFF
2+
RRRRIICCCF
3+
VVRRRCCFFF
4+
VVRCCCJFFF
5+
VVVVCJJCFE
6+
VVIVCCJJEE
7+
VVIIICJJEE
8+
MIIIIIJJEE
9+
MIIISIJEEE
10+
MMMISSJEEE

2024/tests/test_day12.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import pytest
2+
3+
from aoc.days.day12 import DayRunner
4+
5+
from . import get_data
6+
7+
8+
@pytest.mark.parametrize(
9+
"data,result",
10+
[(get_data(12, 1), 140), (get_data(12, 2), 772), (get_data(12, 3), 1930)],
11+
)
12+
def test_sample_part1(data: str, result: int) -> None:
13+
assert DayRunner.part1(data) == result
14+
15+
16+
@pytest.mark.parametrize(
17+
"data,result",
18+
[(get_data(12, 1), 80), (get_data(12, 2), 436), (get_data(12, 3), 1206)],
19+
)
20+
def test_sample_part2(data: str, result: int) -> None:
21+
assert DayRunner.part2(data) == result

0 commit comments

Comments
 (0)