Advent of Code

This commit is contained in:
Peter Norvig 2025-12-04 21:32:27 -08:00 committed by GitHub
parent ac4b9ec9be
commit 134a3b5ac9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -25,7 +25,15 @@
"execution_count": 1,
"id": "d5f1da68-5da6-434d-a068-1d93497a86b3",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Matplotlib is building the font cache; this may take a moment.\n"
]
}
],
"source": [
"%run AdventUtils.ipynb\n",
"current_year = 2025"
@ -123,7 +131,7 @@
{
"data": {
"text/plain": [
"Puzzle 1.1: .0008 seconds, answer 1182 ok"
"Puzzle 1.1: .0004 seconds, answer 1182 ok"
]
},
"execution_count": 4,
@ -157,7 +165,7 @@
{
"data": {
"text/plain": [
"Puzzle 1.2: .1516 seconds, answer 6907 ok"
"Puzzle 1.2: .0968 seconds, answer 6907 ok"
]
},
"execution_count": 5,
@ -187,7 +195,7 @@
{
"data": {
"text/plain": [
"Puzzle 1.2: .0489 seconds, answer 6907 ok"
"Puzzle 1.2: .0312 seconds, answer 6907 ok"
]
},
"execution_count": 6,
@ -238,7 +246,7 @@
{
"data": {
"text/plain": [
"Puzzle 1.2: .0010 seconds, answer 6907 ok"
"Puzzle 1.2: .0007 seconds, answer 6907 ok"
]
},
"execution_count": 8,
@ -350,7 +358,7 @@
},
{
"cell_type": "code",
"execution_count": 75,
"execution_count": 11,
"id": "1345f93d-84c5-43f8-b6c2-9fc7b8f5ed90",
"metadata": {},
"outputs": [],
@ -379,7 +387,7 @@
{
"data": {
"text/plain": [
"Puzzle 2.1: .0030 seconds, answer 23560874270 ok"
"Puzzle 2.1: .0021 seconds, answer 23560874270 ok"
]
},
"execution_count": 12,
@ -450,7 +458,7 @@
{
"data": {
"text/plain": [
"Puzzle 2.1: .0029 seconds, answer 23560874270 ok"
"Puzzle 2.1: .0021 seconds, answer 23560874270 ok"
]
},
"execution_count": 14,
@ -472,7 +480,7 @@
{
"data": {
"text/plain": [
"Puzzle 2.2: .0038 seconds, answer 44143124633 ok"
"Puzzle 2.2: .0032 seconds, answer 44143124633 ok"
]
},
"execution_count": 15,
@ -539,7 +547,7 @@
"source": [
"### Part 1: What is the maximum possible total output joltage?\n",
"\n",
"We can turn on exactly two batteries in each bank, resulting in a two digit number which is the *joltage* of the bank. For example, given the bank \"8647\" we could choose to turn on the \"8\" and \"7\" to produce a joltage of 87. The function `joltage` chooses the biggest first digit, and then the biggest second digit that follows the first digit. Note that the possible choices for the first digit exclude the last digit, because if we chose that, then we couldn't choose a second digit to follow. Note also I chose to return a string rather than an int; that seemed simpler within `joltage` but it does mean the caller might need to do a conversion."
"We can turn on exactly two batteries in each bank, resulting in a two digit number which is the *joltage* of the bank. For example, given the bank \"8647\" we could choose to turn on the \"8\" and \"7\" to produce a joltage of 87. The function `joltage` chooses the biggest first digit, and then the biggest second digit that follows the first digit. Note that the possible choices for the first digit exclude the last digit, because if we chose that, then we couldn't choose a second digit to follow. Note I chose to do the string to int conversion in `total_joltage`; it would also be fine to have `joltage` return an int."
]
},
{
@ -550,10 +558,15 @@
"outputs": [],
"source": [
"def joltage(bank: str) -> str:\n",
" \"\"\"The maximum possible joltage by turning on 2 batteries in the bank.\"\"\"\n",
" choices = bank[:-1] # The first digit can't be the last character\n",
" index = first(bank.index(d) for d in '987654321' if d in choices)\n",
" return bank[index] + max(bank[index + 1:])\n",
" \"\"\"The maximum possible joltage by turning on 2 batteries in the bank.\n",
" Pick the first digit, then the biggest digit from the rest of the bank.\"\"\"\n",
" digit = max(bank[:-1]) # The first digit can't be the last character\n",
" rest = bank[bank.index(digit) + 1:]\n",
" return digit + max(rest)\n",
"\n",
"def total_joltage(banks: List[str]) -> int:\n",
" \"\"\"The maximum possible joltage from all the banks.\"\"\"\n",
" return sum(int(joltage(bank)) for bank in banks)\n",
"\n",
"assert joltage(\"8647\") == \"87\"\n",
"assert joltage(\"1119\") == \"19\""
@ -568,7 +581,7 @@
{
"data": {
"text/plain": [
"Puzzle 3.1: .0004 seconds, answer 17085 ok"
"Puzzle 3.1: .0005 seconds, answer 17085 ok"
]
},
"execution_count": 18,
@ -578,7 +591,7 @@
],
"source": [
"answer(3.1, 17085, lambda:\n",
" sum(int(joltage(b)) for b in banks))"
" total_joltage(banks))"
]
},
{
@ -590,7 +603,7 @@
"\n",
"In Part 2 the elf hits the \"joltage limit safety override\" button, and we can now turn on 12 batteries per bank, resulting in a 12-digit joltage. What is the new maximum possible total joltage?\n",
"\n",
"I will make a change to the function `joltage`, passing it the number of digits remaining to be chosen, *n*. The function stops when we get to 1 digit remaining, and recurses when there is more than one digit remaining. At each step we need to make sure the choice of first digit leaves *n*-1 digits for later choices."
"I will make a change to the two functions, passing in the number of digits to be chosen, *n*. The function `joltage` stops when we get to 1 digit remaining, and recurses when there is more than one digit remaining, choosing the first digit from the bank up to the last *n* - 1 characters, then recursively finding the biggest joltage from the rest, but with *n* - 1 choices. "
]
},
{
@ -601,13 +614,18 @@
"outputs": [],
"source": [
"def joltage(bank: str, n=2) -> str:\n",
" \"\"\"The maximum possible joltage by turning on `n` batteries in the bank.\"\"\"\n",
" \"\"\"The maximum possible joltage by turning on `n` batteries in the bank.\n",
" Pick the first digit, then the maximum joltage from the rest of the bank.\"\"\"\n",
" if n == 1:\n",
" return max(bank)\n",
" else:\n",
" choices = bank[:-(n - 1)]\n",
" index = first(bank.index(d) for d in '987654321' if d in choices)\n",
" return bank[index] + joltage(bank[index + 1:], n - 1)\n",
" digit = max(bank[:-(n - 1)]) # The first digit can't be the last n-1 characters\n",
" rest = bank[bank.index(digit) + 1:]\n",
" return digit + joltage(rest, n - 1)\n",
"\n",
"def total_joltage(banks: List[str], n=2) -> int:\n",
" \"\"\"The maximum possible joltage from all the banks.\"\"\"\n",
" return sum(int(joltage(bank, n)) for bank in banks)\n",
"\n",
"assert joltage(\"811111111111119\", 2) == '89'\n",
"assert joltage(\"818181911112111\", 5) == '92111'\n",
@ -631,7 +649,7 @@
{
"data": {
"text/plain": [
"Puzzle 3.1: .0005 seconds, answer 17085 ok"
"Puzzle 3.1: .0006 seconds, answer 17085 ok"
]
},
"execution_count": 20,
@ -641,7 +659,7 @@
],
"source": [
"answer(3.1, 17085, lambda:\n",
" sum(int(joltage(b)) for b in banks))"
" total_joltage(banks))"
]
},
{
@ -653,7 +671,7 @@
{
"data": {
"text/plain": [
"Puzzle 3.2: .0022 seconds, answer 169408143086082 ok"
"Puzzle 3.2: .0015 seconds, answer 169408143086082 ok"
]
},
"execution_count": 21,
@ -663,7 +681,7 @@
],
"source": [
"answer(3.2, 169408143086082, lambda:\n",
" sum(int(joltage(b, 12)) for b in banks))"
" total_joltage(banks, 12))"
]
},
{
@ -673,12 +691,12 @@
"source": [
"# [Day 4](https://adventofcode.com/2025/day/4): Printing Department\n",
"\n",
"The floor of the printing department is divided into squares. Many squares contain a roll of paper; other squares are empty. The day's input is a map of the floor, with `@` representing a roll of paper. I can handle that with the `Grid` class from my AdventUtils:"
"The floor of the printing department is divided into squares. Some squares contain a roll of paper; other squares are empty. The day's input is a map of the floor, with `@` representing a roll of paper. I can handle that with the `Grid` class from my AdventUtils:"
]
},
{
"cell_type": "code",
"execution_count": 39,
"execution_count": 22,
"id": "c9f227d5-2748-48e1-80c1-7385dad46323",
"metadata": {},
"outputs": [
@ -746,7 +764,7 @@
{
"data": {
"text/plain": [
"Puzzle 4.1: .0540 seconds, answer 1569 ok"
"Puzzle 4.1: .0331 seconds, answer 1569 ok"
]
},
"execution_count": 24,
@ -773,7 +791,7 @@
},
{
"cell_type": "code",
"execution_count": 68,
"execution_count": 25,
"id": "0ed53853-268c-4c2f-a929-cb3e6005a348",
"metadata": {},
"outputs": [],
@ -797,7 +815,7 @@
{
"data": {
"text/plain": [
"Puzzle 4.2: 1.2023 seconds, answer 9280 ok"
"Puzzle 4.2: .7829 seconds, answer 9280 ok"
]
},
"execution_count": 26,
@ -820,7 +838,7 @@
},
{
"cell_type": "code",
"execution_count": 69,
"execution_count": 27,
"id": "15741f57-8527-4427-8cea-84951a1d14ee",
"metadata": {},
"outputs": [],
@ -839,17 +857,17 @@
},
{
"cell_type": "code",
"execution_count": 70,
"execution_count": 28,
"id": "bcba970b-09aa-479b-9c6d-4f6a7ac49fed",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Puzzle 4.2: .1436 seconds, answer 9280 ok"
"Puzzle 4.2: .0916 seconds, answer 9280 ok"
]
},
"execution_count": 70,
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
@ -861,11 +879,22 @@
},
{
"cell_type": "code",
"execution_count": 53,
"execution_count": 29,
"id": "c4afcd9a-bf21-4b50-9081-9739e87eef30",
"metadata": {},
"outputs": [],
"source": []
"source": [
"# [Day 5](https://adventofcode.com/2025/day/5): Cafeteria"
]
},
{
"cell_type": "raw",
"id": "425a0e43-9240-4fdf-983e-53ac0196bea2",
"metadata": {},
"source": [
"ingredient_ids = parse(5, positive_ints)\n",
"ingredient_ids"
]
},
{
"cell_type": "markdown",
@ -877,7 +906,7 @@
},
{
"cell_type": "code",
"execution_count": 48,
"execution_count": 31,
"id": "ba36579c-d0b4-4fd3-939c-0026ecddd7e9",
"metadata": {},
"outputs": [
@ -885,14 +914,14 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Puzzle 1.1: .0008 seconds, answer 1182 ok\n",
"Puzzle 1.2: .0010 seconds, answer 6907 ok\n",
"Puzzle 2.1: .0029 seconds, answer 23560874270 ok\n",
"Puzzle 2.2: .0038 seconds, answer 44143124633 ok\n",
"Puzzle 3.1: .0005 seconds, answer 17085 ok\n",
"Puzzle 3.2: .0022 seconds, answer 169408143086082 ok\n",
"Puzzle 4.1: .0540 seconds, answer 1569 ok\n",
"Puzzle 4.2: .1484 seconds, answer 9280 ok\n"
"Puzzle 1.1: .0004 seconds, answer 1182 ok\n",
"Puzzle 1.2: .0007 seconds, answer 6907 ok\n",
"Puzzle 2.1: .0021 seconds, answer 23560874270 ok\n",
"Puzzle 2.2: .0032 seconds, answer 44143124633 ok\n",
"Puzzle 3.1: .0006 seconds, answer 17085 ok\n",
"Puzzle 3.2: .0015 seconds, answer 169408143086082 ok\n",
"Puzzle 4.1: .0331 seconds, answer 1569 ok\n",
"Puzzle 4.2: .0916 seconds, answer 9280 ok\n"
]
}
],
@ -926,7 +955,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.15"
"version": "3.13.5"
}
},
"nbformat": 4,