From 9a4949ee010490cbfd9049d89dd73e8f7b919c77 Mon Sep 17 00:00:00 2001 From: Peter Norvig Date: Sat, 28 Dec 2024 14:16:19 -0800 Subject: [PATCH] Add files via upload --- ipynb/Advent-2024.ipynb | 217 ++++++++++++++++++++++------------------ 1 file changed, 117 insertions(+), 100 deletions(-) diff --git a/ipynb/Advent-2024.ipynb b/ipynb/Advent-2024.ipynb index 0ba049e..ef2fd9a 100644 --- a/ipynb/Advent-2024.ipynb +++ b/ipynb/Advent-2024.ipynb @@ -670,7 +670,7 @@ { "data": { "text/plain": [ - "Puzzle 4.2: .015 seconds, answer 1822 ok" + "Puzzle 4.2: .016 seconds, answer 1822 ok" ] }, "execution_count": 42, @@ -1063,7 +1063,7 @@ { "data": { "text/plain": [ - "Puzzle 6.2: 1.943 seconds, answer 2162 ok" + "Puzzle 6.2: 1.977 seconds, answer 2162 ok" ] }, "execution_count": 63, @@ -1308,7 +1308,7 @@ { "data": { "text/plain": [ - "Puzzle 7.2: .592 seconds, answer 150077710195188 ok" + "Puzzle 7.2: .600 seconds, answer 150077710195188 ok" ] }, "execution_count": 78, @@ -1603,7 +1603,7 @@ { "data": { "text/plain": [ - "Puzzle 9.1: .019 seconds, answer 6332189866718 ok" + "Puzzle 9.1: .020 seconds, answer 6332189866718 ok" ] }, "execution_count": 93, @@ -1629,21 +1629,22 @@ "\n", "To find all the slices that indicate files, it is easier to run through the disk map than the disk layout. The function `file_slices` quickly finds all such slices.\n", "\n", - "Finding a free space for a file is more difficult, because we need to find one that is big enough. I'll run through the whole layout from left-to-right each time. This will make it *O*(*n*2) rather than *O*(*n*), but hopefully it won't be too slow. (If I wanted to speed it up I could have an array of starting positions for each desired size of free space.)" + "Finding a free space for a file is more difficult, because we need to find one that is big enough. At first I coded a solution that ran through the whole layout from left-to-right each time. That made it *O*(*n*2). So I added a table: `starts[length]` tells me where to start looking for an empty space of size `length`. That speeds things up." ] }, { "cell_type": "code", "execution_count": 95, - "id": "fcf4d832-3d7d-4987-aa57-e6e0f1df16bf", + "id": "8d34e96a-8ea9-4f92-b0aa-839b216ea14b", "metadata": {}, "outputs": [], "source": [ "def compress_layout2(disk_map: Ints) -> list:\n", " \"\"\"Mutate layout by moving files one at a time from the end to the leftmost free space.\"\"\"\n", " layout = disk_layout(disk_map)\n", + " starts = defaultdict(int)\n", " for file in file_slices(disk_map):\n", - " if free := find_freespace(layout, file):\n", + " if free := find_freespace(layout, file, starts):\n", " layout[file], layout[free] = layout[free], layout[file]\n", " return layout\n", "\n", @@ -1658,11 +1659,12 @@ " slices.reverse()\n", " return slices\n", "\n", - "def find_freespace(layout, file_slice) -> Optional[slice]:\n", + "def find_freespace(layout, file_slice, starts) -> Optional[slice]:\n", " \"\"\"Find a slice position big enough to fit the given file slice, or return None if there is no position.\"\"\"\n", " length = file_slice.stop - file_slice.start\n", " run = 0\n", - " for i in range(layout.index(empty), len(layout)):\n", + " for i in range(layout.index(empty, starts[length]), len(layout)):\n", + " starts[length] = i\n", " if i >= file_slice.start:\n", " return None # We only want to move a file left, not right\n", " elif layout[i] is empty:\n", @@ -1683,7 +1685,7 @@ { "data": { "text/plain": [ - "Puzzle 9.2: 2.384 seconds, answer 6353648390778 ok" + "Puzzle 9.2: .021 seconds, answer 6353648390778 ok" ] }, "execution_count": 96, @@ -1792,7 +1794,7 @@ { "data": { "text/plain": [ - "Puzzle 10.1: .005 seconds, answer 744 ok" + "Puzzle 10.1: .004 seconds, answer 744 ok" ] }, "execution_count": 102, @@ -1994,7 +1996,7 @@ { "data": { "text/plain": [ - "Puzzle 11.1: .067 seconds, answer 194482 ok" + "Puzzle 11.1: .068 seconds, answer 194482 ok" ] }, "execution_count": 113, @@ -2055,7 +2057,7 @@ { "data": { "text/plain": [ - "Puzzle 11.1: .001 seconds, answer 194482 ok" + "Puzzle 11.1: .002 seconds, answer 194482 ok" ] }, "execution_count": 117, @@ -2077,7 +2079,7 @@ { "data": { "text/plain": [ - "Puzzle 11.2: .060 seconds, answer 232454623677743 ok" + "Puzzle 11.2: .058 seconds, answer 232454623677743 ok" ] }, "execution_count": 118, @@ -2213,7 +2215,7 @@ { "data": { "text/plain": [ - "Puzzle 12.1: .033 seconds, answer 1402544 ok" + "Puzzle 12.1: .032 seconds, answer 1402544 ok" ] }, "execution_count": 126, @@ -2286,7 +2288,7 @@ { "data": { "text/plain": [ - "Puzzle 12.1: .050 seconds, answer 1402544 ok" + "Puzzle 12.1: .052 seconds, answer 1402544 ok" ] }, "execution_count": 129, @@ -2308,7 +2310,7 @@ { "data": { "text/plain": [ - "Puzzle 12.2: .042 seconds, answer 862486 ok" + "Puzzle 12.2: .043 seconds, answer 862486 ok" ] }, "execution_count": 130, @@ -2986,42 +2988,42 @@ "\n", "\n", "
\n", - " \n", + " \n", "
\n", - " \n", + " oninput=\"anime5889f6e232a4cbba19719532f4cbcc2.set_frame(parseInt(this.value));\">\n", "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", "
\n", - "
\n", - " \n", - " \n", - " Once\n", + " \n", - " \n", - " Loop\n", + " \n", - " \n", + " \n", "
\n", "
\n", "
\n", @@ -3031,9 +3033,9 @@ " /* Instantiate the Animation class. */\n", " /* The IDs given should match those used in the template above. */\n", " (function() {\n", - " var img_id = \"_anim_imgdc0d5558c9a0485aa3c468981a103eb2\";\n", - " var slider_id = \"_anim_sliderdc0d5558c9a0485aa3c468981a103eb2\";\n", - " var loop_select_id = \"_anim_loop_selectdc0d5558c9a0485aa3c468981a103eb2\";\n", + " var img_id = \"_anim_imge5889f6e232a4cbba19719532f4cbcc2\";\n", + " var slider_id = \"_anim_slidere5889f6e232a4cbba19719532f4cbcc2\";\n", + " var loop_select_id = \"_anim_loop_selecte5889f6e232a4cbba19719532f4cbcc2\";\n", " var frames = new Array(3);\n", " \n", " frames[0] = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90\\\n", @@ -4770,14 +4772,14 @@ " /* set a timeout to make sure all the above elements are created before\n", " the object is initialized. */\n", " setTimeout(function() {\n", - " animdc0d5558c9a0485aa3c468981a103eb2 = new Animation(frames, img_id, slider_id, 200.0,\n", + " anime5889f6e232a4cbba19719532f4cbcc2 = new Animation(frames, img_id, slider_id, 200.0,\n", " loop_select_id);\n", " }, 0);\n", " })()\n", "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 156, @@ -5010,42 +5012,42 @@ "\n", "\n", "
\n", - " \n", + " \n", "
\n", - " \n", + " oninput=\"anim7295292aa9074d0193a9f80b1d46cca1.set_frame(parseInt(this.value));\">\n", "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", "
\n", - "
\n", - " \n", - " \n", - " Once\n", + " \n", - " \n", - " Loop\n", + " \n", - " \n", + " \n", "
\n", "
\n", "
\n", @@ -5055,9 +5057,9 @@ " /* Instantiate the Animation class. */\n", " /* The IDs given should match those used in the template above. */\n", " (function() {\n", - " var img_id = \"_anim_imgea6b17f8e6f745568d5445b9aa800110\";\n", - " var slider_id = \"_anim_sliderea6b17f8e6f745568d5445b9aa800110\";\n", - " var loop_select_id = \"_anim_loop_selectea6b17f8e6f745568d5445b9aa800110\";\n", + " var img_id = \"_anim_img7295292aa9074d0193a9f80b1d46cca1\";\n", + " var slider_id = \"_anim_slider7295292aa9074d0193a9f80b1d46cca1\";\n", + " var loop_select_id = \"_anim_loop_select7295292aa9074d0193a9f80b1d46cca1\";\n", " var frames = new Array(1);\n", " \n", " frames[0] = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90\\\n", @@ -5446,14 +5448,14 @@ " /* set a timeout to make sure all the above elements are created before\n", " the object is initialized. */\n", " setTimeout(function() {\n", - " animea6b17f8e6f745568d5445b9aa800110 = new Animation(frames, img_id, slider_id, 200.0,\n", + " anim7295292aa9074d0193a9f80b1d46cca1 = new Animation(frames, img_id, slider_id, 200.0,\n", " loop_select_id);\n", " }, 0);\n", " })()\n", "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 159, @@ -5487,7 +5489,7 @@ { "data": { "text/plain": [ - "Puzzle 14.2: 1.828 seconds, answer 6876 ok" + "Puzzle 14.2: 1.866 seconds, answer 6876 ok" ] }, "execution_count": 161, @@ -5609,7 +5611,7 @@ { "data": { "text/plain": [ - "Puzzle 15.1: .026 seconds, answer 1563092 ok" + "Puzzle 15.1: .027 seconds, answer 1563092 ok" ] }, "execution_count": 166, @@ -5877,7 +5879,7 @@ { "data": { "text/plain": [ - "Puzzle 16.1: .146 seconds, answer 103512 ok" + "Puzzle 16.1: .147 seconds, answer 103512 ok" ] }, "execution_count": 178, @@ -5941,7 +5943,7 @@ { "data": { "text/plain": [ - "Puzzle 16.2: .848 seconds, answer 554 ok" + "Puzzle 16.2: .860 seconds, answer 554 ok" ] }, "execution_count": 181, @@ -6547,7 +6549,7 @@ { "data": { "text/plain": [ - "Puzzle 19.1: .040 seconds, answer 242 ok" + "Puzzle 19.1: .039 seconds, answer 242 ok" ] }, "execution_count": 211, @@ -6594,7 +6596,7 @@ { "data": { "text/plain": [ - "Puzzle 19.2: .186 seconds, answer 595975512785325 ok" + "Puzzle 19.2: .185 seconds, answer 595975512785325 ok" ] }, "execution_count": 214, @@ -6762,7 +6764,7 @@ { "data": { "text/plain": [ - "Puzzle 20.1: .029 seconds, answer 1343 ok" + "Puzzle 20.1: .028 seconds, answer 1343 ok" ] }, "execution_count": 224, @@ -6799,7 +6801,7 @@ { "data": { "text/plain": [ - "Puzzle 20.2: .761 seconds, answer 982891 ok" + "Puzzle 20.2: .768 seconds, answer 982891 ok" ] }, "execution_count": 226, @@ -7281,7 +7283,7 @@ { "data": { "text/plain": [ - "Puzzle 22.1: .318 seconds, answer 14273043166 ok" + "Puzzle 22.1: .331 seconds, answer 14273043166 ok" ] }, "execution_count": 255, @@ -7325,7 +7327,7 @@ "Some details:\n", "- A `defaultdict(int)` is a great data structure for the 4-tuple to bananas mapping (a `Counter` is also good).\n", "- A `deque` with `maxlen=4` is a good data structure for keeping the evolving 4-tuple; just append to the deque and it automatically drops old deltas.\n", - "- In `price_timeline` I call `nth_secret(secret, 1)`, so I wish I had made a separate `next_secret` function in Part 1; it would probably speed things up by a percent or two." + "- In `price_timeline` I could call `nth_secret(secret, 1)`, but I decided to make a separate `next_secret` function. I probably should have done that for Part 1." ] }, { @@ -7347,18 +7349,25 @@ " return bananas\n", " \n", "def price_timeline(secret, n=2000) -> Dict[Deltas, int]:\n", - " \"\"\"Each {delta-4-tuple: price} in the timeline of this secret number for `n` steps.\"\"\"\n", + " \"\"\"Each {delta-4-tuple: price} in the timeline of this secret number, for `n` steps.\"\"\"\n", " timeline = {} # {delta-4-tuple: price} pairs\n", " deltas = deque(maxlen=4) # The 4 most recent price deltas \n", " price = secret % 10 # Initial price\n", " for _ in range(n):\n", - " secret = nth_secret(secret, 1)\n", + " secret = next_secret(secret)\n", " price, previous_price = secret % 10, price\n", " deltas.append(price - previous_price)\n", " D = tuple(deltas)\n", " if len(D) == 4 and D not in timeline:\n", " timeline[D] = price\n", - " return timeline" + " return timeline\n", + "\n", + "def next_secret(secret: int) -> int:\n", + " \"\"\"Compute the next secret number after this secret number.\"\"\"\n", + " secret ^= (secret * 64) % 16777216\n", + " secret ^= (secret // 32) % 16777216\n", + " secret ^= (secret * 2048) % 16777216\n", + " return secret" ] }, { @@ -7370,7 +7379,7 @@ { "data": { "text/plain": [ - "Puzzle 22.2: 1.267 seconds, answer 1667 ok" + "Puzzle 22.2: 1.157 seconds, answer 1667 ok" ] }, "execution_count": 258, @@ -7767,7 +7776,7 @@ { "data": { "text/plain": [ - "Puzzle 23.2: .004 seconds, answer bo,dd,eq,ik,lo,lu,ph,ro,rr,rw,uo,wx,yg ok" + "Puzzle 23.2: .003 seconds, answer bo,dd,eq,ik,lo,lu,ph,ro,rr,rw,uo,wx,yg ok" ] }, "execution_count": 281, @@ -8331,7 +8340,7 @@ "\n", "Here are all the puzzle answers and timings. I got all the puzzles correct! And I did it before midnight (my time) on December 25th, a rarity for me. \n", "\n", - "The median run time is about 5 milliseconds, with 4 puzzles taking over a second. I didn't count the time that `parse` takes, but that is less than a millisecond per day." + "The median run time is about 5 milliseconds, with 3 puzzles taking over a second. I didn't count the time that `parse` takes, but that is less than a millisecond per day." ] }, { @@ -8351,58 +8360,66 @@ "Puzzle 3.1: .001 seconds, answer 156388521 ok\n", "Puzzle 3.2: .000 seconds, answer 75920122 ok\n", "Puzzle 4.1: .021 seconds, answer 2401 ok\n", - "Puzzle 4.2: .015 seconds, answer 1822 ok\n", + "Puzzle 4.2: .016 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.943 seconds, answer 2162 ok\n", + "Puzzle 6.2: 1.977 seconds, answer 2162 ok\n", "Puzzle 7.1: .014 seconds, answer 1985268524462 ok\n", - "Puzzle 7.2: .592 seconds, answer 150077710195188 ok\n", + "Puzzle 7.2: .600 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: .019 seconds, answer 6332189866718 ok\n", - "Puzzle 9.2: 2.384 seconds, answer 6353648390778 ok\n", - "Puzzle 10.1: .005 seconds, answer 744 ok\n", + "Puzzle 9.1: .020 seconds, answer 6332189866718 ok\n", + "Puzzle 9.2: .021 seconds, answer 6353648390778 ok\n", + "Puzzle 10.1: .004 seconds, answer 744 ok\n", "Puzzle 10.2: .006 seconds, answer 1651 ok\n", - "Puzzle 11.1: .001 seconds, answer 194482 ok\n", - "Puzzle 11.2: .060 seconds, answer 232454623677743 ok\n", - "Puzzle 12.1: .050 seconds, answer 1402544 ok\n", - "Puzzle 12.2: .042 seconds, answer 862486 ok\n", + "Puzzle 11.1: .002 seconds, answer 194482 ok\n", + "Puzzle 11.2: .058 seconds, answer 232454623677743 ok\n", + "Puzzle 12.1: .052 seconds, answer 1402544 ok\n", + "Puzzle 12.2: .043 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.828 seconds, answer 6876 ok\n", + "Puzzle 14.2: 1.866 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: .146 seconds, answer 103512 ok\n", - "Puzzle 16.2: .848 seconds, answer 554 ok\n", + "Puzzle 16.1: .147 seconds, answer 103512 ok\n", + "Puzzle 16.2: .860 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: .004 seconds, answer 267265166222235 ok\n", "Puzzle 18.1: .014 seconds, answer 344 ok\n", "Puzzle 18.2: .032 seconds, answer 46,18 ok\n", "Puzzle 19.1: .004 seconds, answer 242 ok\n", - "Puzzle 19.2: .186 seconds, answer 595975512785325 ok\n", + "Puzzle 19.2: .185 seconds, answer 595975512785325 ok\n", "Puzzle 20.1: .023 seconds, answer 1343 ok\n", - "Puzzle 20.2: .761 seconds, answer 982891 ok\n", + "Puzzle 20.2: .768 seconds, answer 982891 ok\n", "Puzzle 21.1: .000 seconds, answer 205160 ok\n", "Puzzle 21.2: .004 seconds, answer 252473394928452 ok\n", - "Puzzle 22.1: .318 seconds, answer 14273043166 ok\n", - "Puzzle 22.2: 1.267 seconds, answer 1667 ok\n", + "Puzzle 22.1: .331 seconds, answer 14273043166 ok\n", + "Puzzle 22.2: 1.157 seconds, answer 1667 ok\n", "Puzzle 23.1: .001 seconds, answer 1170 ok\n", - "Puzzle 23.2: .004 seconds, answer bo,dd,eq,ik,lo,lu,ph,ro,rr,rw,uo,wx,yg ok\n", + "Puzzle 23.2: .003 seconds, answer bo,dd,eq,ik,lo,lu,ph,ro,rr,rw,uo,wx,yg ok\n", "Puzzle 24.1: .001 seconds, answer 36035961805936 ok\n", "Puzzle 24.2: .000 seconds, answer jqf,mdd,skh,wpd,wts,z11,z19,z37 ok\n", "Puzzle 25.1: .022 seconds, answer 3196 ok\n", "\n", "Correct: 49/49\n", "\n", - "Time in seconds: 0.005 median, 0.218 mean, 10.699 total.\n" + "Time in seconds: 0.004 median, 0.170 mean, 8.342 total.\n" ] } ], "source": [ "summary(answers)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f23c694-7302-4d45-8bef-751b9a7356f2", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": {