-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday03.py
103 lines (75 loc) · 2.89 KB
/
day03.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
from itertools import product
from collections import defaultdict
class EnginePart:
def __init__(self, digits: list[str], positions: list[tuple[int, int]]) -> None:
self._digits = digits
self._positions = positions
self._neighbors = None
@property
def neighbors(self):
if not self._neighbors:
all_neighbors = []
for r, c in self._positions:
for r_add, c_add in product([-1, 0, 1], repeat=2):
all_neighbors.append((r+r_add, c+c_add))
self._neighbors = set(all_neighbors) - set(self._positions)
return self._neighbors
@property
def value(self):
return int("".join(self._digits))
def __repr__(self) -> str:
return "{}({}, {})".format(type(self).__name__, self._digits, self._positions)
def get_engine_parts(lines):
engine_parts = []
rows, cols = len(lines), len(lines[0])
for row in range(rows):
col = 0
while col < cols:
if not lines[row][col].isdigit():
col += 1
continue
digits, positions = [], []
while col < cols and lines[row][col].isdigit():
digits.append(lines[row][col])
positions.append((row, col))
col += 1
engine_parts.append(EnginePart(digits, positions))
return engine_parts
def get_symbols(lines):
positions = []
rows, cols = len(lines), len(lines[0])
for row in range(rows):
for col in range(cols):
if not lines[row][col].isdigit() and lines[row][col] != ".":
positions.append((row, col))
return positions
def get_gears(lines):
positions = []
rows, cols = len(lines), len(lines[0])
for row in range(rows):
for col in range(cols):
if lines[row][col] == "*":
positions.append((row, col))
return positions
def main():
with open("input", "r") as f:
lines = [line.strip() for line in f]
# part 1
engine_parts: list[EnginePart] = get_engine_parts(lines)
symbols: set[tuple[int, int]] = set(get_symbols(lines))
valid_engine_parts = []
for engine_part in engine_parts:
if engine_part.neighbors & symbols:
valid_engine_parts.append(engine_part)
total = sum(part.value for part in valid_engine_parts)
print(total)
# part 2
engine_parts: list[EnginePart] = get_engine_parts(lines)
gears: set[tuple[int, int]] = set(get_gears(lines))
gear_to_parts = defaultdict(list)
for engine_part in engine_parts:
for position in engine_part.neighbors & gears:
gear_to_parts[position].append(engine_part)
total = sum(parts[0].value * parts[1].value for parts in gear_to_parts.values() if len(parts) == 2)
print(total)
main()