import os import sys from typing import Literal, cast VERBOSE = os.getenv("AOC_VERBOSE") == "True" Symbol = Literal["|", "-", "L", "J", "7", "F", ".", "S"] lines: list[list[Symbol]] = [ [cast(Symbol, symbol) for symbol in line] for line in sys.stdin.read().splitlines() ] # find starting point si, sj = next( (i, j) for i in range(len(lines)) for j in range(len(lines[0])) if lines[i][j] == "S" ) # find one of the two outputs ni, nj = si, sj for ni, nj, chars in ( (si - 1, sj, "|7F"), (si + 1, sj, "|LJ"), (si, sj - 1, "-LF"), (si, sj + 1, "-J7"), ): if lines[ni][nj] in chars: break # part 1 - find the loop (re-used in part 2) loop = [(si, sj), (ni, nj)] while True: pi, pj = loop[-2] i, j = loop[-1] sym = lines[i][j] if sym == "|" and pi > i or sym in "JL" and pi == i: i -= 1 elif sym == "|" and pi < i or sym in "7F" and pi == i: i += 1 elif sym == "-" and pj > j or sym in "J7" and pj == j: j -= 1 elif sym == "-" and pj < j or sym in "LF" and pj == j: j += 1 if (i, j) == (si, sj): break loop.append((i, j)) answer_1 = len(loop) // 2 print(f"answer 1 is {answer_1}") # part 2 # replace S by an appropriate character for the loop below di1, dj1 = loop[1][0] - loop[0][0], loop[1][1] - loop[0][1] di2, dj2 = loop[0][0] - loop[-1][0], loop[0][1] - loop[-1][1] mapping: dict[tuple[int, int], dict[tuple[int, int], Symbol]] = { (0, 1): {(0, 1): "-", (-1, 0): "F", (1, 0): "L"}, (0, -1): {(0, -1): "-", (-1, 0): "7", (1, 0): "J"}, (1, 0): {(1, 0): "|", (0, 1): "7", (0, -1): "F"}, (-1, 0): {(-1, 0): "|", (0, -1): "L", (0, 1): "J"}, } lines[si][sj] = mapping[di1, dj1][di2, dj2] # find the points inside the loop using an adaptation of ray casting for a discrete # grid (https://en.wikipedia.org/wiki/Ray_casting) # # use a set for faster '... in loop' check # loop_s = set(loop) inside: set[tuple[int, int]] = set() for i in range(len(lines)): cnt = 0 for j in range(len(lines[0])): if (i, j) not in loop_s and cnt % 2 == 1: inside.add((i, j)) if (i, j) in loop_s and lines[i][j] in "|LJ": cnt += 1 if VERBOSE: for i in range(len(lines)): for j in range(len(lines[0])): if (i, j) == (si, sj): print("\033[91mS\033[0m", end="") elif (i, j) in loop: print(lines[i][j], end="") elif (i, j) in inside: print("\033[92mI\033[0m", end="") else: print(".", end="") print() answer_2 = len(inside) print(f"answer 2 is {answer_2}")