Add files via upload
This commit is contained in:
parent
c42268204b
commit
d25fbb0957
@ -262,7 +262,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 2.1: .0012 seconds, answer 257 ok"
|
"Puzzle 2.1: .0011 seconds, answer 257 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 7,
|
"execution_count": 7,
|
||||||
@ -312,7 +312,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 2.2: .0071 seconds, answer 328 ok"
|
"Puzzle 2.2: .0077 seconds, answer 328 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 9,
|
"execution_count": 9,
|
||||||
@ -400,7 +400,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 3.1: .0013 seconds, answer 156388521 ok"
|
"Puzzle 3.1: .0014 seconds, answer 156388521 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 12,
|
"execution_count": 12,
|
||||||
@ -449,7 +449,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 3.2: .0008 seconds, answer 75920122 ok"
|
"Puzzle 3.2: .0009 seconds, answer 75920122 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 14,
|
"execution_count": 14,
|
||||||
@ -539,7 +539,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 4.1: .0704 seconds, answer 2401 ok"
|
"Puzzle 4.1: .0742 seconds, answer 2401 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 17,
|
"execution_count": 17,
|
||||||
@ -577,7 +577,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 4.2: .0602 seconds, answer 1822 ok"
|
"Puzzle 4.2: .0605 seconds, answer 1822 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 18,
|
"execution_count": 18,
|
||||||
@ -708,7 +708,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 5.1: .0014 seconds, answer 5762 ok"
|
"Puzzle 5.1: .0011 seconds, answer 5762 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 21,
|
"execution_count": 21,
|
||||||
@ -793,7 +793,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 5.2: .0020 seconds, answer 4130 ok"
|
"Puzzle 5.2: .0016 seconds, answer 4130 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 24,
|
"execution_count": 24,
|
||||||
@ -875,7 +875,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 6.1: .0047 seconds, answer 5329 ok"
|
"Puzzle 6.1: .0043 seconds, answer 5329 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 26,
|
"execution_count": 26,
|
||||||
@ -912,9 +912,9 @@
|
|||||||
"- An obstacle position must be somewhere on the guard's path, otherwise it would have no effect.\n",
|
"- An obstacle position must be somewhere on the guard's path, otherwise it would have no effect.\n",
|
||||||
"- The instructions say it can't be the guard's initial position.\n",
|
"- The instructions say it can't be the guard's initial position.\n",
|
||||||
"- A loop is when the guard's path returns to the same position with the same facing. This suggests that my Part 1 solution was not completely helpful: to find duplicate positions in the path I would need a set of position/facing pairs, not just positions.\n",
|
"- A loop is when the guard's path returns to the same position with the same facing. This suggests that my Part 1 solution was not completely helpful: to find duplicate positions in the path I would need a set of position/facing pairs, not just positions.\n",
|
||||||
"- Alternatively, any path that has taken a number of steps equal to the number of empty spaces in the grid must be a loop. That seems simpler. \n",
|
"- I can make slightly less work by only storing the corners of the path: the places where the guard turns. \n",
|
||||||
"- The simplest approach for finding obstacle positions is to temporarily place an obstacle on each point on the path, one at a time, and see if it leads to a loop.\n",
|
"- The simplest approach for finding obstacle positions is to temporarily place an obstacle on each point on the path, one at a time, and see if it leads to a loop.\n",
|
||||||
"- There are 5,329 positions on the path, so the runtime should be about 5,000 times longer than Part 1; on the order of 20 seconds or so. I'll try it, and if it seems too slow, I'll try to think of something else."
|
"- There are 5,329 positions on the path, so the runtime should be about 5,000 times longer than Part 1; on the order of 10 seconds or so. I'll try it, and if it seems too slow, I'll try to think of something better."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -926,16 +926,18 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"def is_loopy_path(grid: Grid, guard_pos, facing=North) -> bool:\n",
|
"def is_loopy_path(grid: Grid, guard_pos, facing=North) -> bool:\n",
|
||||||
" \"\"\"Does the path followed by the guard form a loop?\"\"\"\n",
|
" \"\"\"Does the path followed by the guard form a loop?\"\"\"\n",
|
||||||
" N = len(lab_grid.findall('.')) # Number of empty spaces\n",
|
" path = {(guard_pos, facing)}\n",
|
||||||
" for step in range(N):\n",
|
" while True:\n",
|
||||||
" ahead = add2(guard_pos, facing)\n",
|
" ahead = add2(guard_pos, facing)\n",
|
||||||
" if ahead not in grid:\n",
|
" if ahead not in grid:\n",
|
||||||
" return False # Walked off the grid; not a loop\n",
|
" return False # Walked off the grid; not a loop\n",
|
||||||
" elif grid[ahead] == '#':\n",
|
" elif grid[ahead] == '#':\n",
|
||||||
" facing = make_turn(facing, 'R')\n",
|
" facing = make_turn(facing, 'R')\n",
|
||||||
|
" if (guard_pos, facing) in path:\n",
|
||||||
|
" return True\n",
|
||||||
|
" path.add((guard_pos, facing))\n",
|
||||||
" else:\n",
|
" else:\n",
|
||||||
" guard_pos = ahead\n",
|
" guard_pos = ahead\n",
|
||||||
" return True # Ran too many steps; must be a loop\n",
|
|
||||||
" \n",
|
" \n",
|
||||||
"def find_loopy_obstacles(grid: Grid) -> Iterable[Point]:\n",
|
"def find_loopy_obstacles(grid: Grid) -> Iterable[Point]:\n",
|
||||||
" \"\"\"All positions in which placing an obstacle would result in a loopy path for the guard.\"\"\"\n",
|
" \"\"\"All positions in which placing an obstacle would result in a loopy path for the guard.\"\"\"\n",
|
||||||
@ -956,7 +958,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 6.2: 18.6630 seconds, answer 2162 ok"
|
"Puzzle 6.2: 5.3153 seconds, answer 2162 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 28,
|
"execution_count": 28,
|
||||||
@ -984,7 +986,7 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"# [Day 7](https://adventofcode.com/2024/day/7): Bridge Repair\n",
|
"# [Day 7](https://adventofcode.com/2024/day/7): Bridge Repair\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The narrative for today involves calibrating a bridge, and our input consists of lines of integers, with a colon separating the first integer from the rest: "
|
"The narrative for today involves fixing a bridge, and each line of our input represents a calibration equation for the bridge. Unfortunately, some nearby elephants stole all the operators from the equations, so all that is left are the integers:"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1025,7 +1027,15 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"calibrations = parse(7, ints)"
|
"equations = parse(7, ints)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "be207b67-a970-4f79-85be-5d62b7cedd9f",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"<img src=\"https://pbs.twimg.com/media/GeOKVYiX0AAwNMy?format=jpg&name=medium\" width=400> "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1035,9 +1045,9 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"### Part 1: What is the total calibration result of possibly true equations?\n",
|
"### Part 1: What is the total calibration result of possibly true equations?\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Our task is to treat each line as an equation and find operators to balance it. An input line such as \"3267: 81 40 27\", can be made into the equation \"3267 = 81 + 40 * 27\", with the understanding that all evaluations are done left-to-right, so this is \"3267 = ((81 + 40) * 27)\". The two allowable operators are addition and multiplication. Our task is to compute the sum of all the equations that can be balanced.\n",
|
"Our task is to find operators to balance each equation. The input \"`3267: 81 40 27`\" can be made into the equation \"`3267 = 81 + 40 * 27`\", with the understanding that all evaluations are done left-to-right, so this is \"`3267 = ((81 + 40) * 27)`\". The two allowable operators are addition and multiplication. Our task is to compute the sum of all the equations that can be balanced.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The straightforward approach would be to try both operators on every number. If there are *n* numbers on the right hand side of an equation then there will be 2<sup>*n*</sup> possible equations; is that going to be a problem?"
|
"The straightforward approach is to try both operators on every number. If there are *n* numbers in an equation then there will be 2<sup>*n*-2</sup> possible equations; is that going to be a problem?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1058,7 +1068,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"max(map(len, calibrations))"
|
"max(map(len, equations))"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1066,7 +1076,7 @@
|
|||||||
"id": "e0d9b0b2-fe1e-434e-b84e-c044da3d3673",
|
"id": "e0d9b0b2-fe1e-434e-b84e-c044da3d3673",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"No problem! With 13 numbers on a line there are 11 places to choose an operator, and 2<sup>11</sup> = 2048; a small number. I'll define `can_be_calibrated` to keep a set of `results`, updating the set for each new number and each possible operator."
|
"No problem! With 13 numbers on a line there are 2<sup>11</sup> = 2048 equations; a small number. I'll define `can_be_calibrated` to keep a set of `results`, updating the set for each new number and each possible operator. Although the instructions were a bit vague, it appears that when they talk about \"numbers\" in the equations they mean \"positive integers\". That means that neither addition nor multiplication can cause a number to decrease, so once a result exceeds the target, we'll drop it."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1079,9 +1089,9 @@
|
|||||||
"def can_be_calibrated(numbers: ints, operators=(operator.add, operator.mul)) -> bool:\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",
|
" \"\"\"Can the tuple of numbers be calibrated as a correct equation using '+' and '*' ?\"\"\"\n",
|
||||||
" target, first, *rest = numbers\n",
|
" target, first, *rest = numbers\n",
|
||||||
" results = {first}\n",
|
" results = {first} # A set of all possible results of the partial computation\n",
|
||||||
" for y in rest:\n",
|
" for y in rest:\n",
|
||||||
" results = {op(x, y) for x in results for op in operators}\n",
|
" results = {op(x, y) for x in results if x <= target for op in operators}\n",
|
||||||
" return target in results"
|
" return target in results"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -1094,7 +1104,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 7.1: .0471 seconds, answer 1985268524462 ok"
|
"Puzzle 7.1: .0406 seconds, answer 1985268524462 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 32,
|
"execution_count": 32,
|
||||||
@ -1104,7 +1114,7 @@
|
|||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"answer(7.1, 1985268524462, lambda:\n",
|
"answer(7.1, 1985268524462, lambda:\n",
|
||||||
" sum(numbers[0] for numbers in calibrations if can_be_calibrated(numbers)))"
|
" sum(numbers[0] for numbers in equations if can_be_calibrated(numbers)))"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1114,7 +1124,7 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"### Part 2: What is the total calibration result of possibly true equations, allowing concatenation?\n",
|
"### Part 2: What is the total calibration result of possibly true equations, allowing concatenation?\n",
|
||||||
"\n",
|
"\n",
|
||||||
"In Part 2, the equation \"`192: 17 8 14`\" can be balanced by using a concatenate operator, \"`192 = ((17 || 8) + 14)`\". With three operators, the equation with 11 operators now has 3<sup>11</sup> = 177,147, almost 100 times more than Part 1, so this will take a few seconds:"
|
"In Part 2, we add a third operator: concatentation. The equation \"`192: 17 8 14`\" can be balanced by concatenated 17 and 8 to get 178, and then adding 14: \"`192 = ((17 || 8) + 14)`\". With three operators, the equation with 11 operators now has 3<sup>11</sup> = 177,147 possibilities, almost 100 times more than Part 1, so this will take a few seconds:"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1126,7 +1136,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 7.2: 5.1590 seconds, answer 150077710195188 ok"
|
"Puzzle 7.2: 2.6449 seconds, answer 150077710195188 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 33,
|
"execution_count": 33,
|
||||||
@ -1138,7 +1148,7 @@
|
|||||||
"operators3 = (operator.add, operator.mul, lambda x, y: int(str(x) + str(y)))\n",
|
"operators3 = (operator.add, operator.mul, lambda x, y: int(str(x) + str(y)))\n",
|
||||||
" \n",
|
" \n",
|
||||||
"answer(7.2, 150077710195188, lambda:\n",
|
"answer(7.2, 150077710195188, lambda:\n",
|
||||||
" sum(numbers[0] for numbers in calibrations if can_be_calibrated(numbers, operators3)))"
|
" sum(numbers[0] for numbers in equations if can_be_calibrated(numbers, operators3)))"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1201,7 +1211,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 8.1: .0009 seconds, answer 220 ok"
|
"Puzzle 8.1: .0006 seconds, answer 220 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 35,
|
"execution_count": 35,
|
||||||
@ -1398,7 +1408,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 9.1: .0463 seconds, answer 6332189866718 ok"
|
"Puzzle 9.1: .0433 seconds, answer 6332189866718 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 40,
|
"execution_count": 40,
|
||||||
@ -1479,7 +1489,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 9.2: 6.3337 seconds, answer 6353648390778 ok"
|
"Puzzle 9.2: 6.2098 seconds, answer 6353648390778 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 42,
|
"execution_count": 42,
|
||||||
@ -1588,7 +1598,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 10.1: .0153 seconds, answer 744 ok"
|
"Puzzle 10.1: .0141 seconds, answer 744 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 45,
|
"execution_count": 45,
|
||||||
@ -1610,7 +1620,7 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"The **rating** of a trailhead is the number of distinct paths from the trailhead to a peak.\n",
|
"The **rating** of a trailhead is the number of distinct paths from the trailhead to a peak.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"As in Part 1, I'll keep a frontier and update it on each iteration from 1 to 9, but this time the frontier will be a counter of `{position: count}` where the count indicates the number of paths to that position. On each iteration I'll look at each point `f` on the frontier and see which of the neighboring points `p` have the right elevation, and increment the counts for those points by the count for `f`:"
|
"As in Part 1, I'll keep a frontier and update it on each iteration from 1 to 9, but this time the frontier will be a counter of `{position: count}` where the count indicates the number of paths to that position. On each iteration I'll look at each point `f` on the frontier and see which of the neighboring points `p` have the right elevation, and increment the counts for those points by the count for `f`. This approach is linear in the number of positions, whereas if I followed all possible paths depth-first there could be an exponential number of paths."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1639,7 +1649,7 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"Puzzle 10.2: .0175 seconds, answer 1651 ok"
|
"Puzzle 10.2: .0161 seconds, answer 1651 ok"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 47,
|
"execution_count": 47,
|
||||||
@ -1657,7 +1667,195 @@
|
|||||||
"id": "af410d30-7096-4be6-bb20-904b3c8e2f59",
|
"id": "af410d30-7096-4be6-bb20-904b3c8e2f59",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Today I went pretty fast (for me); I started a few minutes late and finished in 15 minutes. From the point of view of a competitive coder I did foolish things like write docstrings and use variables of more than one letter, so while this time was fast for me, it placed out of the top 1000."
|
"Today I went pretty fast (for me); I started a few minutes late and finished in 15 minutes. From the point of view of a competitive coder I did foolish things like write docstrings and use variables of more than one letter, so while this time was fast for me, it placed well out of the top 1000."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "3e01d7f5-d0f0-4e7b-8cab-eef2afc02f6b",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# [Day 11](https://adventofcode.com/2024/day/11): Plutonian Pebbles\n",
|
||||||
|
"\n",
|
||||||
|
"Today's input is a single line consisting of a list of integers, representing numbers enscribed on some stones, which are arranged in a straight line."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 48,
|
||||||
|
"id": "76b68cef-d8de-4145-b65c-b254fedf1671",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
|
||||||
|
"Puzzle input ➜ 1 str:\n",
|
||||||
|
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
|
||||||
|
"0 27 5409930 828979 4471 3 68524 170\n",
|
||||||
|
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
|
||||||
|
"Parsed representation ➜ 1 tuple:\n",
|
||||||
|
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
|
||||||
|
"(0, 27, 5409930, 828979, 4471, 3, 68524, 170)\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"stones = the(parse(11, ints))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "a7302dc5-5163-4f0b-bdcc-8c00e367391c",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Part 1: How many stones will you have after blinking 25 times?\n",
|
||||||
|
"\n",
|
||||||
|
"Every time you blink, the stones appear to change, according to these rules:\n",
|
||||||
|
"- A stone marked 0 changes to 1.\n",
|
||||||
|
"- Otherwise, a stone with an even number of digits splits into two stones, with the first and second halves of those digits.\n",
|
||||||
|
"- Otherwise, the stone's number is multiplied by 2024.\n",
|
||||||
|
"\n",
|
||||||
|
"I'll define `blink` to simulate the effect of a given number of blinks, and `change_stone` to change a single stone, returning a list of wither one or two stones (the two stones computed by `split_stone`):"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 49,
|
||||||
|
"id": "1513df56-3d6f-42cf-8aec-1bdbeb991d90",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def blink(stones: Ints, blinks=25) -> List[int]:\n",
|
||||||
|
" \"\"\"Simulate the changes in the list of stones after blinking `blinks` times.\"\"\"\n",
|
||||||
|
" for _ in range(blinks):\n",
|
||||||
|
" stones = append(map(change_stone, stones))\n",
|
||||||
|
" return stones\n",
|
||||||
|
" \n",
|
||||||
|
"def change_stone(stone: int) -> List[int]:\n",
|
||||||
|
" \"\"\"Change a single stone into one or two, according to the rules.\"\"\"\n",
|
||||||
|
" digits = str(stone)\n",
|
||||||
|
" return ([1] if stone == 0 else\n",
|
||||||
|
" split_stone(digits) if len(digits) % 2 == 0 else\n",
|
||||||
|
" [stone * 2024])\n",
|
||||||
|
"\n",
|
||||||
|
"def split_stone(digits: str) -> List[int]:\n",
|
||||||
|
" \"\"\"Split a stone into two halves.\"\"\"\n",
|
||||||
|
" half = len(digits) // 2\n",
|
||||||
|
" return [int(digits[:half]), int(digits[half:])]"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 50,
|
||||||
|
"id": "eff17cd0-a2c7-4d69-bc55-c0ef97917915",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"Puzzle 11.1: .1570 seconds, answer 194482 ok"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 50,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"answer(11.1, 194482, lambda:\n",
|
||||||
|
" len(blink(stones)))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "2f65e94f-43e8-4f08-85df-827928c57e0b",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Part 2: How many stones would you have after blinking a total of 75 times?\n",
|
||||||
|
"\n",
|
||||||
|
"It looks like the number of stones is roughly doubling every 2 blinks, so for 75 blinks we could have trillions of stones. I'd like something more efficient. I note that:\n",
|
||||||
|
"- Although the puzzle makes it clear that the stones are in a line, it turns out their position in the line is irrelevant.\n",
|
||||||
|
"- Because all the even-digit numbers get split in half, it seems like many small numbers will appear multiple times. In the example, after 6 blinks the number 2 appears 4 times.\n",
|
||||||
|
"- Therefore, I'll keep a `Counter` of stones rather than a list of stones."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 51,
|
||||||
|
"id": "707b5a97-0296-48df-bdab-e34064cc67c2",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def blink2(stones: Ints], blinks=25) -> Counter:\n",
|
||||||
|
" \"\"\"Simulate the changes after blinking `blinks` times and return a Counter of stones.\"\"\"\n",
|
||||||
|
" counts = Counter(stones)\n",
|
||||||
|
" for _ in range(blinks):\n",
|
||||||
|
" counts = accumulate((s, counts[stone]) \n",
|
||||||
|
" for stone in counts \n",
|
||||||
|
" for s in change_stone(stone))\n",
|
||||||
|
" return counts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "f5bf07ce-b48e-40db-8992-b9b571e66554",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Now we can re-run Part 1 (it should be slightly faster), and run Part 2 without fear of having trillion-element lists:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 52,
|
||||||
|
"id": "efdcdbf8-e8ec-4a85-9d09-90a20e08c66a",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"Puzzle 11.1: .0037 seconds, answer 194482 ok"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 52,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"answer(11.1, 194482, lambda:\n",
|
||||||
|
" total(blink2(stones, 25)))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 53,
|
||||||
|
"id": "657b1f13-ffcc-44c6-84f1-398fa2fcdac7",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"Puzzle 11.2: .1285 seconds, answer 232454623677743 ok"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 53,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"answer(11.2, 232454623677743, lambda:\n",
|
||||||
|
" total(blink2(stones, 75)))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "ce377749-b3e2-4ca4-b50d-e7c3d2e7201a",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Again, I did pretty well, with no errors, and moving at what I thought was a good pace, but I didn't even crack the top 2000 on the leaderboard. I guess I spent too much time writing docstrings and type hints, and refactoring as I go."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1672,7 +1870,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 48,
|
"execution_count": 54,
|
||||||
"id": "34813fc9-a000-4cd8-88ae-692851b3242c",
|
"id": "34813fc9-a000-4cd8-88ae-692851b3242c",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@ -1682,24 +1880,26 @@
|
|||||||
"text": [
|
"text": [
|
||||||
"Puzzle 1.1: .0002 seconds, answer 1830467 ok\n",
|
"Puzzle 1.1: .0002 seconds, answer 1830467 ok\n",
|
||||||
"Puzzle 1.2: .0002 seconds, answer 26674158 ok\n",
|
"Puzzle 1.2: .0002 seconds, answer 26674158 ok\n",
|
||||||
"Puzzle 2.1: .0012 seconds, answer 257 ok\n",
|
"Puzzle 2.1: .0011 seconds, answer 257 ok\n",
|
||||||
"Puzzle 2.2: .0071 seconds, answer 328 ok\n",
|
"Puzzle 2.2: .0077 seconds, answer 328 ok\n",
|
||||||
"Puzzle 3.1: .0013 seconds, answer 156388521 ok\n",
|
"Puzzle 3.1: .0014 seconds, answer 156388521 ok\n",
|
||||||
"Puzzle 3.2: .0008 seconds, answer 75920122 ok\n",
|
"Puzzle 3.2: .0009 seconds, answer 75920122 ok\n",
|
||||||
"Puzzle 4.1: .0704 seconds, answer 2401 ok\n",
|
"Puzzle 4.1: .0742 seconds, answer 2401 ok\n",
|
||||||
"Puzzle 4.2: .0602 seconds, answer 1822 ok\n",
|
"Puzzle 4.2: .0605 seconds, answer 1822 ok\n",
|
||||||
"Puzzle 5.1: .0014 seconds, answer 5762 ok\n",
|
"Puzzle 5.1: .0011 seconds, answer 5762 ok\n",
|
||||||
"Puzzle 5.2: .0020 seconds, answer 4130 ok\n",
|
"Puzzle 5.2: .0016 seconds, answer 4130 ok\n",
|
||||||
"Puzzle 6.1: .0047 seconds, answer 5329 ok\n",
|
"Puzzle 6.1: .0043 seconds, answer 5329 ok\n",
|
||||||
"Puzzle 6.2: 18.6630 seconds, answer 2162 ok\n",
|
"Puzzle 6.2: 5.3153 seconds, answer 2162 ok\n",
|
||||||
"Puzzle 7.1: .0471 seconds, answer 1985268524462 ok\n",
|
"Puzzle 7.1: .0406 seconds, answer 1985268524462 ok\n",
|
||||||
"Puzzle 7.2: 5.1590 seconds, answer 150077710195188 ok\n",
|
"Puzzle 7.2: 2.6449 seconds, answer 150077710195188 ok\n",
|
||||||
"Puzzle 8.1: .0009 seconds, answer 220 ok\n",
|
"Puzzle 8.1: .0006 seconds, answer 220 ok\n",
|
||||||
"Puzzle 8.2: .0021 seconds, answer 813 ok\n",
|
"Puzzle 8.2: .0021 seconds, answer 813 ok\n",
|
||||||
"Puzzle 9.1: .0463 seconds, answer 6332189866718 ok\n",
|
"Puzzle 9.1: .0433 seconds, answer 6332189866718 ok\n",
|
||||||
"Puzzle 9.2: 6.3337 seconds, answer 6353648390778 ok\n",
|
"Puzzle 9.2: 6.2098 seconds, answer 6353648390778 ok\n",
|
||||||
"Puzzle 10.1: .0153 seconds, answer 744 ok\n",
|
"Puzzle 10.1: .0141 seconds, answer 744 ok\n",
|
||||||
"Puzzle 10.2: .0175 seconds, answer 1651 ok\n"
|
"Puzzle 10.2: .0161 seconds, answer 1651 ok\n",
|
||||||
|
"Puzzle 11.1: .0037 seconds, answer 194482 ok\n",
|
||||||
|
"Puzzle 11.2: .1285 seconds, answer 232454623677743 ok\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user