advent24-llm / day15 /solution_jerpint.py
jerpint's picture
Add solution files
a4da721
raw
history blame
15.1 kB
from dataclasses import dataclass
def read_data(file):
with open(file) as f:
data = f.readlines()
grid = []
for count, line in enumerate(data):
if line == "\n":
instructions = "".join([l.strip("\n") for l in data[count:]])
break
line = line.strip("\n")
grid.append(list(line))
return grid, instructions
@dataclass
class Position:
i: int
j: int
def is_in_bounds(self, grid):
M = len(grid)
N = len(grid[0])
return self.i in range(M) and self.j in range(N)
def get_next_pos(position: Position, direction):
i, j = position.i, position.j
if direction == "^":
# Up
i -= 1
elif direction == "v":
# Down
i += 1
elif direction == "<":
# Left
j -= 1
elif direction == ">":
# Right
j += 1
return Position(i, j)
def pprint(grid):
grid_copy = grid.copy()
grid_str = ""
for line in grid_copy:
grid_str += "".join(line)
grid_str += "\n"
print("*"*20)
print()
print(grid_str)
print()
print("*"*20)
class Game:
def __init__(self, grid, instructions):
self.grid = grid
self.instructions = list(instructions)
self.robot_pos = self.get_robot_start_pos(self.grid)
self.M = len(grid)
self.N = len(grid[0])
def get_robot_start_pos(self, grid):
M = len(grid)
N = len(grid[0])
for i in range(M):
for j in range(N):
if grid[i][j] == "@":
return Position(i, j)
def pprint(self):
pprint(grid)
def get_blocks_in_direction(self, pos, direction):
i, j = pos.i, pos.j
if direction == "^":
# Up
# i -= 1
return [self.grid[ii][j] for ii in range(i, -1, -1)]
elif direction == "v":
# Down
# i += 1
return [self.grid[ii][j] for ii in range(i, self.M)]
elif direction == "<":
# Left
# j -= 1
return [self.grid[i][jj] for jj in range(j, -1, -1 )]
elif direction == ">":
# Right
# j += 1
return [self.grid[i][jj] for jj in range(j, self.N)]
else:
raise ValueError("Invalid direction")
def get_index(self, blocks: list[str], shape: str):
if shape in blocks:
return blocks.index(shape)
else:
return float("inf")
def update_blocks_in_direction(self, blocks, pos, direction):
i, j = pos.i, pos.j
if direction == "^":
# Up
# i -= 1
for ii, block in zip(range(i, -1, -1), blocks):
self.grid[ii][j] = block
self.robot_pos.i -= 1
elif direction == "v":
# Down
# i += 1
for ii, block in zip(range(i, self.M), blocks):
self.grid[ii][j] = block
self.robot_pos.i += 1
elif direction == "<":
# Left
# j -= 1
# return [grid[i][jj] for jj in range(j, -1, -1 )]
for jj, block in zip(range(j, -1, -1), blocks):
self.grid[i][jj] = block
self.robot_pos.j -= 1
elif direction == ">":
# Right
# j += 1
# return [grid[i][jj] for jj in range(j, self.N)]
for jj, block in zip(range(j, self.N), blocks):
self.grid[i][jj] = block
self.robot_pos.j += 1
return
def move(self, direction):
# Get the blocks in the desired movement direction
blocks = self.get_blocks_in_direction(self.robot_pos, direction)
# Check that a free space appears before a wall
free_space_idx = self.get_index(blocks, ".")
wall_idx = self.get_index(blocks, "#")
valid_move = free_space_idx < wall_idx
if not valid_move:
# Don't do anything
# print("Didn't move!")
return False
# Shit the blocks over 1 until next free space
for jj in range(free_space_idx, 0, -1):
blocks[jj] = blocks[jj-1]
blocks[0] = "."
self.update_blocks_in_direction(blocks, self.robot_pos, direction)
return True
def step(self):
direction = self.instructions.pop(0)
is_moved = self.move(direction)
return direction, is_moved
def compute_gps(self, i, j):
return i * 100 + j
def compute_total_gps(self):
total = 0
for i in range(self.M):
for j in range(self.N):
if self.grid[i][j] == "O":
total += self.compute_gps(i, j)
return total
file = "input.txt"
grid, instructions = read_data(file)
game = Game(grid, instructions)
# game.pprint()
while len(game.instructions) > 0:
direction, is_moved = game.step()
# print("Next move: ", direction)
# game.pprint()
print(game.compute_total_gps())
# ## Part 2
# def get_larger_grid(grid):
# M = len(grid)
# N = len(grid[0])
# for i in range(M):
# for j in range(N):
# if grid[i][j] == "#":
# grid[i][j] = "##"
# elif grid[i][j] == "O":
# grid[i][j] = "[]"
# elif grid[i][j] == ".":
# grid[i][j] = ".."
# elif grid[i][j] == "@":
# grid[i][j] = "@."
# else:
# raise ValueError("Invalid char")
# for i in range(M):
# grid[i] = list("".join(grid[i]))
# return grid
# class Game2(Game):
# def get_blocks_in_direction(self, pos, direction):
# i, j = pos.i, pos.j
# if direction == "^":
# # Up
# # i -= 1
# return [self.grid[ii][j] for ii in range(i, -1, -1)]
# elif direction == "v":
# # Down
# # i += 1
# return [self.grid[ii][j] for ii in range(i, self.M)]
# elif direction == "<":
# # Left
# # j -= 1
# return [self.grid[i][jj] for jj in range(j, -1, -1 )]
# elif direction == ">":
# # Right
# # j += 1
# return [self.grid[i][jj] for jj in range(j, self.N)]
# else:
# raise ValueError("Invalid direction")
# def get_index(self, blocks: list[str], shape: str):
# if shape in blocks:
# return blocks.index(shape)
# else:
# return float("inf")
# def update_blocks_in_direction(self, blocks, pos, direction):
# i, j = pos.i, pos.j
# if direction == "^":
# # Up
# # i -= 1
# for ii, block in zip(range(i, -1, -1), blocks):
# self.grid[ii][j] = block
# self.robot_pos.i -= 1
# elif direction == "v":
# # Down
# # i += 1
# import ipdb; ipdb.set_trace();
# for ii, block in zip(range(i, self.M), blocks):
# self.grid[ii][j] = block
# self.robot_pos.i += 1
# elif direction == "<":
# # Left
# # j -= 1
# # return [grid[i][jj] for jj in range(j, -1, -1 )]
# for jj, block in zip(range(j, -1, -1), blocks):
# self.grid[i][jj] = block
# self.robot_pos.j -= 1
# elif direction == ">":
# # Right
# # j += 1
# # return [grid[i][jj] for jj in range(j, self.N)]
# for jj, block in zip(range(j, self.N), blocks):
# self.grid[i][jj] = block
# self.robot_pos.j += 1
# return
# def move(self, direction):
# # Get the blocks in the desired movement direction
# blocks = self.get_blocks_in_direction(self.robot_pos, direction)
# # Check that a free space appears before a wall
# free_space_idx = self.get_index(blocks, ".")
# wall_idx = self.get_index(blocks, "#")
# rule_1 = free_space_idx < wall_idx
# if direction in ["<", ">"]:
# valid_move = rule_1
# else:
# rule_2 = free_space_idx < wall_idx
# if not valid_move:
# # Don't do anything
# # print("Didn't move!")
# return False
# # Shit the blocks over 1 until next free space
# for jj in range(free_space_idx, 0, -1):
# blocks[jj] = blocks[jj-1]
# blocks[0] = "."
# self.update_blocks_in_direction(blocks, self.robot_pos, direction)
# return True
# file = "test.txt"
# grid, instructions = read_data(file)
# grid = get_larger_grid(grid)
# game = Game2(grid, instructions)
# # def get_larger_grid(grid):
# # M = len(grid)
# # N = len(grid[0])
# # for i in range(M):
# # for j in range(N):
# # if grid[i][j] == "#":
# # grid[i][j] = "##"
# # elif grid[i][j] == "O":
# # grid[i][j] = "[]"
# # elif grid[i][j] == ".":
# # grid[i][j] = ".."
# # elif grid[i][j] == "@":
# # grid[i][j] = "@."
# # else:
# # raise ValueError("Invalid char")
# # return grid
# #
# #
# # class Game2(Game):
# # def get_robot_start_pos(self, grid):
# #
# # M = len(grid)
# # N = len(grid[0])
# #
# # for i in range(M):
# # for j in range(N):
# # if "@" in grid[i][j]:
# # return Position(i, j)
# #
# #
# # def get_index(self, blocks: list[str], shape: str):
# # if shape in blocks:
# # return blocks.index(shape)
# # else:
# # return float("inf")
# #
# #
# # def get_blocks_in_direction(self, pos, direction):
# # i, j = pos.i, pos.j
# #
# # if direction == "^":
# # # Up
# # # i -= 1
# # blocks = [self.grid[ii][j] for ii in range(i, -1, -1)]
# # print(blocks)
# # # return "".join([b[::-1] for b in blocks])
# # return "".join([b for b in blocks])
# #
# # elif direction == "v":
# # # Down
# # # i += 1
# # blocks = [self.grid[ii][j] for ii in range(i, self.M)]
# # print(blocks)
# # return "".join([b[::-1] for b in blocks])
# #
# # elif direction == "<":
# # # Left
# # # j -= 1
# # blocks = [self.grid[i][jj] for jj in range(j, -1, -1 )]
# # return "".join([b[::-1] for b in blocks])
# #
# # elif direction == ">":
# # # Right
# # # j += 1
# # blocks = [self.grid[i][jj] for jj in range(j, self.N)]
# # return "".join([b for b in blocks])
# #
# # else:
# # raise ValueError("Invalid direction")
# #
# #
# # def update_blocks_in_direction(self, blocks: list[str], pos, direction):
# # i, j = pos.i, pos.j
# #
# #
# # # Simple cases first
# # # Might be overcomplicating...
# # if self.grid[i][j] == "@." and direction == ">":
# # self.grid[i][j] = ".@"
# # return True
# #
# # if self.grid[i][j] == ".@" and direction == "<":
# # self.grid[i][j] = "@."
# # return True
# #
# # # Not a simple case
# # # First shift the blocks by 1
# # new_blocks = blocks.copy()
# # new_blocks[1:] = blocks[0:-1]
# # new_blocks[0] = "."
# # new_blocks[-2] = "#" # Always 2 walls at end
# #
# # def reconstruct(new_blocks):
# #
# # # Group them back to 2 by 2
# # reconstructed = []
# # b = "".join(new_blocks)
# # for i in range(0, len(b), 2):
# # reconstructed.append(b[i:i+2])
# # return reconstructed
# #
# #
# #
# # blocks = reconstruct(new_blocks)
# #
# # if direction == "^":
# # # Up
# # # i -= 1
# # for ii, block in zip(range(i, -1, -1), blocks):
# # self.grid[ii][j] = block
# # self.robot_pos.i -= 1
# #
# # elif direction == "v":
# # # Down
# # # i += 1
# # for ii, block in zip(range(i, self.M), blocks):
# # self.grid[ii][j] = block
# # self.robot_pos.i += 1
# #
# # elif direction == "<":
# # # Left
# # # j -= 1
# # # return [grid[i][jj] for jj in range(j, -1, -1 )]
# #
# # for jj, block in zip(range(j, -1, -1), blocks):
# # self.grid[i][jj] = block
# #
# # self.robot_pos.j -= 1
# # elif direction == ">":
# # # Right
# # # j += 1
# # # return [grid[i][jj] for jj in range(j, self.N)]
# #
# # for jj, block in zip(range(j, self.N), blocks):
# # self.grid[i][jj] = block
# # self.robot_pos.j += 1
# # else:
# # raise ValueError("Wrong")
# #
# # return
# #
# # def move(self, direction):
# #
# # # Get the blocks in the desired movement direction
# # blocks = self.get_blocks_in_direction(self.robot_pos, direction)
# #
# # import ipdb; ipdb.set_trace();
# # # Blocks are grouped 2 by 2, here we get tehn in single extended list
# # blocks = list("".join(blocks))
# #
# # # Check that a free space appears before a wall
# # free_space_idx = self.get_index(blocks, ".")
# # wall_idx = self.get_index(blocks, "#")
# #
# # # Check whether it is valid to move or not
# # if direction in [">","<"]:
# # valid_move = free_space_idx < wall_idx
# # else:
# # valid_1 = free_space_idx < wall_idx
# # valid_2 = not("[" in blocks[:free_space_idx] and "]" in blocks[:free_space_idx])
# #
# # if not valid_1:
# # print("Not valid1")
# # if not valid_2:
# # print("Not valid2")
# #
# # valid_move = valid_1 and valid_2
# #
# #
# # if not valid_move:
# # # Don't do anything
# # print("Didn't move!")
# # return False
# #
# # self.update_blocks_in_direction(blocks, self.robot_pos, direction)
# # return True
# #
# #
# #
# #
# #
# #
# # file = "test3.txt"
# #
# # grid, instructions = read_data(file)
# # grid = get_larger_grid(grid)
# # game = Game2(grid, instructions)
# #
# # # game.pprint()
# # # while len(game.instructions) > 0:
# # # direction, is_moved = game.step()
# # # print("Next move: ", direction)
# # # game.pprint()