From 0ce53637fd003b0aceede2b8119fc2efadec1b5e Mon Sep 17 00:00:00 2001 From: Peter Norvig Date: Tue, 10 Aug 2021 01:35:18 -0700 Subject: [PATCH] Add files via upload --- ipynb/RaceTrack.ipynb | 347 +++++++++++++++++++++++++----------------- 1 file changed, 209 insertions(+), 138 deletions(-) diff --git a/ipynb/RaceTrack.ipynb b/ipynb/RaceTrack.ipynb index ed880d6..5c3ee97 100644 --- a/ipynb/RaceTrack.ipynb +++ b/ipynb/RaceTrack.ipynb @@ -22,16 +22,14 @@ ">\n", "\n", "\n", - "# Defining Points and the Track\n", + "# Defining Points and Vectors\n", "\n", - "I will start by defining the following:\n", + "We will need to represent 2-D points on a grid, as well as 2-D vectors for velocity and acceleration. I will use the following choices:\n", "- `Point(x, y)`: a point in the 2-D plane, implemented as a complex number.\n", - "- `Path`: a list of points representing the car's positions as it moves.\n", - "- `track`: all the legal grid points on the race track.\n", - "- `start`: the single starting point.\n", - "- `zero`: a zero vector (your starting velocity vector).\n", - "- `radius`: the radius of the central circle (whose center is defined as the origin).\n", + "- `Vector(x, y)`: a vector in the 2-D plane, also implemented as a complex number.\n", + "- `Path`: a list of points (representing the car's positions as it moves).\n", "- `X(point)`, `Y(point)`: the x- and y-coordinates of a point, respectively.\n", + "- `zero`: a zero vector (the car's starting velocity vector).\n", "- `accelerations`: the nine possible acceleration vectors (to change the car's velocity), mapped to the digit number that The Riddler uses to identify them.\n" ] }, @@ -44,17 +42,14 @@ "import matplotlib.pyplot as plt\n", "from typing import List, Tuple, Dict, Set\n", "\n", - "Point = Vector = complex\n", - "Path = List[Point]\n", - "track = {Point(x, y) for x in range(-7, 8) for y in range(-7, 8) \n", - " if abs(Point(x, y)) >= 3}\n", - "start = Point(0, -5)\n", - "zero = Vector(0, 0)\n", - "radius = 3\n", + "Point = Vector = complex\n", + "Path = List[Point]\n", "\n", "def X(point) -> float: \"x-coordinate\"; return point.real\n", "def Y(point) -> float: \"y-coordinate\"; return point.imag\n", "\n", + "zero = Vector(0, 0)\n", + "\n", "accelerations = {Vector(-1, 1): 1, Vector(0, 1): 2, Vector(1, 1): 3, \n", " Vector(-1, 0): 4, Vector(0, 0): 5, Vector(1, 0): 6, \n", " Vector(-1, -1):7, Vector(0, -1):8, Vector(1, -1):9}" @@ -64,9 +59,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Visualization\n", + "# Defining the Track\n", "\n", - "I think it will be helpful to be able to visualize paths on the racetrack, so I'll define a function to do that now, even before attempting to find solutions:" + "I want to solve the particular problem posed by The Riddler, but I also want some flexibility to race on differently-shaped race tracks. I'll define the class `Track` as a subclass of a `set` (of `Point`s), with some additional attributes:\n", + "- `track.start`: the single starting point.\n", + "- `track.finish`: the two endpoints of the finish line.\n", + "- `track.radius`: the radius of the central circle (whose center is defined as the origin).\n", + "\n", + "The points in the track are all those points on a 15x15 square except the ones that fall inside the circle's radius.\n" ] }, { @@ -75,15 +75,43 @@ "metadata": {}, "outputs": [], "source": [ - "def plot(paths=(), finish=[Point(0, -3), Point(0, -7)]):\n", + "class Track(Set):\n", + " def __init__(self, items, **kwds):\n", + " self.update(items)\n", + " self.__dict__.update(kwds)\n", + "\n", + "radius = 3\n", + "track = Track({Point(x, y) for x in range(-7, 8) for y in range(-7, 8) \n", + " if abs(Point(x, y)) >= radius}, \n", + " start=Point(0, -5), \n", + " finish=[Point(0, -3), Point(0, -7)], \n", + " radius=radius)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Visualization\n", + "\n", + "I think it will be helpful to be able to visualize paths on the track, so I'll define a function to do that now, even before attempting to find solutions:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def plot(paths=(), track=track):\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=1/3, color='k', ec='w'))\n", + " ax.set_aspect('equal')\n", + " ax.add_artist(plt.Circle((0, 0), track.radius, alpha=1/3, color='k', ec='w'))\n", " ax.plot(*XY(track), 'k,' ) # grid points\n", - " ax.plot(*XY([start]), 'ks', ms=10) # start point\n", - " ax.plot(*XY(finish), 'k:') # finish line\n", + " ax.plot(*XY([track.start]), 'ks', ms=10) # start point\n", + " ax.plot(*XY(track.finish), 'k:') # finish line\n", " for path in paths: # paths\n", " ax.plot(*XY(path), 'o-') \n", " plt.title(f'{len(paths)} paths of {set(len(path) - 1 for path in paths)} moves')\n", @@ -99,14 +127,15 @@ "source": [ "Below is my recreation of The Riddler's diagram of the first two moves. Here and throughout I'll use the convention:\n", "- `p` is a point indicating a move\n", - " - In this example, `p` is up and right from the start to `Point(1, -4)`, so the velocity is `Vector(1, 1)`.\n", "- `p1` is where the next point would be if the velocity remains constant.\n", - "- `p2` is where the next point actually is with acceleration applied to change the velocity." + "- `p2` is where the next point actually is with acceleration applied to change the velocity.\n", + "\n", + "In this example, `p` is up and right from the start to `Point(1, -4)`, so the velocity is `Vector(1, 1)`." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -125,7 +154,7 @@ "p1 = p + Vector(1, 1)\n", "p2s = [p1 + a for a in accelerations]\n", "\n", - "plot([[start, p, p2] for p2 in p2s])" + "plot([[track.start, p, p2] for p2 in p2s])" ] }, { @@ -134,21 +163,21 @@ "source": [ "# Circumnavigating the Track\n", "\n", - "The goal of the race is to circumnavigate the center circle. I can test for that by checking if the path goes from the fourth [quadrant](https://mathworld.wolfram.com/Quadrant.html) to the first, second, third, and back to the fourth. The predicate `is_complete(path)` does that.\n", + "The goal of the race is to circumnavigate the center circle. I can test if a path goes from the fourth [quadrant](https://mathworld.wolfram.com/Quadrant.html) to the first, second, third, and back to the fourth. The predicate `is_solution(path)` does that.\n", "\n", "
\n", "\n", "\n", - "If you wanted to generalize this to other race tracks, you could change the definition of `quadrant` (there could be more than 4 \"quadrants,\" and they could have any shape), and change the `goals` in `is_complete`." + "If you wanted to generalize this to other race tracks, you could change the definition of `quadrant` (there could be more than 4 \"quadrants,\" and they could have any shape), and change the `goals` in `is_solution`." ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ - "def is_complete(path, goals=(4, 1, 2, 3, 4)) -> bool:\n", + "def is_solution(path, goals=(4, 1, 2, 3, 4)) -> bool:\n", " \"\"\"Does the path go through all the goal quadrants in the prescribed order?\"\"\"\n", " i = 0 # Index of next goal to be achieved\n", " for p in path:\n", @@ -160,10 +189,7 @@ "\n", "def quadrant(p: Point) -> int: \n", " \"\"\"What quadrant of the 2-D plane is this point in?\"\"\"\n", - " if X(p) >= 0:\n", - " return 1 if Y(p) >= 0 else 4\n", - " else:\n", - " return 2 if Y(p) >= 0 else 3" + " return (1 if Y(p) >= 0 else 4) if X(p) >= 0 else (2 if Y(p) >= 0 else 3)" ] }, { @@ -172,43 +198,12 @@ "source": [ "# Legal Moves\n", "\n", - "I'm considering how to solve for our specific central-circle-track, and also make the code general enough that it can handle other tracks. I'll do that by splitting up responsibility for determining legal moves:\n", - "- `all_moves(path)` is general; it considers points with all 9 accelerations and returns the points that are on the track.\n", + "As stated earlier, I want to solve the specific circular track, and also make the code general enough that it can handle other tracks. I'll do that by splitting up responsibility for determining legal moves:\n", + "- `all_moves(path)` is general; it returns the points on the track that can be reached by applying the 9 accelerations.\n", "- `circular_track_moves(path)` is specific; it limits moves in the following ways:\n", " - It won't make moves that stay in one place (they are legal, but wasteful and not needed on this track).\n", " - It won't pass from the fourth quadrant backwards over the finish line into the third (legal, but wasteful).\n", - " - It won't let a move intersect the central circle (even if the start and end points of the move are outside the circle).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "def all_moves(path, track=track) -> Set[Point]:\n", - " \"\"\"Moves with any allowable acceleration that end up on the track.\"\"\"\n", - " p1 = path[-1] + velocity(path)\n", - " return {(p1 + a) for a in accelerations} & track\n", - " \n", - "def circular_track_moves(path) -> Set[Point]:\n", - " \"\"\"Reasonable moves on the circular track.\"\"\"\n", - " p = path[-1]\n", - " return {p2 for p2 in all_moves(path)\n", - " if p2 != p\n", - " and not (quadrant(p) == 4 and quadrant(p2) == 3) # Don't go backwards\n", - " and not intersects_circle(p, p2)}\n", - "\n", - "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": "markdown", - "metadata": {}, - "source": [ - "The math for solving for the intersection of a line segment and a circle looks [complicated](https://stackoverflow.com/questions/6091728/line-segment-circle-intersection), so instead I just define N+1 points along the line from point *p* to point *p2* and check if any of those points is within the radius of the circle (which by definition is centered on the origin). If N is too small this could miss an intersection, but that shouldn't be a problem for our uses." + " - It won't let a move's line segment intersect the central circle (even if the start and end points of the move are on valid grid points outside of the circle).\n" ] }, { @@ -217,9 +212,40 @@ "metadata": {}, "outputs": [], "source": [ - "def intersects_circle(p: Point, p2: Point, radius=radius) -> bool:\n", + "def all_moves(path, track=track) -> Set[Point]:\n", + " \"\"\"Moves with any allowable acceleration that end up on the track.\"\"\"\n", + " p1 = path[-1] + velocity(path)\n", + " return {(p1 + a) for a in accelerations} & track\n", + " \n", + "def circular_track_moves(path, track=track) -> Set[Point]:\n", + " \"\"\"Reasonable moves on the circular track.\"\"\"\n", + " p = path[-1]\n", + " return {p2 for p2 in all_moves(path, track)\n", + " if p2 != p\n", + " and not (quadrant(p) == 4 and quadrant(p2) == 3) # Don't go backwards\n", + " and not intersects_circle(p, p2, track)}\n", + "\n", + "def velocity(path) -> Vector:\n", + " \"\"\"Velocity of the car when it is at the end of the path.\"\"\"\n", + " return zero if len(path) == 1 else path[-1] - path[-2] " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The math for solving for the intersection of a line segment and a circle [looks complicated](https://stackoverflow.com/questions/6091728/line-segment-circle-intersection), so instead I just define N+1 points along the line from point *p* to point *p2* and check if any of those points is within the radius of the circle (which by definition is centered on the origin). If N is too small this could miss an intersection, but that shouldn't be a problem for our uses." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def intersects_circle(p: Point, p2: Point, track=track) -> bool:\n", " \"\"\"Does any point w on the line from p to p2 fall within radius of center?\"\"\"\n", - " return any(abs(w) < radius for w in waypoints(p, p2))\n", + " return any(abs(w) < track.radius for w in waypoints(p, p2))\n", "\n", "def waypoints(p, p2, N=20) -> List[Point]:\n", " \"\"\"All the points that are i/N of the way from p to p2\"\"\"\n", @@ -233,7 +259,7 @@ "source": [ "# A Frontier of Possible Paths\n", "\n", - "Now I want to expand paths by adding legal moves to the end until I find complete path(s). I could keep all my paths in a `list`, but there will be an exponential number of them (up to 9n paths of length *n* and I estimate *n* will be around 10 to 13).\n", + "Now I want to expand paths by adding legal moves to the end until I find solution(s)–paths that circumnavigate the circle. I could keep all my paths in a `list`, but there will be an exponential number of them (up to 9n paths of length *n* and I estimate *n* will be around 10 to 13).\n", "\n", "Instead I will keep track of a *frontier*, which I define as a mapping of `{(endpoint, velocity): path}`. The idea is that there may be many paths that arrive at the some endpoint with the same velocity in the same number of moves. I only need to keep one of them, because they can all be continued in exactly the same ways.\n", " \n", @@ -242,56 +268,57 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "Frontier = Dict[Tuple[Point, Vector], Path]\n", "\n", - "def expand(frontier, legal_moves=circular_track_moves) -> Frontier:\n", + "def expand(frontier, legal_moves=circular_track_moves, track=track) -> Frontier:\n", " \"\"\"The {(endpoint, velocity): path} frontier extended one move in all legal ways.\"\"\"\n", " return {(p, velocity([path[-1], p])): path + [p] \n", " for path in frontier.values() \n", - " for p in legal_moves(path)}" + " for p in legal_moves(path, track)}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Searching for Fastest Complete Paths\n", + "# Searching for the Fastest Solutions\n", "\n", - "Now all I have to do to solve the problem is repeatedly expand the frontier until some path(s) are complete. The first completed paths found are guaranteed to be the fastest (i.e., have the fewest moves), because we are expanding one move at a time. In the end, I return a list of all the completed paths in the frontier, but there may be many other paths that are not returned, because the frontier only keeps one path for each `(endpoint, velocity)` pair, and there are only so many ways to cross the finish line. " + "Now all I have to do to solve the problem is repeatedly expand the frontier until one or more solutions are found. The first solutions found are guaranteed to be the fastest (i.e., they are the paths with the fewest possible moves), because we are expanding paths one move at a time, and the previous time did not find any solutions. In the end, I return a list of all the solutions in the frontier, but there may be many other paths that are not returned, because the frontier only keeps one path for each `(endpoint, velocity)` pair, and there are only so many ways to cross the finish line. " ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ - "def search(path=[start], legal_moves=circular_track_moves) -> List[Path]:\n", - " \"\"\"Find the shortest possible complete path(s).\"\"\"\n", + "def search(track=track, path=None, legal_moves=circular_track_moves) -> List[Path]:\n", + " \"\"\"Find the shortest possible solution paths.\"\"\"\n", + " if path is None: path = [track.start]\n", " frontier = {(path[-1], velocity(path)): path}\n", - " complete_paths = []\n", - " while not complete_paths:\n", - " frontier = expand(frontier, legal_moves)\n", - " complete_paths = list(filter(is_complete, frontier.values()))\n", - " return complete_paths" + " solutions = []\n", + " while not solutions:\n", + " frontier = expand(frontier, legal_moves, track)\n", + " solutions = list(filter(is_solution, frontier.values()))\n", + " return solutions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Solutions\n", + "# Solutions!\n", "\n", "We are ready to solve the problem:" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -306,7 +333,7 @@ } ], "source": [ - "solutions = search([start])\n", + "solutions = search(track)\n", "\n", "plot(solutions)" ] @@ -315,7 +342,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We see that the fastest solution is 12 moves, and there are at least 7 ways to get there (with other ways discarded).\n", + "We see that the fastest solution is 12 moves, and there are at least 7 ways to get there (with perhaps other ways discarded).\n", "\n", "# Submitting your Answer\n", "\n", @@ -332,7 +359,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -343,7 +370,7 @@ " return [accelerations[velocity(path[:i + 1]) - velocity(path[:i])]\n", " for i in range(1, len(path))]\n", "\n", - "def path_from_digits(digits, start=start) -> Path:\n", + "def path_from_digits(digits, start=track.start) -> Path:\n", " \"\"\"The path that the digits represent.\"\"\"\n", " v = zero # Starting velocity\n", " path = [start]\n", @@ -355,7 +382,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -370,7 +397,7 @@ " [3, 3, 1, 7, 7, 5, 7, 8, 9, 9, 3, 3]]" ] }, - "execution_count": 11, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -390,7 +417,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -458,39 +485,39 @@ "openings = [3, 3], [3, 5], [3, 6], [6, 2], [6, 3], [3, 5, 2, 4, 4]\n", "\n", "for digits in openings:\n", - " plot(search(path_from_digits(digits)))" + " plot(search(track, path=path_from_digits(digits)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Tests and Visualizations\n", + "# Visualizations and Tests\n", "\n", - "To gain more confidence in the code, here are some unit tests and visualizations:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "def test_intersects(expected: bool, segments: List[Path]):\n", - " \"\"\"Test if [p, q] segments get the expected result from `intersects_circle`.\"\"\"\n", - " plot(segments, finish=[])\n", - " for p, q in segments:\n", - " assert intersects_circle(p, q) is expected" + "To gain more confidence in the code, here are some visualizations and unit tests:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, + "outputs": [], + "source": [ + "def test_intersects(expected: bool, segments: List[Path]):\n", + " \"\"\"Test if [p, q] segments get the expected result from `intersects_circle`.\"\"\"\n", + " plot(segments)\n", + " for p, q in segments:\n", + " assert intersects_circle(p, q) is expected" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -510,12 +537,12 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -535,12 +562,12 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -552,7 +579,7 @@ "source": [ "# Waypoints on a line segment that are checked to see if they are outside the circle\n", "p, q = Point(-7, 7), Point(7, 0)\n", - "plot([waypoints(p, q)], finish=[])\n", + "plot([waypoints(p, q)])\n", "assert not intersects_circle(p, q)" ] }, @@ -566,7 +593,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -631,7 +658,7 @@ } ], "source": [ - "frontier = {(start, zero): [start]}\n", + "frontier = {(track.start, zero): [track.start]}\n", "\n", "for i in range(6):\n", " frontier = expand(frontier)\n", @@ -642,12 +669,64 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Additional tests:" + "# A Different Track\n", + "\n", + "Although the code here is not ready to handle large, arbitrary-shaped tracks, it can handle some small variations as is, and other variations with some tweaking. Here I define `track2` to be a track with a larger central circle, and a circular ring of valid points around the circle rather than a full rectangular grid:" ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[6, 6, 3, 1, 1, 2, 4, 7, 4, 7, 7, 8, 9, 9, 9, 9, 5, 3, 6, 3, 3],\n", + " [6, 6, 3, 1, 1, 2, 4, 7, 4, 7, 7, 8, 9, 9, 9, 9, 5, 3, 3, 6, 6],\n", + " [6, 6, 3, 1, 1, 2, 4, 7, 4, 7, 7, 8, 9, 9, 9, 9, 5, 3, 3, 6, 3]]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "radius2 = 10\n", + "track2 = Track({Point(x, y) for x in range(-14, 15) for y in range(-14, 15) \n", + " if radius2 <= abs(Point(x, y)) < 13}, \n", + " start=Point(0, -12), \n", + " finish=[Point(0, -radius2), Point(0, -12)], \n", + " radius=radius2)\n", + "\n", + "solutions2 = search(track2)\n", + " \n", + "plot(solutions2, track=track2)\n", + "\n", + "[digits_from_path(path) for path in solutions2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Additional tests:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -656,21 +735,21 @@ "'tests pass'" ] }, - "execution_count": 18, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "path1 = [start, Point(1, -4)] # First move\n", + "path1 = [track.start, Point(1, -4)] # First move\n", "\n", - "assert start == Point(0, -5) == 0-5j\n", - "assert X(start) == 0 and Y(start) == -5 \n", - "assert velocity([start]) == 0\n", + "assert track.start == Point(0, -5) == 0-5j\n", + "assert X(track.start) == 0 and Y(track.start) == -5 \n", + "assert velocity([track.start]) == 0\n", "assert velocity(path1) == Vector(1, 1)\n", "assert XY(path1) == ([0, 1], [-5, -4])\n", "\n", - "assert quadrant(start) == 4\n", + "assert quadrant(track.start) == 4\n", "assert quadrant(Point(1, 2)) == 1\n", "assert quadrant(Point(-5, 4)) == 2\n", "assert quadrant(Point(-1, -1)) == 3\n", @@ -680,29 +759,21 @@ " 0j,1+2j,2+4j,3+6j,4+8j,5+10j,6+12j,7+14j,8+16j,9+18j,10+20j]\n", "\n", "# There are 9 moves from the start point\n", - "assert all_moves([start]) == {-1-4j, -1-5j, -1-6j, \n", - " 0-4j, 0-5j, 0-6j, \n", - " 1-4j, 1-5j, 1-6j}\n", + "assert all_moves([track.start]) == {\n", + " -1-4j, -1-5j, -1-6j, \n", + " 0-4j, 0-5j, 0-6j, \n", + " 1-4j, 1-5j, 1-6j}\n", "\n", "# But 3 moves are backwards and 1 stays in the same place; those are disallowed\n", - "assert circular_track_moves([start]) == {0-6j, 1-6j, 1-5j, 0-4j, 1-4j}\n", - "assert expand({(start, zero): [start]}) == {\n", + "assert circular_track_moves([track.start]) == {0-6j, 1-6j, 1-5j, 0-4j, 1-4j}\n", + "assert expand({(track.start, zero): [track.start]}) == {\n", " (0-6j, 0-1j): [0-5j, 0-6j],\n", " (1-6j, 1-1j): [0-5j, 1-6j],\n", " (1-5j, 1+0j): [0-5j, 1-5j],\n", " (0-4j, 0+1j): [0-5j, 0-4j],\n", " (1-4j, 1+1j): [0-5j, 1-4j]}\n", "\n", - "def is_valid_path(path, legal_moves=circular_track_moves) -> bool:\n", - " \"\"\"A valid path is complete, starts at start, stays on track, and has all legal moves.\"\"\"\n", - " return (is_complete(path) \n", - " and path[0] == start\n", - " and set(path) <= track\n", - " and all(path[i] in legal_moves(path[:i]) \n", - " for i in range(1, len(path))))\n", - "\n", "for path in solutions:\n", - " assert is_valid_path(path)\n", " digits = digits_from_path(path)\n", " assert path == path_from_digits(digits_from_path(path)) # Inverses\n", " assert digits == digits_from_path(path_from_digits(digits)) # Inverses\n",