Add files via upload
This commit is contained in:
parent
e0b802994f
commit
040b6fa93d
@ -8,15 +8,19 @@
|
||||
"\n",
|
||||
"<div align=right>Peter Norvig, December 2017</div>\n",
|
||||
"\n",
|
||||
"I'm doing the [Advent of Code](https://adventofcode.com) puzzles, just like [last year](https://github.com/norvig/pytudes/blob/master/ipynb/Advent%20of%20Code.ipynb). But this time, I won't repeat the write up my version of the puzzle description each time; you'll have to follow the links in the section headers (e.g. **[Day 1](https://adventofcode.com/2017/day/1)**) to read those. I just show my solutions.\n",
|
||||
"I'm doing the [Advent of Code](https://adventofcode.com) puzzles, just like [last year](https://github.com/norvig/pytudes/blob/master/ipynb/Advent%20of%20Code.ipynb). But this time, I won't write up my interpretation of each day's the puzzle description; you'll have to follow the links in the section headers (e.g. **[Day 1](https://adventofcode.com/2017/day/1)**) to read those. I just show my solutions.\n",
|
||||
"\n",
|
||||
"First, a set of imports and utility functions that might prove useful:"
|
||||
"# Day 0: Imports and Utility Functions\n",
|
||||
"\n",
|
||||
"I might need these:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Python 3.x Utility Functions\n",
|
||||
@ -27,9 +31,10 @@
|
||||
"import random\n",
|
||||
"import urllib.request\n",
|
||||
"\n",
|
||||
"from collections import Counter, defaultdict, namedtuple, deque\n",
|
||||
"from collections import Counter, defaultdict, namedtuple, deque, abc, OrderedDict\n",
|
||||
"from functools import lru_cache\n",
|
||||
"from itertools import permutations, combinations, chain, cycle, product, islice, count as count_from\n",
|
||||
"from itertools import (permutations, combinations, chain, cycle, product, islice, \n",
|
||||
" takewhile, zip_longest, count as count_from)\n",
|
||||
"from heapq import heappop, heappush\n",
|
||||
"\n",
|
||||
"identity = lambda x: x\n",
|
||||
@ -41,20 +46,23 @@
|
||||
"inf = float('inf')\n",
|
||||
"BIG = 10 ** 999\n",
|
||||
"\n",
|
||||
"################ Functions for Input, Parsing\n",
|
||||
"\n",
|
||||
"def Input(day, year=2017):\n",
|
||||
" \"Open this day's input file.\"\n",
|
||||
" filename = 'data/advent{}/input{}.txt'.format(year, day)\n",
|
||||
" try:\n",
|
||||
" return open(filename)\n",
|
||||
" except FileNotFoundError:\n",
|
||||
" return urllib.request.urlopen(\"http://norvig.com/ipython/\" + filename)\n",
|
||||
" return open('data/advent{}/input{}.txt'.format(year, day))\n",
|
||||
" \n",
|
||||
"def array(lines):\n",
|
||||
" \"Convert an iterable of lines into a 2-D array. If lines is a str, do splitlines.\"\n",
|
||||
" \"Parse an iterable of str lines into a 2-D array. If `lines` is a str, do splitlines.\"\n",
|
||||
" if isinstance(lines, str): lines = lines.splitlines()\n",
|
||||
" return [mapt(atom, line.split()) for line in lines]\n",
|
||||
" return mapt(vector, lines)\n",
|
||||
"\n",
|
||||
"def vector(line):\n",
|
||||
" \"Parse a str into a tuple of atoms (numbers or str tokens).\"\n",
|
||||
" return mapt(atom, line.split())\n",
|
||||
"\n",
|
||||
"def atom(token):\n",
|
||||
" \"Parse a str token into a number, or leave it as a str.\"\n",
|
||||
" try:\n",
|
||||
" return int(token)\n",
|
||||
" except ValueError:\n",
|
||||
@ -147,14 +155,14 @@
|
||||
" \n",
|
||||
"def canon(items, typ=None):\n",
|
||||
" \"Canonicalize these order-independent items into a hashable canonical form.\"\n",
|
||||
" typ = (typ or (cat if isinstance(items, str) else tuple))\n",
|
||||
" typ = typ or (cat if isinstance(items, str) else tuple)\n",
|
||||
" return typ(sorted(items))\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",
|
||||
"################ Math\n",
|
||||
"################ Math Functions\n",
|
||||
" \n",
|
||||
"def transpose(matrix): return tuple(zip(*matrix))\n",
|
||||
"\n",
|
||||
@ -163,11 +171,11 @@
|
||||
" return int(n ** 0.5)\n",
|
||||
"\n",
|
||||
"def ints(start, end):\n",
|
||||
" \"The integers from start to end, inclusive. Equivalent to range(start, end+1)\"\n",
|
||||
" \"The integers from start to end, inclusive: range(start, end+1)\"\n",
|
||||
" return range(start, end + 1)\n",
|
||||
"\n",
|
||||
"def floats(start, end, step=1.0):\n",
|
||||
" \"Yields start, start+step, start+2*step, ... up to (maybe including) end.\"\n",
|
||||
" \"Yields from start to end (inclusive), by increments of step.\"\n",
|
||||
" m = (1.0 if step >= 0 else -1.0)\n",
|
||||
" while start * m <= end * m:\n",
|
||||
" yield start\n",
|
||||
@ -185,6 +193,9 @@
|
||||
"def X(point): x, y = point; return x\n",
|
||||
"def Y(point): x, y = point; return y\n",
|
||||
"\n",
|
||||
"origin = (0, 0)\n",
|
||||
"UP, DOWN, LEFT, RIGHT = (0, 1), (0, -1), (-1, 0), (1, 0)\n",
|
||||
"\n",
|
||||
"def neighbors4(point): \n",
|
||||
" \"The four neighboring squares.\"\n",
|
||||
" x, y = point\n",
|
||||
@ -197,13 +208,13 @@
|
||||
" x, y = point \n",
|
||||
" return ((x-1, y-1), (x, y-1), (x+1, y-1),\n",
|
||||
" (x-1, y), (x+1, y),\n",
|
||||
" (x+1, y+1), (x, y+1), (x+1, y+1))\n",
|
||||
" (x-1, y+1), (x, y+1), (x+1, y+1))\n",
|
||||
"\n",
|
||||
"def cityblock_distance(p, q=(0, 0)): \n",
|
||||
"def cityblock_distance(p, q=origin): \n",
|
||||
" \"Manhatten distance between two points.\"\n",
|
||||
" return abs(X(p) - X(q)) + abs(Y(p) - Y(q))\n",
|
||||
"\n",
|
||||
"def distance(p, q=(0, 0)): \n",
|
||||
"def distance(p, q=origin): \n",
|
||||
" \"Hypotenuse distance between two points.\"\n",
|
||||
" return math.hypot(X(p) - X(q), Y(p) - Y(q))\n",
|
||||
"\n",
|
||||
@ -223,9 +234,11 @@
|
||||
" if re.search(pattern, line):\n",
|
||||
" print(line)\n",
|
||||
"\n",
|
||||
"################ A* and Breadth-First Search (we track states, not actions)\n",
|
||||
"################ A* and Breadth-First Search (tracking states, not actions)\n",
|
||||
"\n",
|
||||
"def Astar(start, moves_func, h_func, cost_func=lambda s, s2: 1):\n",
|
||||
"def always(value): return (lambda *args: value)\n",
|
||||
"\n",
|
||||
"def Astar(start, moves_func, h_func, cost_func=always(1)):\n",
|
||||
" \"Find a shortest sequence of states from start to a goal state (a state s with h_func(s) == 0).\"\n",
|
||||
" frontier = [(h_func(start), start)] # A priority queue, ordered by path length, f = g + h\n",
|
||||
" previous = {start: None} # start state has no previous state; other states will\n",
|
||||
@ -248,6 +261,82 @@
|
||||
" return Astar(start, moves_func, lambda s: (0 if goal_func(s) else 1))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'pass'"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def tests():\n",
|
||||
" # Functions for Input, Parsing\n",
|
||||
" assert array('''1 2 3\n",
|
||||
" 4 5 6''') == ((1, 2, 3), \n",
|
||||
" (4, 5, 6))\n",
|
||||
" assert vector('testing 1 2 3.') == ('testing', 1, 2, 3.0)\n",
|
||||
" \n",
|
||||
" # Functions on Iterables\n",
|
||||
" assert first('abc') == first(['a', 'b', 'c']) == 'a'\n",
|
||||
" assert first_true([0, None, False, {}, 42, 43]) == 42\n",
|
||||
" assert nth('abc', 1) == nth(iter('abc'), 1) == 'b'\n",
|
||||
" assert cat(upto('abcdef', 'd')) == 'abcd'\n",
|
||||
" assert cat(['do', 'g']) == 'dog'\n",
|
||||
" assert groupby([-3, -2, -1, 1, 2], abs) == {1: [-1, 1], 2: [-2, 2], 3: [-3]}\n",
|
||||
" assert list(grouper(range(8), 3)) == [(0, 1, 2), (3, 4, 5), (6, 7, None)]\n",
|
||||
" assert list(overlapping((0, 1, 2, 3, 4), 3)) == [(0, 1, 2), (1, 2, 3), (2, 3, 4)]\n",
|
||||
" assert list(overlapping('abcdefg', 4)) == ['abcd', 'bcde', 'cdef', 'defg'] \n",
|
||||
" assert list(pairwise((0, 1, 2, 3, 4))) == [(0, 1), (1, 2), (2, 3), (3, 4)]\n",
|
||||
" assert sequence('seq') == 'seq'\n",
|
||||
" assert sequence((i**2 for i in range(5))) == (0, 1, 4, 9, 16)\n",
|
||||
" assert join(range(5)) == '01234'\n",
|
||||
" assert join(range(5), ', ') == '0, 1, 2, 3, 4'\n",
|
||||
" assert multiply([1, 2, 3, 4]) == 24\n",
|
||||
" assert transpose(((1, 2, 3), (4, 5, 6))) == ((1, 4), (2, 5), (3, 6))\n",
|
||||
" assert isqrt(9) == 3 == isqrt(10)\n",
|
||||
" assert ints(1, 100) == range(1, 101)\n",
|
||||
" assert identity('anything') == 'anything'\n",
|
||||
" assert set(powerset({1, 2, 3})) == {(), (1,), (1, 2), (1, 2, 3), (1, 3), (2,), (2, 3), (3,)}\n",
|
||||
" assert quantify(['testing', 1, 2, 3, int, len], callable) == 2 # int and len are callable\n",
|
||||
" assert quantify([0, False, None, '', [], (), {}, 42]) == 1 # Only 42 is truish\n",
|
||||
" assert set(shuffled('abc')) == set('abc')\n",
|
||||
" assert canon('abecedarian') == 'aaabcdeeinr'\n",
|
||||
" assert canon([9, 1, 4]) == canon({1, 4, 9}) == (1, 4, 9)\n",
|
||||
" assert mapt(math.sqrt, [1, 9, 4]) == (1, 3, 2)\n",
|
||||
" \n",
|
||||
" # Math\n",
|
||||
" assert transpose([(1, 2, 3), (4, 5, 6)]) == ((1, 4), (2, 5), (3, 6))\n",
|
||||
" assert isqrt(10) == isqrt(9) == 3\n",
|
||||
" assert ints(1, 5) == range(1, 6)\n",
|
||||
" assert list(floats(1, 5)) == [1., 2., 3., 4., 5.]\n",
|
||||
" assert multiply(ints(1, 10)) == math.factorial(10) == 3628800\n",
|
||||
" \n",
|
||||
" # 2-D points\n",
|
||||
" P = (3, 4)\n",
|
||||
" assert X(P) == 3 and Y(P) == 4\n",
|
||||
" assert cityblock_distance(P) == cityblock_distance(P, origin) == 7\n",
|
||||
" assert distance(P) == distance(P, origin) == 5\n",
|
||||
" \n",
|
||||
" # Search\n",
|
||||
" assert Astar((4, 4), neighbors8, distance) == [(4, 4), (3, 3), (2, 2), (1, 1), (0, 0)]\n",
|
||||
" assert bfs((4, 4), neighbors8, {origin}) == [(4, 4), (3, 3), (2, 2), (1, 1), (0, 0)]\n",
|
||||
" forty2 = always(42)\n",
|
||||
" assert forty2() == forty2('?') == forty2(4, 2) == 42\n",
|
||||
"\n",
|
||||
" return 'pass'\n",
|
||||
"\n",
|
||||
"tests()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@ -257,19 +346,19 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"raw = '3294199471327195994824832197564859876682638188889768298894243832665654681412886862234525991553276578641265589959178414218389329361496673991614673626344552179413995562266818138372393213966143124914469397692587251112663217862879233226763533911128893354536353213847122251463857894159819828724827969576432191847787772732881266875469721189331882228146576832921314638221317393256471998598117289632684663355273845983933845721713497811766995367795857965222183668765517454263354111134841334631345111596131682726196574763165187889337599583345634413436165539744188866156771585647718555182529936669683581662398618765391487164715724849894563314426959348119286955144439452731762666568741612153254469131724137699832984728937865956711925592628456617133695259554548719328229938621332325125972547181236812263887375866231118312954369432937359357266467383318326239572877314765121844831126178173988799765218913178825966268816476559792947359956859989228917136267178571776316345292573489873792149646548747995389669692188457724414468727192819919448275922166321158141365237545222633688372891451842434458527698774342111482498999383831492577615154591278719656798277377363284379468757998373193231795767644654155432692988651312845433511879457921638934877557575241394363721667237778962455961493559848522582413748218971212486373232795878362964873855994697149692824917183375545192119453587398199912564474614219929345185468661129966379693813498542474732198176496694746111576925715493967296487258237854152382365579876894391815759815373319159213475555251488754279888245492373595471189191353244684697662848376529881512529221627313527441221459672786923145165989611223372241149929436247374818467481641931872972582295425936998535194423916544367799522276914445231582272368388831834437562752119325286474352863554693373718848649568451797751926315617575295381964426843625282819524747119726872193569785611959896776143539915299968276374712996485367853494734376257511273443736433464496287219615697341973131715166768916149828396454638596713572963686159214116763'\n",
|
||||
"\n",
|
||||
"digits = mapt(int, raw)\n",
|
||||
"digits = mapt(int, '3294199471327195994824832197564859876682638188889768298894243832665654681412886862234525991553276578641265589959178414218389329361496673991614673626344552179413995562266818138372393213966143124914469397692587251112663217862879233226763533911128893354536353213847122251463857894159819828724827969576432191847787772732881266875469721189331882228146576832921314638221317393256471998598117289632684663355273845983933845721713497811766995367795857965222183668765517454263354111134841334631345111596131682726196574763165187889337599583345634413436165539744188866156771585647718555182529936669683581662398618765391487164715724849894563314426959348119286955144439452731762666568741612153254469131724137699832984728937865956711925592628456617133695259554548719328229938621332325125972547181236812263887375866231118312954369432937359357266467383318326239572877314765121844831126178173988799765218913178825966268816476559792947359956859989228917136267178571776316345292573489873792149646548747995389669692188457724414468727192819919448275922166321158141365237545222633688372891451842434458527698774342111482498999383831492577615154591278719656798277377363284379468757998373193231795767644654155432692988651312845433511879457921638934877557575241394363721667237778962455961493559848522582413748218971212486373232795878362964873855994697149692824917183375545192119453587398199912564474614219929345185468661129966379693813498542474732198176496694746111576925715493967296487258237854152382365579876894391815759815373319159213475555251488754279888245492373595471189191353244684697662848376529881512529221627313527441221459672786923145165989611223372241149929436247374818467481641931872972582295425936998535194423916544367799522276914445231582272368388831834437562752119325286474352863554693373718848649568451797751926315617575295381964426843625282819524747119726872193569785611959896776143539915299968276374712996485367853494734376257511273443736433464496287219615697341973131715166768916149828396454638596713572963686159214116763')\n",
|
||||
"N = len(digits)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@ -278,7 +367,7 @@
|
||||
"1158"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -289,9 +378,16 @@
|
||||
" if digits[i] == digits[i - 1])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Part Two**:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@ -300,7 +396,7 @@
|
||||
"1132"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -315,7 +411,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"I was able to do this warmup puzzle very quickly; too bad I started a few hours too late to make in on the leader board. I created a recurring calendar reminder so I'll be less likely to be late in the future."
|
||||
"This was an easy warmup puzzle. I forgot that Advent of Code was starting at 9:00PM my time, so I started late, but even if I had started on time, I doubt I would have been fast enough to score points. (I created a recurring calendar reminder so I'll be more likely to start on time in the future.)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -327,8 +423,10 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rows = array('''790\t99\t345\t1080\t32\t143\t1085\t984\t553\t98\t123\t97\t197\t886\t125\t947\n",
|
||||
@ -351,7 +449,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@ -360,7 +458,7 @@
|
||||
"46402"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -369,9 +467,16 @@
|
||||
"sum(abs(max(row) - min(row)) for row in rows)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Part Two**:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@ -380,7 +485,7 @@
|
||||
"265"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -396,9 +501,281 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Today I remembered to start on time, but I was too slow to score any points; the best I could do was 112th place on Part Two. \n",
|
||||
"This day was also very easy. In Part One, I was slowed down by a typo: I had `\"=\"` instead of `\"-\"` in `\"max(row) - min(row)\"`. I was confused by Python's misleading error message, which said `\"SyntaxError: keyword can't be an expression\"`. Later on, Alex Martelli explained to me that the message meant that in `abs(max(row)=...)` it thought that `max(row)` was a keyword argument to `abs`. \n",
|
||||
"\n",
|
||||
"In Part One, my big mistake was typing `\"=\"` instead of `\"-\"` in `\"max(row) - min(row)\"`. I was confused by Python's misleading error message, which said `\"SyntaxError: keyword can't be an expression\"` and pointed at `\"max\"`."
|
||||
"In Part Two, note that to check that `a/b` is an exact integer, I used `a // b == a / b`, which I think is more clear and less error-prone than the expression one would typically use here, `a % b == 0`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# [Day 3](https://adventofcode.com/2017/day/3): Spiral Memory"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"N = 277678"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This one takes some thinking, not just fast typing. I analyzed the problem as having three parts:\n",
|
||||
"- Generate a spiral\n",
|
||||
"- Find the Nth square on the spiral. \n",
|
||||
"- Find the distance from that square to the center.\n",
|
||||
"\n",
|
||||
"I suspect many people will do all three of these in one function. That's probably the best way to get the answer quickly, but I'd rather be clear than quick, so I'll factor out each part, according to the single responsibility principle. My function `spiral()` will generate the coordinates of squares on an infinite spiral, in order, going out from the center square, `(0, 0)`.\n",
|
||||
"\n",
|
||||
"How to make a spiral? My analysis is that, after the center square, the spiral goes 1 square right, then 1 square up, then 2 square left, then 2 square down, to complete one revolution; the next revolution starts with 3 square going up, and so on. I'll call each of these a `leg`, so `spiral` consists of four calls to `leg`, with increments to the `length` after every two legs. \n",
|
||||
"\n",
|
||||
"One thing is less clear than I would like: the variable `square` is modified by the function `leg` (in other words, it is an in/out parameter). A small test confirms that this matches the puzzle description:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[(0, 0),\n",
|
||||
" (1, 0),\n",
|
||||
" (1, 1),\n",
|
||||
" (0, 1),\n",
|
||||
" (-1, 1),\n",
|
||||
" (-1, 0),\n",
|
||||
" (-1, -1),\n",
|
||||
" (0, -1),\n",
|
||||
" (1, -1),\n",
|
||||
" (2, -1)]"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def spiral():\n",
|
||||
" \"Yield the (x, y) coordinates of successive points in an infinite spiral.\"\n",
|
||||
" length = 1\n",
|
||||
" square = [0, 0]\n",
|
||||
" yield tuple(square)\n",
|
||||
" while True:\n",
|
||||
" yield from leg(square, length, RIGHT)\n",
|
||||
" yield from leg(square, length, UP)\n",
|
||||
" length += 1\n",
|
||||
" yield from leg(square, length, LEFT)\n",
|
||||
" yield from leg(square, length, DOWN)\n",
|
||||
" length += 1 \n",
|
||||
" \n",
|
||||
"def leg(square, length, delta):\n",
|
||||
" \"Complete one leg of given length, mutating `square` and yielding a copy at each step.\"\n",
|
||||
" for _ in range(length):\n",
|
||||
" square[:] = (X(square) + X(delta), Y(square) + Y(delta))\n",
|
||||
" yield tuple(square) \n",
|
||||
" \n",
|
||||
"list(islice(spiral(), 10))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we can find the `N`th square. As this is Python, indexes start at 0, whereas the problem starts at 1, so I have to subtract 1. Then I can find the distance to the origin:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"(212, -263)"
|
||||
]
|
||||
},
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"nth(spiral(), N - 1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"475"
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"cityblock_distance(_)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"That's the right answer. I was slow arriving at it because I forgot the second `length += 1` in `spiral` and it took a while to debug. (I had the right analysis, but just left out a line of code.)\n",
|
||||
"\n",
|
||||
"For **Part Two** I can re-use my `spiral` generator, yay! Here's a function to sum the neighboring squares (I can use my `neighbors8` function, yay!):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def spiralsums():\n",
|
||||
" \"Yield the values of a spiral where each point has the sum of the 8 neighbors.\"\n",
|
||||
" value = defaultdict(int)\n",
|
||||
" for p in spiral():\n",
|
||||
" value[p] = sum(value[q] for q in neighbors8(p)) or 1\n",
|
||||
" yield value[p]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[1, 1, 2, 4, 5, 10, 11, 23, 25, 26, 54, 57]"
|
||||
]
|
||||
},
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"list(islice(spiralsums(), 12))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Looks good, so let's get the answer:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"279138"
|
||||
]
|
||||
},
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"first(x for x in spiralsums() if x > N)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# [Day 4](https://adventofcode.com/2017/day/4): High-Entropy Passphrases\n",
|
||||
"\n",
|
||||
"This is the first time I will have to store an input file and read it with the function `Input`. It should be straightforward, though:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"337"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def isvalid(line):\n",
|
||||
" words = line.split()\n",
|
||||
" return len(words) == len(set(words))\n",
|
||||
"\n",
|
||||
"quantify(Input(4), isvalid)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Part Two:**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"231"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def isvalid2(line):\n",
|
||||
" words = mapt(canon, line.split())\n",
|
||||
" return len(words) == len(set(words))\n",
|
||||
"\n",
|
||||
"quantify(Input(4), isvalid2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"It took me less than five minutes, and my preparation with `Input` and `canon` helped, but I was still too slow to score any points."
|
||||
]
|
||||
}
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user