diff --git a/2024/06/part1.py b/2024/06/part1.py index a15e3e1..0326a0e 100644 --- a/2024/06/part1.py +++ b/2024/06/part1.py @@ -1,15 +1,143 @@ +import numpy as np +from enum import Enum -def load_map(filename="input"): - with open(filename, "r") as fp: - data = fp.read - +''' idee: sla ook het kleine voorbeeld op - lees data in - maak object "kaart" - maak op object - show() (prints map to screen) guard_directions = ["^", ">", "v", "<"] guard_path = [] # list of tuples (x, y) +''' +class Map: + directions = ["^", ">", "v", "<"] + #step_per_direction = [(0, -1), (1, 0), (0, 1), (-1, 0)] + step_per_direction = [(-1, 0), (0, 1), (1, 0), (0, -1)] + + class Tiles(Enum): + BORDER = "+" + FREE = "." + OBSTACLE = "#" + + def __init__(self): + self.trace = [] + self.pos = None + self.direction = None + + def next_pos(self): + """ + Returns next position given the state of this Map. + """ + + next_pos = tuple([self.pos[i] + self.step_per_direction[self.directions.index(self.direction)][i] for i in range(len(self.pos))]) + print("next_pos", next_pos) + return next_pos + + def pos_in_map(self, pos): + """ + Returns whether pos is in the map. + """ + print("pos_in_map", pos) + return pos[0] >= 0 and pos[0] < self.map.shape[0] \ + and pos[1] >= 0 and pos[0] < self.map.shape[1] + + def look_ahead(self): + next_step = self.next_pos() + print("look_ahead.next_step", next_step) + if not self.pos_in_map(next_step): + return self.Tiles.BORDER + if self.map[*next_step] == "#": + return self.Tiles.OBSTACLE + if self.map[*next_step] == ".": + return self.Tiles.FREE + + def next_direction(self, direction: str): + """ + Return the direction turning right given direction. + """ + + assert direction in self.directions, "Invalid direction given" + + if self.directions[-1] == direction: + return self.directions[0] + else: + return self.directions[self.directions.index(direction) + 1] + + def seek_guard_in_map(self): + """ + Looks for the guard in the map and returns its position. + + Will raise an exception if multiple or none are found. + """ + + guard_locations = [] + for direction in self.directions: + guard_locations.extend(list(zip(*np.where(m.map == direction)))) + return guard_locations + + def load_map(self, filename="input"): + """ + Reads a map from a file without verifying its contents. + """ + + with open(filename, "r") as fp: + data = fp.read().splitlines() + chararray = np.array(data, dtype=str)\ + .view("U1")\ + .reshape((len(data), -1)) + self.map = chararray + + # Find the location of the guard in the map. + guards = self.seek_guard_in_map() + print(guards) + assert len(guards) == 1, "There should only be one guard in the map." + + print(guards) + self.pos = guards[0] + self.trace.append(self.pos) + self.direction = m.map[self.pos] + # TODO: Use enum. + #self.map[self.pos] = self.Tiles.FREE + self.map[self.pos] = "." + + def step(self): + """ + Take a step, turn or stop. + """ + + next_tile = self.look_ahead() + print("step.next_tile", next_tile) + + if next_tile == self.Tiles.FREE: + self.pos = self.next_pos() + self.trace.append(self.pos) + return True + elif next_tile == self.Tiles.OBSTACLE: + self.direction = self.next_direction(self.direction) + return True + elif next_tile == self.Tiles.BORDER: + return False + + assert False, "Should not come here :')" + + def show(self): + """Prints the current map to stdout.""" + + for i in range(len(self.map)): + for j in range(len(self.map[0])): + if self.pos == (i, j): + print(self.direction, end="") + else: + print(self.map[i][j], end="") + print() + +if __name__ == "__main__": + m = Map() + #m.load_map("testinput") + m.load_map("input") + + while m.step(): + print(m.pos, m.direction) + #m.show() + print(len(m.trace), m.trace) + print(len(set(m.trace))) diff --git a/2024/06/testinput b/2024/06/testinput new file mode 100644 index 0000000..a4eb402 --- /dev/null +++ b/2024/06/testinput @@ -0,0 +1,10 @@ +....#..... +.........# +.......... +..#....... +.......#.. +.......... +.#..^..... +........#. +#......... +......#...