day15 - cleanup

This commit is contained in:
Stefan Harmuth 2024-12-15 08:55:43 +01:00
parent 00a4fdb529
commit d27138f2b0

View File

@ -1,4 +1,5 @@
from collections import deque
from enum import Enum
from tools.aoc import AOCDay
from tools.coordinate import Coordinate
from tools.grid import Grid
@ -20,71 +21,57 @@ LARGER = {
}
class Tile(str, Enum):
EMPTY = "."
WALL = "#"
BOX = "O"
BOX_LEFT = "["
BOX_RIGHT = "]"
def sokoban(grid: Grid, start: Coordinate, moves: str) -> Grid:
for move in moves:
dir_ = MOVES[move]
next_pos = start + dir_
if grid.get(next_pos) == ".":
start += dir_
if grid.get(next_pos) == Tile.WALL:
continue
elif grid.get(next_pos) == "#":
continue
elif grid.get(next_pos) == "O":
pos_behind_box = next_pos + dir_
while grid.get(pos_behind_box) == "O":
pos_behind_box += dir_
if grid.get(pos_behind_box) == "#":
continue
grid.set(pos_behind_box, "O")
elif grid.get(next_pos) == Tile.EMPTY:
start = next_pos
grid.set(start, ".")
continue
if move in ["<", ">"]:
# easy mode
pos_behind_box = next_pos + dir_
while grid.get(pos_behind_box) in ["[", "]"]:
pos_behind_box += dir_ * 2
if grid.get(pos_behind_box) == "#":
continue
while pos_behind_box != start:
grid.set(pos_behind_box, grid.get(pos_behind_box - dir_))
pos_behind_box -= dir_
else:
# recursive mode
# neither a wall, nor empty space? There must be a box in the way
to_move = set()
wall_in_the_way = False
Q = deque([next_pos])
boxes = set()
while Q:
pos = Q.popleft()
if grid.get(pos) == "#":
queue = deque([next_pos])
while queue:
pos = queue.popleft()
pos_tile = grid.get(pos)
if pos_tile == Tile.EMPTY:
continue
if pos_tile == Tile.WALL:
wall_in_the_way = True
break
elif grid.get(pos) == ".":
if (pos, pos_tile) in to_move:
continue
Q.append(pos + dir_)
if grid.get(pos) == "[":
boxes.add((pos, pos + (1, 0)))
Q.append(pos + dir_ + (1, 0))
to_move.add((pos, pos_tile))
queue.append(pos + dir_)
if pos_tile in [Tile.BOX_LEFT, Tile.BOX_RIGHT]:
if pos_tile == Tile.BOX_LEFT:
queue.append(pos + (1, 0))
else:
boxes.add((pos + (-1, 0), pos))
Q.append(pos + dir_ + (-1, 0))
queue.append(pos + (-1, 0))
if wall_in_the_way:
continue
for box_l, box_r in boxes:
grid.set(box_l, ".")
grid.set(box_r, ".")
for box, _ in to_move:
grid.set(box, Tile.EMPTY)
for box_l, box_r in boxes:
grid.set(box_l + dir_, "[")
grid.set(box_r + dir_, "]")
for box, box_tile in to_move:
grid.set(box + dir_, box_tile)
start = next_pos
@ -108,7 +95,7 @@ class Day(AOCDay):
map_, moves = self.getMultiLineInputAsArray()
if part2:
map_ = ["".join([LARGER[x] for x in y]) for y in map_]
grid = Grid.from_data(map_, default=".")
grid = Grid.from_data(map_, default=Tile.EMPTY, translate={r"\.#O\[\]": Tile})
start = list(grid.find("@"))[0]
grid.set(start, ".")