diff --git a/ipynb/Advent-2024.ipynb b/ipynb/Advent-2024.ipynb
index ff90cc6..eacf85b 100644
--- a/ipynb/Advent-2024.ipynb
+++ b/ipynb/Advent-2024.ipynb
@@ -136,7 +136,7 @@
{
"data": {
"text/plain": [
- "Puzzle 1.1: .0002 seconds, answer 1830467 ok"
+ "Puzzle 1.1: .000 seconds, answer 1830467 ok"
]
},
"execution_count": 8,
@@ -181,7 +181,7 @@
{
"data": {
"text/plain": [
- "Puzzle 1.2: .0001 seconds, answer 26674158 ok"
+ "Puzzle 1.2: .000 seconds, answer 26674158 ok"
]
},
"execution_count": 11,
@@ -284,7 +284,7 @@
{
"data": {
"text/plain": [
- "Puzzle 2.1: .0004 seconds, answer 257 ok"
+ "Puzzle 2.1: .000 seconds, answer 257 ok"
]
},
"execution_count": 16,
@@ -334,7 +334,7 @@
{
"data": {
"text/plain": [
- "Puzzle 2.2: .0022 seconds, answer 328 ok"
+ "Puzzle 2.2: .002 seconds, answer 328 ok"
]
},
"execution_count": 19,
@@ -419,7 +419,7 @@
{
"data": {
"text/plain": [
- "Puzzle 3.1: .0006 seconds, answer 156388521 ok"
+ "Puzzle 3.1: .001 seconds, answer 156388521 ok"
]
},
"execution_count": 24,
@@ -463,7 +463,7 @@
{
"data": {
"text/plain": [
- "Puzzle 3.2: .0004 seconds, answer 75920122 ok"
+ "Puzzle 3.2: .000 seconds, answer 75920122 ok"
]
},
"execution_count": 27,
@@ -553,7 +553,7 @@
{
"data": {
"text/plain": [
- "Puzzle 4.1: .0331 seconds, answer 2401 ok"
+ "Puzzle 4.1: .033 seconds, answer 2401 ok"
]
},
"execution_count": 32,
@@ -608,7 +608,7 @@
{
"data": {
"text/plain": [
- "Puzzle 4.2: .0273 seconds, answer 1822 ok"
+ "Puzzle 4.2: .027 seconds, answer 1822 ok"
]
},
"execution_count": 35,
@@ -738,7 +738,7 @@
{
"data": {
"text/plain": [
- "Puzzle 5.1: .0007 seconds, answer 5762 ok"
+ "Puzzle 5.1: .001 seconds, answer 5762 ok"
]
},
"execution_count": 41,
@@ -823,7 +823,7 @@
{
"data": {
"text/plain": [
- "Puzzle 5.2: .0008 seconds, answer 4130 ok"
+ "Puzzle 5.2: .001 seconds, answer 4130 ok"
]
},
"execution_count": 46,
@@ -923,7 +923,7 @@
{
"data": {
"text/plain": [
- "Puzzle 6.1: .0016 seconds, answer 5329 ok"
+ "Puzzle 6.1: .002 seconds, answer 5329 ok"
]
},
"execution_count": 52,
@@ -993,7 +993,7 @@
{
"data": {
"text/plain": [
- "Puzzle 6.2: 1.9960 seconds, answer 2162 ok"
+ "Puzzle 6.2: 1.968 seconds, answer 2162 ok"
]
},
"execution_count": 55,
@@ -1139,7 +1139,7 @@
{
"data": {
"text/plain": [
- "Puzzle 7.1: .0137 seconds, answer 1985268524462 ok"
+ "Puzzle 7.1: .014 seconds, answer 1985268524462 ok"
]
},
"execution_count": 64,
@@ -1181,7 +1181,7 @@
{
"data": {
"text/plain": [
- "Puzzle 7.2: .8158 seconds, answer 150077710195188 ok"
+ "Puzzle 7.2: .801 seconds, answer 150077710195188 ok"
]
},
"execution_count": 67,
@@ -1229,7 +1229,7 @@
{
"data": {
"text/plain": [
- "Puzzle 7.2: .6577 seconds, answer 150077710195188 ok"
+ "Puzzle 7.2: .656 seconds, answer 150077710195188 ok"
]
},
"execution_count": 70,
@@ -1323,7 +1323,7 @@
{
"data": {
"text/plain": [
- "Puzzle 8.1: .0029 seconds, answer 220 ok"
+ "Puzzle 8.1: .003 seconds, answer 220 ok"
]
},
"execution_count": 75,
@@ -1378,7 +1378,7 @@
{
"data": {
"text/plain": [
- "Puzzle 8.1: .0027 seconds, answer 220 ok"
+ "Puzzle 8.1: .003 seconds, answer 220 ok"
]
},
"execution_count": 78,
@@ -1400,7 +1400,7 @@
{
"data": {
"text/plain": [
- "Puzzle 8.2: .0030 seconds, answer 813 ok"
+ "Puzzle 8.2: .003 seconds, answer 813 ok"
]
},
"execution_count": 79,
@@ -1513,7 +1513,7 @@
{
"data": {
"text/plain": [
- "Puzzle 9.1: .0202 seconds, answer 6332189866718 ok"
+ "Puzzle 9.1: .020 seconds, answer 6332189866718 ok"
]
},
"execution_count": 85,
@@ -1593,7 +1593,7 @@
{
"data": {
"text/plain": [
- "Puzzle 9.2: 2.7791 seconds, answer 6353648390778 ok"
+ "Puzzle 9.2: 2.731 seconds, answer 6353648390778 ok"
]
},
"execution_count": 88,
@@ -1702,7 +1702,7 @@
{
"data": {
"text/plain": [
- "Puzzle 10.1: .0047 seconds, answer 744 ok"
+ "Puzzle 10.1: .005 seconds, answer 744 ok"
]
},
"execution_count": 94,
@@ -1753,7 +1753,7 @@
{
"data": {
"text/plain": [
- "Puzzle 10.2: .0062 seconds, answer 1651 ok"
+ "Puzzle 10.2: .006 seconds, answer 1651 ok"
]
},
"execution_count": 97,
@@ -1895,7 +1895,7 @@
{
"data": {
"text/plain": [
- "Puzzle 11.1: .0660 seconds, answer 194482 ok"
+ "Puzzle 11.1: .068 seconds, answer 194482 ok"
]
},
"execution_count": 104,
@@ -1956,7 +1956,7 @@
{
"data": {
"text/plain": [
- "Puzzle 11.1: .0015 seconds, answer 194482 ok"
+ "Puzzle 11.1: .002 seconds, answer 194482 ok"
]
},
"execution_count": 108,
@@ -1978,7 +1978,7 @@
{
"data": {
"text/plain": [
- "Puzzle 11.2: .0596 seconds, answer 232454623677743 ok"
+ "Puzzle 11.2: .060 seconds, answer 232454623677743 ok"
]
},
"execution_count": 109,
@@ -2110,7 +2110,7 @@
{
"data": {
"text/plain": [
- "Puzzle 12.1: .0332 seconds, answer 1402544 ok"
+ "Puzzle 12.1: .033 seconds, answer 1402544 ok"
]
},
"execution_count": 117,
@@ -2183,7 +2183,7 @@
{
"data": {
"text/plain": [
- "Puzzle 12.1: .0501 seconds, answer 1402544 ok"
+ "Puzzle 12.1: .051 seconds, answer 1402544 ok"
]
},
"execution_count": 120,
@@ -2205,7 +2205,7 @@
{
"data": {
"text/plain": [
- "Puzzle 12.2: .0423 seconds, answer 862486 ok"
+ "Puzzle 12.2: .042 seconds, answer 862486 ok"
]
},
"execution_count": 121,
@@ -2325,7 +2325,7 @@
{
"data": {
"text/plain": [
- "Puzzle 13.1: .0098 seconds, answer 29598 ok"
+ "Puzzle 13.1: .010 seconds, answer 29598 ok"
]
},
"execution_count": 126,
@@ -2447,7 +2447,7 @@
{
"data": {
"text/plain": [
- "Puzzle 13.2: .0004 seconds, answer 93217456941970 ok"
+ "Puzzle 13.2: .000 seconds, answer 93217456941970 ok"
]
},
"execution_count": 133,
@@ -2477,7 +2477,7 @@
{
"data": {
"text/plain": [
- "Puzzle 13.1: .0002 seconds, answer 29598 ok"
+ "Puzzle 13.1: .000 seconds, answer 29598 ok"
]
},
"execution_count": 135,
@@ -2582,7 +2582,7 @@
{
"data": {
"text/plain": [
- "Puzzle 14.1: .0001 seconds, answer 216027840 ok"
+ "Puzzle 14.1: .000 seconds, answer 216027840 ok"
]
},
"execution_count": 140,
@@ -2837,42 +2837,42 @@
"\n",
"\n",
"
\n",
- "
\n",
+ "
\n",
"
\n",
- "
\n",
+ " oninput=\"anim48c518432d5b41ef99bf29888413d888.set_frame(parseInt(this.value));\">\n",
"
\n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
"
\n",
- "
\n",
"
\n",
"
\n",
@@ -2882,9 +2882,9 @@
" /* Instantiate the Animation class. */\n",
" /* The IDs given should match those used in the template above. */\n",
" (function() {\n",
- " var img_id = \"_anim_img94aebc698f514824b456d60045f1f0fa\";\n",
- " var slider_id = \"_anim_slider94aebc698f514824b456d60045f1f0fa\";\n",
- " var loop_select_id = \"_anim_loop_select94aebc698f514824b456d60045f1f0fa\";\n",
+ " var img_id = \"_anim_img48c518432d5b41ef99bf29888413d888\";\n",
+ " var slider_id = \"_anim_slider48c518432d5b41ef99bf29888413d888\";\n",
+ " var loop_select_id = \"_anim_loop_select48c518432d5b41ef99bf29888413d888\";\n",
" var frames = new Array(3);\n",
" \n",
" frames[0] = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8AAAALQCAYAAABfdxm0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90\\\n",
@@ -5656,14 +5656,14 @@
" /* set a timeout to make sure all the above elements are created before\n",
" the object is initialized. */\n",
" setTimeout(function() {\n",
- " anim94aebc698f514824b456d60045f1f0fa = new Animation(frames, img_id, slider_id, 200.0,\n",
+ " anim48c518432d5b41ef99bf29888413d888 = new Animation(frames, img_id, slider_id, 200.0,\n",
" loop_select_id);\n",
" }, 0);\n",
" })()\n",
"\n"
],
"text/plain": [
- ""
+ ""
]
},
"execution_count": 144,
@@ -5896,42 +5896,42 @@
"\n",
"\n",
"\n",
- "
\n",
+ "
\n",
"
\n",
- "
\n",
+ " oninput=\"anim75c15803e4bc421ab6d6396a5ebe956b.set_frame(parseInt(this.value));\">\n",
"
\n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
- " \n",
+ " \n",
" \n",
"
\n",
- "
\n",
"
\n",
"
\n",
@@ -5941,9 +5941,9 @@
" /* Instantiate the Animation class. */\n",
" /* The IDs given should match those used in the template above. */\n",
" (function() {\n",
- " var img_id = \"_anim_imge1d73e0327fa420190c43c3033a2c763\";\n",
- " var slider_id = \"_anim_slidere1d73e0327fa420190c43c3033a2c763\";\n",
- " var loop_select_id = \"_anim_loop_selecte1d73e0327fa420190c43c3033a2c763\";\n",
+ " var img_id = \"_anim_img75c15803e4bc421ab6d6396a5ebe956b\";\n",
+ " var slider_id = \"_anim_slider75c15803e4bc421ab6d6396a5ebe956b\";\n",
+ " var loop_select_id = \"_anim_loop_select75c15803e4bc421ab6d6396a5ebe956b\";\n",
" var frames = new Array(1);\n",
" \n",
" frames[0] = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8AAAALQCAYAAABfdxm0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90\\\n",
@@ -6621,14 +6621,14 @@
" /* set a timeout to make sure all the above elements are created before\n",
" the object is initialized. */\n",
" setTimeout(function() {\n",
- " anime1d73e0327fa420190c43c3033a2c763 = new Animation(frames, img_id, slider_id, 200.0,\n",
+ " anim75c15803e4bc421ab6d6396a5ebe956b = new Animation(frames, img_id, slider_id, 200.0,\n",
" loop_select_id);\n",
" }, 0);\n",
" })()\n",
"\n"
],
"text/plain": [
- ""
+ ""
]
},
"execution_count": 147,
@@ -6660,7 +6660,7 @@
{
"data": {
"text/plain": [
- "Puzzle 14.2: 1.8947 seconds, answer 6876 ok"
+ "Puzzle 14.2: 1.893 seconds, answer 6876 ok"
]
},
"execution_count": 149,
@@ -6779,7 +6779,7 @@
{
"data": {
"text/plain": [
- "Puzzle 15.1: .0252 seconds, answer 1563092 ok"
+ "Puzzle 15.1: .025 seconds, answer 1563092 ok"
]
},
"execution_count": 154,
@@ -6856,7 +6856,7 @@
{
"data": {
"text/plain": [
- "Puzzle 15.1: .0300 seconds, answer 1563092 ok"
+ "Puzzle 15.1: .029 seconds, answer 1563092 ok"
]
},
"execution_count": 157,
@@ -6878,7 +6878,7 @@
{
"data": {
"text/plain": [
- "Puzzle 15.2: .0427 seconds, answer 1582688 ok"
+ "Puzzle 15.2: .042 seconds, answer 1582688 ok"
]
},
"execution_count": 158,
@@ -7035,7 +7035,7 @@
{
"data": {
"text/plain": [
- "Puzzle 16.1: .1493 seconds, answer 103512 ok"
+ "Puzzle 16.1: .147 seconds, answer 103512 ok"
]
},
"execution_count": 166,
@@ -7099,7 +7099,7 @@
{
"data": {
"text/plain": [
- "Puzzle 16.2: .8634 seconds, answer 554 ok"
+ "Puzzle 16.2: .855 seconds, answer 554 ok"
]
},
"execution_count": 169,
@@ -7231,7 +7231,7 @@
{
"data": {
"text/plain": [
- "Puzzle 17.1: .0000 seconds, answer 2,1,0,1,7,2,5,0,3 ok"
+ "Puzzle 17.1: .000 seconds, answer 2,1,0,1,7,2,5,0,3 ok"
]
},
"execution_count": 175,
@@ -7395,7 +7395,7 @@
{
"data": {
"text/plain": [
- "Puzzle 17.2: .0235 seconds, answer 267265166222235 ok"
+ "Puzzle 17.2: .024 seconds, answer 267265166222235 ok"
]
},
"execution_count": 183,
@@ -7504,7 +7504,7 @@
{
"data": {
"text/plain": [
- "Puzzle 18.1: .0143 seconds, answer 344 ok"
+ "Puzzle 18.1: .014 seconds, answer 344 ok"
]
},
"execution_count": 188,
@@ -7557,7 +7557,7 @@
{
"data": {
"text/plain": [
- "Puzzle 18.2: .0323 seconds, answer 46,18 ok"
+ "Puzzle 18.2: .033 seconds, answer 46,18 ok"
]
},
"execution_count": 191,
@@ -7657,7 +7657,7 @@
{
"data": {
"text/plain": [
- "Puzzle 19.1: .0407 seconds, answer 242 ok"
+ "Puzzle 19.1: .040 seconds, answer 242 ok"
]
},
"execution_count": 197,
@@ -7704,7 +7704,7 @@
{
"data": {
"text/plain": [
- "Puzzle 19.2: .1904 seconds, answer 595975512785325 ok"
+ "Puzzle 19.2: .183 seconds, answer 595975512785325 ok"
]
},
"execution_count": 200,
@@ -7753,7 +7753,7 @@
{
"data": {
"text/plain": [
- "Puzzle 19.1: .0037 seconds, answer 242 ok"
+ "Puzzle 19.1: .004 seconds, answer 242 ok"
]
},
"execution_count": 204,
@@ -7773,17 +7773,201 @@
},
{
"cell_type": "markdown",
- "id": "c3317844-2b4a-4756-8a59-b765aa467445",
+ "id": "efc9dc54-cdcc-40d5-85d5-b8ed8da61ba2",
"metadata": {},
"source": [
- "# Summary\n",
+ "# [Day 20](https://adventofcode.com/2024/day/20): Race Condition\n",
"\n",
- "So far, I've solved all the puzzles. The median run time is around 10 milliseconds, but three problems take over a second."
+ "Yet another problem with a grid, this one depicting a racetrack:"
]
},
{
"cell_type": "code",
"execution_count": 206,
+ "id": "156dcbf7-79ec-41a7-a9f2-397a827b9856",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
+ "Puzzle input ➜ 141 strs:\n",
+ "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
+ "################################################################################################ ...\n",
+ "#...#...#...........#...#...#...#...#.....#...###...#...###.........#...#...#.......#...#...#... ...\n",
+ "#.#.#.#.#.#########.#.#.#.#.#.#.#.#.#.###.#.#.###.#.#.#.###.#######.#.#.#.#.#.#####.#.#.#.#.#.#. ...\n",
+ "#.#...#.#...#.....#...#...#...#.#.#.#...#...#...#.#...#...#.......#...#...#.#.....#.#.#...#.#.#. ...\n",
+ "#.#####.###.#.###.#############.#.#.###.#######.#.#######.#######.#########.#####.#.#.#####.#.#. ...\n",
+ "#.#.....###...###.......#.......#.#.....#.......#.......#...#.....#...#.....#...#.#.#.....#...#. ...\n",
+ "#.#.###################.#.#######.#######.#############.###.#.#####.#.#.#####.#.#.#.#####.#####. ...\n",
+ "#.#.#...###...#...#.....#.......#.......#.###...#...###...#.#...#...#...###...#.#.#...###.....#. ...\n",
+ "...\n"
+ ]
+ }
+ ],
+ "source": [
+ "racetrack = Grid(parse(20))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "57918fd0-bb72-4c5e-8e1f-3bcf164a1d72",
+ "metadata": {},
+ "source": [
+ "### How many cheats would save you at least 100 picoseconds?\n",
+ "\n",
+ "We are told that the grid depicts a single path from start (`S`) to end (`E`). Each step (in one of the four cardinal directions) takes one picosecond. But you are allowed to cheat once during the race by going through a wall: you can take two steps where the first step is into a wall and the second is back on the track. We are asked how many such cheats would save 100 picoseconds or more.\n",
+ "\n",
+ "This is an all-paths-to-the-goal problem, which should make you think [Dijkstra's algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm). My function `dijkstra` will return a dict of `{(x, y): distance_to_end}`. It works by maintaining a queue, `Q` of points to be considered, and one at a time popping a point off the queue, and for each neighbor that is not a wall, add the neighbor to the queue and record the distance to the neighbor as being one more than the distance to the point in the dict `D`. Since we are told the grid is single-path, we don't have to worry about updating entries in `D` for a second path to a point.\n",
+ "\n",
+ "Then my function `cheats` yields all `(start_position, end_position, time_saved)` tuples where the time saved is at least the given lower bound."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 208,
+ "id": "4c4ef05c-b548-49f9-b092-847e9752e745",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def dijkstra(grid, end_char='E') -> Dict[Point, int]:\n",
+ " \"\"\"All-paths distances from each point to the end square on the grid: {(x, y): distance}.\"\"\"\n",
+ " end = the(grid.findall(end_char))\n",
+ " D = {end: 0}\n",
+ " Q = [end]\n",
+ " while Q:\n",
+ " p = Q.pop()\n",
+ " for p2 in grid.neighbors(p):\n",
+ " if grid[p2] != '#' and p2 not in D:\n",
+ " Q.append(p2)\n",
+ " D[p2] = D[p] + 1\n",
+ " return D\n",
+ "\n",
+ "def cheats(racetrack, lower_bound=1) -> Iterable[Tuple[Point, Point, int]]:\n",
+ " \"\"\"All ways of cheating by taking one step onto a wall and a second step back on track.\"\"\"\n",
+ " D = dijkstra(racetrack, 'E')\n",
+ " return ((p1, p3, t)\n",
+ " for p1 in D\n",
+ " for p2 in racetrack.neighbors(p1) if racetrack[p2] == '#'\n",
+ " for p3 in racetrack.neighbors(p2)\n",
+ " if p3 in D and (t := D[p1] - D[p3] - 2) >= lower_bound)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 209,
+ "id": "1bbd8b72-c503-4384-aaea-a5bed45a4491",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Puzzle 20.1: .029 seconds, answer 1343 ok"
+ ]
+ },
+ "execution_count": 209,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "answer(20.1, 1343, lambda:\n",
+ " quantify(cheats(racetrack, 100)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0f86c3a4-47e7-4731-8acf-9133b3e41838",
+ "metadata": {},
+ "source": [
+ "At first I had a puzzling **bug**. I had a lot of confidence in my code, so I addressed it by carefully re-reading the problem description. Then I realized my mistake: I didn't count the 2 picoseconds of cheating as part of the total time. I fixed that by inserting the \"`-2`\" in the last line of `cheats`. In the process of carefully re-reading, I realized that the path through the grid is a single path; I didn't need a queue of points in `dijkstra`; the queue will always be just one point. But changing it wouldn't have a big effect on efficiency, so I'll keep it as is.\n",
+ "\n",
+ "### How many big cheats would save you at least 100 picoseconds?\n",
+ "\n",
+ "In Part 2 you can use a much bigger cheat, of up to 20 picoseconds. (But you can still only use one cheat.) I'll tackle this by looking at all points in a neighborhood of radius 20 from each starting point on the path."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 211,
+ "id": "d370e24c-9b82-4415-82a5-7afe2be17654",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Puzzle 20.2: .764 seconds, answer 982891 ok"
+ ]
+ },
+ "execution_count": 211,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "def big_cheats(racetrack, lower_bound=1, radius=20) -> Iterable[Tuple[Point, Point, int]]:\n",
+ " \"\"\"All ways of cheating by taking up to `radius` steps through walls and back to the track.\"\"\"\n",
+ " D = dijkstra(racetrack, 'E')\n",
+ " return ((p1, p2, t)\n",
+ " for p1 in D\n",
+ " for p2 in neighborhood(p1, radius)\n",
+ " if p2 in D and (t := D[p1] - D[p2] - taxi_distance(p1, p2)) >= lower_bound)\n",
+ "\n",
+ "def neighborhood(point, radius) -> List[Point]:\n",
+ " \"\"\"All points within `radius` of `point` (using taxi distance).\"\"\"\n",
+ " (x, y) = point\n",
+ " return [(x + dx, y+ dy) \n",
+ " for dx in range(-radius, radius + 1)\n",
+ " for dy in range(-(radius - abs(dx)), radius - abs(dx) + 1)]\n",
+ "\n",
+ "answer(20.2, 982891, lambda:\n",
+ " quantify(big_cheats(racetrack, 100, 20)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0022ec12-5359-455f-ace8-c8615d7cd1d2",
+ "metadata": {},
+ "source": [
+ "This solution is backwards-compatible with Part 1:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 213,
+ "id": "332e9c72-db9a-4b90-a649-45f7bf955e84",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Puzzle 20.1: .023 seconds, answer 1343 ok"
+ ]
+ },
+ "execution_count": 213,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "answer(20.1, 1343, lambda:\n",
+ " quantify(big_cheats(racetrack, 100, 2)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c3317844-2b4a-4756-8a59-b765aa467445",
+ "metadata": {},
+ "source": [
+ "# Summary\n",
+ "\n",
+ "So far, I've solved all the puzzles. The median run time is about 10 milliseconds, but three problems take over a second."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 215,
"id": "34813fc9-a000-4cd8-88ae-692851b3242c",
"metadata": {},
"outputs": [
@@ -7791,48 +7975,50 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Puzzle 1.1: .0002 seconds, answer 1830467 ok\n",
- "Puzzle 1.2: .0001 seconds, answer 26674158 ok\n",
- "Puzzle 2.1: .0004 seconds, answer 257 ok\n",
- "Puzzle 2.2: .0022 seconds, answer 328 ok\n",
- "Puzzle 3.1: .0006 seconds, answer 156388521 ok\n",
- "Puzzle 3.2: .0004 seconds, answer 75920122 ok\n",
- "Puzzle 4.1: .0331 seconds, answer 2401 ok\n",
- "Puzzle 4.2: .0273 seconds, answer 1822 ok\n",
- "Puzzle 5.1: .0007 seconds, answer 5762 ok\n",
- "Puzzle 5.2: .0008 seconds, answer 4130 ok\n",
- "Puzzle 6.1: .0016 seconds, answer 5329 ok\n",
- "Puzzle 6.2: 1.9960 seconds, answer 2162 ok\n",
- "Puzzle 7.1: .0137 seconds, answer 1985268524462 ok\n",
- "Puzzle 7.2: .6577 seconds, answer 150077710195188 ok\n",
- "Puzzle 8.1: .0027 seconds, answer 220 ok\n",
- "Puzzle 8.2: .0030 seconds, answer 813 ok\n",
- "Puzzle 9.1: .0202 seconds, answer 6332189866718 ok\n",
- "Puzzle 9.2: 2.7791 seconds, answer 6353648390778 ok\n",
- "Puzzle 10.1: .0047 seconds, answer 744 ok\n",
- "Puzzle 10.2: .0062 seconds, answer 1651 ok\n",
- "Puzzle 11.1: .0015 seconds, answer 194482 ok\n",
- "Puzzle 11.2: .0596 seconds, answer 232454623677743 ok\n",
- "Puzzle 12.1: .0501 seconds, answer 1402544 ok\n",
- "Puzzle 12.2: .0423 seconds, answer 862486 ok\n",
- "Puzzle 13.1: .0002 seconds, answer 29598 ok\n",
- "Puzzle 13.2: .0004 seconds, answer 93217456941970 ok\n",
- "Puzzle 14.1: .0001 seconds, answer 216027840 ok\n",
- "Puzzle 14.2: 1.8947 seconds, answer 6876 ok\n",
- "Puzzle 15.1: .0300 seconds, answer 1563092 ok\n",
- "Puzzle 15.2: .0427 seconds, answer 1582688 ok\n",
- "Puzzle 16.1: .1493 seconds, answer 103512 ok\n",
- "Puzzle 16.2: .8634 seconds, answer 554 ok\n",
- "Puzzle 17.1: .0000 seconds, answer 2,1,0,1,7,2,5,0,3 ok\n",
- "Puzzle 17.2: .0235 seconds, answer 267265166222235 ok\n",
- "Puzzle 18.1: .0143 seconds, answer 344 ok\n",
- "Puzzle 18.2: .0323 seconds, answer 46,18 ok\n",
- "Puzzle 19.1: .0037 seconds, answer 242 ok\n",
- "Puzzle 19.2: .1904 seconds, answer 595975512785325 ok\n",
+ "Puzzle 1.1: .000 seconds, answer 1830467 ok\n",
+ "Puzzle 1.2: .000 seconds, answer 26674158 ok\n",
+ "Puzzle 2.1: .000 seconds, answer 257 ok\n",
+ "Puzzle 2.2: .002 seconds, answer 328 ok\n",
+ "Puzzle 3.1: .001 seconds, answer 156388521 ok\n",
+ "Puzzle 3.2: .000 seconds, answer 75920122 ok\n",
+ "Puzzle 4.1: .033 seconds, answer 2401 ok\n",
+ "Puzzle 4.2: .027 seconds, answer 1822 ok\n",
+ "Puzzle 5.1: .001 seconds, answer 5762 ok\n",
+ "Puzzle 5.2: .001 seconds, answer 4130 ok\n",
+ "Puzzle 6.1: .002 seconds, answer 5329 ok\n",
+ "Puzzle 6.2: 1.968 seconds, answer 2162 ok\n",
+ "Puzzle 7.1: .014 seconds, answer 1985268524462 ok\n",
+ "Puzzle 7.2: .656 seconds, answer 150077710195188 ok\n",
+ "Puzzle 8.1: .003 seconds, answer 220 ok\n",
+ "Puzzle 8.2: .003 seconds, answer 813 ok\n",
+ "Puzzle 9.1: .020 seconds, answer 6332189866718 ok\n",
+ "Puzzle 9.2: 2.731 seconds, answer 6353648390778 ok\n",
+ "Puzzle 10.1: .005 seconds, answer 744 ok\n",
+ "Puzzle 10.2: .006 seconds, answer 1651 ok\n",
+ "Puzzle 11.1: .002 seconds, answer 194482 ok\n",
+ "Puzzle 11.2: .060 seconds, answer 232454623677743 ok\n",
+ "Puzzle 12.1: .051 seconds, answer 1402544 ok\n",
+ "Puzzle 12.2: .042 seconds, answer 862486 ok\n",
+ "Puzzle 13.1: .000 seconds, answer 29598 ok\n",
+ "Puzzle 13.2: .000 seconds, answer 93217456941970 ok\n",
+ "Puzzle 14.1: .000 seconds, answer 216027840 ok\n",
+ "Puzzle 14.2: 1.893 seconds, answer 6876 ok\n",
+ "Puzzle 15.1: .029 seconds, answer 1563092 ok\n",
+ "Puzzle 15.2: .042 seconds, answer 1582688 ok\n",
+ "Puzzle 16.1: .147 seconds, answer 103512 ok\n",
+ "Puzzle 16.2: .855 seconds, answer 554 ok\n",
+ "Puzzle 17.1: .000 seconds, answer 2,1,0,1,7,2,5,0,3 ok\n",
+ "Puzzle 17.2: .024 seconds, answer 267265166222235 ok\n",
+ "Puzzle 18.1: .014 seconds, answer 344 ok\n",
+ "Puzzle 18.2: .033 seconds, answer 46,18 ok\n",
+ "Puzzle 19.1: .004 seconds, answer 242 ok\n",
+ "Puzzle 19.2: .183 seconds, answer 595975512785325 ok\n",
+ "Puzzle 20.1: .023 seconds, answer 1343 ok\n",
+ "Puzzle 20.2: .764 seconds, answer 982891 ok\n",
"\n",
- "Correct: 38/38\n",
+ "Correct: 40/40\n",
"\n",
- "Time in seconds: 0.0099 median, 0.2355 mean, 8.9491 total.\n"
+ "Time in seconds: 0.014 median, 0.241 mean, 9.638 total.\n"
]
}
],
diff --git a/ipynb/AdventUtils.ipynb b/ipynb/AdventUtils.ipynb
index 6a18489..fa258fd 100644
--- a/ipynb/AdventUtils.ipynb
+++ b/ipynb/AdventUtils.ipynb
@@ -194,7 +194,7 @@
" \n",
" def __repr__(self) -> str:\n",
" \"\"\"The repr of an answer shows what happened.\"\"\"\n",
- " secs = f'{self.secs:7.4f}'.replace(' 0.', ' .')\n",
+ " secs = f'{self.secs:6.3f}'.replace(' 0.', ' .')\n",
" comment = (f'' if self.got == unknown else\n",
" f' ok' if self.ok else \n",
" f' WRONG; expected answer is {self.solution}')\n",
@@ -206,7 +206,7 @@
" print(answers[d])\n",
" times = [answers[d].secs for d in answers]\n",
" print(f'\\nCorrect: {quantify(answers[d].ok for d in answers)}/{len(answers)}')\n",
- " print(f'\\nTime in seconds: {median(times):.4f} median, {mean(times):.4f} mean, {sum(times):.4f} total.')"
+ " print(f'\\nTime in seconds: {median(times):.3f} median, {mean(times):.3f} mean, {sum(times):.3f} total.')"
]
},
{