advent-of-code/2023/python/day03.py

100 lines
2.5 KiB
Python
Raw Normal View History

2023-12-03 21:04:40 +00:00
import matrix
import shared
import itertools
import functools
2023-12-03 21:18:14 +00:00
from pprint import pprint
from collections import defaultdict
2023-12-03 21:04:40 +00:00
2023-12-08 18:42:42 +00:00
SYMBOLS = "*%@#+-/$=&"
2023-12-03 21:04:40 +00:00
def get_all_numbers_and_starting_coords(mat):
2023-12-03 21:29:10 +00:00
"""
2023-12-08 18:42:42 +00:00
for a coordinate, walks right until it encounters a non digit,
when it does, it adds that number string to a collection,
and starts over, walking right until it continues to next row
2023-12-03 21:29:10 +00:00
"""
2023-12-03 21:04:40 +00:00
nums = []
for y, row in enumerate(mat):
x = 0
while x < len(row):
2023-12-08 18:42:42 +00:00
num = matrix.number_starting_at(mat, x, y)
2023-12-03 21:04:40 +00:00
if num is None:
x += 1
continue
2023-12-08 18:42:42 +00:00
nums.append(((x, y), num))
2023-12-03 21:04:40 +00:00
x += len(num)
return nums
2023-12-08 18:42:42 +00:00
2023-12-03 21:29:10 +00:00
def get_row_coords(x1, y, length):
"""
for a given x,y point, it just creates the rest of the x/y coords to the right of this coord for a run
"""
2023-12-03 21:04:40 +00:00
coords = []
2023-12-08 18:42:42 +00:00
for x in range(x1, x1 + length):
coords.append((x, y))
2023-12-03 21:04:40 +00:00
return coords
2023-12-08 18:42:42 +00:00
2023-12-03 21:29:10 +00:00
def process_number(mx, coords, num):
line_coords = get_row_coords(*coords, len(num))
for coord in line_coords:
2023-12-08 18:42:42 +00:00
any_symbols = [
(cs, v) for cs, v in matrix.get_neighbor_coords(mx, *coord) if v in SYMBOLS
]
2023-12-03 21:29:10 +00:00
if any_symbols:
return True, any_symbols[0]
return False, None
2023-12-08 18:42:42 +00:00
2023-12-03 21:04:40 +00:00
# @shared.profile
def part1(mat):
choose = []
nums = get_all_numbers_and_starting_coords(mat)
for coords, num in nums:
2023-12-03 21:07:42 +00:00
valid, symbol_coord = process_number(mat, coords, num)
2023-12-03 21:04:40 +00:00
if valid:
choose.append(num)
total = 0
for n in choose:
total += int(n)
print(total)
# @shared.profile
def part2(mat):
2023-12-03 21:18:14 +00:00
splats = matrix.find_in_matrix(mat, "*", False)
2023-12-03 21:04:40 +00:00
_nums = get_all_numbers_and_starting_coords(mat)
2023-12-03 21:18:14 +00:00
symbols = defaultdict(list)
nums = get_all_numbers_and_starting_coords(mat)
for coords, num in nums:
valid, sc = process_number(mat, coords, num)
if valid:
2023-12-08 18:42:42 +00:00
symbols[(sc[0]["r"], sc[0]["c"])].append(num)
2023-12-03 21:18:14 +00:00
total = 0
for splat in splats:
neighbors = symbols[splat]
if len(neighbors) != 2:
continue
ratio = int(neighbors[0]) * int(neighbors[1])
total += ratio
print(total)
2023-12-03 21:04:40 +00:00
def main():
mat = shared.load_file_char_matrix(shared.get_fname(3))
with shared.elapsed_timer() as elapsed:
part1(mat)
print("🕒", elapsed())
with shared.elapsed_timer() as elapsed:
part2(mat)
print("🕒", elapsed())
if __name__ == "__main__":
main()