Add files via upload

This commit is contained in:
Peter Norvig 2024-12-17 23:17:19 -08:00 committed by GitHub
parent 0f16deb1a9
commit 268e1edcdb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 459 additions and 170 deletions

View File

@ -334,7 +334,7 @@
{
"data": {
"text/plain": [
"Puzzle 2.2: .0021 seconds, answer 328 ok"
"Puzzle 2.2: .0023 seconds, answer 328 ok"
]
},
"execution_count": 19,
@ -463,7 +463,7 @@
{
"data": {
"text/plain": [
"Puzzle 3.2: .0004 seconds, answer 75920122 ok"
"Puzzle 3.2: .0005 seconds, answer 75920122 ok"
]
},
"execution_count": 27,
@ -608,7 +608,7 @@
{
"data": {
"text/plain": [
"Puzzle 4.2: .0272 seconds, answer 1822 ok"
"Puzzle 4.2: .0268 seconds, answer 1822 ok"
]
},
"execution_count": 35,
@ -823,7 +823,7 @@
{
"data": {
"text/plain": [
"Puzzle 5.2: .0009 seconds, answer 4130 ok"
"Puzzle 5.2: .0008 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: .0014 seconds, answer 5329 ok"
]
},
"execution_count": 52,
@ -993,7 +993,7 @@
{
"data": {
"text/plain": [
"Puzzle 6.2: 1.9934 seconds, answer 2162 ok"
"Puzzle 6.2: 1.9643 seconds, answer 2162 ok"
]
},
"execution_count": 55,
@ -1121,14 +1121,6 @@
"metadata": {},
"outputs": [],
"source": [
"def can_be_calibrated(numbers: ints, operators=(operator.add, operator.mul)) -> bool:\n",
" \"\"\"Can the tuple of numbers be calibrated as a correct equation using '+' and '*' ?\"\"\"\n",
" target, first, *rest = numbers\n",
" results = {first} # A set of all possible results of the partial computation\n",
" for y in rest:\n",
" results = {op(x, y) for x in results if x <= target for op in operators}\n",
" return target in results\n",
"\n",
"def can_be_calibrated(numbers: ints, operators=(operator.add, operator.mul)) -> bool:\n",
" \"\"\"Can the tuple of numbers be calibrated as a correct equation using '+' and '*' ?\"\"\"\n",
" target, first, *rest = numbers\n",
@ -1147,7 +1139,7 @@
{
"data": {
"text/plain": [
"Puzzle 7.1: .0214 seconds, answer 1985268524462 ok"
"Puzzle 7.1: .0213 seconds, answer 1985268524462 ok"
]
},
"execution_count": 64,
@ -1179,7 +1171,7 @@
{
"data": {
"text/plain": [
"Puzzle 7.2: 1.0915 seconds, answer 150077710195188 ok"
"Puzzle 7.2: 1.0804 seconds, answer 150077710195188 ok"
]
},
"execution_count": 66,
@ -1275,7 +1267,7 @@
{
"data": {
"text/plain": [
"Puzzle 8.1: .0027 seconds, answer 220 ok"
"Puzzle 8.1: .0029 seconds, answer 220 ok"
]
},
"execution_count": 71,
@ -1330,7 +1322,7 @@
{
"data": {
"text/plain": [
"Puzzle 8.1: .0029 seconds, answer 220 ok"
"Puzzle 8.1: .0026 seconds, answer 220 ok"
]
},
"execution_count": 74,
@ -1352,7 +1344,7 @@
{
"data": {
"text/plain": [
"Puzzle 8.2: .0031 seconds, answer 813 ok"
"Puzzle 8.2: .0030 seconds, answer 813 ok"
]
},
"execution_count": 75,
@ -1465,7 +1457,7 @@
{
"data": {
"text/plain": [
"Puzzle 9.1: .0193 seconds, answer 6332189866718 ok"
"Puzzle 9.1: .0197 seconds, answer 6332189866718 ok"
]
},
"execution_count": 81,
@ -1545,7 +1537,7 @@
{
"data": {
"text/plain": [
"Puzzle 9.2: 2.7416 seconds, answer 6353648390778 ok"
"Puzzle 9.2: 2.7519 seconds, answer 6353648390778 ok"
]
},
"execution_count": 84,
@ -1654,7 +1646,7 @@
{
"data": {
"text/plain": [
"Puzzle 10.1: .0047 seconds, answer 744 ok"
"Puzzle 10.1: .0045 seconds, answer 744 ok"
]
},
"execution_count": 90,
@ -1705,7 +1697,7 @@
{
"data": {
"text/plain": [
"Puzzle 10.2: .0059 seconds, answer 1651 ok"
"Puzzle 10.2: .0062 seconds, answer 1651 ok"
]
},
"execution_count": 93,
@ -1847,7 +1839,7 @@
{
"data": {
"text/plain": [
"Puzzle 11.1: .0658 seconds, answer 194482 ok"
"Puzzle 11.1: .0671 seconds, answer 194482 ok"
]
},
"execution_count": 100,
@ -1908,7 +1900,7 @@
{
"data": {
"text/plain": [
"Puzzle 11.1: .0016 seconds, answer 194482 ok"
"Puzzle 11.1: .0015 seconds, answer 194482 ok"
]
},
"execution_count": 104,
@ -1930,7 +1922,7 @@
{
"data": {
"text/plain": [
"Puzzle 11.2: .0595 seconds, answer 232454623677743 ok"
"Puzzle 11.2: .0599 seconds, answer 232454623677743 ok"
]
},
"execution_count": 105,
@ -2062,7 +2054,7 @@
{
"data": {
"text/plain": [
"Puzzle 12.1: .0334 seconds, answer 1402544 ok"
"Puzzle 12.1: .0329 seconds, answer 1402544 ok"
]
},
"execution_count": 113,
@ -2157,7 +2149,7 @@
{
"data": {
"text/plain": [
"Puzzle 12.2: .0434 seconds, answer 862486 ok"
"Puzzle 12.2: .0430 seconds, answer 862486 ok"
]
},
"execution_count": 117,
@ -2277,7 +2269,7 @@
{
"data": {
"text/plain": [
"Puzzle 13.1: .0106 seconds, answer 29598 ok"
"Puzzle 13.1: .0102 seconds, answer 29598 ok"
]
},
"execution_count": 122,
@ -2789,42 +2781,42 @@
"</style>\n",
"\n",
"<div class=\"animation\">\n",
" <img id=\"_anim_imgae252cea00e945ac938aee942061fc97\">\n",
" <img id=\"_anim_img1e0a1734c1b64f26ba0a7f3051a934a3\">\n",
" <div class=\"anim-controls\">\n",
" <input id=\"_anim_sliderae252cea00e945ac938aee942061fc97\" type=\"range\" class=\"anim-slider\"\n",
" <input id=\"_anim_slider1e0a1734c1b64f26ba0a7f3051a934a3\" type=\"range\" class=\"anim-slider\"\n",
" name=\"points\" min=\"0\" max=\"1\" step=\"1\" value=\"0\"\n",
" oninput=\"animae252cea00e945ac938aee942061fc97.set_frame(parseInt(this.value));\">\n",
" oninput=\"anim1e0a1734c1b64f26ba0a7f3051a934a3.set_frame(parseInt(this.value));\">\n",
" <div class=\"anim-buttons\">\n",
" <button title=\"Decrease speed\" aria-label=\"Decrease speed\" onclick=\"animae252cea00e945ac938aee942061fc97.slower()\">\n",
" <button title=\"Decrease speed\" aria-label=\"Decrease speed\" onclick=\"anim1e0a1734c1b64f26ba0a7f3051a934a3.slower()\">\n",
" <i class=\"fa fa-minus\"></i></button>\n",
" <button title=\"First frame\" aria-label=\"First frame\" onclick=\"animae252cea00e945ac938aee942061fc97.first_frame()\">\n",
" <button title=\"First frame\" aria-label=\"First frame\" onclick=\"anim1e0a1734c1b64f26ba0a7f3051a934a3.first_frame()\">\n",
" <i class=\"fa fa-fast-backward\"></i></button>\n",
" <button title=\"Previous frame\" aria-label=\"Previous frame\" onclick=\"animae252cea00e945ac938aee942061fc97.previous_frame()\">\n",
" <button title=\"Previous frame\" aria-label=\"Previous frame\" onclick=\"anim1e0a1734c1b64f26ba0a7f3051a934a3.previous_frame()\">\n",
" <i class=\"fa fa-step-backward\"></i></button>\n",
" <button title=\"Play backwards\" aria-label=\"Play backwards\" onclick=\"animae252cea00e945ac938aee942061fc97.reverse_animation()\">\n",
" <button title=\"Play backwards\" aria-label=\"Play backwards\" onclick=\"anim1e0a1734c1b64f26ba0a7f3051a934a3.reverse_animation()\">\n",
" <i class=\"fa fa-play fa-flip-horizontal\"></i></button>\n",
" <button title=\"Pause\" aria-label=\"Pause\" onclick=\"animae252cea00e945ac938aee942061fc97.pause_animation()\">\n",
" <button title=\"Pause\" aria-label=\"Pause\" onclick=\"anim1e0a1734c1b64f26ba0a7f3051a934a3.pause_animation()\">\n",
" <i class=\"fa fa-pause\"></i></button>\n",
" <button title=\"Play\" aria-label=\"Play\" onclick=\"animae252cea00e945ac938aee942061fc97.play_animation()\">\n",
" <button title=\"Play\" aria-label=\"Play\" onclick=\"anim1e0a1734c1b64f26ba0a7f3051a934a3.play_animation()\">\n",
" <i class=\"fa fa-play\"></i></button>\n",
" <button title=\"Next frame\" aria-label=\"Next frame\" onclick=\"animae252cea00e945ac938aee942061fc97.next_frame()\">\n",
" <button title=\"Next frame\" aria-label=\"Next frame\" onclick=\"anim1e0a1734c1b64f26ba0a7f3051a934a3.next_frame()\">\n",
" <i class=\"fa fa-step-forward\"></i></button>\n",
" <button title=\"Last frame\" aria-label=\"Last frame\" onclick=\"animae252cea00e945ac938aee942061fc97.last_frame()\">\n",
" <button title=\"Last frame\" aria-label=\"Last frame\" onclick=\"anim1e0a1734c1b64f26ba0a7f3051a934a3.last_frame()\">\n",
" <i class=\"fa fa-fast-forward\"></i></button>\n",
" <button title=\"Increase speed\" aria-label=\"Increase speed\" onclick=\"animae252cea00e945ac938aee942061fc97.faster()\">\n",
" <button title=\"Increase speed\" aria-label=\"Increase speed\" onclick=\"anim1e0a1734c1b64f26ba0a7f3051a934a3.faster()\">\n",
" <i class=\"fa fa-plus\"></i></button>\n",
" </div>\n",
" <form title=\"Repetition mode\" aria-label=\"Repetition mode\" action=\"#n\" name=\"_anim_loop_selectae252cea00e945ac938aee942061fc97\"\n",
" <form title=\"Repetition mode\" aria-label=\"Repetition mode\" action=\"#n\" name=\"_anim_loop_select1e0a1734c1b64f26ba0a7f3051a934a3\"\n",
" class=\"anim-state\">\n",
" <input type=\"radio\" name=\"state\" value=\"once\" id=\"_anim_radio1_ae252cea00e945ac938aee942061fc97\"\n",
" <input type=\"radio\" name=\"state\" value=\"once\" id=\"_anim_radio1_1e0a1734c1b64f26ba0a7f3051a934a3\"\n",
" >\n",
" <label for=\"_anim_radio1_ae252cea00e945ac938aee942061fc97\">Once</label>\n",
" <input type=\"radio\" name=\"state\" value=\"loop\" id=\"_anim_radio2_ae252cea00e945ac938aee942061fc97\"\n",
" <label for=\"_anim_radio1_1e0a1734c1b64f26ba0a7f3051a934a3\">Once</label>\n",
" <input type=\"radio\" name=\"state\" value=\"loop\" id=\"_anim_radio2_1e0a1734c1b64f26ba0a7f3051a934a3\"\n",
" checked>\n",
" <label for=\"_anim_radio2_ae252cea00e945ac938aee942061fc97\">Loop</label>\n",
" <input type=\"radio\" name=\"state\" value=\"reflect\" id=\"_anim_radio3_ae252cea00e945ac938aee942061fc97\"\n",
" <label for=\"_anim_radio2_1e0a1734c1b64f26ba0a7f3051a934a3\">Loop</label>\n",
" <input type=\"radio\" name=\"state\" value=\"reflect\" id=\"_anim_radio3_1e0a1734c1b64f26ba0a7f3051a934a3\"\n",
" >\n",
" <label for=\"_anim_radio3_ae252cea00e945ac938aee942061fc97\">Reflect</label>\n",
" <label for=\"_anim_radio3_1e0a1734c1b64f26ba0a7f3051a934a3\">Reflect</label>\n",
" </form>\n",
" </div>\n",
"</div>\n",
@ -2834,9 +2826,9 @@
" /* Instantiate the Animation class. */\n",
" /* The IDs given should match those used in the template above. */\n",
" (function() {\n",
" var img_id = \"_anim_imgae252cea00e945ac938aee942061fc97\";\n",
" var slider_id = \"_anim_sliderae252cea00e945ac938aee942061fc97\";\n",
" var loop_select_id = \"_anim_loop_selectae252cea00e945ac938aee942061fc97\";\n",
" var img_id = \"_anim_img1e0a1734c1b64f26ba0a7f3051a934a3\";\n",
" var slider_id = \"_anim_slider1e0a1734c1b64f26ba0a7f3051a934a3\";\n",
" var loop_select_id = \"_anim_loop_select1e0a1734c1b64f26ba0a7f3051a934a3\";\n",
" var frames = new Array(3);\n",
" \n",
" frames[0] = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8AAAALQCAYAAABfdxm0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90\\\n",
@ -5608,14 +5600,14 @@
" /* set a timeout to make sure all the above elements are created before\n",
" the object is initialized. */\n",
" setTimeout(function() {\n",
" animae252cea00e945ac938aee942061fc97 = new Animation(frames, img_id, slider_id, 200.0,\n",
" anim1e0a1734c1b64f26ba0a7f3051a934a3 = new Animation(frames, img_id, slider_id, 200.0,\n",
" loop_select_id);\n",
" }, 0);\n",
" })()\n",
"</script>\n"
],
"text/plain": [
"<matplotlib.animation.FuncAnimation at 0x16967e060>"
"<matplotlib.animation.FuncAnimation at 0x16078a5a0>"
]
},
"execution_count": 140,
@ -5848,42 +5840,42 @@
"</style>\n",
"\n",
"<div class=\"animation\">\n",
" <img id=\"_anim_imge46cbc345c6d4e34aba519ec8cb115f1\">\n",
" <img id=\"_anim_img4e5b0d0e6fe24e0ea5f0bb1cec42557f\">\n",
" <div class=\"anim-controls\">\n",
" <input id=\"_anim_slidere46cbc345c6d4e34aba519ec8cb115f1\" type=\"range\" class=\"anim-slider\"\n",
" <input id=\"_anim_slider4e5b0d0e6fe24e0ea5f0bb1cec42557f\" type=\"range\" class=\"anim-slider\"\n",
" name=\"points\" min=\"0\" max=\"1\" step=\"1\" value=\"0\"\n",
" oninput=\"anime46cbc345c6d4e34aba519ec8cb115f1.set_frame(parseInt(this.value));\">\n",
" oninput=\"anim4e5b0d0e6fe24e0ea5f0bb1cec42557f.set_frame(parseInt(this.value));\">\n",
" <div class=\"anim-buttons\">\n",
" <button title=\"Decrease speed\" aria-label=\"Decrease speed\" onclick=\"anime46cbc345c6d4e34aba519ec8cb115f1.slower()\">\n",
" <button title=\"Decrease speed\" aria-label=\"Decrease speed\" onclick=\"anim4e5b0d0e6fe24e0ea5f0bb1cec42557f.slower()\">\n",
" <i class=\"fa fa-minus\"></i></button>\n",
" <button title=\"First frame\" aria-label=\"First frame\" onclick=\"anime46cbc345c6d4e34aba519ec8cb115f1.first_frame()\">\n",
" <button title=\"First frame\" aria-label=\"First frame\" onclick=\"anim4e5b0d0e6fe24e0ea5f0bb1cec42557f.first_frame()\">\n",
" <i class=\"fa fa-fast-backward\"></i></button>\n",
" <button title=\"Previous frame\" aria-label=\"Previous frame\" onclick=\"anime46cbc345c6d4e34aba519ec8cb115f1.previous_frame()\">\n",
" <button title=\"Previous frame\" aria-label=\"Previous frame\" onclick=\"anim4e5b0d0e6fe24e0ea5f0bb1cec42557f.previous_frame()\">\n",
" <i class=\"fa fa-step-backward\"></i></button>\n",
" <button title=\"Play backwards\" aria-label=\"Play backwards\" onclick=\"anime46cbc345c6d4e34aba519ec8cb115f1.reverse_animation()\">\n",
" <button title=\"Play backwards\" aria-label=\"Play backwards\" onclick=\"anim4e5b0d0e6fe24e0ea5f0bb1cec42557f.reverse_animation()\">\n",
" <i class=\"fa fa-play fa-flip-horizontal\"></i></button>\n",
" <button title=\"Pause\" aria-label=\"Pause\" onclick=\"anime46cbc345c6d4e34aba519ec8cb115f1.pause_animation()\">\n",
" <button title=\"Pause\" aria-label=\"Pause\" onclick=\"anim4e5b0d0e6fe24e0ea5f0bb1cec42557f.pause_animation()\">\n",
" <i class=\"fa fa-pause\"></i></button>\n",
" <button title=\"Play\" aria-label=\"Play\" onclick=\"anime46cbc345c6d4e34aba519ec8cb115f1.play_animation()\">\n",
" <button title=\"Play\" aria-label=\"Play\" onclick=\"anim4e5b0d0e6fe24e0ea5f0bb1cec42557f.play_animation()\">\n",
" <i class=\"fa fa-play\"></i></button>\n",
" <button title=\"Next frame\" aria-label=\"Next frame\" onclick=\"anime46cbc345c6d4e34aba519ec8cb115f1.next_frame()\">\n",
" <button title=\"Next frame\" aria-label=\"Next frame\" onclick=\"anim4e5b0d0e6fe24e0ea5f0bb1cec42557f.next_frame()\">\n",
" <i class=\"fa fa-step-forward\"></i></button>\n",
" <button title=\"Last frame\" aria-label=\"Last frame\" onclick=\"anime46cbc345c6d4e34aba519ec8cb115f1.last_frame()\">\n",
" <button title=\"Last frame\" aria-label=\"Last frame\" onclick=\"anim4e5b0d0e6fe24e0ea5f0bb1cec42557f.last_frame()\">\n",
" <i class=\"fa fa-fast-forward\"></i></button>\n",
" <button title=\"Increase speed\" aria-label=\"Increase speed\" onclick=\"anime46cbc345c6d4e34aba519ec8cb115f1.faster()\">\n",
" <button title=\"Increase speed\" aria-label=\"Increase speed\" onclick=\"anim4e5b0d0e6fe24e0ea5f0bb1cec42557f.faster()\">\n",
" <i class=\"fa fa-plus\"></i></button>\n",
" </div>\n",
" <form title=\"Repetition mode\" aria-label=\"Repetition mode\" action=\"#n\" name=\"_anim_loop_selecte46cbc345c6d4e34aba519ec8cb115f1\"\n",
" <form title=\"Repetition mode\" aria-label=\"Repetition mode\" action=\"#n\" name=\"_anim_loop_select4e5b0d0e6fe24e0ea5f0bb1cec42557f\"\n",
" class=\"anim-state\">\n",
" <input type=\"radio\" name=\"state\" value=\"once\" id=\"_anim_radio1_e46cbc345c6d4e34aba519ec8cb115f1\"\n",
" <input type=\"radio\" name=\"state\" value=\"once\" id=\"_anim_radio1_4e5b0d0e6fe24e0ea5f0bb1cec42557f\"\n",
" >\n",
" <label for=\"_anim_radio1_e46cbc345c6d4e34aba519ec8cb115f1\">Once</label>\n",
" <input type=\"radio\" name=\"state\" value=\"loop\" id=\"_anim_radio2_e46cbc345c6d4e34aba519ec8cb115f1\"\n",
" <label for=\"_anim_radio1_4e5b0d0e6fe24e0ea5f0bb1cec42557f\">Once</label>\n",
" <input type=\"radio\" name=\"state\" value=\"loop\" id=\"_anim_radio2_4e5b0d0e6fe24e0ea5f0bb1cec42557f\"\n",
" checked>\n",
" <label for=\"_anim_radio2_e46cbc345c6d4e34aba519ec8cb115f1\">Loop</label>\n",
" <input type=\"radio\" name=\"state\" value=\"reflect\" id=\"_anim_radio3_e46cbc345c6d4e34aba519ec8cb115f1\"\n",
" <label for=\"_anim_radio2_4e5b0d0e6fe24e0ea5f0bb1cec42557f\">Loop</label>\n",
" <input type=\"radio\" name=\"state\" value=\"reflect\" id=\"_anim_radio3_4e5b0d0e6fe24e0ea5f0bb1cec42557f\"\n",
" >\n",
" <label for=\"_anim_radio3_e46cbc345c6d4e34aba519ec8cb115f1\">Reflect</label>\n",
" <label for=\"_anim_radio3_4e5b0d0e6fe24e0ea5f0bb1cec42557f\">Reflect</label>\n",
" </form>\n",
" </div>\n",
"</div>\n",
@ -5893,9 +5885,9 @@
" /* Instantiate the Animation class. */\n",
" /* The IDs given should match those used in the template above. */\n",
" (function() {\n",
" var img_id = \"_anim_imge46cbc345c6d4e34aba519ec8cb115f1\";\n",
" var slider_id = \"_anim_slidere46cbc345c6d4e34aba519ec8cb115f1\";\n",
" var loop_select_id = \"_anim_loop_selecte46cbc345c6d4e34aba519ec8cb115f1\";\n",
" var img_id = \"_anim_img4e5b0d0e6fe24e0ea5f0bb1cec42557f\";\n",
" var slider_id = \"_anim_slider4e5b0d0e6fe24e0ea5f0bb1cec42557f\";\n",
" var loop_select_id = \"_anim_loop_select4e5b0d0e6fe24e0ea5f0bb1cec42557f\";\n",
" var frames = new Array(1);\n",
" \n",
" frames[0] = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8AAAALQCAYAAABfdxm0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90\\\n",
@ -6573,14 +6565,14 @@
" /* set a timeout to make sure all the above elements are created before\n",
" the object is initialized. */\n",
" setTimeout(function() {\n",
" anime46cbc345c6d4e34aba519ec8cb115f1 = new Animation(frames, img_id, slider_id, 200.0,\n",
" anim4e5b0d0e6fe24e0ea5f0bb1cec42557f = new Animation(frames, img_id, slider_id, 200.0,\n",
" loop_select_id);\n",
" }, 0);\n",
" })()\n",
"</script>\n"
],
"text/plain": [
"<matplotlib.animation.FuncAnimation at 0x16ab7be90>"
"<matplotlib.animation.FuncAnimation at 0x160058d10>"
]
},
"execution_count": 143,
@ -6612,7 +6604,7 @@
{
"data": {
"text/plain": [
"Puzzle 14.2: 1.8776 seconds, answer 6876 ok"
"Puzzle 14.2: 1.8645 seconds, answer 6876 ok"
]
},
"execution_count": 145,
@ -6731,7 +6723,7 @@
{
"data": {
"text/plain": [
"Puzzle 15.1: .0241 seconds, answer 1563092 ok"
"Puzzle 15.1: .0248 seconds, answer 1563092 ok"
]
},
"execution_count": 150,
@ -6808,7 +6800,7 @@
{
"data": {
"text/plain": [
"Puzzle 15.1: .0296 seconds, answer 1563092 ok"
"Puzzle 15.1: .0299 seconds, answer 1563092 ok"
]
},
"execution_count": 153,
@ -6830,7 +6822,7 @@
{
"data": {
"text/plain": [
"Puzzle 15.2: .0418 seconds, answer 1582688 ok"
"Puzzle 15.2: .0415 seconds, answer 1582688 ok"
]
},
"execution_count": 154,
@ -6987,7 +6979,7 @@
{
"data": {
"text/plain": [
"Puzzle 16.1: .1477 seconds, answer 103512 ok"
"Puzzle 16.1: .1473 seconds, answer 103512 ok"
]
},
"execution_count": 162,
@ -7051,7 +7043,7 @@
{
"data": {
"text/plain": [
"Puzzle 16.2: .8603 seconds, answer 554 ok"
"Puzzle 16.2: .8496 seconds, answer 554 ok"
]
},
"execution_count": 165,
@ -7101,6 +7093,16 @@
"()\n",
"('Program', 2, 4, 1, 7, 7, 5, 0, 3, 4, 4, 1, 7, 5, 5, 3, 0)\n"
]
},
{
"data": {
"text/plain": [
"Computer(A=52042868, B=0, C=0, prog=[2, 4, 1, 7, 7, 5, 0, 3, 4, 4, 1, 7, 5, 5, 3, 0])"
]
},
"execution_count": 167,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
@ -7115,27 +7117,7 @@
" case ['Program', *vals]: kwds['prog'] = vals\n",
" return Computer(**kwds)\n",
" \n",
"computer = initialize(parse(17, atoms))"
]
},
{
"cell_type": "code",
"execution_count": 168,
"id": "68cecfae-c690-45f1-8a23-94733624a774",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Computer(A=52042868, B=0, C=0, prog=[2, 4, 1, 7, 7, 5, 0, 3, 4, 4, 1, 7, 5, 5, 3, 0])"
]
},
"execution_count": 168,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"computer = initialize(parse(17, atoms))\n",
"computer"
]
},
@ -7151,7 +7133,7 @@
},
{
"cell_type": "code",
"execution_count": 170,
"execution_count": 169,
"id": "d98f88cc-c435-43fc-bcb5-52e6dd70fdb1",
"metadata": {},
"outputs": [],
@ -7160,21 +7142,20 @@
" \"\"\"Run the program on the computer, yielding each output.\"\"\"\n",
" A, B, C, prog = computer\n",
" pc = 0\n",
" def combo(v): return A if v == 4 else B if v == 5 else C if v == 6 else v\n",
" while pc < len(prog):\n",
" op, val = prog[pc:pc+2]\n",
" pc += 2\n",
" combo = (A if val == 4 else B if val == 5 else C if val == 6 else val)\n",
" match op:\n",
" case 0: A = A // (2 ** combo(val))\n",
" case 6: B = A // (2 ** combo(val))\n",
" case 7: C = A // (2 ** combo(val))\n",
" case 0: A = A // (2 ** combo)\n",
" case 6: B = A // (2 ** combo)\n",
" case 7: C = A // (2 ** combo)\n",
" case 1: B = B ^ val\n",
" case 4: B = B ^ C\n",
" case 2: B = combo(val) % 8\n",
" case 5: yield combo(val) % 8\n",
" case 2: B = combo % 8\n",
" case 5: yield combo % 8\n",
" case 3: \n",
" if A != 0:\n",
" pc = val"
" if A: pc = val"
]
},
{
@ -7187,7 +7168,7 @@
},
{
"cell_type": "code",
"execution_count": 172,
"execution_count": 171,
"id": "860f24e5-92ad-4361-8920-102ebc573598",
"metadata": {},
"outputs": [
@ -7197,7 +7178,7 @@
"Puzzle 17.1: .0000 seconds, answer 2,1,0,1,7,2,5,0,3 ok"
]
},
"execution_count": 172,
"execution_count": 171,
"metadata": {},
"output_type": "execute_result"
}
@ -7214,19 +7195,53 @@
"source": [
"### Part 2: What is the lowest positive initial value for register A that causes the program to output a copy of itself?\n",
"\n",
"In Part 2, we find that register A has been corrupted, and we need to restore it to the value that will make the program output a copy of itself. I was afraid of this! In past years there were problems where you had to actually understand what a program was doing in order to answer; you couldn't use brute force. I'll try looking at some possible values, but I'm pretty sure it won't work. Another day I'll try to figure it out."
"In Part 2, we find that register A has been corrupted, and we need to restore it to the value that will make the program output a copy of itself (a [Quine](https://en.wikipedia.org/wiki/Quine_%28computing%29)). I was afraid of this! AoC always has a problem where you have to write an interpreter for a program in some obscure language, but then in Part 2 you have to actually understand what the program is doing; you can't use brute force. (I tried brute force up to A=10,000,000 with no luck.)\n",
"\n",
"To try to understand my program, here it is in pseudocode:\n",
"\n",
" top: B = A % 8 # 2, 4\n",
" B = B ^ 7 # 1, 7\n",
" C = A / 2 ** B # 7, 5\n",
" A = A / 2 ** 3 # 0, 3\n",
" B = B ^ C # 4, 4\n",
" B = B ^ 7 # 1, 7\n",
" output B # 5, 5\n",
" if A: goto top # 3, 0\n",
"\n",
"I can summarize that as:\n",
"\n",
" top: B and C are defined in terms of the last octal digit of A, and prior value of B\n",
" A is shifted to eliminate the last octal digit\n",
" output B \n",
" if A: goto top \n",
"\n",
"So I realized that one octal digit of `A` is eliminated on each pass through the loop, and when `A` hits zero, we exit. Each pass outputs one octal digit, so `A` in octal has to be the same length as my program; somewhere in the ten trillion range. Good thing I gave up on brute force. \n",
"\n",
"I realized that I should go right-to-left, outputing one octal digit at a time, and appending one octal digit at a time to `A`. After some trial and error I got the following:"
]
},
{
"cell_type": "code",
"execution_count": 173,
"id": "bb745303-dd20-486f-bbdd-7ae77f995c2c",
"metadata": {},
"outputs": [],
"source": [
"def run_with(computer=computer, **kwds) -> Ints: \n",
" \"\"\"Run the program with registers set to the given values.\"\"\"\n",
" return list(run_program(computer._replace(**kwds)))"
]
},
{
"cell_type": "code",
"execution_count": 174,
"id": "809bcd1b-e428-4449-971e-0bc63aca08fb",
"id": "54ac9b9c-70d9-4356-91c5-40fb285634b4",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'No answer!'"
"[2, 4, 1, 7, 7, 5, 0, 3, 4, 4, 1, 7, 5, 5, 3, 0]"
]
},
"execution_count": 174,
@ -7235,8 +7250,279 @@
}
],
"source": [
"first(i for i in range(100_000)\n",
" if list(run_program(computer._replace(A=i))) == computer.prog) or 'No answer!'"
"computer.prog"
]
},
{
"cell_type": "code",
"execution_count": 175,
"id": "36d89d9a-c8fc-41be-820b-cb13e40793c0",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[0]"
]
},
"execution_count": 175,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"run_with(A=0o7)"
]
},
{
"cell_type": "code",
"execution_count": 176,
"id": "892fef38-5f9b-4370-a242-f7a10df5487b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[3, 0]"
]
},
"execution_count": 176,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"run_with(A=0o72)"
]
},
{
"cell_type": "code",
"execution_count": 177,
"id": "b3d11d5e-30c2-419f-bc11-3f26fbdddfbb",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[5, 3, 0]"
]
},
"execution_count": 177,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"run_with(A=0o726)"
]
},
{
"cell_type": "markdown",
"id": "f40f775f-bb9d-459c-80c3-ac09b6b42904",
"metadata": {},
"source": [
"That is, my program ends in `5,3,0`, and an octal `7` outputs a `0`; an octal `0o72` outputs `3,0`, and octal `0o726` outputs `5,3,0`. So here's my approach for finding the Quine program:\n",
"- I'm going to keerp a set of candidate values for `A` as the set `As`.\n",
"- The set starts with just `{0}`.\n",
"- On each iteration I try appending each octal digit to each element of the set `As`.\n",
"- I keep the candidate `A` values whose output matches the tail of the program's output.\n",
"- Iterate this for each digit and return the set of `A` vcalues that produce the whole program.\n",
"- Take the minium of the set."
]
},
{
"cell_type": "code",
"execution_count": 179,
"id": "a49c6de9-4e6b-47e5-bcf0-2972a95c1af3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Puzzle 17.2: .0232 seconds, answer 267265166222235 ok"
]
},
"execution_count": 179,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def quine(computer) -> Set[int]:\n",
" \"\"\"Find the values of `A` that cause the output to match the program.\"\"\"\n",
" As = {0}\n",
" for d in reversed(range(len(computer.prog))):\n",
" tail = computer.prog[d:]\n",
" candidates = {(A << 3) + i for A in As for i in range(8)}\n",
" As = {A for A in candidates if run_with(A=A) == tail}\n",
" return As\n",
"\n",
"answer(17.2, 267265166222235, \n",
" lambda: min(quine(computer)))"
]
},
{
"cell_type": "markdown",
"id": "c7f9e900-45be-401f-a6f2-a1d7b751fae6",
"metadata": {},
"source": [
"# [Day 18](https://adventofcode.com/2024/day/18): RAM Run\n",
"\n",
"In today's narrative, we're inside a computer, on a 2D memory board, and bytes are falling down, at specified (x, y) positions, as given in our input:"
]
},
{
"cell_type": "code",
"execution_count": 181,
"id": "d14e1966-2feb-4553-9a0a-12595ef4f7d7",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
"Puzzle input ➜ 3450 strs:\n",
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
"40,65\n",
"17,1\n",
"34,45\n",
"31,51\n",
"29,43\n",
"25,9\n",
"14,27\n",
"5,29\n",
"...\n",
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
"Parsed representation ➜ 3450 tuples:\n",
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
"(40, 65)\n",
"(17, 1)\n",
"(34, 45)\n",
"(31, 51)\n",
"(29, 43)\n",
"(25, 9)\n",
"(14, 27)\n",
"(5, 29)\n",
"...\n"
]
}
],
"source": [
"falling_bytes = parse(18, ints)"
]
},
{
"cell_type": "markdown",
"id": "1229cec7-a456-4dd6-a668-8a00591c63f7",
"metadata": {},
"source": [
"### Part 1: What is the minimum number of steps needed to reach the exit?\n",
"\n",
"When a byte falls it creates a barrier. Our task is to find a path that avoids the barriers, from the start in the upper left to the exit in the lower right of a 71 x 71 grid that is the memory board. \n",
"\n",
"This is another search problem, like the maze in Day 16, but without the complications; this time we can take a step in any of the four cardinal directions at unit cost. The problem description says that we should first consider just the first kilobyte (1024 bytes), and I was worried that if I just hand those points to my `Grid` class, it wouldn't cover the whole 71 x 71 grid. Therefore, I created a grid with empty spaces, and then updated with the falling bytes. The function `memory_path` returns a path, and we can then ask for its length to get the answer."
]
},
{
"cell_type": "code",
"execution_count": 183,
"id": "83af4751-38c9-4830-a2fa-78515b59bc97",
"metadata": {},
"outputs": [],
"source": [
"def memory_path(falling_bytes: Tuple[Point], width=71, height=71) -> Grid:\n",
" \"\"\"Make a Grid of the given size with the points as obstacles.\"\"\"\n",
" grid = Grid(['.' * width] * height)\n",
" grid.update({p: '#' for p in falling_bytes})\n",
" problem = GridProblem(grid=grid, initial=(0, 0), goal=sub(grid.size, (1, 1)))\n",
" return A_star_search(problem)"
]
},
{
"cell_type": "code",
"execution_count": 184,
"id": "29da25e2-f3c2-43e3-8769-1d4fcecb807b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Puzzle 18.1: .0138 seconds, answer 344 ok"
]
},
"execution_count": 184,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"answer(18.1, 344, lambda:\n",
" len(memory_path(falling_bytes[:1024])))"
]
},
{
"cell_type": "markdown",
"id": "792bc31e-964d-47fe-a09b-6a95724e641e",
"metadata": {},
"source": [
"### Part 2: What are the coordinates of the first byte that will prevent the exit from being reachable from your starting position?\n",
"\n",
"After 1024 bytes fall there is a path from start to exit, but as more bytes fall we might have to switch to a different path, and eventually there may be no path. We're asked for the first byte position that blocks the last remaining path. I can think of three ways to handle this:\n",
"1) Add falling bytes one at a time and repeat the A-star search each time. **Slow!**\n",
"2) Add falling bytes in binary search fashion: We know adding no bytes is good for getting a path and adding all of them is bad; try half way and then update good or bad depending on whether we found a path. **Pretty fast.**\n",
"3) Optimize (2) by checking which of the falling bytes intersects with the current path; if *n* bytes are ok, and byte *n*+1 is not on the path for *n*, then *n*+1 is ok. Might be a bit faster, but in my opinion not worth the code complexity. We could also incrementally add and remove "
]
},
{
"cell_type": "code",
"execution_count": 186,
"id": "4c0a8dcb-c3af-45e7-9273-8776e8c3ea1d",
"metadata": {},
"outputs": [],
"source": [
"def memory_blocker(falling_bytes) -> Point:\n",
" \"\"\"Which falling byte is the first to block a path to the exit? Do binary search.\"\"\"\n",
" good = 0\n",
" bad = len(falling_bytes) - 1\n",
" while bad - good > 1:\n",
" mid = (good + bad) // 2\n",
" path = memory_path(falling_bytes[:mid + 1])\n",
" if path == search_failure:\n",
" bad = mid\n",
" else:\n",
" good = mid\n",
" return falling_bytes[bad]"
]
},
{
"cell_type": "code",
"execution_count": 187,
"id": "22371144-5d51-440a-918f-a63de73b13ad",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Puzzle 18.2: .0348 seconds, answer 46,18 ok"
]
},
"execution_count": 187,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"answer(18.2, '46,18', lambda:\n",
" cat(memory_blocker(falling_bytes), ','))"
]
},
{
"cell_type": "markdown",
"id": "552f1c6e-052e-43d0-b13f-e8f66f274d63",
"metadata": {},
"source": [
"I admit I initially had an off-by-one **bug** here. I wanted `bad` to be an index into the falling bytes, but it is also natural to have it be the end of a range; I was confused about my choice."
]
},
{
@ -7246,12 +7532,12 @@
"source": [
"# Summary\n",
"\n",
"So far, I've solved all the puzzles except 17.2. Most of them run in well under a second (the median is less than a hundreth of a second), but four of them take over a second."
"So far, I've solved all the puzzles. Most of them run in well under a second (the median is less than a hundreth of a second), but four of them take over a second."
]
},
{
"cell_type": "code",
"execution_count": 176,
"execution_count": 190,
"id": "34813fc9-a000-4cd8-88ae-692851b3242c",
"metadata": {},
"outputs": [
@ -7262,40 +7548,43 @@
"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: .0021 seconds, answer 328 ok\n",
"Puzzle 2.2: .0023 seconds, answer 328 ok\n",
"Puzzle 3.1: .0006 seconds, answer 156388521 ok\n",
"Puzzle 3.2: .0004 seconds, answer 75920122 ok\n",
"Puzzle 3.2: .0005 seconds, answer 75920122 ok\n",
"Puzzle 4.1: .0328 seconds, answer 2401 ok\n",
"Puzzle 4.2: .0272 seconds, answer 1822 ok\n",
"Puzzle 4.2: .0268 seconds, answer 1822 ok\n",
"Puzzle 5.1: .0007 seconds, answer 5762 ok\n",
"Puzzle 5.2: .0009 seconds, answer 4130 ok\n",
"Puzzle 6.1: .0016 seconds, answer 5329 ok\n",
"Puzzle 6.2: 1.9934 seconds, answer 2162 ok\n",
"Puzzle 7.1: .0214 seconds, answer 1985268524462 ok\n",
"Puzzle 7.2: 1.0915 seconds, answer 150077710195188 ok\n",
"Puzzle 8.1: .0029 seconds, answer 220 ok\n",
"Puzzle 8.2: .0031 seconds, answer 813 ok\n",
"Puzzle 9.1: .0193 seconds, answer 6332189866718 ok\n",
"Puzzle 9.2: 2.7416 seconds, answer 6353648390778 ok\n",
"Puzzle 10.1: .0047 seconds, answer 744 ok\n",
"Puzzle 10.2: .0059 seconds, answer 1651 ok\n",
"Puzzle 11.1: .0016 seconds, answer 194482 ok\n",
"Puzzle 11.2: .0595 seconds, answer 232454623677743 ok\n",
"Puzzle 5.2: .0008 seconds, answer 4130 ok\n",
"Puzzle 6.1: .0014 seconds, answer 5329 ok\n",
"Puzzle 6.2: 1.9643 seconds, answer 2162 ok\n",
"Puzzle 7.1: .0213 seconds, answer 1985268524462 ok\n",
"Puzzle 7.2: 1.0804 seconds, answer 150077710195188 ok\n",
"Puzzle 8.1: .0026 seconds, answer 220 ok\n",
"Puzzle 8.2: .0030 seconds, answer 813 ok\n",
"Puzzle 9.1: .0197 seconds, answer 6332189866718 ok\n",
"Puzzle 9.2: 2.7519 seconds, answer 6353648390778 ok\n",
"Puzzle 10.1: .0045 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: .0599 seconds, answer 232454623677743 ok\n",
"Puzzle 12.1: .0307 seconds, answer 1402544 ok\n",
"Puzzle 12.2: .0434 seconds, answer 862486 ok\n",
"Puzzle 12.2: .0430 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.8776 seconds, answer 6876 ok\n",
"Puzzle 15.1: .0296 seconds, answer 1563092 ok\n",
"Puzzle 15.2: .0418 seconds, answer 1582688 ok\n",
"Puzzle 16.1: .1477 seconds, answer 103512 ok\n",
"Puzzle 16.2: .8603 seconds, answer 554 ok\n",
"Puzzle 14.2: 1.8645 seconds, answer 6876 ok\n",
"Puzzle 15.1: .0299 seconds, answer 1563092 ok\n",
"Puzzle 15.2: .0415 seconds, answer 1582688 ok\n",
"Puzzle 16.1: .1473 seconds, answer 103512 ok\n",
"Puzzle 16.2: .8496 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: .0232 seconds, answer 267265166222235 ok\n",
"Puzzle 18.1: .0138 seconds, answer 344 ok\n",
"Puzzle 18.2: .0348 seconds, answer 46,18 ok\n",
"\n",
"Correct: 33/33\n",
"Correct: 36/36\n",
"\n",
"Time in seconds: 0.0047 median, 0.2740 mean, 9.0435 total.\n"
"Time in seconds: 0.0100 median, 0.2517 mean, 9.0607 total.\n"
]
}
],

View File

@ -198,7 +198,7 @@
" comment = (f'' if self.got == unknown else\n",
" f' ok' if self.ok else \n",
" f' WRONG; expected answer is {self.solution}')\n",
" return f'Puzzle {self.puzzle:4.1f}: {secs} seconds, answer {self.got:<15}{comment}'\n",
" return f'Puzzle {self.puzzle:4.1f}: {secs} seconds, answer {self.got:<17}{comment}'\n",
"\n",
"def summary(answers):\n",
" \"\"\"Print a report that summarizes the answers.\"\"\"\n",
@ -554,7 +554,8 @@
" def neighbors(self, point) -> List[Point]:\n",
" \"\"\"Points on the grid that neighbor `point`.\"\"\"\n",
" return [add2(point, Δ) for Δ in self.directions \n",
" if add2(point, Δ) in self or self.default not in (KeyError, None)]\n",
" if (add2(point, Δ) in self) \n",
" or (self.default not in (KeyError, None))]\n",
" \n",
" def neighbor_contents(self, point) -> Iterable:\n",
" \"\"\"The contents of the neighboring points.\"\"\"\n",
@ -664,8 +665,7 @@
"class GridProblem(SearchProblem):\n",
" \"\"\"Problem for searching a grid from a start to a goal location.\n",
" A state is just an (x, y) location in the grid.\"\"\"\n",
" def actions(self, loc): return self.grid.neighbors(loc)\n",
" def result(self, loc1, loc2): return loc2\n",
" def actions(self, pos): return [p for p in self.grid.neighbors(pos) if self.grid[pos] != '#']\n",
" def h(self, node): return taxi_distance(node.state, self.goal) \n",
"\n",
"class Node:\n",