import lib EXAMPLE = """ ..F7. .FJ|. SJ.L7 |F--J LJ... """ EXAMPLE2 = """ ........... .S-------7. .|F-----7|. .||.....||. .||.....||. .|L-7.F-J|. .|..|.|..|. .L--J.L--J. ........... """ EXAMPLE3 = """ .......... .S------7. .|F----7|. .||OOOO||. .||OOOO||. .|L-7F-J|. .|II||II|. .L--JL--J. .......... """ EXAMPLE4 = """ FF7FSF7F7F7F7F7F---7 L|LJ||||||||||||F--J FL-7LJLJ||||||LJL-77 F--JF--7||LJLJIF7FJ- L---JF-JLJIIIIFJLJJ7 |F|F-JF---7IIIL7L|7| |FFJF7L7F-JF7IIL---7 7-L-JL7||F7|L7F-7F7| L.L7LFJ|||||FJL7||LJ L7JLJL-JLJLJL--JLJ.L """ # | is a vertical pipe connecting north and south. # - is a horizontal pipe connecting east and west. # L is a 90-degree bend connecting north and east. # J is a 90-degree bend connecting north and west. # 7 is a 90-degree bend connecting south and west. # F is a 90-degree bend connecting south and east. # . is ground; there is no pipe in this tile. # S is the starting position of the animal; there is a pipe on this tile, but your sketch doesn't show what shape the pipe has. # Mapping of in-direction to out-direction for each piece. DIRS = { '|': { (1, 0): (1, 0), (-1, 0): (-1, 0), }, '-': { (0, -1): (0, -1), (0, 1): (0, 1), }, 'L': { (1, 0): (0, 1), (0, -1): (-1, 0), }, 'J': { (0, 1): (-1, 0), (1, 0): (0, -1), }, '7': { (0, 1): (1, 0), (-1, 0): (0, -1), }, 'F': { (-1, 0): (0, 1), (0, -1): (1, 0), } } RIGHTS = { '|': { (1, 0): [(0, -1)], (-1, 0): [(0, 1)], }, '-': { (0, -1): [(-1, 0)], (0, 1): [(1, 0)], }, 'L': { (1, 0): [(0, -1), (1, 0)], (0, -1): [(-1, 1)], }, 'J': { (0, 1): [(1, 0), (0, 1)], (1, 0): [(-1, -1)], }, '7': { (0, 1): [(1, -1)], (-1, 0): [(0, 1), (-1, 0)], }, 'F': { (-1, 0): [(1, 1)], (0, -1): [(-1, 0), (0, -1)], } } def solve(lines: list[str], return_path=False): res = 0 maze = [] start = () max_path, max_right = [], [] maze = list(map(list, lines)) for i, row in enumerate(maze): for j, col in enumerate(row): if col == "S": start = (i , j) row_max, col_max = len(maze), len(maze[0]) for current_dir in [(0, 1), (0, -1), (1, 0), (-1, 0)]: current_field = start steps = 0 path = [] right = [] # print(f"START: {start} {current_dir=}") while True: path.append(current_field) next_field = (current_field[0] + current_dir[0], current_field[1] + current_dir[1]) if next_field == start: break if next_field[0] < 0 or next_field[1] < 0 or next_field[0] >= row_max or next_field[1] >= col_max: # print(f"BREAK: Cannot go to {next_field=}!") break prev_dir = current_dir next_char = maze[next_field[0]][next_field[1]] try: current_dir = DIRS[next_char][current_dir] except KeyError: # print(f"BREAK: Cannot go from {current_field=} with {current_dir=} to {next_field=} ({next_char})!") break for rights in RIGHTS[next_char][prev_dir]: rf = (next_field[0] + rights[0], next_field[1] + rights[1]) right.append(rf) current_field = next_field steps += 1 res = max(res, (steps + 1) // 2) if len(path) > len(max_path): max_path = path max_right = right if return_path: return res, max_path, max_right else: return res def solve2(lines: list[str]): row_max = len(lines) col_max = len(lines[0]) length, path, right = solve(lines, True) def clean(fields): fields = list(set(fields)) cleaned = [] for f in fields: if f in path: continue if f[0] < 0 or f[1] < 0 or f[0] >= row_max or f[1] >= col_max: continue cleaned.append(f) return cleaned right = clean(right) visited = set() to_visit = list(right) while to_visit: current = to_visit.pop() for nb in [(0, 1), (0, -1), (1, 0), (-1, 0)]: f = (current[0] + nb[0], current[1] + nb[1]) if f[0] < 0 or f[1] < 0 or f[0] >= row_max or f[1] >= col_max: continue if f not in visited and f not in path: right.append(f) to_visit.append(f) visited.add(f) right = clean(right) n_all = row_max * col_max n_right = len(right) n_left = n_all - n_right - len(path) return min(n_left, n_right) def main(): lines = lib.str_to_lines_no_empty(EXAMPLE) print("Example 1:", solve(lines)) lines = lib.str_to_lines_no_empty(open("i10.txt").read()) print("Solution 1:", solve(lines)) lines = lib.str_to_lines_no_empty(EXAMPLE4) print("Example 2:", solve2(lines)) lines = lib.str_to_lines_no_empty(open("i10.txt").read()) print("Solution 2:", solve2(lines)) if __name__ == "__main__": main()