Add files via upload

This commit is contained in:
Peter Norvig authored and GitHub committed 2019-01-23 01:56:30 -08:00
1 parent 4a25ff4dad
commit db46e8df33
1 file changed
+665 -59
+665 -59
View File
@@ -11,7 +11,7 @@
"Here are my solutions to [Advent of Code 2018](https://adventofcode.com/2018), following up on my solutions for [2017](Advent%202017.ipynb) and [2016](Advent%20of%20Code.ipynb). In order to understand each day's two-part puzzle, you'll need to click on the header links below (e.g. **[Day 1: Chronal Calibration](https://adventofcode.com/2018/day/1)**) and read the description. This year I didn't find time to race in real time when the puzzles are released; instead I'm doing batch processing, doing a couple of puzzles every few days. You can see I'm currently behind.\n", "Here are my solutions to [Advent of Code 2018](https://adventofcode.com/2018), following up on my solutions for [2017](Advent%202017.ipynb) and [2016](Advent%20of%20Code.ipynb). In order to understand each day's two-part puzzle, you'll need to click on the header links below (e.g. **[Day 1: Chronal Calibration](https://adventofcode.com/2018/day/1)**) and read the description. This year I didn't find time to race in real time when the puzzles are released; instead I'm doing batch processing, doing a couple of puzzles every few days. You can see I'm currently behind.\n",
"\n", "\n",
"\n", "\n",
"# Utility Functions" "# Imports and Utility Functions"
] ]
}, },
{ {
@@ -22,39 +22,18 @@
"source": [ "source": [
"#### IMPORTS\n", "#### IMPORTS\n",
"\n", "\n",
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"import re\n", "import re\n",
"from collections import Counter, defaultdict, namedtuple, deque\n", "from collections import Counter, defaultdict, namedtuple, deque\n",
"from itertools import chain, cycle, product, count as count_from\n", "from itertools import chain, cycle, product, islice, count as count_from\n",
"from functools import lru_cache\n", "from functools import lru_cache, total_ordering\n",
"from dataclasses import dataclass\n",
"\n", "\n",
"#### CONSTANTS\n", "#### CONSTANTS\n",
"\n", "\n",
"alphabet = 'abcdefghijklmnopqrstuvwxyz'\n",
"ALPHABET = alphabet.upper()\n",
"infinity = float('inf')\n", "infinity = float('inf')\n",
"\n", "bignum = 10 ** 100\n",
"#### SIMPLE UTILITY FUNCTIONS\n",
"\n",
"cat = ''.join\n",
"\n",
"def ints(start, end, step=1):\n",
" \"The integers from start to end, inclusive: range(start, end+1)\"\n",
" return range(start, end + 1, step)\n",
"\n",
"def quantify(iterable, pred=bool):\n",
" \"Count how many times the predicate is true of an item in iterable.\"\n",
" return sum(map(pred, iterable))\n",
"\n",
"def multimap(items):\n",
" \"Given (key, val) pairs, return {key: [val, ....], ...}.\"\n",
" result = defaultdict(list)\n",
" for (key, val) in items:\n",
" result[key].append(val)\n",
" return result\n",
"\n",
"def mapt(fn, *args): \n",
" \"Do a map, and make the results into a tuple.\"\n",
" return tuple(map(fn, *args))\n",
"\n", "\n",
"#### FILE INPUT AND PARSING\n", "#### FILE INPUT AND PARSING\n",
"\n", "\n",
@@ -64,7 +43,36 @@
"\n", "\n",
"def integers(text): \n", "def integers(text): \n",
" \"A tuple of all integers in a string (ignore other characters).\"\n", " \"A tuple of all integers in a string (ignore other characters).\"\n",
" return mapt(int, re.findall(r'-?\\d+', text))" " return mapt(int, re.findall(r'-?\\d+', text))\n",
"\n",
"#### UTILITY FUNCTIONS\n",
"\n",
"def mapt(fn, *args): \n",
" \"Do a map, and make the results into a tuple.\"\n",
" return tuple(map(fn, *args))\n",
"\n",
"def first(iterable, default=None):\n",
" \"Return first item in iterable, or default.\"\n",
" return next(iter(iterable), default)\n",
"\n",
"def nth(iterable, n): return next(islice(iter(iterable), n, n+1))\n",
"\n",
"cat = ''.join\n",
"\n",
"def rangei(start, end, step=1):\n",
" \"\"\"Inclusive, range from start to end: rangei(a, b) = range(a, b+1).\"\"\"\n",
" return range(start, end + 1, step) \n",
"\n",
"def quantify(iterable, pred=bool):\n",
" \"Count how many items in iterable have pred(item) true.\"\n",
" return sum(map(pred, iterable))\n",
"\n",
"def multimap(items):\n",
" \"Given (key, val) pairs, return {key: [val, ....], ...}.\"\n",
" result = defaultdict(list)\n",
" for (key, val) in items:\n",
" result[key].append(val)\n",
" return result"
] ]
}, },
{ {
@@ -272,7 +280,7 @@
"\n", "\n",
"def value_ge(dic, threshold):\n", "def value_ge(dic, threshold):\n",
" \"How many items in dic have a value >= threshold?\"\n", " \"How many items in dic have a value >= threshold?\"\n",
" return sum(dic[x] >= threshold for x in dic)\n", " return quantify(dic[x] >= threshold for x in dic)\n",
"\n", "\n",
"value_ge(claimed(input3), 2)" "value_ge(claimed(input3), 2)"
] ]
@@ -305,14 +313,14 @@
"source": [ "source": [
"# Part 2\n", "# Part 2\n",
"\n", "\n",
"def process2(claims):\n", "def claimed2(claims):\n",
" \"Which claim has only positions that are claimed by nobody else?\"\n", " \"Which claim has only positions that are claimed by nobody else?\"\n",
" C = claimed(claims)\n", " C = claimed(claims)\n",
" for (id, x, y, w, h) in claims:\n", " for (id, x, y, w, h) in claims:\n",
" if all(C[pos] == 1 for pos in product(range(x, x+w), range(y, y+h))):\n", " if all(C[pos] == 1 for pos in product(range(x, x+w), range(y, y+h))):\n",
" return id\n", " return id\n",
"\n", "\n",
"process2(input3)" "claimed2(input3)"
] ]
}, },
{ {
@@ -547,6 +555,9 @@
"source": [ "source": [
"input5 = cat(Input(5))\n", "input5 = cat(Input(5))\n",
"\n", "\n",
"alphabet = 'abcdefghijklmnopqrstuvwxyz'\n",
"ALPHABET = alphabet.upper()\n",
"\n",
"OR = '|'.join\n", "OR = '|'.join\n",
"reaction = OR(OR([c + C, C + c]) for c, C in zip(alphabet, ALPHABET))\n", "reaction = OR(OR([c + C, C + c]) for c, C in zip(alphabet, ALPHABET))\n",
"\n", "\n",
@@ -887,32 +898,32 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"{'C': 195,\n", "{'U': 354,\n",
" 'H': 266,\n",
" 'Y': 84,\n",
" 'P': 408,\n",
" 'V': 215,\n",
" 'L': 426,\n",
" 'T': 503,\n",
" 'I': 423,\n", " 'I': 423,\n",
" 'F': 332,\n",
" 'D': 259,\n",
" 'Z': 665,\n",
" 'B': 61,\n",
" 'O': 273,\n",
" 'R': 743,\n",
" 'A': 60,\n",
" 'N': 579,\n",
" 'M': 133,\n", " 'M': 133,\n",
" 'U': 354,\n",
" 'Q': 350,\n",
" 'W': 144,\n",
" 'S': 505,\n",
" 'K': 132,\n",
" 'J': 813,\n",
" 'X': 897,\n", " 'X': 897,\n",
" 'K': 132,\n",
" 'W': 144,\n",
" 'J': 813,\n",
" 'T': 503,\n",
" 'D': 259,\n",
" 'B': 61,\n",
" 'P': 408,\n",
" 'L': 426,\n",
" 'E': 198,\n",
" 'O': 273,\n",
" 'A': 60,\n",
" 'F': 332,\n",
" 'Y': 84,\n",
" 'C': 195,\n",
" 'V': 215,\n",
" 'Z': 665,\n",
" 'S': 505,\n",
" 'G': 66,\n", " 'G': 66,\n",
" 'E': 198}" " 'H': 266,\n",
" 'N': 579,\n",
" 'Q': 350,\n",
" 'R': 743}"
] ]
}, },
"execution_count": 35, "execution_count": 35,
@@ -1165,7 +1176,7 @@
" \"Add `marbles` to `circle`, rotating according to rules and scoring every 23 marbles.\"\n", " \"Add `marbles` to `circle`, rotating according to rules and scoring every 23 marbles.\"\n",
" circle = deque([0])\n", " circle = deque([0])\n",
" scores = Counter()\n", " scores = Counter()\n",
" for m in ints(1, marbles):\n", " for m in rangei(1, marbles):\n",
" player = (m - 1) % players + 1\n", " player = (m - 1) % players + 1\n",
" if m % 23:\n", " if m % 23:\n",
" circle.rotate(-1)\n", " circle.rotate(-1)\n",
@@ -1284,8 +1295,8 @@
"def lightshow(points, chars='.#'):\n", "def lightshow(points, chars='.#'):\n",
" \"Print out the locations of the points.\"\n", " \"Print out the locations of the points.\"\n",
" xmin, xmax, ymin, ymax = bounds(points)\n", " xmin, xmax, ymin, ymax = bounds(points)\n",
" for y in ints(ymin, ymax):\n", " for y in rangei(ymin, ymax):\n",
" print(cat(chars[(x, y) in points] for x in ints(xmin, xmax)))" " print(cat(chars[(x, y) in points] for x in rangei(xmin, xmax)))"
] ]
}, },
{ {
@@ -1396,7 +1407,7 @@
"\n", "\n",
"def maxpower(bounds=300, width=3):\n", "def maxpower(bounds=300, width=3):\n",
" \"Return (power, topleft, width) of square within `bounds` of maximum power.\"\n", " \"Return (power, topleft, width) of square within `bounds` of maximum power.\"\n",
" toplefts = product(ints(1, bounds - width), repeat=2)\n", " toplefts = product(rangei(1, bounds - width), repeat=2)\n",
" return max((total_power(topleft, width), topleft, width)\n", " return max((total_power(topleft, width), topleft, width)\n",
" for topleft in toplefts)\n", " for topleft in toplefts)\n",
"\n", "\n",
@@ -1434,7 +1445,7 @@
" I[x, y] = key((x, y)) + I[x, y - 1] + I[x - 1, y] - I[x - 1, y - 1]\n", " I[x, y] = key((x, y)) + I[x, y - 1] + I[x - 1, y] - I[x - 1, y - 1]\n",
" return I\n", " return I\n",
"\n", "\n",
"def total_power(topleft, width=3, I=summed_area(ints(1, 300), power_level)):\n", "def total_power(topleft, width=3, I=summed_area(rangei(1, 300), power_level)):\n",
" \"Total power in square with given topleft corner and width (from `I`).\"\n", " \"Total power in square with given topleft corner and width (from `I`).\"\n",
" x, y = topleft\n", " x, y = topleft\n",
" xmin, ymin, xmax, ymax = x - 1, y - 1, x + width - 1, y + width - 1\n", " xmin, ymin, xmax, ymax = x - 1, y - 1, x + width - 1, y + width - 1\n",
@@ -1472,6 +1483,601 @@
"source": [ "source": [
"assert _[1] + _[2:] == (284, 172, 12), 'Day 11.2'" "assert _[1] + _[2:] == (284, 172, 12), 'Day 11.2'"
] ]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# [Day 12: Subterranean Sustainability](https://adventofcode.com/2018/day/12)\n",
"\n",
"One-dimensional cellular automata. Fun! AT first I thought I would represent a row of plants as a string, but I realized I'd also need to track the start position of the string, so I decided it was easier to represent a row of plants as a set of index numbers of pots that are live. I'll make `grow()` yield all future generations:"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1447"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def Plants(row):\n",
" \"Convert '#..#.#' => {0, 3, 5}\"\n",
" return {i for i, c in enumerate(row) if c == '#'}\n",
"\n",
"input12 = Input(12, str.split)\n",
"plants = Plants(input12[0][-1])\n",
"rules = {rule[0]: rule[-1] for rule in input12 if '=>' in rule}\n",
"\n",
"def grow(plants=plants, rules=rules):\n",
" \"Grow plants using rules, yielding each generation (including 0th).\"\n",
" while True:\n",
" yield plants\n",
" extent = rangei(min(plants) - 3, max(plants) + 3)\n",
" plants = {i for i in extent if lives(plants, i, rules)}\n",
"\n",
"def lives(plants, i, rules):\n",
" \"Does pot i live in next generation, according to rules?\"\n",
" neighborhood = cat('.#'[j in plants] for j in rangei(i - 2, i + 2))\n",
" return rules[neighborhood] == '#'\n",
"\n",
"sum(nth(grow(), 20))"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [],
"source": [
"assert _ == 1447, 'Day 12.1' "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Cool, my answer is leet-er than `1337`. But Part 2, asks for 50 billion generations. Maybe the pattern reaches a fixed point, or cycles, like the blinker in Conway's Life game. Let's plot the number of plants, and their sums, over the first couple hundred generations and see if there is a pattern:"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Part 2\n",
"\n",
"gens = list(islice(grow(), 200))\n",
"plt.plot(mapt(len, gens), label='x');"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"plt.plot(mapt(sum, gens));"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"OK, no problem: after a while the sum settles down and grows at a constant rate. I can figure out what that rate is:"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[2580, 2601, 2622]"
]
},
"execution_count": 64,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[sum(plants) for plants in gens[100:103]]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is growing by 21 each time. So my answer should be 2580 + 21 × (50 billion - 100). More generally:"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1050000000480"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def nth_plant_sum(n, k=100):\n",
" \"The sum of plants in the nth generation, assuming linear growth after k generations.\"\n",
" a, b = map(sum, islice(grow(), k, k + 2))\n",
" return a + (n - k) * (b - a)\n",
"\n",
"nth_plant_sum(50 * 10 ** 9)"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [],
"source": [
"assert _ == 1050000000480, 'Day 12.2'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, *why* does it grow by 21 each time? Well, we saw in the plot of lengths above that the length eventually remains constant; we can see the last few:"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[21, 21, 21]"
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[len(g) for g in gens[-3:]]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are 21 plants in each generation; here is one generation:"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{59,\n",
" 60,\n",
" 61,\n",
" 71,\n",
" 72,\n",
" 73,\n",
" 84,\n",
" 85,\n",
" 86,\n",
" 137,\n",
" 138,\n",
" 139,\n",
" 149,\n",
" 150,\n",
" 151,\n",
" 159,\n",
" 160,\n",
" 161,\n",
" 194,\n",
" 195,\n",
" 196}"
]
},
"execution_count": 68,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"gens[100]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see that the plants are bunched into groups of three. What happens to a group of three?"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{0: {1, 2, 3},\n",
" 1: {2, 3, 4},\n",
" 2: {3, 4, 5},\n",
" 3: {4, 5, 6},\n",
" 4: {5, 6, 7},\n",
" 5: {6, 7, 8}}"
]
},
"execution_count": 69,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dict(zip(range(6), grow(plants={1, 2, 3})))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"They move one to the right each generation; moving 7 groups of 3 one to the right results in adding 21 to the sum."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# [Day 13: Mine Cart Madness](https://adventofcode.com/2018/day/13)\n",
"\n",
"I need to do the following:\n",
"\n",
"- Parse the picture of the world into a data structure.\n",
"- Keep track of the carts, and have them make the right moves. \n",
"- Continue until there is a collision.\n",
"\n",
"Since this has to do with headings and turns, I'm going to use complex numbers to represent points, headings, and turns; multiplying a complex heading by a complex turn results in a new heading. Then adding the heading to a point results in a new point. I'll redefine the `X` and `Y` accessors to handle either the complex points used here or the tuple points used previously:"
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {},
"outputs": [],
"source": [
"Point = complex\n",
"\n",
"def X(point): return point.real if isinstance(point, complex) else point[0]\n",
"def Y(point): return point.imag if isinstance(point, complex) else point[1]\n",
"\n",
"# Headings: HU, HD, HR, HL = Head up, down, right, left\n",
"# Turns: TL, TR, TS, TB = Turn left, right, straight, backwards\n",
"HU = TL = Point(0, -1)\n",
"HD = TR = -TL\n",
"HR = TS = Point(1, 0)\n",
"HL = TB = -TS\n",
"\n",
"headings = {'>': HR, '<': HL, '^': HU, 'v': HD}\n",
"inverse_headings = dict((headings[ch], ch) for ch in headings)\n",
"\n",
"assert HU * TR == HR and TR ** 4 == TL ** 4 == TS and HR * TB == HL and HU == -HD and TR == -TL"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we need to define a `Cart`, and the `World` they will live in. We use the [`dataclass`](https://docs.python.org/3/library/dataclasses.html) facility from Python 3."
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {},
"outputs": [],
"source": [
"@dataclass\n",
"class Cart:\n",
" name: str\n",
" pos: Point\n",
" heading: Point\n",
" turns: object\n",
" \n",
"@dataclass\n",
"class World:\n",
" grid: tuple\n",
" carts: list\n",
"\n",
" def __init__(self, lines):\n",
" table = str.maketrans('<>^v', '--||')\n",
" names = cycle(alphabet)\n",
" self.grid = [line.translate(table) for line in lines]\n",
" self.carts = [Cart(next(names), Point(x, y), headings[h], cycle((TL, TS, TR)))\n",
" for (y, line) in enumerate(lines)\n",
" for (x, h) in enumerate(line)\n",
" if h in headings]\n",
" \n",
" def __getitem__(self, point): return self.grid[int(Y(point))][int(X(point))]\n",
" \n",
" def show(self):\n",
" \"Print a representation of the world.\"\n",
" for y, line in enumerate(self.grid):\n",
" for x, ch in enumerate(line):\n",
" cart = first(c for c in self.carts if c.pos == Point(x, y))\n",
" ch = inverse_headings[cart.heading] if cart else ch\n",
" print(ch, end='')\n",
" print()\n",
" print()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now the function `madmad(world)`, which simulates moving the carts until a collision."
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {},
"outputs": [],
"source": [
"def madmad(world, show=False):\n",
" \"Simulate the mine cart madness until a collision.\"\n",
" while True:\n",
" if show: world.show()\n",
" for cart in sorted(world.carts, key=lambda c: (Y(c.pos), X(c.pos))):\n",
" cart.heading *= turn(cart, world)\n",
" cart.pos += cart.heading\n",
" if collision(cart, world):\n",
" if show: world.show()\n",
" return cart.pos\n",
"\n",
"def turn(cart, world):\n",
" \"Which way should the cart turn (depends on character it is on).\"\n",
" ch = world[cart.pos]\n",
" if ch == '+':\n",
" return next(cart.turns) \n",
" if ch == '/':\n",
" return (TR if cart.heading in (HU, HD) else TL)\n",
" if ch == '\\\\': \n",
" return (TR if cart.heading in (HR, HL) else TL)\n",
" else:\n",
" return TS\n",
" \n",
"def collision(cart, world):\n",
" \"Has this cart collided with any other cart?\"\n",
" return any(cart.pos == other.pos for other in world.carts if other is not cart)"
]
},
{
"cell_type": "code",
"execution_count": 73,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/->-\\ \n",
"| | /----\\ \n",
"| /-+--+-\\ | \n",
"| | | | v | \n",
"\\-+-/ \\-+--/ \n",
" \\------/\n",
"\n",
"/-->\\ \n",
"| | /----\\ \n",
"| /-+--+-\\ | \n",
"| | | | | | \n",
"\\-+-/ \\-v--/ \n",
" \\------/\n",
"\n",
"/---> \n",
"| | /----\\ \n",
"| /-+--+-\\ | \n",
"| | | | | | \n",
"\\-+-/ \\-+>-/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| v /----\\ \n",
"| /-+--+-\\ | \n",
"| | | | | | \n",
"\\-+-/ \\-+->/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | /----\\ \n",
"| /-v--+-\\ | \n",
"| | | | | | \n",
"\\-+-/ \\-+--> \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | /----\\ \n",
"| /-+>-+-\\ | \n",
"| | | | | ^ \n",
"\\-+-/ \\-+--/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | /----\\ \n",
"| /-+->+-\\ ^ \n",
"| | | | | | \n",
"\\-+-/ \\-+--/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | /----^ \n",
"| /-+-->-\\ | \n",
"| | | | | | \n",
"\\-+-/ \\-+--/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | /---<\\ \n",
"| /-+--+>\\ | \n",
"| | | | | | \n",
"\\-+-/ \\-+--/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | /--<-\\ \n",
"| /-+--+-> | \n",
"| | | | | | \n",
"\\-+-/ \\-+--/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | /-<--\\ \n",
"| /-+--+-\\ | \n",
"| | | | v | \n",
"\\-+-/ \\-+--/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | /<---\\ \n",
"| /-+--+-\\ | \n",
"| | | | | | \n",
"\\-+-/ \\-v--/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | <----\\ \n",
"| /-+--+-\\ | \n",
"| | | | | | \n",
"\\-+-/ \\<+--/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | /----\\ \n",
"| /-+--v-\\ | \n",
"| | | | | | \n",
"\\-+-/ <-+--/ \n",
" \\------/\n",
"\n",
"/---\\ \n",
"| | /----\\ \n",
"| /-+--+-\\ | \n",
"| | | ^ | | \n",
"\\-+-/ \\-+--/ \n",
" \\------/\n",
"\n"
]
},
{
"data": {
"text/plain": [
"(7+3j)"
]
},
"execution_count": 73,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"example = r'''\n",
"/->-\\ \n",
"| | /----\\ \n",
"| /-+--+-\\ | \n",
"| | | | v | \n",
"\\-+-/ \\-+--/ \n",
" \\------/ \n",
"'''.strip().splitlines()\n",
"\n",
"madmad(World(example), True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The answer, `7, 3`, is correct, and everything looks good!\n",
"\n",
"Unfortunately, I got an error when trying it on the actual (larger) input.\n",
"\n",
"Even more unfortunately, I ran out of spare time to debug this problem and to move on to the remaining days. Maybe next year!"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {},
"outputs": [
{
"ename": "IndexError",
"evalue": "string index out of range",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-74-b8cd35d8126d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmadmad\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mWorld\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mInput\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m13\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-72-4f9a5f11a5c3>\u001b[0m in \u001b[0;36mmadmad\u001b[0;34m(world, show)\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mshow\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mworld\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshow\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mcart\u001b[0m \u001b[0;32min\u001b[0m \u001b[0msorted\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mworld\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcarts\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mY\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpos\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpos\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mcart\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheading\u001b[0m \u001b[0;34m*=\u001b[0m \u001b[0mturn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcart\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mworld\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 7\u001b[0m \u001b[0mcart\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpos\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0mcart\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheading\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcollision\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcart\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mworld\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-72-4f9a5f11a5c3>\u001b[0m in \u001b[0;36mturn\u001b[0;34m(cart, world)\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mturn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcart\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mworld\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;34m\"Which way should the cart turn (depends on character it is on).\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 14\u001b[0;31m \u001b[0mch\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mworld\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcart\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpos\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 15\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mch\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'+'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcart\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mturns\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-71-0fcfb1457844>\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, point)\u001b[0m\n\u001b[1;32m 20\u001b[0m if h in headings]\n\u001b[1;32m 21\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 22\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0m__getitem__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpoint\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mY\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpoint\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpoint\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 23\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mshow\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mIndexError\u001b[0m: string index out of range"
]
}
],
"source": [
"madmad(World(Input(13)))"
]
} }
], ],
"metadata": { "metadata": {