Add files via upload
This commit is contained in:
1 parent
8f1a8587f6
commit
d96d2490a3
1 file changed
+386
@@ -0,0 +1,386 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<div align=\"right\" style=\"text-align: right\"><i>Peter Norvig<br>August 2021</i></div>\n",
|
||||
"\n",
|
||||
"# RaceTrack\n",
|
||||
"\n",
|
||||
"From 538's [The Riddler](https://fivethirtyeight.com/features/can-you-zoom-around-the-race-track/) on 6 August 2021:\n",
|
||||
"\n",
|
||||
"> The game of [RaceTrack](https://link.springer.com/chapter/10.1007/978-3-642-13122-6_26) was published by recreational mathematician Martin Gardner in 1973. There have been a few modifications and even some neat [digital versions](https://harmmade.com/vectorracer/#) since then, and it’s high time we had a race here on The Riddler. So without further ado, welcome to the Riddler-opolis 500!\n",
|
||||
">\n",
|
||||
"> You begin at the midpoint of the starting line at the bottom (the thicker border), and your goal is to circumnavigate the race track shown below in a single counterclockwise loop. You’ll be moving from point to point on the grid, without ever venturing into the gray surrounding square or the central circle. If the center is at the origin (with radius 3), the starting point in blue is at (0, -5). The starting line is between (0, -3) and (0, -7).\n",
|
||||
">\n",
|
||||
"> For your first move, you can choose among nine grid points surrounding and including the starting position. From there, you have inertia. So for your second move, you again have nine possible destinations, but they are determined by your current velocity vector. That is, you can maintain your current direction and speed, or you can alter your destination by one point in any direction (horizontally, vertically or diagonally). For example, if your first move was up and to the right, then your possible second moves are shown below, although two of them will cause you to crash into the wall.\n",
|
||||
">\n",
|
||||
"> \n",
|
||||
">\n",
|
||||
"> How quickly can you navigate the track? At no time can your path venture into the wall. (Being tangent to the wall is allowed, as is being on a grid point along a wall.)\n",
|
||||
">\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Defining Points and the Track\n",
|
||||
"\n",
|
||||
"First some imports: "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"from typing import List, Tuple, Iterator\n",
|
||||
"import math"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now define a `Point` in the 2-D plane as a complex number, and a `Path` as a list of points. Then define some global variables: the points in the `track`; the `finish` line; the `start` point; the `zero` vector; and the allowable `deltas` (the nine possible changes on each move)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"Point = Vector = complex\n",
|
||||
"Path = List[Point]\n",
|
||||
"def X(point) -> float: return point.real\n",
|
||||
"def Y(point) -> float: return point.imag\n",
|
||||
"\n",
|
||||
"track = {Point(x, y) for x in range(-7, 8) for y in range(-7, 8) if abs(Point(x, y)) >= 3}\n",
|
||||
"finish = [Point(0, -3), Point(0, -7)]\n",
|
||||
"start = sum(finish) / 2 # midpoint of finish line\n",
|
||||
"zero = Vector(0, 0)\n",
|
||||
"deltas = [Vector(x, y) for y in (1, 0, -1) for x in (-1, 0, 1) ]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Visualization\n",
|
||||
"\n",
|
||||
"I think it will be helpful to introduce a way to visualize the track and the path(s) on it:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def plot(paths=(), track=track, start=start, finish=finish):\n",
|
||||
" \"\"\"Plot the track and any paths, along with the start and finish line.\"\"\"\n",
|
||||
" fig, ax = plt.subplots()\n",
|
||||
" plt.xticks([]); plt.yticks([])\n",
|
||||
" ax.set_aspect('equal');\n",
|
||||
" ax.add_artist(plt.Circle((0, 0), 3, alpha=0.2, color='k'))\n",
|
||||
" ax.plot(*XY(track), 'k,' ) # grid points\n",
|
||||
" for path in paths:\n",
|
||||
" ax.plot(*XY(path), 'o-') # paths\n",
|
||||
" ax.plot(*XY([start]), 'bD') # start\n",
|
||||
" ax.plot(*XY(finish), 'b:') # finish\n",
|
||||
" lengths = {len(path) - 1 for path in paths}\n",
|
||||
" plt.title(f'{len(paths)} paths, lengths {lengths}')\n",
|
||||
"\n",
|
||||
"def XY(points): return [X(p) for p in points], [Y(p) for p in points]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Here is a single path consisting of the first move from the start point:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"path = [start, Point(1, -4)]\n",
|
||||
"plot([path])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Here are nine paths for the second move (two of which crash into the circle in the center):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def velocity(path) -> Vector:\n",
|
||||
" \"\"\"Velocity of the car at the end of the path.\"\"\"\n",
|
||||
" return zero if len(path) == 1 else path[-1] - path[-2] "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"plot([path + [Point(path[-1] + velocity(path) + d)] for d in deltas])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Complete Paths and Legal Moves\n",
|
||||
"\n",
|
||||
"For our circle-in-the-middle track, I can say that a path `is_complete` if the path goes from the fourth quadrant to the first, second, third, and back to the fourth:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def Q1(p) -> bool: return X(p) >= 0 and Y(p) >= 0 # upper right\n",
|
||||
"def Q2(p) -> bool: return X(p) < 0 and Y(p) >= 0 # upper left\n",
|
||||
"def Q3(p) -> bool: return X(p) < 0 and Y(p) < 0 # lower left \n",
|
||||
"def Q4(p) -> bool: return X(p) >= 0 and Y(p) < 0 # lower right\n",
|
||||
" \n",
|
||||
"def is_complete(path, regions=(Q4, Q1, Q2, Q3, Q4)) -> bool:\n",
|
||||
" \"\"\"Does the path complete a tour of the regions, in order?\"\"\"\n",
|
||||
" for p in path:\n",
|
||||
" if regions[0](p):\n",
|
||||
" regions = regions[1:]\n",
|
||||
" return not regions"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now I'll define the `legal_moves` that can be made. Given a path, `legal_moves(path)` yields `(Point, Vector)` tuples giving every possible new point position and velocity. Each point must be a point on the track (not inside the circle), the velocity vector can differ from the previous velocity vector only by an allowable delta, and the line from the previous final point on the path to the new point must not intersect the circle. \n",
|
||||
"\n",
|
||||
"I have inserted a hack here: to make sure that paths start off going counterclockwise, for the first two steps I insist that the deltas be either up or to the right or zero.\n",
|
||||
"\n",
|
||||
"I got the calculation for `intersects_circle` from several posts on math overflow."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def legal_moves(path, track=track, deltas=deltas) -> Iterator[Tuple[Point, Vector]]:\n",
|
||||
" \"\"\"What (point, velocity) pairs can be reached in one step from this path?\"\"\"\n",
|
||||
" if len(path) <= 2: # Make sure we start counterclockwwise\n",
|
||||
" deltas = [Point(x, y) for y in (0, 1) for x in (0, 1)]\n",
|
||||
" p, v = path[-1], velocity(path)\n",
|
||||
" for d in deltas:\n",
|
||||
" new_p = p + v + d\n",
|
||||
" new_v = v + d\n",
|
||||
" if new_p in track and not intersects_circle(p, new_p, 3, zero):\n",
|
||||
" yield new_p, new_v\n",
|
||||
" \n",
|
||||
"def intersects_circle(p, q, r, c):\n",
|
||||
" \"\"\"Does a line from p to q intersect a circle of radius r at center c?\"\"\"\n",
|
||||
" if p == q:\n",
|
||||
" return abs(c - p) < r\n",
|
||||
" norm = (q - p) / abs(q - p)\n",
|
||||
" v = abs(X(norm) * Y(c - p) - Y(norm) * X(c - p)) # Norm of the 2D cross-product\n",
|
||||
" return (v < r)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Finding a Fastest Path\n",
|
||||
"\n",
|
||||
"I can use a breadth-first search, adding each legal move to each path until I find path(s) that are complete. \n",
|
||||
"\n",
|
||||
"I keep track of a `frontier`, which is a mapping of `{(point, velocity): path}` for all paths of the longest length explored so far. The reason for this is that there may be an exponential number of paths that arrive at the some position with the same velocity in the same number of moves. But none of them will have any advantage in reaching the finish line ahead of the others, so I only need to keep one of them. In the end, I return the completed paths I have found, but there may be many other paths that are not returned, because I only kept one for each `(point, velocity)` pair along the way. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def search(path=[start]) -> Path:\n",
|
||||
" \"\"\"Find the shortest possible complete path(s).\"\"\"\n",
|
||||
" frontier = {(path[-1], velocity(path)): path}\n",
|
||||
" completed = []\n",
|
||||
" while not completed:\n",
|
||||
" frontier = {(p, v): path + [p] \n",
|
||||
" for path in frontier.values() \n",
|
||||
" for p, v in legal_moves(path)}\n",
|
||||
" completed = [path for path in frontier.values() if is_complete(path)]\n",
|
||||
" return completed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"plot(search([start]))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To give you an idea of some of the paths that were not shown, here are completions of a path called `tight`:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"tight = [start, Point(1, -4), Point(2, -3), Point(3, -1), Point(3, 1), Point(2, 3)]\n",
|
||||
"plot(search(tight))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Submitting your Answer\n",
|
||||
"\n",
|
||||
"I'll need some help to put my answers into the form requested by The Riddler:\n",
|
||||
"\n",
|
||||
"> Finally, submitting your answer can be tricky work. Please be sure to submit both your total time, as well as your sequence of moves. Each move should be assigned a digit from 1 through 9, corresponding to the nine possible destinations of the move:\n",
|
||||
">\n",
|
||||
"> 1 2 3\n",
|
||||
"> 4 5 6\n",
|
||||
"> 7 8 9"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def decode_path(path) -> List[int]:\n",
|
||||
" \"\"\"The digits representing the moves (as coded changes in acceleration).\"\"\"\n",
|
||||
" return [deltas.index(velocity(path[:i + 1]) - velocity(path[:i])) + 1\n",
|
||||
" for i in range(1, len(path))]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[[3, 3, 1, 7, 7, 5, 7, 8, 9, 9, 3, 6],\n",
|
||||
" [3, 3, 1, 7, 7, 5, 7, 8, 9, 9, 3, 9],\n",
|
||||
" [3, 3, 1, 7, 7, 5, 7, 8, 9, 9, 3, 3],\n",
|
||||
" [3, 3, 1, 7, 7, 5, 7, 8, 9, 9, 6, 3],\n",
|
||||
" [3, 3, 1, 7, 7, 5, 7, 8, 9, 9, 6, 6],\n",
|
||||
" [3, 5, 2, 4, 4, 8, 8, 7, 9, 6, 6, 3],\n",
|
||||
" [3, 5, 2, 4, 4, 8, 8, 7, 9, 6, 6, 6],\n",
|
||||
" [3, 5, 2, 4, 4, 8, 8, 7, 9, 6, 6, 9],\n",
|
||||
" [3, 5, 2, 4, 4, 8, 8, 7, 9, 9, 3, 6],\n",
|
||||
" [3, 5, 2, 4, 4, 8, 8, 7, 9, 9, 3, 9],\n",
|
||||
" [3, 5, 2, 4, 4, 8, 8, 7, 9, 9, 3, 3],\n",
|
||||
" [3, 5, 2, 4, 4, 8, 8, 7, 9, 9, 6, 3]]"
|
||||
]
|
||||
},
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"[decode_path(path) for path in search() + search(tight)]"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
Reference in new issue
Block a user