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