Day 10 - cleanup

This commit is contained in:
Stefan Harmuth 2023-12-10 11:55:15 +01:00
parent c83cb8598b
commit 606a4bf4b2

206
day10.py
View File

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