Skip to content

15

https://adventofcode.com/2024/day/15

Prob1

python
import sys

from typing import Tuple, Set

walls: Set[Tuple[int, int]] = set()
boxes: Set[Tuple[int, int]] = set()
op_list = ''
cur: Tuple[int, int] = (0, 0)

y = 0
for line in sys.stdin:
    line = line.strip()
    if line == '':
        continue
    if line.startswith('#'):
        for x, ch in enumerate(line):
            p = (x, y)
            if ch == '#':
                walls.add(p)
            elif ch == 'O':
                boxes.add(p)
            elif ch == '@':
                cur = p
        y += 1
    else:
        op_list += line

print(walls)
print(boxes)
print(op_list)

dir_tab = {
    '>': (1, 0),
    '<': (-1, 0),
    'v': (0, 1),
    '^': (0, -1),
}

for op in op_list:
    px, py = cur
    dx, dy = dir_tab[op]
    nx, ny = px + dx, py + dy

    np = (nx, ny)

    if np in walls:
        continue

    if np not in boxes:
        cur = np
        continue

    affect_box: Tuple[int, int] = np
    while True:
        nx, ny = nx + dx, ny + dy
        np = (nx, ny)
        if np in boxes:
            continue

        if np in walls:
            # ok, no move
            break

        # empty space, we can make a move!
        cur = affect_box
        boxes.remove(affect_box)
        boxes.add(np)
        break

ans = 0
for (bx, by) in boxes:
    ans += 100*by + bx

print(ans)

Prob2

python
import sys

from queue import Queue

from typing import Tuple, Set, List

walls: Set[Tuple[int, int]] = set()
boxes: Set[Tuple[int, int]] = set()
op_list = ''
cur: Tuple[int, int] = (0, 0)

y = 0
for line in sys.stdin:
    line = line.strip()
    if line == '':
        continue
    if line.startswith('#'):
        for x, ch in enumerate(line):
            if ch == '#':
                walls.add((2*x, y))
                walls.add((2*x + 1, y))
            elif ch == 'O':
                boxes.add((2*x, y))
            elif ch == '@':
                cur = (2*x, y)
        y += 1
    else:
        op_list += line

print(walls)
print(boxes)
print(op_list)

dir_tab = {
    '>': (1, 0),
    '<': (-1, 0),
    'v': (0, 1),
    '^': (0, -1),
}

for op in op_list:
    dx, dy = dir_tab[op]

    px, py = cur
    nx, ny = px + dx, py + dy
    np = (nx, ny)

    if np in walls:
        continue

    affect_boxes: Set[Tuple[int, int]] = set()
    visited_boxes: Set[Tuple[int, int]] = set()
    affect_queue = Queue()
    pushable = True

    if np in boxes:
        affect_boxes.add(np)
        affect_queue.put(np)

    n2p = (nx - 1, ny)
    if n2p in boxes:
        affect_boxes.add(n2p)
        affect_queue.put(n2p)

    while not affect_queue.empty():
        px, py = affect_queue.get()
        visited_boxes.add((px, py))

        n1p = px + dx, py + dy
        n2p = px + dx + 1, py + dy
        n3p = px + dx - 1, py + dy

        if n1p in walls or n2p in walls:
            pushable = False
            break

        if n1p in boxes and n1p not in visited_boxes:
            affect_boxes.add(n1p)
            affect_queue.put(n1p)

        if n2p in boxes and n2p not in visited_boxes:
            affect_boxes.add(n2p)
            affect_queue.put(n2p)

        if n3p in boxes and n3p not in visited_boxes:
            affect_boxes.add(n3p)
            affect_queue.put(n3p)

    if not pushable:
        # print('not pushable')
        continue

    new_boxes: List[Tuple[int, int]] = []
    for (bx, by) in affect_boxes:
        new_boxes.append((bx + dx, by + dy))

    print('affect', affect_boxes, '->', new_boxes)

    for box in affect_boxes:
        boxes.remove(box)

    for box in new_boxes:
        boxes.add(box)

    px, py = cur
    cur = (px + dx, py + dy)

    # print(boxes)

print(boxes)

ans = 0
for (bx, by) in boxes:
    ans += 100*by + bx

print(ans)

Changelog

Just observe 👀