diff --git a/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb b/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb index 7745f56..016a1ed 100644 --- a/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb +++ b/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb @@ -59,7 +59,7 @@ " jupyterlab-lsp ipykernel ipywidgets \\\n", " matplotlib pandas networkx sympy \\\n", " dazbo-commons \\\n", - " python-dotenv tqdm" + " colorama python-dotenv tqdm" ] }, { @@ -98,6 +98,7 @@ "import networkx as nx\n", "import numpy as np\n", "import pandas as pd\n", + "from colorama import Fore, Back, Style\n", "from dotenv import load_dotenv\n", "from IPython.core.display import Markdown\n", "from IPython.display import display\n", @@ -1953,7 +1954,7 @@ " SPACE = \".\"\n", " OBSTACLE = \"#\"\n", " \n", - " DIRECTIONS = \"^>v<\"\n", + " DIRECTIONS = \"^>v<\" # Each successive direction is the result of turning right (i.e. 90 degrees)\n", " DIRECTIONS_MAP = {\n", " '^': Point(0, -1),\n", " '>': Point(1, 0),\n", @@ -1972,7 +1973,7 @@ " self._start_direction_idx = self._directions_idx\n", "\n", " self._visited_with_direction = set()\n", - " self._visited_map = {}\n", + " self._visited_map = {} # We can use this to print the route\n", " self._in_loop = False\n", " \n", " self._update_visited()\n", @@ -1985,13 +1986,13 @@ " self._directions_idx = self._start_direction_idx\n", " \n", " self._visited_with_direction = set()\n", - " self._visited_map = {}\n", + " self._visited_map: dict[Point, str] = {}\n", " self._in_loop = False\n", " \n", " self._update_visited()\n", " self._clear_obstacle()\n", " \n", - " def add_obstacle(self, location: tuple):\n", + " def add_obstacle(self, location: Point):\n", " self._pre_obstacle_added = (location, self.value_at_point(location))\n", " self.set_value_at_point(location, GuardMap.OBSTACLE)\n", " \n", @@ -2000,7 +2001,7 @@ " self.set_value_at_point(self._pre_obstacle_added[0], self._pre_obstacle_added[1])\n", " \n", " @property\n", - " def in_loop(self):\n", + " def in_loop(self) -> bool:\n", " return self._in_loop\n", " \n", " @property\n", @@ -2009,40 +2010,43 @@ " return self._visited_map\n", " \n", " @property\n", - " def distinct_visited_count(self):\n", + " def distinct_visited_count(self) -> int:\n", " return len(self._visited_map)\n", " \n", " def _update_visited(self):\n", + " \"\"\" Update visited locations \"\"\"\n", + " \n", + " # Update our dict of where we've been\n", " self._visited_map[self._guard_location] = self._guard_direction\n", " \n", + " # For loop checking, we need to check if we've seen this location AND this orientation\n", " location_config = (self._guard_location, self._guard_direction)\n", " if location_config in self._visited_with_direction:\n", " self._in_loop = True # We've done this before!\n", " else:\n", " self._visited_with_direction.add(location_config)\n", "\n", - " def guard_move(self) -> bool:\n", + " def move(self) -> bool:\n", " \"\"\" \n", " Move guard one space in current direction.\n", " If we can't move forward in this direction, make turn and move.\n", " Return True if we move, or False if we leave the map\n", " \"\"\"\n", " while True:\n", - " next_point = Point(self._guard_location.x + GuardMap.DIRECTIONS_MAP[self._guard_direction].x,\n", - " self._guard_location.y + GuardMap.DIRECTIONS_MAP[self._guard_direction].y)\n", + " # Move one step in the direction the guard is pointing\n", + " next_point = self._guard_location + GuardMap.DIRECTIONS_MAP[self._guard_direction]\n", " \n", - " # leaving the map?\n", - " if not self.valid_location(next_point):\n", + " if not self.valid_location(next_point): # leaving the map?\n", " return False\n", " \n", - " next_value = self.value_at_point(next_point)\n", - " \n", " # Are we at an obstacle? If so, rotate right and try again\n", + " next_value = self.value_at_point(next_point)\n", " if (next_value == GuardMap.OBSTACLE):\n", + " # Increment the direction index\n", " self._directions_idx = (self._directions_idx + 1) % len(GuardMap.DIRECTIONS)\n", " self._guard_direction = GuardMap.DIRECTIONS[self._directions_idx]\n", " continue\n", - " else:\n", + " else: # No obstacle, so we can move to this location\n", " self._guard_location = next_point\n", " self._update_visited()\n", " break # We've successfully moved\n", @@ -2051,7 +2055,7 @@ " \n", " def _locate_guard(self) -> Point:\n", " for point in self.all_points():\n", - " if self.value_at_point(point) not in (GuardMap.SPACE, GuardMap.OBSTACLE):\n", + " if self.value_at_point(point) in GuardMap.DIRECTIONS:\n", " return point\n", " \n", " def __str__(self) -> str:\n", @@ -2061,7 +2065,7 @@ " for x, char in enumerate(row):\n", " locn = Point(x,y)\n", " if locn in self._visited_map.keys():\n", - " row_str += self._visited_map[locn]\n", + " row_str += Fore.YELLOW + self._visited_map[locn] + Fore.RESET\n", " else:\n", " row_str += char\n", " \n", @@ -2078,7 +2082,7 @@ "source": [ "def solve_part1(data):\n", " guard_map = GuardMap(data)\n", - " while guard_map.guard_move():\n", + " while guard_map.move():\n", " pass\n", "\n", " logger.debug(f\"\\n{guard_map}\") \n", @@ -2156,7 +2160,7 @@ " \n", " # Initial route\n", " guard_map = GuardMap(data)\n", - " while guard_map.guard_move():\n", + " while guard_map.move():\n", " pass\n", " \n", " # Route taken, excluding starting point\n", @@ -2165,10 +2169,9 @@ " loop_locations = 0\n", " \n", " for location in tqdm(route):\n", - " # guard_map = GuardMap(data)\n", " guard_map.reset()\n", " guard_map.add_obstacle(location)\n", - " while guard_map.guard_move():\n", + " while guard_map.move():\n", " if guard_map.in_loop:\n", " loop_locations += 1\n", " break\n",