Skip to content

Commit

Permalink
2024 day 15 part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
lancelote committed Dec 23, 2024
1 parent 1f1aa9f commit 97da4b8
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
- 2021 - ★★★★★ ★★★★★ ★★★★★ ★★★
- 2022 - ★★★★★ ★★★★★ ★★★★★ ★☆
- 2023 - ★★★★★ ★★★★★ ★★★★★ ★★★☆
- 2024 - ★★★★★ ★★★★★ ★★★★
- 2024 - ★★★★★ ★★★★★ ★★★★

## How to use

Expand Down
132 changes: 132 additions & 0 deletions src/year2024/day15a.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
"""2024 - Day 15 Part 1: Warehouse Woes"""

from __future__ import annotations

from abc import ABC
from abc import abstractmethod
from dataclasses import dataclass
from enum import StrEnum


class Instruction(StrEnum):
NORTH = "^"
EAST = ">"
SOUTH = "v"
WEST = "<"


SHIFTS = {
# dr, dc
Instruction.NORTH: (-1, 0),
Instruction.EAST: (0, +1),
Instruction.SOUTH: (+1, 0),
Instruction.WEST: (0, -1),
}


@dataclass
class Object(ABC):
r: int
c: int
symbol: str

@abstractmethod
def move(self, instruction: Instruction, warehouse: Warehouse) -> bool:
raise NotImplementedError


class Moveable(Object, ABC):
def move(self, instruction: Instruction, warehouse: Warehouse) -> bool:
dr, dc = SHIFTS[instruction]
nr, nc = self.r + dr, self.c + dc

if (nr, nc) in warehouse.objects:
neighbor = warehouse.objects[(nr, nc)]
if neighbor.move(instruction, warehouse):
self.update_position(nr, nc, warehouse)
return True
else:
return False
else:
self.update_position(nr, nc, warehouse)
return True

def update_position(self, nr: int, nc: int, warehouse: Warehouse) -> None:
del warehouse.objects[(self.r, self.c)]
self.r, self.c = nr, nc
warehouse.objects[(nr, nc)] = self


class Wall(Object):
def move(self, instruction: Instruction, warehouse: Warehouse) -> bool:
return False


class Box(Moveable):
@property
def gps(self) -> int:
return self.r * 100 + self.c


class Robot(Moveable): ...


@dataclass
class Warehouse:
height: int
width: int
robot: Robot
objects: dict[tuple[int, int], Object]
boxes: list[Box]

@classmethod
def from_text(cls, text: str) -> Warehouse:
robot = Robot(r=0, c=0, symbol="@")
objects: dict[tuple[int, int], Object] = {}
boxes: list[Box] = []

lines = text.split("\n")
height, width = len(lines), len(lines[0])

for r, row in enumerate(lines):
for c, x in enumerate(row):
if x == "#":
objects[(r, c)] = Wall(r, c, symbol="#")
elif x == "@":
robot.r, robot.c = r, c
objects[(r, c)] = robot
elif x == "O":
box = Box(r, c, symbol="O")
boxes.append(box)
objects[(r, c)] = box

return cls(height, width, robot, objects, boxes)

def move_robot(self, instructions: list[Instruction]) -> None:
for instruction in instructions:
self.robot.move(instruction, self)

@property
def gps_sum(self) -> int:
return sum(box.gps for box in self.boxes)

def __str__(self) -> str:
lines = [["."] * self.width for _ in range(self.height)]

for (r, c), v in self.objects.items():
lines[r][c] = v.symbol

return "\n".join("".join(line) for line in lines)


def process_data(task: str) -> tuple[Warehouse, list[Instruction]]:
first, second = task.split("\n\n")
warehouse = Warehouse.from_text(first)
instructions = [Instruction(x) for x in second if x in Instruction]
return warehouse, instructions


def solve(task: str) -> int:
warehouse, instructions = process_data(task)
warehouse.move_robot(instructions)
return warehouse.gps_sum
52 changes: 52 additions & 0 deletions tests/src/year2024/test_day15a.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""2024 - Day 15 Part 1: Warehouse Woes"""

from textwrap import dedent

from src.year2024.day15a import solve


def test_solve_small():
task = dedent(
"""
########
#..O.O.#
##@.O..#
#...O..#
#.#.O..#
#...O..#
#......#
########
<^^>>>vv<v>>v<<
"""
).strip()
assert solve(task) == 2028


def test_solve_large():
task = dedent(
"""
##########
#..O..O.O#
#......O.#
#.OO..O.O#
#..O@..O.#
#O#..O...#
#O..O..O.#
#.OO.O.OO#
#....O...#
##########
<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^
vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<
<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><
^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^
>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>
^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>
v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^
"""
).strip()
assert solve(task) == 10092

0 comments on commit 97da4b8

Please sign in to comment.