diff --git a/2024/day15/day15.py b/2024/day15/day15.py new file mode 100644 index 0000000..9d459d2 --- /dev/null +++ b/2024/day15/day15.py @@ -0,0 +1,99 @@ +DIRECTIONS = { + "^": 0 - 1j, # up + ">": 1 + 0j, # right + "v": 0 + 1j, # down + "<": -1 + 0j, # left +} + + +def find_start_pos(grid): + for y, row in enumerate(grid): + for x, _ in enumerate(row): + if grid[y][x] == "@": + return complex(x, y) + + +def get_pos(grid, pos): + x, y = int(pos.real), int(pos.imag) + if 0 <= x < len(grid[0]) and 0 <= y < len(grid): + return grid[y][x] + return None + + +def set_pos(grid, pos, val): + x, y = int(pos.real), int(pos.imag) + grid[y][x] = val + + +def debug_print(grid, move): + print("Move ", move) + for row in grid: + print("".join(row)) + + +def push(grid, pos, movement): + direction = DIRECTIONS[movement] + start_pos = pos + direction + # Find the end pos of a consecutive "O" chain + end_pos = start_pos + while get_pos(grid, end_pos + direction) == "O": + end_pos += direction + if get_pos(grid, end_pos + direction) == ".": + if movement == ">": + start_x, end_x = int(start_pos.real), int(end_pos.real) + y = int(start_pos.imag) + for i in range(end_x, start_x - 1, -1): + grid[y][i+1] = "O" # shift "O" to the right + grid[y][start_x] = "." + elif movement == "<": + start_x, end_x = int(start_pos.real), int(end_pos.real) + y = int(start_pos.imag) + for i in range(start_x, end_x + 1): + grid[y][i+1] = "O" # shift "O" to the left + grid[y][start_x] = "." + elif movement == "v": + start_y, end_y = int(start_pos.imag), int(end_pos.imag) + x = int(start_pos.real) + for i in range(start_y, end_y + 1): + grid[i+1][x] = "O" # shift "O" down + grid[start_y][x] = "." + elif movement == "^": + start_y, end_y = int(start_pos.imag), int(end_pos.imag) + x = int(start_pos.real) + for i in range(end_y, start_y - 1, -1): + grid[i+1][x] = "O" # shift "O" up + grid[start_y][x] = "." + + +def main(content): + grid, movements = content.split("\n\n") + grid = [list(x) for x in grid.split("\n")] + movements = movements.replace("\n", "") + pos = find_start_pos(grid) + + for movement in movements: + new_pos = pos + DIRECTIONS[movement] + v = get_pos(grid, new_pos) + match v: + case ".": + set_pos(grid, pos, ".") + set_pos(grid, new_pos, "@") + pos = new_pos + case "O": + push(grid, pos, movement) + if get_pos(grid, new_pos) == ".": + set_pos(grid, new_pos, "@") + set_pos(grid, pos, ".") + pos = new_pos + case "#": pass + case c: raise RuntimeError("This should never happen", c) + debug_print(grid, movement) + + +if __name__ == "__main__": + import sys + infile = sys.argv[1] if len(sys.argv) > 1 else "example.txt" + with open(infile) as f: + content = f.read() + main(content) +