with open('input.text', 'r') as file: data: list[str] = file.readlines() y_bound = len(data) x_bound = len(data[0]) class Vector: x: int y: int def __init__(self, x: int, y: int): self.x = x self.y = y def __add__(self, other): return Vector(self.x + other.x, self.y + other.y) def __str__(self): return f'{self.x}, {self.y}' def __eq__(self, value): return self.x == value.x and self.y == value.y class Guard: pos: Vector dir: Vector def __init__(self, p: Vector, d: Vector): self.pos = p self.dir = d def move(self, ob) -> Vector | None | int: new_pos = self.pos + self.dir # Check if need to turn if new_pos in ob: return new_pos # Check if move out of bounds if new_pos.y < 0 or new_pos.y >= y_bound or new_pos.x < 0 or new_pos.x >= x_bound: return -1 self.pos = new_pos return None def turn(self): temp_x = self.dir.x self.dir.x = -self.dir.y self.dir.y = temp_x # Parse Data obstacles = [] guard = None for y, line in enumerate(data): for x, char in enumerate(line): match char: case '#': obstacles.append(Vector(x, y)) case '^': guard = Guard(Vector(x, y), Vector(0, -1)) starting_pos = guard.pos # Part 1 been = [starting_pos] while True: ob = guard.move(obstacles) if type(ob) == Vector: guard.turn() elif type(ob) == int: break if guard.pos not in been: been.append(guard.pos) print(f'Part 1: {len(been)}') # Part 2 total = 0 been.remove(starting_pos) for i, place in enumerate(been): print(i) temp_obstacles = obstacles.copy() temp_obstacles.append(place) guard.pos = starting_pos guard.dir = Vector(0, -1) steps = 0 while True: ob = guard.move(temp_obstacles) if type(ob) == Vector: guard.turn() elif type(ob) == int: break else: steps += 1 # Yup, this is what I count as in a loop... if steps >= 6500: total += 1 break print(f'Part 2: {total}')