From 1a7f6304ee325f44f665f0653b9d718c647d3111 Mon Sep 17 00:00:00 2001 From: Kees van Kempen Date: Thu, 26 Dec 2024 11:35:43 +0100 Subject: [PATCH] 2024(6): try part 2 * My code is way too slow. * I should put the obstacle in the path before starting the walk, as it could be that the obstacle is ran into earlier. --- 2024/06/part1.py | 60 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/2024/06/part1.py b/2024/06/part1.py index ac918bf..674b0d0 100644 --- a/2024/06/part1.py +++ b/2024/06/part1.py @@ -1,12 +1,16 @@ import numpy as np from enum import Enum +import copy verbose = False class Map: + """ + Handles a map with obstacles and how a guard walks through it. + """ + 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): @@ -37,7 +41,7 @@ class Map: if verbose: 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] + and pos[1] >= 0 and pos[1] < self.map.shape[1] def look_ahead(self): next_step = self.next_pos() @@ -97,9 +101,16 @@ class Map: self.pos = guards[0] self.trace.append(self.pos) self.direction = self.map[self.pos] - # TODO: Use enum. - #self.map[self.pos] = self.Tiles.FREE - self.map[self.pos] = "." + self.map[self.pos] = self.Tiles.FREE.value + + class LoopException(Exception): + """ + Gets thrown when the map results in the guard walking in an + infinite loop. + """ + + pass + def step(self): """ @@ -110,6 +121,9 @@ class Map: if verbose: print("step.next_tile", next_tile) + if self.is_stuck_in_loop(): + raise self.LoopException() + if next_tile == self.Tiles.FREE: # TODO: Really take a step! Do not only turn. self.pos = self.next_pos() @@ -134,14 +148,48 @@ class Map: print(self.map[i][j], end="") print() + def is_stuck_in_loop(self): + """ + Returns whether the guard is stuck in loop. + + This only happens when enough steps are taken. Currently, it + checks whether the current position is already part of the trace + at least four times, so that it has travelled the position at + least twice from at least one direction. + """ + + return self.trace.count(self.pos) > 4 + + def copy(self): + if verbose: + print(f"Deep copying") + return copy.deepcopy(self) + + if __name__ == "__main__": m = Map() #m.load_map("testinput") m.load_map("input") + loop_obstacles = [] + while m.step(): if verbose: print(m.pos, m.direction) + + # Create a copy + forked_map = m.copy() + forked_map.map[forked_map.next_pos()] = Map.Tiles.OBSTACLE.value + print(f"Forking at {forked_map.next_pos()}... ", end="") + try: + while forked_map.step(): + continue + except Map.LoopException: + print("loop.") + loop_obstacles.append(m.next_pos()) + else: + print("no loop") #m.show() #print(len(m.trace), m.trace) - print(len(set(m.trace))) + #print(len(set(m.trace))) + print(len(loop_obstacles))