83 lines
2.5 KiB
Python
83 lines
2.5 KiB
Python
|
from typing import Tuple, List
|
||
|
|
||
|
|
||
|
def browse_schema(schema):
|
||
|
total_parts = 0
|
||
|
buf = []
|
||
|
max_row, max_col = len(schema), len(schema[0])
|
||
|
|
||
|
for y in range(max_row):
|
||
|
for x in range(max_col):
|
||
|
item = schema[y][x]
|
||
|
if item.isnumeric():
|
||
|
# continue parsing full number
|
||
|
buf.append(item)
|
||
|
elif buf:
|
||
|
# end of a number, do the engine part check
|
||
|
if buf:
|
||
|
neighbors = get_neighbors((x, y), len(buf), schema)
|
||
|
|
||
|
if is_engine_part(neighbors):
|
||
|
part_number = int("".join(buf))
|
||
|
total_parts += part_number
|
||
|
|
||
|
buf.clear() # reached end of a number, clear buffer
|
||
|
|
||
|
print(f"Part 1, sum of the parts numbers = {total_parts}")
|
||
|
print(f"Part 2, sum of the gear ratios = TODO")
|
||
|
|
||
|
|
||
|
def is_engine_part(neighbors: List[str]) -> bool:
|
||
|
# get list of symbols (not '.', \n or a number)
|
||
|
symbols = filter(lambda x: not x.isnumeric() and not x in (".", "\n"), neighbors)
|
||
|
return next(symbols, None) is not None
|
||
|
|
||
|
|
||
|
def get_neighbors(pos: Tuple[int, int], length: int, schema: List[List[str]]) -> List[str]:
|
||
|
x, y = pos
|
||
|
start_x = x - length
|
||
|
neighbors = [get_neighbors_of_digit((x, y), schema) for x in range(start_x, x)]
|
||
|
neighbors = [item for sublist in neighbors for item in sublist] # flatten list of list
|
||
|
return neighbors
|
||
|
|
||
|
|
||
|
def get_neighbors_of_digit(pos: Tuple[int, int], schema: List[List[str]]) -> List[str]:
|
||
|
max_row, max_col = len(schema), len(schema[0])
|
||
|
x, y = pos
|
||
|
neighbors = []
|
||
|
|
||
|
# top
|
||
|
if y-1 >= 0:
|
||
|
neighbors.append(schema[y-1][x])
|
||
|
# bottom:
|
||
|
if y+1 < max_row:
|
||
|
neighbors.append(schema[y+1][x])
|
||
|
# left
|
||
|
if x-1 >= 0:
|
||
|
neighbors.append(schema[y][x-1])
|
||
|
# right
|
||
|
if x+1 < max_col:
|
||
|
neighbors.append(schema[y][x+1])
|
||
|
# top-left
|
||
|
if y-1 >= 0 and x-1 >= 0:
|
||
|
neighbors.append(schema[y-1][x-1])
|
||
|
# top-right
|
||
|
if y-1 >= 0 and x+1 < max_col:
|
||
|
neighbors.append(schema[y-1][x+1])
|
||
|
# bottom-left
|
||
|
if y+1 < max_row and x-1 >= 0:
|
||
|
neighbors.append(schema[y+1][x-1])
|
||
|
# bottom-right
|
||
|
if y+1 < max_row and x+1 < max_col:
|
||
|
neighbors.append(schema[y+1][x+1])
|
||
|
|
||
|
return neighbors
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
import sys
|
||
|
infile = sys.argv[1]
|
||
|
with open(infile) as f:
|
||
|
schema = [[c for c in line] for line in f.readlines()]
|
||
|
browse_schema(schema)
|