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()
|