advent-of-code/2024-python/output/day_15.py
Anders Englöf Ytterström 7688ddb763 Solve 2024:15 p2 "Warehouse Woes"
Glad this one is over. 150 lines of pure mayhem.
2025-01-05 00:06:18 +01:00

145 lines
4.1 KiB
Python

from output import D, matrix
def solve(data):
O = {k: v for k, v in zip("^>v<", D)}
grid, movements = data.split("\n\n")
grid, H, W = matrix(grid)
movements = "".join(movements.split())
grid_1 = {
(r, c): value for r, row in enumerate(grid) for c, value in enumerate(row)
}
grid_2 = {}
for pos, value in grid_1.items():
r2, c2 = pos
match value:
case "O":
grid_2[(r2, c2 * 2)] = "["
grid_2[(r2, c2 * 2 + 1)] = "]"
case "@":
grid_2[(r2, c2 * 2)] = "@"
grid_2[(r2, c2 * 2 + 1)] = "."
case _:
grid_2[(r2, c2 * 2)] = value
grid_2[(r2, c2 * 2 + 1)] = value
answers = []
for grid, W in [(grid_1, W), (grid_2, W * 2)]:
pos = next((r, c) for r in range(H) for c in range(W) if grid[(r, c)] == "@")
for move in movements:
r, c = pos
dr, dc = O[move]
moved = False
match move:
case "^":
targets = [((v, c), grid[(v, c)]) for v in range(r)][::-1]
case "<":
targets = [((r, v), grid[(r, v)]) for v in range(c)][::-1]
case "v":
targets = [((v, c), grid[(v, c)]) for v in range(r + 1, H)]
case ">":
targets = [((r, v), grid[(r, v)]) for v in range(c + 1, W)]
if "." not in map(lambda pv: pv[1], targets):
continue
if grid[(r + dr, c + dc)] == ".":
moved = True
if grid[(r + dr, c + dc)] == "O" or (
grid[(r + dr, c + dc)] in "[]" and dc != 0
):
canmove = False
flips = []
for tpos, tvalue in targets:
flips.append((tpos, tvalue))
if tvalue == "#":
break
if tvalue == ".":
canmove = True
break
if canmove:
rotated = [value for _, value in flips]
rotated = rotated[-1:] + rotated[:-1]
for offset, pos in enumerate(flips):
grid[pos[0]] = rotated[offset]
moved = True
if grid[(r + dr, c + dc)] in "[]" and dc == 0 and dr != 0:
canmove = True
bs = set()
bmod = O[move][0]
Q = [(r + bmod, c)]
while Q:
rr, cc = Q.pop(0)
if (rr, cc) in bs:
continue
bs.add((rr, cc))
if grid[(rr, cc)] == "#":
canmove = False
continue
if grid[(rr, cc)] in "@.":
continue
match grid[(rr, cc)]:
case "]":
Q.append((rr + bmod, cc))
Q.append((rr, cc - 1))
case "[":
Q.append((rr + bmod, cc))
Q.append((rr, cc + 1))
if canmove:
patchset = {
(rr, cc): (rr + bmod, cc)
for rr, cc in bs
if grid[(rr, cc)] != "."
}
dotset = set(bs) - set(patchset.values())
for psf, pst in sorted(patchset.items())[::-bmod]:
psnv = grid[psf]
grid[pst] = psnv
for rk in dotset:
grid[rk] = "."
moved = True
if moved:
grid[(r, c)] = "."
grid[(r + dr, c + dc)] = "@"
pos = r + dr, c + dc
answers.append(sum(k[0] * 100 + k[1] for k, v in grid.items() if v in "O["))
p1, p2 = answers
return p1, p2
if __name__ == "__main__":
with open("./input/15.txt", "r") as f:
inp = f.read().strip()
p1, p2 = solve(inp)
print(p1)
print(p2)