Skip to content

Commit 0e6db48

Browse files
committed
[AdventOfCode] Add day3 solutions
1 parent 32c7bde commit 0e6db48

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed

AdventOfCode/2023/day_3.py

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# ---------------------------------------------------------------------------------------
2+
# URL : https://adventofcode.com/2023/day/3
3+
# Title : Gear Ratios
4+
# Tags : tag-adventofcode
5+
# ---------------------------------------------------------------------------------------
6+
7+
# region --------------------------------------------Shared part--------------------------------------------------------
8+
9+
import math
10+
import sys
11+
from collections import defaultdict, Counter
12+
from typing import List
13+
14+
from utils import read_lines
15+
16+
list_to_string = lambda _a: "".join(map(str, _a))
17+
list_to_string_list = lambda _a: " ".join(map(str, _a))
18+
_dp = lambda default_value: defaultdict(lambda: default_value)
19+
fact = lambda number: math.factorial(number)
20+
cnt = lambda _a: Counter(_a)
21+
22+
23+
def lcm(a, b):
24+
return a * b // math.gcd(a, b)
25+
26+
27+
def print_dp(_dict):
28+
for item in _dict.items():
29+
print(f"{item[0]} = {item[1]}")
30+
31+
32+
MOD = 10 ** 9 + 7
33+
INF = sys.maxsize
34+
A = 911382323
35+
M = 9999999999879998
36+
37+
38+
# endregion
39+
40+
# -------------------------------------------------------Solution-------------------------------------------------------
41+
42+
class EnginePart:
43+
def __init__(self):
44+
self.number = ""
45+
self.parts = set()
46+
47+
def get_number(self):
48+
return int(self.number)
49+
50+
def is_empty(self):
51+
return self.number == ""
52+
53+
def is_part_of_engine(self):
54+
return len(self.parts) != 0
55+
56+
def get_gears(self):
57+
return list(filter(lambda x: x[0] == "*", self.parts))
58+
59+
def has_gear(self):
60+
return len(self.get_gears()) != 0
61+
62+
63+
def get_engine_parts_from_data(data: List[str]) -> List[EnginePart]:
64+
matrix = _dp(0)
65+
len_i = len(data)
66+
len_j = len(data[0])
67+
68+
for i in range(len_i):
69+
for j in range(len_j):
70+
matrix[i, j] = data[i][j]
71+
72+
engine_parts = []
73+
74+
for i in range(len_i):
75+
engine = EnginePart()
76+
77+
for j in range(len_j):
78+
if matrix[i, j].isdigit():
79+
engine.number += matrix[i, j]
80+
81+
if (i + 1 < len_i
82+
and j + 1 < len_j
83+
and not matrix[i + 1, j + 1].isdigit()
84+
and matrix[i + 1, j + 1] != "."):
85+
engine.parts.add((matrix[i + 1, j + 1], i + 1, j + 1))
86+
87+
if (i + 1 < len_i
88+
and not matrix[i + 1, j].isdigit()
89+
and matrix[i + 1, j] != "."):
90+
engine.parts.add((matrix[i + 1, j], i + 1, j))
91+
92+
if (i + 1 < len_i
93+
and j - 1 > -1
94+
and not matrix[i + 1, j - 1].isdigit()
95+
and matrix[i + 1, j - 1] != "."):
96+
engine.parts.add((matrix[i + 1, j - 1], i + 1, j - 1))
97+
98+
if (j + 1 < len_j
99+
and not matrix[i, j + 1].isdigit()
100+
and matrix[i, j + 1] != "."):
101+
engine.parts.add((matrix[i, j + 1], i, j + 1))
102+
103+
if (j - 1 > -1
104+
and not matrix[i, j - 1].isdigit()
105+
and matrix[i, j - 1] != "."):
106+
engine.parts.add((matrix[i, j - 1], i, j - 1))
107+
108+
if (i - 1 > -1
109+
and j - 1 > -1
110+
and not matrix[i - 1, j - 1].isdigit()
111+
and matrix[i - 1, j - 1] != "."):
112+
engine.parts.add((matrix[i - 1, j - 1], i - 1, j - 1))
113+
114+
if (i - 1 > -1
115+
and not matrix[i - 1, j].isdigit()
116+
and matrix[i - 1, j] != "."):
117+
engine.parts.add((matrix[i - 1, j], i - 1, j))
118+
119+
if (i - 1 > -1
120+
and j + 1 < len_j
121+
and not matrix[i - 1, j + 1].isdigit()
122+
and matrix[i - 1, j + 1] != "."):
123+
engine.parts.add((matrix[i - 1, j + 1], i - 1, j + 1))
124+
125+
else:
126+
if not engine.is_empty() and engine.is_part_of_engine():
127+
engine_parts.append(engine)
128+
129+
engine = EnginePart()
130+
131+
if not engine.is_empty() and engine.is_part_of_engine():
132+
engine_parts.append(engine)
133+
134+
return engine_parts
135+
136+
137+
def solve_1(data: List[str]) -> None:
138+
engine_parts = get_engine_parts_from_data(data)
139+
result = sum(map(lambda x: x.get_number(), engine_parts))
140+
141+
print(result)
142+
143+
144+
def solve_2(data: List[str]) -> None:
145+
engine_parts = get_engine_parts_from_data(data)
146+
engine_parts = list(filter(lambda x: x.has_gear(), engine_parts))
147+
gears_count = _dp(0)
148+
gears_results = _dp(1)
149+
result = 0
150+
151+
for i in range(len(engine_parts)):
152+
for gear in engine_parts[i].get_gears():
153+
gears_count[gear] += 1
154+
gears_results[gear] *= engine_parts[i].get_number()
155+
156+
for gear, count in gears_count.items():
157+
if count == 2:
158+
result += gears_results[gear]
159+
160+
print(result)
161+
162+
163+
if __name__ == "__main__":
164+
input_data = read_lines()
165+
166+
solve_1(input_data.copy())
167+
solve_2(input_data.copy())

0 commit comments

Comments
 (0)