This commit is contained in:
Peter Norvig
2022-12-12 23:05:13 -08:00
committed by GitHub
parent 43283b63b1
commit e31786e7e4

View File

@@ -329,7 +329,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0.000 seconds for correct answer: 8,401\n"
"0.001 seconds for correct answer: 8,401\n"
]
}
],
@@ -878,7 +878,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0.049 seconds for correct answer: 1,829\n"
"0.050 seconds for correct answer: 1,829\n"
]
}
],
@@ -920,7 +920,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0.054 seconds for correct answer: 291,840\n"
"0.055 seconds for correct answer: 291,840\n"
]
}
],
@@ -1043,7 +1043,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0.019 seconds for correct answer: 6,236\n"
"0.021 seconds for correct answer: 6,236\n"
]
}
],
@@ -1091,8 +1091,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0.025 seconds for correct answer: 6,236\n",
"0.109 seconds for correct answer: 2,449\n"
"0.023 seconds for correct answer: 6,236\n",
"0.108 seconds for correct answer: 2,449\n"
]
}
],
@@ -1491,7 +1491,7 @@
"output_type": "stream",
"text": [
"0.001 seconds for correct answer: 54,036\n",
"0.285 seconds for correct answer: 13,237,873,355\n"
"0.282 seconds for correct answer: 13,237,873,355\n"
]
}
],
@@ -1593,7 +1593,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0.035 seconds for correct answer: 394\n"
"0.036 seconds for correct answer: 394\n"
]
}
],
@@ -1650,7 +1650,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Almost a thousand locations; so the search would take over 30 seconds. [Who's got that kind of time?](https://www.gocomics.com/calvinandhobbes/1995/08/17) Instead I'll invent yet another problem subclass, `HillClimbProblem2`, which starts at a dummy state that is off the grid, and can transition with zero cost from that state to any location with height 1:"
"Almost a thousand locations; so the search would take about 30 seconds. [Who's got that kind of time?](https://www.gocomics.com/calvinandhobbes/1995/08/17) Instead I'll invent yet another problem subclass, `HillClimbProblem2`, which starts at a dummy state that is off the grid, and can transition with zero cost from that state to any location with height 1:"
]
},
{
@@ -1662,7 +1662,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0.038 seconds for correct answer: 388\n"
"0.039 seconds for correct answer: 388\n"
]
}
],
@@ -1674,7 +1674,7 @@
" return A_star_search(HillClimbProblem2(off_grid, goal, grid=grid))\n",
"\n",
"class HillClimbProblem2(GridProblem):\n",
" \"\"\"A GridProblem where heights are letters, and you can't climb upward more than one letter.\"\"\"\n",
" \"\"\"Like HillClimbProblem, but with a free pass to any location with height 1.\"\"\"\n",
" \n",
" def action_cost(self, s1, a, s2): return 0 if s1 == off_grid else 1\n",
" \n",
@@ -1692,6 +1692,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"https://pbs.twimg.com/media/FjzvfwfXEB4Pnuc?format=jpg&name=small\" width=400>\n",
"\n",
"#### Part 3: Exploration\n",
"\n",
"I'm interested in seeing what the landscape looks like. We can repurpose the code used to show the forest:"
@@ -1723,6 +1725,165 @@
" cmap=plt.get_cmap('YlGn')))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# [Day 13](https://adventofcode.com/2022/day/13): Distress Signal\n",
"\n",
"\n",
"The input is divided into paragraphs, where each paragraph has two nested list structures, with integer values."
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
"Puzzle input ➜ 449 lines:\n",
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
"[[[[],[7,10,6,5],[],[8]],0,1,[[8,10]],4],[[[4,0,3,2,0]],7],[[],3,[[0,2],8,5],[],[[2,10,4,6]]],[3 ...\n",
"[[0,2,7],[],[10,[[0,7,3,6]]],[2,[8],3]]\n",
"\n",
"[[],[[0,8,[],[0,8,6,7,10]],4,10,[[],9,[1],4,10],3],[[7,1,0],10,[[1,10,7,8],[3,7],[3,6],5],1,0],[ ...\n",
"[[[],0,[[4,5,10],8]],[0,5],[[[1,8,8,8],2],0,[7,9],3]]\n",
"\n",
"...\n",
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
"Parsed representation ➜ 150 tuples:\n",
"────────────────────────────────────────────────────────────────────────────────────────────────────\n",
"([[[[], [7, 10, 6, 5], [], [8]], 0, 1, [[8, 10]], 4], [[[4, 0, 3, 2, 0]], 7], [[], 3, [[0, 2], 8 ...\n",
"([[], [[0, 8, [], [0, 8, 6, 7, 10]], 4, 10, [[], 9, [1], 4, 10], 3], [[7, 1, 0], 10, [[1, 10, 7, ...\n",
"([[3, [[10, 2, 8], 3, 0, [2, 1], 7]], [[[1, 9, 5, 5, 8], 1, 9, [9, 2, 4, 5]], 2, 1, [[], [4, 3], ...\n",
"([[4, 0], [[[5, 7, 10, 9], [1, 8, 0, 3], [10]], 9, 10, []], [5, [[1, 3], 5, 3, [], [4, 8, 0, 2, ...\n",
"([[], [2, [[3, 0, 5]]], [1, [7], [0, [10, 3, 9], 10, [8, 2, 4, 2, 2], [5]], [[0, 2, 3, 1], 3, [8 ...\n",
"([[7], [0, [2], 3], [1, 0], [[], 2], [1, [[6], [4, 3, 10, 2, 5], [6, 9, 3, 3, 0], [8, 5], 10], [ ...\n",
"...\n"
]
}
],
"source": [
"in13 = parse(13, (lambda text: mapt(literal_eval, text.splitlines())), paragraphs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Part 1: Determine which pairs of packets are already in the right order. What is the sum of the indices of those pairs?\n",
"\n",
"The notion of \"right order\" is almost the same as \"less than\", except that an integer is equal to a singleton list. I was confused for a bit because the rules don't say whether two identical lists are in the right order or not. I decided that `right_order` should return `True` or `False` for inputs that are different, and `None` for inputs that are equal. "
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [],
"source": [
"def right_order(left, right) -> Union[bool, None]:\n",
" \"\"\"Are the two packets in the right order? Return `None` if equal.\"\"\"\n",
" types = type(left), type(right)\n",
" if types == (int, int):\n",
" return (None if left == right else left <= right)\n",
" elif types == (int, list):\n",
" return right_order([left], right)\n",
" elif types == (list, int):\n",
" return right_order(left, [right])\n",
" else:\n",
" for L, R in zip(left, right):\n",
" result = right_order(L, R)\n",
" if result != None:\n",
" return result\n",
" return (None if len(left) == len(right) else len(left) < len(right))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That makes things pretty straightforward, but I threw in some test cases just to make sure: "
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [],
"source": [
"assert right_order([1,1,3,1,1], [1,1,5,1,1])\n",
"assert right_order([[1],[2,3,4]], [[1],4])\n",
"assert not right_order([7,7,7,7], [7,7,7]) \n",
"assert not right_order([1,[2,[3,[4,[5,6,7]]]],8,9], [1,[2,[3,[4,[5,6,0]]]],8,9])\n",
"assert right_order([1,2,3], [1,2,3]) == None"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"At this point I'm ready to compute the answer, and was happy to see it worked the first time:"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.000 seconds for correct answer: 5,882\n"
]
}
],
"source": [
"answer(13.1, 5882, lambda: sum(i for i, (L, R) in enumerate(in13, 1) if right_order(L, R)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Part 2: Organize all of the packets into the correct order. What is the decoder key for the distress signal?\n",
"\n",
"This should be easy; all I have to do is sort using `right_order`, then look up the resulting indices of the two divider packets (taking care to use 1-based rather than 0-based indexing). I tried to sort using `key=right_order` and got an error message reminding me how foolish I am: `right_order` is not a key function (of one argument), it is a comparison function (of two arguments).\n",
"\n",
"In Python 2, the `sorted` function did accept a two-argument `cmp` function, but in Python 3 that functionality is gone. I had to look it up to find that the `functools.cmp_to_key` function converts a comparison function to a key function, and that a `cmp_to_key` comparison function returns -1/0/+1, not True/None/False like my `right_order` does. Once I correct for that, it works fine."
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.007 seconds for correct answer: 24,948\n"
]
}
],
"source": [
"def decode(packets, dividers=[[[2]],[[6]]]):\n",
" \"\"\"Sort the packets and the dividers, and return their product of the indices of the dividers.\"\"\"\n",
" ordered = sorted(append(packets) + dividers, key=functools.cmp_to_key(cmp_order))\n",
" return prod(ordered.index(d) + 1 for d in dividers)\n",
"\n",
"def cmp_order(left, right) -> int:\n",
" \"\"\"Call `right_order` and convert True/None/False to -1/0/+1.\"\"\"\n",
" return {True: -1, None: 0, False: +1}[right_order(left, right)]\n",
" \n",
"answer(13.2, 24948, lambda: decode(in13))"
]
},
{
"cell_type": "markdown",
"metadata": {},
@@ -1734,7 +1895,7 @@
},
{
"cell_type": "code",
"execution_count": 45,
"execution_count": 50,
"metadata": {},
"outputs": [
{
@@ -1744,7 +1905,7 @@
" 1.2: '0.000 seconds for correct answer: 206,582',\n",
" 2.1: '0.001 seconds for correct answer: 13,268',\n",
" 2.2: '0.001 seconds for correct answer: 15,508',\n",
" 3.1: '0.000 seconds for correct answer: 8,401',\n",
" 3.1: '0.001 seconds for correct answer: 8,401',\n",
" 3.2: '0.000 seconds for correct answer: 2,641',\n",
" 4.1: '0.000 seconds for correct answer: 477',\n",
" 4.2: '0.000 seconds for correct answer: 830',\n",
@@ -1754,19 +1915,21 @@
" 6.2: '0.002 seconds for correct answer: 3,059',\n",
" 7.1: '0.001 seconds for correct answer: 1,232,307',\n",
" 7.2: '0.001 seconds for correct answer: 7,268,994',\n",
" 8.1: '0.049 seconds for correct answer: 1,829',\n",
" 8.2: '0.054 seconds for correct answer: 291,840',\n",
" 9.1: '0.025 seconds for correct answer: 6,236',\n",
" 9.2: '0.109 seconds for correct answer: 2,449',\n",
" 8.1: '0.050 seconds for correct answer: 1,829',\n",
" 8.2: '0.055 seconds for correct answer: 291,840',\n",
" 9.1: '0.023 seconds for correct answer: 6,236',\n",
" 9.2: '0.108 seconds for correct answer: 2,449',\n",
" 10.1: '0.000 seconds for correct answer: 12,560',\n",
" 10.2: '0.012 seconds for correct answer: PLPAFBCL',\n",
" 11.1: '0.001 seconds for correct answer: 54,036',\n",
" 11.2: '0.285 seconds for correct answer: 13,237,873,355',\n",
" 12.1: '0.035 seconds for correct answer: 394',\n",
" 12.2: '0.038 seconds for correct answer: 388'}"
" 11.2: '0.282 seconds for correct answer: 13,237,873,355',\n",
" 12.1: '0.036 seconds for correct answer: 394',\n",
" 12.2: '0.039 seconds for correct answer: 388',\n",
" 13.1: '0.000 seconds for correct answer: 5,882',\n",
" 13.2: '0.007 seconds for correct answer: 24,948'}"
]
},
"execution_count": 45,
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}