diff --git a/day10.py b/day10.py index 8188b6e..d0197f7 100644 --- a/day10.py +++ b/day10.py @@ -4,63 +4,82 @@ from tools.coordinate import Coordinate from tools.grid import Grid from typing import Any -VALID_NEIGHBOURS = { - Coordinate(1, 0): { - "check": ["F", "-", "L", "S"], - "valid": ["7", "-", "J"], + +LOOKUP = { + "|": { + Coordinate(0, 1): {"o_dir": [Coordinate(-1, 0)], "i_dir": [Coordinate(1, 0)], "n_dir": Coordinate(0, 1)}, + Coordinate(0, -1): {"o_dir": [Coordinate(1, 0)], "i_dir": [Coordinate(-1, 0)], "n_dir": Coordinate(0, -1)}, }, - Coordinate(0, 1): { - "check": ["7", "|", "F", "S"], - "valid": ["J", "|", "L"], + "-": { + Coordinate(1, 0): {"o_dir": [Coordinate(0, 1)], "i_dir": [Coordinate(0, -1)], "n_dir": Coordinate(1, 0)}, + Coordinate(-1, 0): {"o_dir": [Coordinate(0, -1)], "i_dir": [Coordinate(0, 1)], "n_dir": Coordinate(-1, 0)}, }, - Coordinate(-1, 0): { - "check": ["J", "-", "7", "S"], - "valid": ["F", "-", "L"], + "7": { + Coordinate(1, 0): { + "o_dir": None, + "i_dir": [Coordinate(0, -1), Coordinate(1, 0)], + "n_dir": Coordinate(0, 1), + }, + Coordinate(0, -1): { + "o_dir": [Coordinate(1, 0), Coordinate(0, -1)], + "i_dir": None, + "n_dir": Coordinate(-1, 0), + }, }, - Coordinate(0, -1): { - "check": ["L", "|", "J", "S"], - "valid": ["F", "|", "7"], + "J": { + Coordinate(0, 1): { + "o_dir": None, + "i_dir": [Coordinate(1, 0), Coordinate(0, 1)], + "n_dir": Coordinate(-1, 0), + }, + Coordinate(1, 0): { + "o_dir": [Coordinate(1, 0), Coordinate(0, 1)], + "i_dir": None, + "n_dir": Coordinate(0, -1), + }, + }, + "F": { + Coordinate(0, -1): { + "o_dir": None, + "i_dir": [Coordinate(-1, 0), Coordinate(0, -1)], + "n_dir": Coordinate(1, 0), + }, + Coordinate(-1, 0): { + "o_dir": [Coordinate(-1, 0), Coordinate(0, -1)], + "i_dir": None, + "n_dir": Coordinate(0, 1), + }, + }, + "L": { + Coordinate(-1, 0): { + "o_dir": None, + "i_dir": [Coordinate(-1, 0), Coordinate(0, 1)], + "n_dir": Coordinate(0, -1), + }, + Coordinate(0, 1): { + "o_dir": [Coordinate(-1, 0), Coordinate(0, 1)], + "i_dir": None, + "n_dir": Coordinate(1, 0), + }, }, } def remove_clutter(grid: Grid, start: Coordinate): pipe_coords = set() - pipe_coords.add(start) - q = deque() - q.append(start) - while q: - cur = q.pop() - for c, v in VALID_NEIGHBOURS.items(): - dc = cur + c - if dc not in pipe_coords and grid.get(cur) in v["check"] and grid.get(dc) in v["valid"]: - pipe_coords.add(dc) - q.append(dc) + for x in LOOKUP[grid.get(start)]: + dir_ = LOOKUP[grid.get(start)][x]["n_dir"] + break + while start not in pipe_coords: + pipe_coords.add(start) + start += dir_ + dir_ = LOOKUP[grid.get(start)][dir_]["n_dir"] for c in grid.getActiveCells(): if c not in pipe_coords: grid.set(c, False) -def get_farthest(grid: Grid, start: Coordinate) -> int: - q = deque() - q.append((0, start)) - visited = set() - max_dist = 0 - while q: - dist, cur = q.popleft() - if cur in visited: - continue - visited.add(cur) - for c, v in VALID_NEIGHBOURS.items(): - dc = cur + c - if dc not in visited and grid.get(cur) in v["check"] and grid.get(dc) in v["valid"]: - q.append((dist + 1, dc)) - max_dist = max(max_dist, dist + 1) - - return max_dist - - def get_area(grid: Grid, start: Coordinate) -> set[Coordinate]: if grid.get(start): return set() @@ -81,66 +100,7 @@ def get_area(grid: Grid, start: Coordinate) -> set[Coordinate]: return area -def walk(grid: Grid) -> int: - LOOKUP = { - "|": { - Coordinate(0, 1): {"o_dir": [Coordinate(-1, 0)], "i_dir": [Coordinate(1, 0)], "n_dir": Coordinate(0, 1)}, - Coordinate(0, -1): {"o_dir": [Coordinate(1, 0)], "i_dir": [Coordinate(-1, 0)], "n_dir": Coordinate(0, -1)}, - }, - "-": { - Coordinate(1, 0): {"o_dir": [Coordinate(0, 1)], "i_dir": [Coordinate(0, -1)], "n_dir": Coordinate(1, 0)}, - Coordinate(-1, 0): {"o_dir": [Coordinate(0, -1)], "i_dir": [Coordinate(0, 1)], "n_dir": Coordinate(-1, 0)}, - }, - "7": { - Coordinate(1, 0): { - "o_dir": None, - "i_dir": [Coordinate(0, -1), Coordinate(1, 0)], - "n_dir": Coordinate(0, 1), - }, - Coordinate(0, -1): { - "o_dir": [Coordinate(1, 0), Coordinate(0, -1)], - "i_dir": None, - "n_dir": Coordinate(-1, 0), - }, - }, - "J": { - Coordinate(0, 1): { - "o_dir": None, - "i_dir": [Coordinate(1, 0), Coordinate(0, 1)], - "n_dir": Coordinate(-1, 0), - }, - Coordinate(1, 0): { - "o_dir": [Coordinate(1, 0), Coordinate(0, 1)], - "i_dir": None, - "n_dir": Coordinate(0, -1), - }, - }, - "F": { - Coordinate(0, -1): { - "o_dir": None, - "i_dir": [Coordinate(-1, 0), Coordinate(0, -1)], - "n_dir": Coordinate(1, 0), - }, - Coordinate(-1, 0): { - "o_dir": [Coordinate(-1, 0), Coordinate(0, -1)], - "i_dir": None, - "n_dir": Coordinate(0, 1), - }, - }, - "L": { - Coordinate(-1, 0): { - "o_dir": None, - "i_dir": [Coordinate(-1, 0), Coordinate(0, 1)], - "n_dir": Coordinate(0, -1), - }, - Coordinate(0, 1): { - "o_dir": [Coordinate(-1, 0), Coordinate(0, 1)], - "i_dir": None, - "n_dir": Coordinate(1, 0), - }, - }, - } - +def walk(grid: Grid, part2: bool = False) -> int: cur = None for x in grid.rangeX(): for y in grid.rangeY(): @@ -152,32 +112,38 @@ def walk(grid: Grid) -> int: assert grid.get(cur) == "F" + pipe_len = 0 direction = Coordinate(0, 1) outside = get_area(grid, cur + Coordinate(0, -1)) inside = set() visited = set() while cur not in visited: + pipe_len += 1 visited.add(cur) cur += direction c = grid.get(cur) - oc = LOOKUP[c][direction]["o_dir"] - ic = LOOKUP[c][direction]["i_dir"] + if part2: + oc = LOOKUP[c][direction]["o_dir"] + ic = LOOKUP[c][direction]["i_dir"] - if oc is not None: - for doc in oc: - check = cur + doc - if check not in outside and not grid.get(check): - outside |= get_area(grid, check) + if oc is not None: + for doc in oc: + check = cur + doc + if check not in outside and not grid.get(check): + outside |= get_area(grid, check) - if ic is not None: - for dic in ic: - check = cur + dic - if check not in inside and not grid.get(check): - inside |= get_area(grid, check) + if ic is not None: + for dic in ic: + check = cur + dic + if check not in inside and not grid.get(check): + inside |= get_area(grid, check) direction = LOOKUP[c][direction]["n_dir"] - return len(inside) + if part2: + return len(inside) + else: + return pipe_len // 2 class Day(AOCDay): @@ -196,7 +162,7 @@ class Day(AOCDay): ], ] - def parse_input(self) -> (Grid, Coordinate): + def parse_input(self) -> Grid: grid = Grid() start = None for y, line in enumerate(self.getInput()): @@ -227,15 +193,13 @@ class Day(AOCDay): grid.set(start, "-") remove_clutter(grid, start) - return grid, start + return grid def part1(self) -> Any: - grid, start = self.parse_input() - return get_farthest(grid, start) + return walk(self.parse_input()) def part2(self) -> Any: - grid, _ = self.parse_input() - return walk(grid) + return walk(self.parse_input(), True) if __name__ == "__main__":