From a65716adbc148febc642aa082e0f84d3e7d1c914 Mon Sep 17 00:00:00 2001 From: StarlitGhost <679547+StarlitGhost@users.noreply.github.com> Date: Sun, 15 Dec 2024 16:48:54 +0000 Subject: [PATCH] [2024/15] p2 solved --- .aoc_tiles/tiles/2024/15.png | Bin 4812 -> 4860 bytes 2024/15/example_p2 | 9 +++ 2024/15/script.py | 134 +++++++++++++++++++++++++++++------ README.md | 4 +- 4 files changed, 123 insertions(+), 24 deletions(-) create mode 100644 2024/15/example_p2 diff --git a/.aoc_tiles/tiles/2024/15.png b/.aoc_tiles/tiles/2024/15.png index 728586e6bf380e7093b8373eac41f3945e3e480e..b544c6eb202c7e77ffd1e18d7b3b0fbbc95186a8 100644 GIT binary patch literal 4860 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 i<07n3Q4Mf?nEU_wee$uXAdV;i0000 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 mdWAa@=Y2Hp`6$WRq;;%0000 'Robot': self.pos = Vec2(pos) + def process(self, instructions: str, grid: Grid): + for instr in instructions: + if instr == '\n': + continue + self.move(Dir.map_nswe('^v<>')[instr], grid) + + if aoc.args.verbose: + print(instr) + print(grid) + def move(self, dir: Dir, grid: Grid) -> bool: if grid[self.pos + dir].move(dir, grid): grid[self.pos] = Air(self.pos) @@ -22,17 +33,60 @@ def __str__(self) -> str: class Box: def __init__(self, pos: Vec2) -> 'Box': self.pos = Vec2(pos) + self.width = 1 + self.last_draw = -1 + + def touching(self, dir: Dir, grid: Grid) -> set[Union['Box', 'Wall', 'Air']]: + if dir in {Dir.NORTH, Dir.SOUTH}: + cells = filter(lambda c: type(c) is not Air, + (grid[self.pos + Vec2(Dir.EAST) * i + dir] + for i in range(self.width))) + else: + cells = filter(lambda c: type(c) is not Air, + [grid[self.pos + (dir if dir == Dir.WEST else Vec2(dir) * self.width)]]) + cells = set(cells) + + return cells + + def can_move(self, dir: Dir, grid: Grid) -> bool: + return all(cell.can_move(dir, grid) for cell in self.touching(dir, grid)) def move(self, dir: Dir, grid: Grid) -> bool: - if grid[self.pos + dir].move(dir, grid): - grid[self.pos] = Air(self.pos) - self.pos += dir - grid[self.pos] = self - return True - return False + if not self.can_move(dir, grid): + return False + + for cell in self.touching(dir, grid): + grid[cell.pos].move(dir, grid) + + self.pos += dir + if dir == Dir.WEST: + grid[self.pos + Vec2(Dir.EAST) * self.width] = Air(None) + for i in range(self.width): + grid[self.pos + Vec2(Dir.EAST) * i] = self + elif dir == Dir.EAST: + grid[self.pos + Vec2(Dir.WEST)] = Air(None) + for i in range(self.width): + grid[self.pos + Vec2(Dir.EAST) * i] = self + else: + for i in range(self.width): + grid[self.pos + Vec2(Dir.EAST) * i - dir] = Air(None) + grid[self.pos + Vec2(Dir.EAST) * i] = self + return True + + def gps(self) -> int: + return 100 * self.pos.y + self.pos.x def __str__(self) -> str: - return 'O' + if self.width == 1: + return 'O' + elif self.width == 2: + self.last_draw += 1 + if self.last_draw > 1: + self.last_draw = 0 + return '[]'[self.last_draw] + + def __repr__(self) -> str: + return f"Box at {self.pos}" class Wall: @@ -42,9 +96,15 @@ def __init__(self, pos: Vec2) -> 'Wall': def move(self, dir: Dir, grid: Grid) -> bool: return False + def can_move(self, dir: Dir, grid: Grid) -> bool: + return False + def __str__(self) -> str: return '#' + def __repr__(self) -> str: + return f"Wall at {self.pos}" + class Air: def __init__(self, pos: Vec2) -> 'Air': @@ -53,38 +113,68 @@ def __init__(self, pos: Vec2) -> 'Air': def move(self, dir: Dir, grid: Grid) -> bool: return True + def can_move(self, dir: Dir, grid: Grid) -> bool: + return True + def __str__(self) -> str: return '.' -def convert(cell: str, pos: Vec2) -> Robot | Box | Wall | Air: - return {'@': Robot, '#': Wall, 'O': Box, '.': Air}[cell](pos) - +def build_warehouse(floorplan: str, wide: bool = False) -> tuple[Grid, Robot, list[Box]]: + floorplan = floorplan.splitlines() + if wide: + new_floorplan = [] + for row in floorplan: + new_row = [] + for c in row: + new_row.append({'#': '##', '@': '@.', 'O': '[]', '.': '..'}[c]) + new_floorplan.append(''.join(new_row)) + floorplan = new_floorplan -def main(): - warehouse, instructions = aoc.read_sections() - warehouse = Grid(warehouse.splitlines()) + warehouse = Grid(floorplan) robot = None boxes = [] for cell, pos in warehouse.by_cell(): + if cell == ']': + warehouse[pos] = warehouse[Vec2(pos) + Dir.WEST] + warehouse[pos].width = 2 + continue warehouse[pos] = convert(cell, pos) if type(warehouse[pos]) is Box: boxes.append(warehouse[pos]) elif type(warehouse[pos]) is Robot: robot = warehouse[pos] + return warehouse, robot, boxes - if aoc.args.verbose or aoc.args.progress: - print(warehouse) - for instr in instructions: - if instr == '\n': - continue - robot.move(Dir.map_nswe('^v<>')[instr], warehouse) +def convert(cell: str, pos: Vec2) -> Robot | Box | Wall | Air: + return { + '@': Robot, + 'O': Box, + '[': Box, + '#': Wall, + '.': Air + }[cell](pos) - if aoc.args.verbose or aoc.args.progress: - print(warehouse) - print(f"p1: {sum(box.pos.y * 100 + box.pos.x for box in boxes)}") +def main(): + floorplan, instructions = aoc.read_sections() + + warehouse, robot, boxes = build_warehouse(floorplan) + if aoc.args.verbose or aoc.args.progress: + print(warehouse) + robot.process(instructions, warehouse) + if aoc.args.progress: + print(warehouse) + print(f"p1: {sum(box.gps() for box in boxes)}") + + warehouse, robot, boxes = build_warehouse(floorplan, wide=True) + if aoc.args.verbose or aoc.args.progress: + print(warehouse) + robot.process(instructions, warehouse) + if aoc.args.progress: + print(warehouse) + print(f"p2: {sum(box.gps() for box in boxes)}") if __name__ == "__main__": diff --git a/README.md b/README.md index a84999d..3280cea 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ My solutions to the yearly Advents of Code

- Advent of Code - 190/480 ⭐ + Advent of Code - 191/480 ⭐

- 2024 - 29 ⭐ - Python + 2024 - 30 ⭐ - Python