From 68447bb44219e4cc234acb9fdf86a77c0c2e94b8 Mon Sep 17 00:00:00 2001 From: Dazbo Date: Wed, 3 Jan 2024 08:57:11 +0000 Subject: [PATCH] Fixed horizontal and diagonal ray casting --- .../Dazbo's_Advent_of_Code_2023.ipynb | 62 +++++++++++++++---- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/src/AoC_2023/Dazbo's_Advent_of_Code_2023.ipynb b/src/AoC_2023/Dazbo's_Advent_of_Code_2023.ipynb index 53cb21b..8224e4d 100644 --- a/src/AoC_2023/Dazbo's_Advent_of_Code_2023.ipynb +++ b/src/AoC_2023/Dazbo's_Advent_of_Code_2023.ipynb @@ -3570,6 +3570,35 @@ " \"S\": [\"N\", \"E\", \"S\", \"W\"] # start location\n", " }\n", " \n", + " def infer_start_type(self, loop: list[Point]) -> str:\n", + " \"\"\" Determine the pipe type of the start point. It does this by determining\n", + " the two connected pipes in the loop. From their directions and types, we know what the S\n", + " must be.\n", + " \"\"\"\n", + " start_posn = len(loop) // 2\n", + " assert self.value_at_point(loop[start_posn]) == \"S\", \"Middle of the loop should be start\"\n", + " \n", + " dirs = set()\n", + " for vector in [loop[start_posn+1] - loop[start_posn], loop[start_posn-1] - loop[start_posn]]:\n", + " (x, y) = vector.x, vector.y\n", + " match (x, y):\n", + " case Vectors.N.value:\n", + " dirs.add(\"N\")\n", + " case Vectors.E.value:\n", + " dirs.add(\"E\")\n", + " case Vectors.S.value:\n", + " dirs.add(\"S\")\n", + " case Vectors.W.value:\n", + " dirs.add(\"W\")\n", + " case _:\n", + " assert False, \"Invalid direction\"\n", + " \n", + " for pipe_type, directions in PipeGrid.directions_for_pipe.items():\n", + " if dirs == set(directions):\n", + " return pipe_type\n", + " \n", + " assert False, \"No valid pipe type found\" \n", + " \n", " def valid_neighbours_for_loop_pipe(self, point: Point) -> list[Point]:\n", " \"\"\" Get valid neighbours, given a current location that is the main pipe loop. \"\"\"\n", " valid = []\n", @@ -3893,6 +3922,8 @@ " This function constructs the loop path starting from the 'furthest' point, which is\n", " the most distant point from the start in the grid, back to the starting point. The path\n", " is constructed in two halves and then combined.\n", + " \n", + " Note, the start point is therefore the point in the middle.\n", " \"\"\"\n", " start = next(point for point in grid.all_points()\n", " if grid.value_at_point(point) == \"S\")\n", @@ -4033,7 +4064,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Altternative Solutions and Useful Resources\n", + "### Alternative Solutions and Useful Resources\n", "\n", "There are a few other ways to solve this problem. \n", "\n", @@ -4100,9 +4131,11 @@ " loop_path = get_loop_path(grid, furthest, came_from) # get complete enclosed main loop\n", " loop_points = set(loop_path)\n", " cleaned_grid = remove_junk_parts(grid, loop_points) \n", - " logger.debug(f\"\\n{cleaned_grid}\")\n", + " # logger.debug(f\"\\n{cleaned_grid}\")\n", "\n", - " # //todo replace S with appropriate char. Determine S based on the prev and next directions\n", + " # update \"S\" to be actual pipe type\n", + " start_type = grid.infer_start_type(loop_path)\n", + " cleaned_grid.set_value_at_point(loop_path[len(loop_path)//2], start_type)\n", " \n", " inside = 0\n", " # sweep each low, from left to right\n", @@ -4126,7 +4159,9 @@ " loop_points = set(loop_path)\n", " cleaned_grid = remove_junk_parts(grid, loop_points)\n", " \n", - " # //todo replace S with appropriate char. Determine S based on the prev and next directions\n", + " # update \"S\" to be actual pipe type\n", + " start_type = grid.infer_start_type(loop_path)\n", + " cleaned_grid.set_value_at_point(loop_path[len(loop_path)//2], start_type)\n", " \n", " inside = 0\n", " # sweep diagonally, in the right/down direction\n", @@ -4220,14 +4255,6 @@ "\n", "sample_answers = [4, 4, 8, 10]\n", "\n", - "# Shoelace + Pick's Theorem\n", - "for func in (d10_with_shoelace_and_picks, \n", - " d10_with_horizontal_ray_casting,\n", - " d10_with_diagonal_ray_casting,\n", - " d10_with_scale_up):\n", - " logger.info(f\"Solving with {func.__name__}() ...\")\n", - " test_and_run_with_solve(func)\n", - "\n", "def test_and_run_with_solve(solve:func):\n", " for curr_input, curr_ans in zip(sample_inputs, sample_answers):\n", " curr_grid = parse_grid(curr_input.splitlines())\n", @@ -4240,7 +4267,16 @@ "\n", " grid = parse_grid(input_data)\n", " soln = func(grid, furthest, came_from)\n", - " logger.info(f\"Part 2 soln={soln}\")" + " logger.info(f\"Part 2 soln={soln}\")\n", + " \n", + "# Shoelace + Pick's Theorem\n", + "for func in (d10_with_shoelace_and_picks, \n", + " d10_with_horizontal_ray_casting,\n", + " d10_with_diagonal_ray_casting,\n", + " d10_with_scale_up):\n", + " logger.info(f\"Solving with {func.__name__}() ...\")\n", + " test_and_run_with_solve(func)\n", + "\n" ] }, {