Skip to content

Commit 90b79e5

Browse files
committed
AoC 2024 Day 15 - refactor
1 parent e3186a6 commit 90b79e5

File tree

1 file changed

+50
-53
lines changed

1 file changed

+50
-53
lines changed

src/main/python/AoC2024_15.py

Lines changed: 50 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,15 @@
55

66
import sys
77
from typing import Callable
8+
from typing import NamedTuple
89

910
from aoc import my_aocd
1011
from aoc.common import InputData
1112
from aoc.common import SolutionBase
1213
from aoc.common import aoc_samples
1314
from aoc.geometry import Direction
1415
from aoc.grid import Cell
15-
16-
Grid = list[list[str]]
17-
Input = tuple[Grid, list[Direction]]
18-
Output1 = int
19-
Output2 = int
20-
16+
from aoc.grid import CharGrid
2117

2218
TEST1 = """\
2319
########
@@ -56,85 +52,94 @@
5652
"""
5753

5854

55+
class GridSupplier(NamedTuple):
56+
grid_in: list[str]
57+
58+
def get_grid(self) -> CharGrid:
59+
return CharGrid.from_strings(self.grid_in)
60+
61+
def get_wide_grid(self) -> CharGrid:
62+
grid = [
63+
"".join(Solution.SCALE_UP[ch] for ch in line)
64+
for line in self.grid_in
65+
]
66+
return CharGrid.from_strings(grid)
67+
68+
69+
Input = tuple[GridSupplier, list[Direction]]
70+
Output1 = int
71+
Output2 = int
72+
73+
5974
class Solution(SolutionBase[Input, Output1, Output2]):
6075
FLOOR, WALL, ROBOT = ".", "#", "@"
6176
BOX, BIG_BOX_LEFT, BIG_BOX_RIGHT = "O", "[", "]"
6277
SCALE_UP = {
63-
WALL: [WALL, WALL],
64-
BOX: [BIG_BOX_LEFT, BIG_BOX_RIGHT],
65-
FLOOR: [FLOOR, FLOOR],
66-
ROBOT: [ROBOT, FLOOR],
78+
WALL: WALL + WALL,
79+
BOX: BIG_BOX_LEFT + BIG_BOX_RIGHT,
80+
FLOOR: FLOOR + FLOOR,
81+
ROBOT: ROBOT + FLOOR,
6782
}
6883

6984
def parse_input(self, input_data: InputData) -> Input:
7085
blocks = my_aocd.to_blocks(input_data)
71-
grid = [list(line) for line in blocks[0]]
7286
dirs = [Direction.from_str(ch) for ch in "".join(blocks[1])]
73-
return grid, dirs
87+
return GridSupplier(blocks[0]), dirs
7488

7589
def solve(
7690
self,
77-
grid: Grid,
78-
robot: Cell,
91+
grid: CharGrid,
7992
dirs: list[Direction],
80-
get_to_move: Callable[[Grid, Cell, Direction], list[Cell]],
93+
get_to_move: Callable[[CharGrid, Cell, Direction], list[Cell]],
8194
) -> int:
95+
robot = next(grid.get_all_equal_to(Solution.ROBOT))
8296
for dir in dirs:
8397
to_move = get_to_move(grid, robot, dir)
8498
if len(to_move) == 0:
8599
continue
86-
to_move.pop(0)
87-
vals = [list(row) for row in grid]
88-
grid[robot.row][robot.col] = Solution.FLOOR
89-
nxt_robot = robot.at(dir)
90-
grid[nxt_robot.row][nxt_robot.col] = Solution.ROBOT
91-
robot = nxt_robot
100+
vals = {tm: grid.get_value(tm) for tm in to_move}
101+
robot = robot.at(dir)
92102
for cell in to_move:
93-
grid[cell.row][cell.col] = Solution.FLOOR
103+
grid.set_value(cell, Solution.FLOOR)
94104
for cell in to_move:
95-
nxt = cell.at(dir)
96-
grid[nxt.row][nxt.col] = vals[cell.row][cell.col]
105+
grid.set_value(cell.at(dir), vals[cell])
97106
return sum(
98-
r * 100 + c
99-
for r in range(len(grid))
100-
for c in range(len(grid[r]))
101-
if grid[r][c] in {Solution.BOX, Solution.BIG_BOX_LEFT}
107+
cell.row * 100 + cell.col
108+
for cell in grid.find_all_matching(
109+
lambda cell: grid.get_value(cell)
110+
in {Solution.BOX, Solution.BIG_BOX_LEFT}
111+
)
102112
)
103113

104114
def part_1(self, input: Input) -> Output1:
105-
def get_to_move(grid: Grid, robot: Cell, dir: Direction) -> list[Cell]:
115+
def get_to_move(
116+
grid: CharGrid, robot: Cell, dir: Direction
117+
) -> list[Cell]:
106118
to_move = [robot]
107119
for cell in to_move:
108120
nxt = cell.at(dir)
109121
if nxt in to_move:
110122
continue
111-
match grid[nxt.row][nxt.col]:
123+
match grid.get_value(nxt):
112124
case Solution.WALL:
113125
return []
114126
case Solution.BOX:
115127
to_move.append(nxt)
116128
return to_move
117129

118-
grid_in, dirs = input
119-
grid = [list(row) for row in grid_in]
120-
for r in range(len(grid)):
121-
for c in range(len(grid[r])):
122-
if grid[r][c] == Solution.ROBOT:
123-
robot = Cell(r, c)
124-
break
125-
else:
126-
continue
127-
break
128-
return self.solve(grid, robot, dirs, get_to_move)
130+
grid, dirs = input
131+
return self.solve(grid.get_grid(), dirs, get_to_move)
129132

130133
def part_2(self, input: Input) -> Output2:
131-
def get_to_move(grid: Grid, robot: Cell, dir: Direction) -> list[Cell]:
134+
def get_to_move(
135+
grid: CharGrid, robot: Cell, dir: Direction
136+
) -> list[Cell]:
132137
to_move = [robot]
133138
for cell in to_move:
134139
nxt = cell.at(dir)
135140
if nxt in to_move:
136141
continue
137-
match grid[nxt.row][nxt.col]:
142+
match grid.get_value(nxt):
138143
case Solution.WALL:
139144
return []
140145
case Solution.BIG_BOX_LEFT:
@@ -145,16 +150,8 @@ def get_to_move(grid: Grid, robot: Cell, dir: Direction) -> list[Cell]:
145150
to_move.append(nxt.at(Direction.LEFT))
146151
return to_move
147152

148-
grid_in, dirs = input
149-
grid = []
150-
for r, row in enumerate(grid_in):
151-
line = []
152-
for c, ch in enumerate(row):
153-
if ch == Solution.ROBOT:
154-
robot = Cell(r, 2 * c)
155-
line.extend(Solution.SCALE_UP[ch])
156-
grid.append(line)
157-
return self.solve(grid, robot, dirs, get_to_move)
153+
grid, dirs = input
154+
return self.solve(grid.get_wide_grid(), dirs, get_to_move)
158155

159156
@aoc_samples(
160157
(

0 commit comments

Comments
 (0)