102 lines
2.8 KiB
Python
102 lines
2.8 KiB
Python
import re
|
|
|
|
NUMBERS = "0123456789"
|
|
EXAMPLE = """
|
|
467..114..
|
|
...*......
|
|
..35..633.
|
|
......#...
|
|
617*......
|
|
.....+.58.
|
|
..592.....
|
|
......755.
|
|
...$.*....
|
|
.664.598..
|
|
"""
|
|
|
|
def clean(text: str) -> list[str]:
|
|
return list(filter(lambda l: l.strip() != "", text.splitlines()))
|
|
|
|
def is_adj_to_symbol(x, y, lines):
|
|
non_symbol = re.compile(r"[^0-9\.]")
|
|
for xo, yo in [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]:
|
|
try:
|
|
if x + xo < 0 or y + yo < 0:
|
|
continue
|
|
if non_symbol.match(lines[y + yo][x + xo]):
|
|
return True
|
|
except IndexError:
|
|
pass
|
|
return False
|
|
|
|
def solve(lines: list[str]):
|
|
d = ""
|
|
adj_to_symbol = False
|
|
s = 0
|
|
for (y, line) in enumerate(lines):
|
|
for (x, c) in enumerate(line):
|
|
if c not in NUMBERS:
|
|
if len(d) > 0 and adj_to_symbol:
|
|
s += int(d)
|
|
d = ""
|
|
adj_to_symbol = False
|
|
else:
|
|
if is_adj_to_symbol(x, y, lines):
|
|
adj_to_symbol = True
|
|
d = d + c
|
|
return s
|
|
|
|
def get_entire_number(x, y, lines):
|
|
assert(lines[y][x] in NUMBERS)
|
|
x_start = x - 1
|
|
while lines[y][x_start] in NUMBERS and x_start >= 0:
|
|
x_start -= 1
|
|
x_start += 1
|
|
x_start_orig = x_start
|
|
r = ""
|
|
while x_start < len(lines[0]) and lines[y][x_start] in NUMBERS:
|
|
r += lines[y][x_start]
|
|
x_start += 1
|
|
return x_start_orig, int(r)
|
|
|
|
def find_sourrounding_numbers(x, y, lines):
|
|
full_coords = []
|
|
numbers = []
|
|
for xo, yo in [(-1, -1), (0, -1), (1, -1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1)]:
|
|
new_x = x + xo
|
|
new_y = y + yo
|
|
if new_x < 0 or new_y < 0 or new_x >= len(lines[0]) or new_y >= len(lines):
|
|
continue
|
|
if lines[new_y][new_x] in NUMBERS:
|
|
x_start_orig, n = get_entire_number(new_x, new_y, lines)
|
|
if (x_start_orig, new_y, n) not in full_coords:
|
|
numbers.append(n)
|
|
full_coords.append((x_start_orig, y + yo, n))
|
|
return numbers
|
|
|
|
def solve2(lines: list[str]):
|
|
s = 0
|
|
for (y, line) in enumerate(lines):
|
|
for (x, c) in enumerate(line):
|
|
if c == '*':
|
|
numbers = find_sourrounding_numbers(x, y, lines)
|
|
if len(numbers) == 2:
|
|
# print(numbers)
|
|
s += numbers[0] * numbers[1]
|
|
return s
|
|
|
|
def main():
|
|
example = clean(EXAMPLE)
|
|
print("Example 1:", solve(example))
|
|
data = clean(open("i3.txt").read())
|
|
print("Solution 1:", solve(data))
|
|
|
|
example = clean(EXAMPLE)
|
|
print("Example 2:", solve2(example))
|
|
|
|
data = clean(open("i3.txt").read())
|
|
print("Solution 2:", solve2(data))
|
|
|
|
if __name__ == "__main__":
|
|
main()
|