diff --git a/ipynb/Advent-2025-AI.ipynb b/ipynb/Advent-2025-AI.ipynb index e50f9f6..df8c8ca 100644 --- a/ipynb/Advent-2025-AI.ipynb +++ b/ipynb/Advent-2025-AI.ipynb @@ -7,20 +7,20 @@ "source": [ "
Peter Norvig, December 2025
\n", "\n", - "# Advent of Code 2025: The AI Edition\n", + "# Advent of Code 2025: The AI LLM Edition\n", "\n", "I enjoy doing the [**Advent of Code**](https://adventofcode.com/) (AoC) programming puzzles, and **my** solutions are [**over here**](Advent2025.ipynb). \n", "\n", "In **this** notebook I show some solutions by various AI Large Language Models: Gemini, Claude, and ChatGPT.\n", "\n", - "In order to understand what's going on here, you'll have to look at the problem descriptions at [**Advent of Code**](https://adventofcode.com/2025).\n", + "In order to understand what's going on here, you'll have to look at the problem descriptions at [**Advent of Code**](https://adventofcode.com/2025) for each day.\n", "\n", - "Each day I'll choose a model and give it the prompt \"*Write code to solve the following problem:*\" followed by the full text of the AoC Part 1 problem description. Then I'll prompt again with \"*There is a change to the specification:*\" followed by the AoC Part 2 description. So far the LLMs are doing quite well. \n", + "Each day I'll choose a model and give it the prompt \"*Write code to solve the following problem:*\" followed by the full text of the AoC Part 1 problem description. Then I'll prompt again with \"*There is a change to the specification:*\" followed by the AoC Part 2 description. \n", "\n", "For brevity, I have removed some of the models' output, such as:\n", "- Prose descriptions of the programs. (In most cases these were accurate and thorough!)\n", - "- The \"`__main__`\" idiom for running code from the command line.\n", - "- Test examples to run.\n", + "- The \"`__main__`\" idiom for running code from the command line\n", + "- Usage examples on how to run the program (and in a few cases, unit tests)\n", "\n", "Overall, the models did well, producing code that gives the correct answer in a reasonable run time. Some of the cosde could be improved stylistically. (But I guess if you're vibe coding and not looking at the code, maybe that doesn't matter.)\n", "\n", @@ -47,7 +47,7 @@ "source": [ "# [Day 1](https://adventofcode.com/2025/day/1) Gemini 3 Pro\n", "\n", - "I started with the Gemini 3 Pro Fast model, which produced this following code:" + "For **Part 1** I started with the Gemini 3 Pro Fast model, which produced this following code:" ] }, { @@ -147,7 +147,7 @@ "id": "47a04265-2dab-4a4c-9a24-e1c4c1b93c6b", "metadata": {}, "source": [ - "For Part 2 I gave Gemini Fast the updated instructions, and again it had a nice analysis and the following code:" + "For **Part 2** I gave Gemini Fast the updated instructions, and again it had a nice analysis and the following code:" ] }, { @@ -253,7 +253,7 @@ { "data": { "text/plain": [ - "Puzzle 1.2: .0018 seconds, answer 7509 WRONG; expected answer is 6907" + "Puzzle 1.2: .0017 seconds, answer 7509 WRONG; expected answer is 6907" ] }, "execution_count": 5, @@ -271,7 +271,7 @@ "id": "d640d8e4-6940-416d-93af-b55d82482a35", "metadata": {}, "source": [ - "Too bad. I switched to the Gemini 3 Pro \"Thinking\" model and gave the prompt \"*That's not quite right.*\" It responded with\n", + "Too bad; the code has a **bug**. I switched to the Gemini 3 Pro \"Thinking\" model and gave the prompt \"*That's not quite right.*\" It responded with\n", "\n", ">It seems I made a subtle logic error in my previous calculation for the Right (R) rotation.\n", ">\n", @@ -354,7 +354,7 @@ { "data": { "text/plain": [ - "Puzzle 1.2: .0024 seconds, answer 6907 ok" + "Puzzle 1.2: .0015 seconds, answer 6907 ok" ] }, "execution_count": 7, @@ -374,7 +374,7 @@ "source": [ "# [Day 2](https://adventofcode.com/2025/day/2) Claude Opus 4.5\n", "\n", - "I gave Claude the instructions for Day 2 Part 1 and it wrote some code that produces the correct answer but prints a lot of unneccessary debugging output along the way. I prompted it to \"*Change the code to not print anything, just return the answer*\" and got the following:" + "I gave Claude the instructions for **Part 1** and it wrote some code that produces the correct answer but prints a lot of unneccessary debugging output along the way. I prompted it to \"*Change the code to not print anything, just return the answer*\" and got the following:" ] }, { @@ -434,7 +434,7 @@ { "data": { "text/plain": [ - "Puzzle 2.1: .1263 seconds, answer 23560874270 ok" + "Puzzle 2.1: .1307 seconds, answer 23560874270 ok" ] }, "execution_count": 9, @@ -454,7 +454,7 @@ "id": "a31d006f-8cf2-4e4c-92d3-d7b7def22227", "metadata": {}, "source": [ - "When given the Part 2 instructions, Claude wrote the following code:" + "When given the **Part 2** instructions, Claude wrote the following code:" ] }, { @@ -518,7 +518,7 @@ { "data": { "text/plain": [ - "Puzzle 2.2: .1350 seconds, answer 44143124633 ok" + "Puzzle 2.2: .1311 seconds, answer 44143124633 ok" ] }, "execution_count": 11, @@ -538,7 +538,7 @@ "source": [ "# [Day 3](https://adventofcode.com/2025/day/3) ChatGPT 5.1 Auto\n", "\n", - "ChatGPT gave a very brief analysis of the problem and then wrote a program that was designed to be called from the command line, using the `\"__main__\"` idiom. I told it \"I don't want to run it like that, I want a function that I can pass the input text and have it return an int.\" and it produced this code (lacking comments or doc strings):" + "Fpr **Part 1** ChatGPT gave a very brief analysis of the problem and then wrote a program that was designed to be called from the command line, using the `\"__main__\"` idiom. I told it \"*I don't want to run it like that, I want a function that I can pass the input text and have it return an int*\" and it produced this code (conspicuously lacking comments or doc strings):" ] }, { @@ -589,7 +589,7 @@ { "data": { "text/plain": [ - "Puzzle 3.1: .0044 seconds, answer 17085 ok" + "Puzzle 3.1: .0042 seconds, answer 17085 ok" ] }, "execution_count": 13, @@ -609,7 +609,7 @@ "id": "4a07f37f-c5e3-4484-a7b1-2cae0ff5bd01", "metadata": {}, "source": [ - "For Part 2 ChatGPT did well (and for some reason included comments and doc strings this time):" + "For **Part 2** ChatGPT did well (and for some reason included comments and doc strings this time):" ] }, { @@ -672,7 +672,7 @@ { "data": { "text/plain": [ - "Puzzle 3.2: .0076 seconds, answer 169408143086082 ok" + "Puzzle 3.2: .0073 seconds, answer 169408143086082 ok" ] }, "execution_count": 15, @@ -692,7 +692,7 @@ "source": [ "# [Day 4](https://adventofcode.com/2025/day/4): Gemini 3 Pro\n", "\n", - "Gemini produced a solution to Part 1 that is straightforward and efficient, although perhaps could use some abstraction (e.g. if they had a function to count neighbors, they wouldn't need the `continue`)." + "Gemini produced a solution to **Part 1** that is straightforward and efficient, although perhaps could use some abstraction (e.g. if they had a function to count neighbors, they wouldn't need the `continue`)." ] }, { @@ -765,7 +765,7 @@ { "data": { "text/plain": [ - "Puzzle 4.1: .0171 seconds, answer 1569 ok" + "Puzzle 4.1: .0173 seconds, answer 1569 ok" ] }, "execution_count": 17, @@ -785,7 +785,7 @@ "id": "76845e18-6209-4995-a825-568782b79d0d", "metadata": {}, "source": [ - "For Part 2, Gemini chose the \"repeatedly remove acessible rolls\" approach rather than the more efficient (and arguable more elegant) \"remove a roll and check its neighbors\" approach." + "For **Part 2**, Gemini chose the \"repeatedly remove acessible rolls\" approach rather than the more efficient (and arguable more elegant) \"remove a roll and check its neighbors\" approach." ] }, { @@ -858,7 +858,7 @@ { "data": { "text/plain": [ - "Puzzle 4.2: .3960 seconds, answer 9280 ok" + "Puzzle 4.2: .3959 seconds, answer 9280 ok" ] }, "execution_count": 19, @@ -967,7 +967,7 @@ { "data": { "text/plain": [ - "Puzzle 4.2: .0937 seconds, answer 9280 ok" + "Puzzle 4.2: .0900 seconds, answer 9280 ok" ] }, "execution_count": 21, @@ -987,7 +987,7 @@ "source": [ "# [Day 5](https://adventofcode.com/2025/day/5): Claude Opus 4.5\n", "\n", - "Claude produces a straightforward program that solves Part 1 just fine and demonstrates good use of abstraction." + "Claude produces a straightforward program that solves **Part 1** just fine and demonstrates good use of abstraction. This time it has nice doc strings; for Day 2 it had none. Go figure." ] }, { @@ -1061,7 +1061,7 @@ { "data": { "text/plain": [ - "Puzzle 5.1: .0058 seconds, answer 635 ok" + "Puzzle 5.1: .0055 seconds, answer 635 ok" ] }, "execution_count": 23, @@ -1081,7 +1081,7 @@ "id": "dabe3fbc-0fa6-46d0-adfb-f6413f3a63d5", "metadata": {}, "source": [ - "For Part 2, Claude chose to sort ranges and then merge them. That's a reasonable approach." + "For **Part 2**, Claude chose to sort ranges, then merge them, then count the total of the sizes of the ranges. That's a reasonable approach–it involves an extra step of merging ranges (instead of just counting on the fly) but it could be useful to have the merged ranges." ] }, { @@ -1180,7 +1180,7 @@ "source": [ "# [Day 6](https://adventofcode.com/2025/day/6): ChatGPT 5.1 Auto\n", "\n", - "ChatGPT produced a program that is correct, but has poor abstraction, with one long 63-line function. (It also contains a pet peeve of mine: the pattern \"`if some_boolean: True else: False`\" can always be replaced with \"`some_boolean`\".)" + "For **Part 1** ChatGPT produced a program that is correct, but has poor abstraction, with one long 63-line function. (It also contains a pet peeve of mine: in lines 17–20 the pattern \"`if some_boolean: True else: False`\" can always be replaced with \"`some_boolean`\".)" ] }, { @@ -1276,7 +1276,7 @@ { "data": { "text/plain": [ - "Puzzle 6.1: .0078 seconds, answer 5877594983578 ok" + "Puzzle 6.1: .0085 seconds, answer 5877594983578 ok" ] }, "execution_count": 27, @@ -1296,7 +1296,7 @@ "id": "28de0612-03f3-4587-88cb-18ef9b10ee00", "metadata": {}, "source": [ - "For Part 2 we get an even-longer function, with even more complications. For example in \"Determine the operator\"; the 14 lines could be replaced with `op = (add if '+' in segment else mul)`. However, the program is correct." + "For **Part 2** we get an even-longer function, with even more complications. For example in \"Determine the operator\"; the 14 lines could be replaced with `op = (add if '+' in segment else mul)`. I think ChatGPT ws trying to be robust against errors in the input. However, the program is correct." ] }, { @@ -1404,7 +1404,7 @@ { "data": { "text/plain": [ - "Puzzle 6.2: .0064 seconds, answer 11159825706149 ok" + "Puzzle 6.2: .0060 seconds, answer 11159825706149 ok" ] }, "execution_count": 29, @@ -1417,6 +1417,231 @@ " solve(lines))" ] }, + { + "cell_type": "markdown", + "id": "110a8177-d4d8-4a61-9f74-1ed6444ec38f", + "metadata": {}, + "source": [ + "# [Day 7](https://adventofcode.com/2025/day/7): Gemini 3 Pro\n", + "\n", + "Gemini's code for **Part 1** is a bit verbose, but gets the job done." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "adbbd7bc-1eca-4638-a551-470d27edae0d", + "metadata": {}, + "outputs": [], + "source": [ + "def solve_tachyon_manifold(puzzle_input):\n", + " # 1. Parse the Grid\n", + " grid = puzzle_input.splitlines()\n", + " grid = [line for line in grid if line] # Remove empty lines\n", + " \n", + " if not grid:\n", + " return 0\n", + "\n", + " height = len(grid)\n", + " width = max(len(row) for row in grid)\n", + " \n", + " # Pad rows to ensure uniform width\n", + " grid = [row.ljust(width, '.') for row in grid]\n", + "\n", + " # 2. Find Start Position 'S'\n", + " # We scan the first row (or all rows if S is buried, but usually it's top)\n", + " active_beams = set()\n", + " for y in range(height):\n", + " if 'S' in grid[y]:\n", + " active_beams.add(grid[y].index('S'))\n", + " # We assume beams start flowing from this row downwards\n", + " # so we break and start the simulation from this row\n", + " start_row = y\n", + " break\n", + " else:\n", + " return 0 # No start found\n", + "\n", + " split_count = 0\n", + "\n", + " # 3. Simulate Row by Row\n", + " # We iterate through the rows starting from the one containing 'S'\n", + " for y in range(start_row, height):\n", + " next_beams = set()\n", + " \n", + " # Check every column that currently has a beam\n", + " for x in active_beams:\n", + " cell = grid[y][x]\n", + " \n", + " if cell == '^':\n", + " # SPLITTER: \n", + " # 1. Increment total split count\n", + " split_count += 1\n", + " \n", + " # 2. Create new beams left and right\n", + " # Check boundaries to ensure we don't wrap around or error\n", + " if x - 1 >= 0:\n", + " next_beams.add(x - 1)\n", + " if x + 1 < width:\n", + " next_beams.add(x + 1)\n", + " \n", + " else:\n", + " # EMPTY SPACE (.) or START (S):\n", + " # The beam continues straight down\n", + " next_beams.add(x)\n", + " \n", + " # Update the active beams for the next row iteration\n", + " active_beams = next_beams\n", + " \n", + " # Optimization: If no beams are left, stop early\n", + " if not active_beams:\n", + " break\n", + "\n", + " return split_count" + ] + }, + { + "cell_type": "markdown", + "id": "f8de5310-3556-4150-a050-5303cd10702e", + "metadata": {}, + "source": [ + "The solution is correct:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "9ef96af9-87b7-4e9b-a5fb-e310bc8e8163", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Puzzle 7.1: .0009 seconds, answer 1681 ok" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "puzzle_input = get_text(7)\n", + "\n", + "answer(7.1, 1681, lambda:\n", + " solve_tachyon_manifold(puzzle_input))" + ] + }, + { + "cell_type": "markdown", + "id": "c56012a6-b9e7-4053-84c1-79fa457436b1", + "metadata": {}, + "source": [ + "For **Part 2**, Gemini gets the key ideas (although it is a bit old-fashioned to use a `defaultdict(int)` instead of a `Counter`)." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "3e05450f-0cdc-401f-99bc-17d7dfb83143", + "metadata": {}, + "outputs": [], + "source": [ + "from collections import defaultdict\n", + "\n", + "def solve_quantum_tachyon_manifold(puzzle_input):\n", + " # 1. Parse the Grid\n", + " grid = puzzle_input.splitlines()\n", + " grid = [line for line in grid if line]\n", + " \n", + " if not grid:\n", + " return 0\n", + "\n", + " height = len(grid)\n", + " width = max(len(row) for row in grid)\n", + " # Pad rows to ensure uniform width\n", + " grid = [row.ljust(width, '.') for row in grid]\n", + "\n", + " # 2. Find Start Position 'S'\n", + " # 'counts' maps column_index -> number_of_timelines_at_this_column\n", + " counts = defaultdict(int)\n", + " start_row = 0\n", + " found = False\n", + " \n", + " for y in range(height):\n", + " if 'S' in grid[y]:\n", + " start_x = grid[y].index('S')\n", + " counts[start_x] = 1 # We start with 1 timeline\n", + " start_row = y\n", + " found = True\n", + " break\n", + " \n", + " if not found:\n", + " return 0\n", + "\n", + " # 3. Simulate Row by Row\n", + " # We process the grid from the start row down to the bottom.\n", + " # Each iteration calculates where the particles end up in the *next* row.\n", + " for y in range(start_row, height):\n", + " next_counts = defaultdict(int)\n", + " \n", + " for x, num_timelines in counts.items():\n", + " # Determine what is at this position\n", + " # If the timeline has drifted out of bounds, treat it as empty space (.)\n", + " if 0 <= x < width:\n", + " char = grid[y][x]\n", + " else:\n", + " char = '.'\n", + "\n", + " if char == '^':\n", + " # SPLITTER:\n", + " # The timelines here split. The count moves to both left and right.\n", + " # If 5 timelines hit this splitter, 5 go left AND 5 go right.\n", + " next_counts[x - 1] += num_timelines\n", + " next_counts[x + 1] += num_timelines\n", + " else:\n", + " # EMPTY SPACE (.) or START (S):\n", + " # The timelines pass straight through.\n", + " next_counts[x] += num_timelines\n", + " \n", + " # Move to the next row\n", + " counts = next_counts\n", + "\n", + " # 4. Sum Total Timelines\n", + " # After processing the final row, 'counts' holds the number of timelines \n", + " # exiting the bottom of the manifold at each column.\n", + " return sum(counts.values())" + ] + }, + { + "cell_type": "markdown", + "id": "dc634316-8e9d-46d7-9380-f50345bf6149", + "metadata": {}, + "source": [ + "The answer is correct:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "555b979d-77a8-4bda-b59c-85ce82df2230", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Puzzle 7.2: .0016 seconds, answer 422102272495018 ok" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "answer(7.2, 422102272495018, lambda:\n", + " solve_quantum_tachyon_manifold(puzzle_input))" + ] + }, { "cell_type": "markdown", "id": "8aa26008-a652-4860-9c84-5ba4344d32f3", @@ -1429,8 +1654,8 @@ }, { "cell_type": "code", - "execution_count": 30, - "id": "2d03c39d-42f5-4f51-89b9-638d8d4a4a35", + "execution_count": 35, + "id": "16ce8af4-a1da-4280-9078-116ced3e9941", "metadata": {}, "outputs": [ { @@ -1438,34 +1663,26 @@ "output_type": "stream", "text": [ "Puzzle 1.1: .0013 seconds, answer 1182 ok\n", - "Puzzle 1.2: .0024 seconds, answer 6907 ok\n", - "Puzzle 2.1: .1263 seconds, answer 23560874270 ok\n", - "Puzzle 2.2: .1350 seconds, answer 44143124633 ok\n", - "Puzzle 3.1: .0044 seconds, answer 17085 ok\n", - "Puzzle 3.2: .0076 seconds, answer 169408143086082 ok\n", - "Puzzle 4.1: .0171 seconds, answer 1569 ok\n", - "Puzzle 4.2: .0937 seconds, answer 9280 ok\n", - "Puzzle 5.1: .0058 seconds, answer 635 ok\n", + "Puzzle 1.2: .0015 seconds, answer 6907 ok\n", + "Puzzle 2.1: .1307 seconds, answer 23560874270 ok\n", + "Puzzle 2.2: .1311 seconds, answer 44143124633 ok\n", + "Puzzle 3.1: .0042 seconds, answer 17085 ok\n", + "Puzzle 3.2: .0073 seconds, answer 169408143086082 ok\n", + "Puzzle 4.1: .0173 seconds, answer 1569 ok\n", + "Puzzle 4.2: .0900 seconds, answer 9280 ok\n", + "Puzzle 5.1: .0055 seconds, answer 635 ok\n", "Puzzle 5.2: .0002 seconds, answer 369761800782619 ok\n", - "Puzzle 6.1: .0078 seconds, answer 5877594983578 ok\n", - "Puzzle 6.2: .0064 seconds, answer 11159825706149 ok\n" + "Puzzle 6.1: .0085 seconds, answer 5877594983578 ok\n", + "Puzzle 6.2: .0060 seconds, answer 11159825706149 ok\n", + "Puzzle 7.1: .0009 seconds, answer 1681 ok\n", + "Puzzle 7.2: .0016 seconds, answer 422102272495018 ok\n", + "\n", + "Time in seconds: total = 0.406, mean = 0.029, max = 0.131\n" ] - }, - { - "data": { - "text/plain": [ - "0.40801501274108887" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "for d in sorted(answers):\n", - " print(answers[d])\n", - "sum(a.secs for a in answers.values())" + "summary(answers)" ] } ], diff --git a/ipynb/Advent-2025.ipynb b/ipynb/Advent-2025.ipynb index 009f728..e541d30 100644 --- a/ipynb/Advent-2025.ipynb +++ b/ipynb/Advent-2025.ipynb @@ -43,7 +43,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 2, "id": "ed911a15-addc-4c04-8546-2c9f37aee341", "metadata": {}, "outputs": [ @@ -112,7 +112,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 4, "id": "eb90f15c-8f87-4d94-b49c-fcaa53aab8ae", "metadata": {}, "outputs": [ @@ -122,7 +122,7 @@ "1182" ] }, - "execution_count": 46, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -141,17 +141,17 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "8387c4bd-a0b7-46d7-b726-d2d4b383b3cf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 1.1: .0006 seconds, answer 1182 ok" + "Puzzle 1.1: .0005 seconds, answer 1182 ok" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -175,17 +175,17 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "bfb5bd2d-d768-47b3-9897-d28f83f2202a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 1.2: .1425 seconds, answer 6907 ok" + "Puzzle 1.2: .1389 seconds, answer 6907 ok" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -205,7 +205,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "e0b676d8-3d4f-4b36-835d-b045ece53bd6", "metadata": {}, "outputs": [], @@ -225,7 +225,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "id": "8969191e-bd50-4187-8e4b-64524bc8427a", "metadata": {}, "outputs": [ @@ -235,7 +235,7 @@ "Puzzle 1.2: .0009 seconds, answer 6907 ok" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -265,7 +265,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 9, "id": "63bb5099-68ab-41b3-8d0c-2f409433b3f2", "metadata": {}, "outputs": [ @@ -312,7 +312,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "d682f3f2-415e-4556-b6c8-43e331a38703", "metadata": {}, "outputs": [ @@ -322,7 +322,7 @@ "1990936" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -344,7 +344,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 11, "id": "1345f93d-84c5-43f8-b6c2-9fc7b8f5ed90", "metadata": {}, "outputs": [], @@ -370,17 +370,17 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 12, "id": "8b0d12b3-f184-4149-8b49-f9ff78663d46", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 2.1: .0032 seconds, answer 23560874270 ok" + "Puzzle 2.1: .0031 seconds, answer 23560874270 ok" ] }, - "execution_count": 55, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -402,7 +402,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 13, "id": "4fbf52e7-a06a-4000-8627-80d159788da1", "metadata": {}, "outputs": [], @@ -435,7 +435,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 14, "id": "5a29e5bc-3b07-4800-9a0f-4bd433e01c55", "metadata": {}, "outputs": [], @@ -454,17 +454,17 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 15, "id": "8a7c6c25-4b5f-4178-8559-166ba1a9f924", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 2.1: .0027 seconds, answer 23560874270 ok" + "Puzzle 2.1: .0030 seconds, answer 23560874270 ok" ] }, - "execution_count": 69, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -476,17 +476,17 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 16, "id": "32fefd65-df2a-4ea3-9acd-7525ebd32380", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 2.2: .0033 seconds, answer 44143124633 ok" + "Puzzle 2.2: .0041 seconds, answer 44143124633 ok" ] }, - "execution_count": 70, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -516,7 +516,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 17, "id": "04ef4f2f-2b07-43cd-87d4-a8f63f7fe840", "metadata": {}, "outputs": [ @@ -555,7 +555,7 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 18, "id": "0168ada2-b53e-4215-9e6a-2468759f095c", "metadata": {}, "outputs": [], @@ -574,7 +574,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 19, "id": "3f6390f5-78b7-4472-acf9-8855d2c2453e", "metadata": {}, "outputs": [], @@ -585,7 +585,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 20, "id": "9cc62ae9-b313-4b82-b8fb-bab9c0ef5cb6", "metadata": {}, "outputs": [ @@ -595,7 +595,7 @@ "Puzzle 3.1: .0006 seconds, answer 17085 ok" ] }, - "execution_count": 75, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -619,7 +619,7 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 21, "id": "b9507c12-421b-41af-b926-a4d3d83f622d", "metadata": {}, "outputs": [], @@ -642,7 +642,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 22, "id": "4a58a657-8f32-4001-a4ff-f30dfbe7e5e7", "metadata": {}, "outputs": [], @@ -662,7 +662,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 23, "id": "fe3cff78-81c0-4d4a-bb4d-f0f841067e0d", "metadata": {}, "outputs": [ @@ -672,7 +672,7 @@ "Puzzle 3.1: .0006 seconds, answer 17085 ok" ] }, - "execution_count": 87, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -684,17 +684,17 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 24, "id": "f971839e-81ea-49b4-a92f-a44884be645d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 3.2: .0022 seconds, answer 169408143086082 ok" + "Puzzle 3.2: .0020 seconds, answer 169408143086082 ok" ] }, - "execution_count": 88, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -716,7 +716,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 25, "id": "c9f227d5-2748-48e1-80c1-7385dad46323", "metadata": {}, "outputs": [ @@ -758,7 +758,7 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 26, "id": "6fe5bd44-8a28-4d7a-bc8b-edc4af8f23c3", "metadata": {}, "outputs": [], @@ -783,17 +783,17 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 27, "id": "a5ef09cf-b204-41eb-80d8-de107d385dbb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 4.1: .0530 seconds, answer 1569 ok" + "Puzzle 4.1: .0541 seconds, answer 1569 ok" ] }, - "execution_count": 90, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -817,7 +817,7 @@ }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 28, "id": "0ed53853-268c-4c2f-a929-cb3e6005a348", "metadata": {}, "outputs": [], @@ -834,17 +834,17 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": 29, "id": "2fb17a51-05f7-42ec-8d6c-222121a026cf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 4.2: 1.2244 seconds, answer 9280 ok" + "Puzzle 4.2: 1.2345 seconds, answer 9280 ok" ] }, - "execution_count": 92, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -864,7 +864,7 @@ }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 30, "id": "54f20b5e-6713-459c-8d40-e545ce6b8e42", "metadata": {}, "outputs": [], @@ -883,17 +883,17 @@ }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 31, "id": "bcba970b-09aa-479b-9c6d-4f6a7ac49fed", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 4.2: .1397 seconds, answer 9280 ok" + "Puzzle 4.2: .1421 seconds, answer 9280 ok" ] }, - "execution_count": 94, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -915,7 +915,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 32, "id": "4b508db5-aeae-410e-a062-1b2d4ce41253", "metadata": {}, "outputs": [ @@ -948,7 +948,7 @@ " \"\"\"Parse either ranges like \"3-5\", or integers like \"8\".\"\"\"\n", " return mapt(positive_ints, lines(text)) if '-' in text else ints(text)\n", " \n", - "fresh_ranges, available_ingredient_ids = parse(day=5, parse_ingredients, sections=paragraphs)" + "fresh_ranges, available_ingredient_ids = parse(day=5, parser=parse_ingredients, sections=paragraphs)" ] }, { @@ -963,7 +963,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 33, "id": "ae5b33e4-92f5-4fe2-bd5a-6b22095724fa", "metadata": {}, "outputs": [], @@ -976,17 +976,17 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 34, "id": "112a84f7-9bb8-45f0-9d7e-f600f37f0fdf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 5.1: .0072 seconds, answer 635 ok" + "Puzzle 5.1: .0076 seconds, answer 635 ok" ] }, - "execution_count": 30, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } @@ -1010,7 +1010,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 35, "id": "47a660d2-746c-433f-b4ae-9d01f70bc504", "metadata": {}, "outputs": [ @@ -1020,7 +1020,7 @@ "476036797138761" ] }, - "execution_count": 31, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } @@ -1039,7 +1039,7 @@ }, { "cell_type": "code", - "execution_count": 97, + "execution_count": 36, "id": "f52e8ecd-325e-4ed4-8928-de9365b5b7d4", "metadata": {}, "outputs": [], @@ -1057,7 +1057,7 @@ }, { "cell_type": "code", - "execution_count": 98, + "execution_count": 37, "id": "fab6f1ed-543f-4f42-b1d5-2551742e3a4f", "metadata": {}, "outputs": [ @@ -1067,7 +1067,7 @@ "Puzzle 5.2: .0001 seconds, answer 369761800782619 ok" ] }, - "execution_count": 98, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } @@ -1091,7 +1091,7 @@ }, { "cell_type": "code", - "execution_count": 100, + "execution_count": 38, "id": "bca852a9-e4c5-4706-abfc-afc6d4a4eeb5", "metadata": {}, "outputs": [ @@ -1126,7 +1126,7 @@ }, { "cell_type": "code", - "execution_count": 102, + "execution_count": 39, "id": "92f320f4-c7a3-4dfd-ae61-6b1b180bdc93", "metadata": {}, "outputs": [], @@ -1141,17 +1141,17 @@ }, { "cell_type": "code", - "execution_count": 103, + "execution_count": 40, "id": "92a47f3a-127f-41e8-bee1-6276885bd36b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 6.1: .0013 seconds, answer 5877594983578 ok" + "Puzzle 6.1: .0014 seconds, answer 5877594983578 ok" ] }, - "execution_count": 103, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" } @@ -1178,13 +1178,18 @@ "\n", "The problem in the leftmost column is not \"`4 + 6 + 827 + 9472`\"; rather it is \"`9 + 84 + 27 + 4672`\".\n", "\n", - "That means I can't just split each line into numbers, I'll have to be careful to maintain the blank spaces, and I have to know the difference between a blank space that marks a separator between problems versus a blank space that marks the lack of a digit within a problem. In `grand_total2` I first break each line into columns (which requires finding the column indexes that are all blank spaces), then I do the math." + "That means I can't just split each line into numbers, I'll have to be careful to maintain the blank spaces to the right and left of the digits, and I have to know in what position each column starts and ends. That part was tricky, so here's an explanation:\n", + "- I note from the worksheet above that each column starts at a position above a `+` or `*` sign.\n", + "- Each column ends one character befpre the next `+` or `*` sign (one character is a blank space to separate columns).\n", + "- For the last column there is no terminator, so I'll add the string `' *'` to the operator line before computing the start positions.\n", + "\n", + "In `grand_total2` I first break each line into columns, take the transpose of that (to give a list of problems), do the math on each problem, and return the sum of the results. Within `cephalopodish_math` I call `vertically`, whioch again does a transpose and then puts the digits together into an integer." ] }, { "cell_type": "code", - "execution_count": 104, - "id": "f332aec9-dbfa-4bf9-b338-9a33c5f3bd89", + "execution_count": 41, + "id": "5866583b-245d-4a43-a037-229bf35f1be2", "metadata": {}, "outputs": [], "source": [ @@ -1196,37 +1201,40 @@ "def break_into_columns(worksheet: List[str]) -> List[List[str]]:\n", " \"\"\"Break a whole worksheet into columns by finding the `blanks` (the columns with\n", " only blank spaces) and then separating each line at these posisitons.\"\"\"\n", - " worksheet = [' ' + line + ' ' for line in worksheet] # Blanks on each end of line\n", " *number_lines, operator_line = worksheet\n", - " blanks = [i for i in range(len(worksheet[0]))\n", - " if all(line[i] == ' ' for line in number_lines)]\n", - " return [break_line_into_columns(line, blanks) for line in worksheet]\n", + " operator_line = operator_line.ljust(len(worksheet[0])) + ' *'\n", + " column_starts = [i for i, ch in enumerate(operator_line) if ch != ' ']\n", + " return [break_line_into_columns(line, column_starts) for line in worksheet]\n", "\n", - "def break_line_into_columns(line: str, blanks: List[int]) -> List[str]:\n", + "def break_line_into_columns(line: str, column_starts: List[int]) -> List[str]:\n", " \"\"\"Break one line into columns, as specified by the list of `blanks` positions.\"\"\"\n", - " return [line[blanks[i]+1:blanks[i + 1]] \n", - " for i in range(len(blanks) - 1)]\n", + " return [line[column_starts[i]:column_starts[i + 1]-1] \n", + " for i in range(len(column_starts) - 1)]\n", "\n", "def cephalopodish_math(problem) -> int:\n", " \"\"\"Return the sum or product of the vertically-arranged numbers.\"\"\"\n", " *numbers, op = problem\n", - " sum_or_prod = {'+': sum, '*': prod}[op.strip()]\n", - " return sum_or_prod(int(cat(digits)) for digits in T(numbers))" + " sum_or_prod = (sum if op.strip() == '+' else prod)\n", + " return sum_or_prod(vertically(numbers))\n", + "\n", + "def vertically(numbers: List[str]) -> List[int]:\n", + " \"\"\"Return a list of integers found by read numbers vertically by column.\"\"\"\n", + " return [int(cat(digits)) for digits in T(numbers)]" ] }, { "cell_type": "code", - "execution_count": 105, + "execution_count": 42, "id": "39a8fa78-946f-45aa-8d36-76883f4aeaff", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Puzzle 6.2: .0048 seconds, answer 11159825706149 ok" + "Puzzle 6.2: .0039 seconds, answer 11159825706149 ok" ] }, - "execution_count": 105, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" } @@ -1241,26 +1249,39 @@ "id": "ca461ef3-50c3-4189-b724-5f2b3898f27d", "metadata": {}, "source": [ - "I initially had an `IndexError` **bug** because the operator line is shorter then the numbers lines. Then I had an off-by-one **bug** that made me mess up the problem in the last column. To debug my errors I worked on the smaller example worksheet, doing things like this:" + "I initially had an `IndexError` **bug** because the operator line is shorter then the numbers lines. Then I had an off-by-one **bug** that messed up the problem in the last column. To debug my errors I worked on the smaller example worksheet, doing things like this:" ] }, { "cell_type": "code", - "execution_count": 106, + "execution_count": 43, "id": "a13dbe89-3178-433f-9a50-28ed9a2f8358", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "3263827" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "worksheet2 = \"\"\"\\\n", + "example = \"\"\"\\\n", "123 328 51 64 \n", " 45 64 387 23 \n", " 6 98 215 314\n", - "* + * +\"\"\".splitlines()" + "* + * +\"\"\".splitlines()\n", + "\n", + "grand_total2(example)" ] }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 44, "id": "3aa0b661-367a-4316-905a-60f1d9e6df01", "metadata": {}, "outputs": [ @@ -1270,48 +1291,216 @@ "[['123', '328', ' 51', '64 '],\n", " [' 45', '64 ', '387', '23 '],\n", " [' 6', '98 ', '215', '314'],\n", - " ['* ', '+ ', '* ', '+ ']]" + " ['* ', '+ ', '* ', '+']]" ] }, - "execution_count": 107, + "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "break_into_columns(worksheet2)" + "break_into_columns(example)" ] }, { "cell_type": "code", - "execution_count": 110, + "execution_count": 45, "id": "13392d9c-fef8-4946-b945-48ad6bc7eca9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "('123', ' 45', ' 6', '* ')" + "[('123', ' 45', ' 6', '* '),\n", + " ('328', '64 ', '98 ', '+ '),\n", + " (' 51', '387', '215', '* '),\n", + " ('64 ', '23 ', '314', '+')]" ] }, - "execution_count": 110, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "problems = T(break_into_columns(worksheet2))\n", - "problems[0]" + "T(break_into_columns(example))" ] }, { "cell_type": "code", - "execution_count": 115, + "execution_count": 46, + "id": "e29df77c-7385-4ba9-a27b-4074a78a0d74", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 24, 356]" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vertically(('123', \n", + " ' 45', \n", + " ' 6'))" + ] + }, + { + "cell_type": "code", + "execution_count": 47, "id": "9a25ff50-f465-4de3-95ca-71b7a3d9569b", "metadata": {}, "outputs": [], "source": [ - "assert cephalopodish_math(problems[0]) == 1 * 24 * 356" + "assert cephalopodish_math(('123', ' 45', ' 6', '* ')) == 1 * 24 * 356 == 8544" + ] + }, + { + "cell_type": "markdown", + "id": "953679f2-8b55-4bcb-b46f-db0d7c435ea3", + "metadata": {}, + "source": [ + "# [Day 7](https://adventofcode.com/2025/day/7): Laboratories\n", + "\n", + "In the teleporter lab, we locate a diagram of a tachyon manifold, which is in need of repair. We obtain a diagram of the manifold, in which the `S` marks the start of the tachyon beams and a `^` is a splitter. \n", + "\n", + "I could parse this as a `Grid`, but I think I will just keep it as a list of strings. The main idea of a `Grid` is dealing with the 4 or 8 neighbors; a concept that this problem does not use." + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "e85af831-b6cf-4073-a131-ce68debaea75", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "────────────────────────────────────────────────────────────────────────────────────────────────────\n", + "Puzzle input ➜ 142 strs:\n", + "────────────────────────────────────────────────────────────────────────────────────────────────────\n", + "......................................................................S......................... ...\n", + "................................................................................................ ...\n", + "......................................................................^......................... ...\n", + "................................................................................................ ...\n", + ".....................................................................^.^........................ ...\n", + "................................................................................................ ...\n", + "....................................................................^.^.^....................... ...\n", + "................................................................................................ ...\n", + "...\n" + ] + } + ], + "source": [ + "manifold = parse(7)" + ] + }, + { + "cell_type": "markdown", + "id": "59927e26-3252-4c26-8aef-014afdb6deaf", + "metadata": {}, + "source": [ + "### Part 1: How many times will the beam be split?\n", + "\n", + "Tachyon beams move downwards unless they enounter a splitter, in which case they split into two beams, one immediately to the left of the splitter and one to the right, which each continue down from there. We're asked how many splits occur. If two beams end up in the same place they count as one beam, so if that beam is split again, that's just one more split, not two more.\n", + "\n", + "That suggests I should keep a `set` of current beam positions, and update the set every time we go down one line. (It is a set rather than a list so that duplicate beam positins count as one, not as two.) I also need to keep track of a count of the number of splits, and return that at the end:" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "77852da2-0599-40e1-b949-f33ed69277c3", + "metadata": {}, + "outputs": [], + "source": [ + "### Part 1: How many times will the beam be split?\n", + "\n", + "def count_splits(manifold: List[str]) -> int:\n", + " \"\"\"How many beam split events occur as the beams make their way through the manifold?\"\"\"\n", + " beams = {manifold[0].index('S')}\n", + " split_count = 0\n", + " for line in manifold:\n", + " for b in list(beams):\n", + " if line[b] == '^': # Replace the beam position with one on each side\n", + " split_count += 1\n", + " beams.remove(b)\n", + " beams.update({b - 1, b + 1})\n", + " return split_count" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "0e14ad5e-6871-4a9c-bd94-5a863c2341e0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Puzzle 7.1: .0008 seconds, answer 1681 ok" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "answer(7.1, 1681, lambda:\n", + " count_splits(manifold))" + ] + }, + { + "cell_type": "markdown", + "id": "7e8174b9-2b66-41ce-9677-807a90b88ec5", + "metadata": {}, + "source": [ + "### Part 2: In total, how many different timelines would a single tachyon particle end up on?\n", + "\n", + "Now we're told this is a *quantum* tachyon manifold and we need to know how many different timelines a single tachyon appears in, or equivalently, how many different paths can the tachyon beams take. \n", + "\n", + "We can't just count the number of beams in the last line, because if a beam in position *b* takes two diffferent paths to get there, that counts as two, not one. Instead, I'll replace the `set` from Part 1 with a `Counter` of `{beam_position: number_of_paths_to_get_here}`. If a beam at position *b* with *n* paths to get there encounters a splitter, then in the next step both positions *b* - 1 and *b* + 1 are incremented by *n*. In the end we return the sum of all the numbers of paths.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "c231059d-edad-4f1c-b584-e811fa8fad46", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Puzzle 7.2: .0013 seconds, answer 422102272495018 ok" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def count_timelines(manifold: List[str]) -> int:\n", + " \"\"\"How many possible paths are there to the final line of the manifold?\"\"\"\n", + " beams = Counter({manifold[0].index('S'): 1})\n", + " for line in manifold:\n", + " for b, n in list(beams.items()):\n", + " if line[b] == '^':\n", + " beams[b] = 0\n", + " beams[b - 1] += n\n", + " beams[b + 1] += n\n", + " return sum(beams.values())\n", + "\n", + "answer(7.2, 422102272495018, lambda:\n", + " count_timelines(manifold))" ] }, { @@ -1324,7 +1513,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 52, "id": "ba36579c-d0b4-4fd3-939c-0026ecddd7e9", "metadata": {}, "outputs": [ @@ -1332,44 +1521,28 @@ "name": "stdout", "output_type": "stream", "text": [ - "Puzzle 1.1: .0006 seconds, answer 1182 ok\n", + "Puzzle 1.1: .0005 seconds, answer 1182 ok\n", "Puzzle 1.2: .0009 seconds, answer 6907 ok\n", - "Puzzle 2.1: .0031 seconds, answer 23560874270 ok\n", - "Puzzle 2.2: .0040 seconds, answer 44143124633 ok\n", + "Puzzle 2.1: .0030 seconds, answer 23560874270 ok\n", + "Puzzle 2.2: .0041 seconds, answer 44143124633 ok\n", "Puzzle 3.1: .0006 seconds, answer 17085 ok\n", "Puzzle 3.2: .0020 seconds, answer 169408143086082 ok\n", - "Puzzle 4.1: .0531 seconds, answer 1569 ok\n", - "Puzzle 4.2: .1394 seconds, answer 9280 ok\n", - "Puzzle 5.1: .0072 seconds, answer 635 ok\n", + "Puzzle 4.1: .0541 seconds, answer 1569 ok\n", + "Puzzle 4.2: .1421 seconds, answer 9280 ok\n", + "Puzzle 5.1: .0076 seconds, answer 635 ok\n", "Puzzle 5.2: .0001 seconds, answer 369761800782619 ok\n", - "Puzzle 6.1: .0015 seconds, answer 5877594983578 ok\n", - "Puzzle 6.2: .0082 seconds, answer 11159825706149 ok\n" + "Puzzle 6.1: .0014 seconds, answer 5877594983578 ok\n", + "Puzzle 6.2: .0039 seconds, answer 11159825706149 ok\n", + "Puzzle 7.1: .0008 seconds, answer 1681 ok\n", + "Puzzle 7.2: .0013 seconds, answer 422102272495018 ok\n", + "\n", + "Time in seconds: total = 0.222, mean = 0.016, max = 0.142\n" ] - }, - { - "data": { - "text/plain": [ - "0.22060370445251465" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "for d in sorted(answers):\n", - " print(answers[d])\n", - "sum(a.secs for a in answers.values())" + "summary(answers)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "72764869-84bf-4471-91a9-bf65889de29c", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": {