Skip to content

Commit

Permalink
Doc updates
Browse files Browse the repository at this point in the history
  • Loading branch information
derailed-dash committed Dec 22, 2024
1 parent 4d45cf4 commit 8f1d170
Showing 1 changed file with 54 additions and 24 deletions.
78 changes: 54 additions & 24 deletions src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
},
{
"cell_type": "code",
"execution_count": 171,
"execution_count": 45,
"metadata": {
"id": "p5Ki_HvOJUWk",
"tags": []
Expand Down Expand Up @@ -258,7 +258,7 @@
},
{
"cell_type": "code",
"execution_count": 174,
"execution_count": 48,
"metadata": {
"id": "lwP0r3BAaxjt",
"tags": []
Expand Down Expand Up @@ -331,7 +331,7 @@
},
{
"cell_type": "code",
"execution_count": 175,
"execution_count": 49,
"metadata": {
"id": "Y6nbd6WMryWi",
"tags": []
Expand Down Expand Up @@ -359,7 +359,7 @@
},
{
"cell_type": "code",
"execution_count": 176,
"execution_count": 50,
"metadata": {
"id": "A8sU4Ez_bBKl",
"tags": []
Expand Down Expand Up @@ -529,7 +529,7 @@
},
{
"cell_type": "code",
"execution_count": 177,
"execution_count": 51,
"metadata": {
"id": "DT5FSYliC9wp",
"tags": []
Expand Down Expand Up @@ -7805,7 +7805,7 @@
"\n",
"To summarise, there are the following keypads:\n",
"\n",
"- One directional keypad that you are using. (_diretional-remote 3_)\n",
"- One directional keypad that you are using. (_directional-remote 3_)\n",
"- Two directional keypads that robots are using. (_directional-remotes 1 and 2_)\n",
"- One numeric keypad (on a door) that a robot is using. (_numeric_)\n",
"\n",
Expand Down Expand Up @@ -7853,9 +7853,9 @@
"\n",
"Let's think it through.\n",
"\n",
"Each successive key press on the _numeric_ keypad will require a combination of movement buttons on _direction remote 1_. We want the shortest combinations. \n",
"Each successive keypress on the _numeric_ keypad will require a combination of movement buttons on _direction remote 1_. We want the shortest combinations. \n",
"\n",
"E.g.\n",
"There are finite number of shortest-path ways for getting from any one position to any other position on the keypad. E.g.\n",
"\n",
"```text\n",
"A -> 9: ^^^A\n",
Expand All @@ -7865,9 +7865,9 @@
"2 -> 9: ^^>A, ^>^A, >^^A\n",
"```\n",
"\n",
"We need to start with all shortest combinations, because we don't know which one will be optimal for the next remote.\n",
"When we work out the movements needed on our first directional keypad, we don't know which numeric keypad routes will require the fewest number of directional keypad presses. Consequently, we need to start with _all_ shortest paths for any given numeric keypad combination.\n",
"\n",
"Now, to get from these directions from the next remote we need new mappings for each pair, e.g.\n",
"Now, to get from these directions from the next remote we need the corresponding routes between each pair of keys in the directional remote. E.g.\n",
"\n",
"```text\n",
"A -> >: vA\n",
Expand All @@ -7880,27 +7880,55 @@
"\n",
"These mappings are repeatable onto the next remote, and the remote after that. So we can definitely cache these and reuse them between robots.\n",
"\n",
"An example: if we're at `2` and we want to press `9`, these are the keypresses that are required on each upstream keypad:\n",
"We're given 029A as an example. Let's look at the process of pressing `9`, starting at `2`.\n",
"\n",
"```text\n",
"Start\n",
"Numberic keypad: (2) 9 \n",
"Direction remote 1: (A) > ^ ^ A \n",
"Direction remote 2: (A) v A < ^ A A > A \n",
"Direction remote 3: (A) <vA >^A <v<A >^A >A A vA ^A \n",
"KEYPAD START KEYPRESSES\n",
"-------------------------------------------------------\n",
"Numberic keypad (2) 9 \n",
"Direction remote 1 (A) > ^ ^ A \n",
"Direction remote 2 (A) v A < ^ A A > A \n",
"Direction remote 3 (A) <vA >^A <v<A >^A >A A vA ^A \n",
"```\n",
"\n",
"- So we can map all `numeric keypad` pairs to `direction remote 1` presses. \n",
"- And we can map all `remote n` pairs to `remote n+1` presses.\n",
"- All upstream mappings will end in an `A`, i.e. the button press on the remote that causes the button press on the previous.\n"
"- And we can map all presses on `remote n` to presses on `remote n+1`.\n",
"- All upstream mappings will end in an `A`, i.e. the button press on the remote that causes the button press on the downstream keypad.\n",
"\n",
"#### Solution Approach\n",
"\n",
"I crreate a `KeyboardMapping` class. This class:\n",
"\n",
"- Has a static class attribute for directions (`^v<>`) mapped to point vectors.\n",
"- Has a static class attribute for point vectors mapped to directions.\n",
"- Instantiates based on an array that represents a keypad. We run `_build_keypad_dict()`, which goes through all rows and chars, and:\n",
" - Builds a dict that maps location (point) to key (e.g. `A`, `1`, `<`, etc)\n",
" - Builds a reverse dict that maps key to point.\n",
"- Precomputes the path (in terms of directions `^v<>` and a final `A` press) that is required to move from any key to any other key on the keypad. It does this by running a BFS from every key to every other key.\n",
" - For each button pair, we create a path dictionary, with a key of `(start, end)` buttons, and a value of a list of upstream button presses.\n",
" - For each step along the way, we determine the direction from the valid vector point, and add it to the path list.\n",
" - Note that unlike a typical BFS that exits when we find the goal (i.e. the end button), in this case we want to store all paths that an equal shortest distance. We start by initialising a `best_path_len` to be a long number (I've gone with one longer than what is possible in the keypad). Everytime we reach the end, we determine if the new path is shorter. If it is, we update our `best_path_len`, and add in this path to `all_paths`. If we haven't reached the end, we add the next point / path to our BFS queue.\n",
" - Finally, for each pair, we convert the list of button presses to a string, and add our `A` button press.\n",
"- The method `moves_for_sequence()` is able to take a sequence that is valid for the current keypad type (e.g. `029A` for a numeric keypad) and return the set of moves that repesent the shortest navigational keypad button presses that will result in this sequence.\n",
"\n",
"In this example:\n",
"\n",
"```text\n",
"Numeric pad presses required: 0 -> 2 -> 9 -> A\n",
"Nav 1 pad presses required <^,^< ^^>,^>^,>^^ vvv\n",
"Paths 2 3 1 \n",
"```\n",
"\n",
"So "
]
},
{
"cell_type": "code",
"execution_count": 26,
"execution_count": 65,
"metadata": {},
"outputs": [],
"source": [
"\n",
"class KeypadMapping():\n",
" POINTS_FOR_DIRECTIONS = { \"^\": Point(0, -1), \n",
" \"v\": Point(0, 1), \n",
Expand Down Expand Up @@ -7935,7 +7963,7 @@
" for start in self._button_to_point: # E.g. 7\n",
" for end in self._button_to_point: # E.g. 6\n",
" if start == end:\n",
" paths[start, end] = { \"A\" } # No need to move from a point to itself\n",
" paths[start, end] = [\"A\"] # No need to move from a point to itself\n",
" continue # Go to next end\n",
" \n",
" # Now BFS to get all paths from start to end\n",
Expand Down Expand Up @@ -7979,11 +8007,13 @@
" Output looks like ('<A^A^^>AvvvA', ... )\n",
" \"\"\"\n",
" \n",
" sequential_paths = []\n",
" sequential_paths: list[set] = []\n",
" # Turn a sequence into successive pairs of buttons\n",
" for (start, end) in zip(\"A\" + code, code): # E.g. ('A', '0'), ('0', '2'), ('2', '9'), ('9', 'A')\n",
" sequential_paths.append(self._paths_for_pair[start, end])\n",
" sequential_paths.append(self._paths_for_pair[start, end]) # E.g. {'vv>A', 'v>vA', '>vvA'}\n",
" \n",
" # Now we need the cartesian product of all the paths, and flattened into single strings\n",
" # Now we need the cartesian product of all the paths for each button pair\n",
" # and flatten into single strings\n",
" moves_for_seq = tuple(\"\".join(path) for path in product(*sequential_paths))\n",
" return moves_for_seq\n",
" \n",
Expand All @@ -7996,7 +8026,7 @@
},
{
"cell_type": "code",
"execution_count": 27,
"execution_count": 68,
"metadata": {},
"outputs": [],
"source": [
Expand Down

0 comments on commit 8f1d170

Please sign in to comment.