Add files via upload

This commit is contained in:
Peter Norvig
2021-12-16 10:53:52 -08:00
committed by GitHub
parent a31e9a3f23
commit 368285e511

View File

@@ -2439,43 +2439,75 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"With 250,000 points in the full map, I think it will take several minutes (not hours, not seconds), to find the optimal path with the `search_grid` algorithm. I really wish I had used A* search; I think it would run in just a few seconds."
"With 250,000 points in the full map, I estimated it would take several minutes to run the `search_grid` algorithm. I tested it, and it was 5 minutes. I wasn't satisfied with that, so I copied over the [A* search](https://en.wikipedia.org/wiki/A*_search_algorithm) from my [AoC 2017](https://github.com/norvig/pytudes/blob/main/ipynb/Advent%202017.ipynb) notebook, and supplied ity with the proper functions to make a move, compute the cost of a move, and estimate the distance to the goal (the `h_func` or \"heuristic function\"). A* is guaranteed to find an optimal path if the heuristic function never overestimates the cost from a state to the goal, so I use as an estimate the cost if every grid point along the way had a risk level of 1."
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 4min 21s, sys: 271 ms, total: 4min 22s\n",
"Wall time: 4min 22s\n"
]
},
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"%time answer(15.2, search_grid(repeat_grid(in15, 5)), 2957)"
"from heapq import heappop, heappush\n",
"\n",
"def Astar(start, moves_func, h_func, cost_func) -> Tuple[int, list]:\n",
" \"\"\"Find a (cost, path) tuple for the lowest-cost path from start to goal.\n",
" A goal is any state where h_func(s) == 0.\"\"\"\n",
" frontier = [(h_func(start), start)] # A priority queue, ordered by path_cost(s) + h(s)\n",
" previous = {start: None} # start state has no previous state; other states will\n",
" path_cost = {start: 0} # The cost of the best path to a state.\n",
" Path = lambda s: ([] if (s is None) else Path(previous[s]) + [s])\n",
" while frontier:\n",
" (f, s) = heappop(frontier)\n",
" if h_func(s) == 0:\n",
" return path_cost[s], Path(s)\n",
" for s2 in moves_func(s):\n",
" g = path_cost[s] + cost_func(s, s2)\n",
" if s2 not in path_cost or g < path_cost[s2]:\n",
" heappush(frontier, (g + h_func(s2), s2))\n",
" path_cost[s2] = g\n",
" previous[s2] = s\n",
" \n",
"def Astar_search_grid(grid):\n",
" \"\"\"The total cost of the best path from (0, 0) to bottom-right on grid.\"\"\"\n",
" start, goal = (0, 0), max(grid)\n",
" def moves_func(s): return grid.neighbors(s)\n",
" def h_func(s): return sum(goal) - sum(s)\n",
" def cost_func(s, s2): return grid[s2]\n",
" return Astar(start, moves_func, h_func, cost_func)[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With A* search the run time is greatly improved, from 5 minutes down to about 1 second."
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"answer(15.2, Astar_search_grid(repeat_grid(in15, 5)), 2957)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"OK, 5 minutes wasn't so bad. I may come back and improve on this later (or maybe not).\n",
"\n",
"Gary Grady's drawing represents the risk involved in finding a path that avoids bumping into the ceiling above or the chitons below.\n",
"\n",
"<img src=\"https://pbs.twimg.com/media/FGrU-PKXIAQ6sa8?format=jpg&name=medium\" width=400 title=\"@GaryJGrady\">"
@@ -2492,7 +2524,7 @@
},
{
"cell_type": "code",
"execution_count": 66,
"execution_count": 67,
"metadata": {},
"outputs": [
{
@@ -2513,14 +2545,14 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"- **Part 1:** The puzzle is to parse this hexadecimal transmission into data packets, according to the rules contained in [the instructions](https://adventofcode.com/2021/day/16), and add up all of the version numbers.\n",
"- **Part 1:** The puzzle is to parse this hexadecimal transmission into data packets, according to the rules contained in [the instructions](https://adventofcode.com/2021/day/16), and add up all of the version numbers of the packets.\n",
"\n",
"The gist of [the instructions](https://adventofcode.com/2021/day/16) is to consider the hexadecimal sequence as a bit string, parse the bit string into bit fields, and construct nested packets based on the values of the fields. Here are basic types for `Bits` (bit string) and `Packet`, along with functions to convert from a hexadecimal string to a bit string, and from there to an int: "
"The gist of [the instructions](https://adventofcode.com/2021/day/16) is to consider the hexadecimal sequence as a bit string, divide the bit string into bit fields, and construct nested packets based on the values of the fields. Here are basic types for `Bits` (a bit string) and `Packet` (which contains a version umber `V`, a type ID `T`, and a `contents` field which can be either a number or a list of packets), along with functions to convert from a hexadecimal string to a bit string, and from there to an int: "
]
},
{
"cell_type": "code",
"execution_count": 67,
"execution_count": 68,
"metadata": {},
"outputs": [],
"source": [
@@ -2529,6 +2561,7 @@
"\n",
"def bits_from_hex(hex) -> Bits: \n",
" \"\"\"Convert a hexadecimal string into a bit string, making sure each hex digit is 4 bits.\"\"\"\n",
" # I could have used just `bin(int(hex, 16))`, except that wouldn't left-zero-pad when needed.\n",
" return cat(f'{int(x, 16):04b}' for x in hex)\n",
"\n",
"def int2(bits: Bits) -> int: \n",
@@ -2536,6 +2569,26 @@
" return int(bits, 2)"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'0b11111111'"
]
},
"execution_count": 69,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(int('ff', 16))"
]
},
{
"cell_type": "markdown",
"metadata": {},
@@ -2545,7 +2598,7 @@
},
{
"cell_type": "code",
"execution_count": 68,
"execution_count": 70,
"metadata": {},
"outputs": [],
"source": [
@@ -2595,7 +2648,7 @@
},
{
"cell_type": "code",
"execution_count": 69,
"execution_count": 71,
"metadata": {},
"outputs": [
{
@@ -2604,7 +2657,7 @@
"True"
]
},
"execution_count": 69,
"execution_count": 71,
"metadata": {},
"output_type": "execute_result"
}
@@ -2631,7 +2684,7 @@
},
{
"cell_type": "code",
"execution_count": 70,
"execution_count": 72,
"metadata": {},
"outputs": [],
"source": [
@@ -2667,7 +2720,7 @@
},
{
"cell_type": "code",
"execution_count": 71,
"execution_count": 73,
"metadata": {},
"outputs": [
{
@@ -2676,7 +2729,7 @@
"True"
]
},
"execution_count": 71,
"execution_count": 73,
"metadata": {},
"output_type": "execute_result"
}