lines = open('inputs/day3.txt').readlines() xlen = len(lines) ylen = len(lines[0]) def symbol_positions(lines: list[str]) -> list[tuple]: positions = [] symbols = [] for idx, line in enumerate(lines): for idy, c in enumerate(line.strip('\n')): if not c.isdigit() and c != ".": positions.append((idx, idy)) symbols.append(c) return positions, symbols def find_first_digit(lines: list[str], coords: tuple) -> tuple: x, y = coords if y == 0: return coords elif not lines[x][y-1].isdigit(): return coords else: return find_first_digit(lines, (x, y-1)) def full_number(lines: list[str], coords: tuple) -> int: x, y = coords nr = lines[x][y] counter = 1 while (y + counter) < (ylen - 1): if lines[x][y + counter].isdigit(): nr += lines[x][y + counter] counter += 1 else: break return int(nr) def adjacent_numbers(lines: list[str], xy: tuple) -> tuple: # returns bool and coords of first digit in number coords = [] x, y = xy neighbours_exist = False if x > 0: if lines[x-1][y].isdigit(): neighbours_exist = True coords.append(find_first_digit(lines, (x-1, y))) if y > 0: if lines[x-1][y-1].isdigit(): neighbours_exist = True coords.append(find_first_digit(lines, (x-1, y-1))) if y < (ylen - 1): if lines[x-1][y+1].isdigit(): neighbours_exist = True coords.append(find_first_digit(lines, (x-1, y+1))) if x < (xlen - 1): if lines[x+1][y].isdigit(): neighbours_exist = True coords.append(find_first_digit(lines, (x+1, y))) if y > 0: if lines[x+1][y-1].isdigit(): neighbours_exist = True coords.append(find_first_digit(lines, (x+1, y-1))) if y < (ylen - 1): if lines[x+1][y+1].isdigit(): neighbours_exist = True coords.append(find_first_digit(lines, (x+1, y+1))) if y > 0: if lines[x][y-1].isdigit(): neighbours_exist = True coords.append(find_first_digit(lines, (x, y-1))) if y < (ylen - 1): if lines[x][y+1].isdigit(): neighbours_exist = True coords.append(find_first_digit(lines, (x, y+1))) return neighbours_exist, set(coords) positions, symbols = symbol_positions(lines) numbers_pos = [] for s in positions: has_neighbour, coords = adjacent_numbers(lines, s) if has_neighbour: numbers_pos.append(coords) number_coords = set([x for y in numbers_pos for x in y]) numbers = [] for nr in number_coords: numbers.append(full_number(lines, nr)) print(f'Solution Part 1: {sum(numbers)}') gear_ratios = [] for p, c in zip(positions, symbols): if c == "*": has_neighbour, coords = adjacent_numbers(lines, p) coords = list(coords) if len(coords) == 2: gear_ratios.append(full_number(lines, coords[0]) * full_number(lines, coords[1])) print(f"Solution Part 2: {sum(gear_ratios)}")