Add files via upload

This commit is contained in:
Peter Norvig 2017-12-01 08:48:41 -08:00 committed by GitHub
parent d2673fb0bd
commit 10324c5a8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

252
ipynb/Advent 2017.ipynb Normal file
View File

@ -0,0 +1,252 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 89,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# Python 3.x\n",
"\n",
"import re\n",
"import numpy as np\n",
"import math\n",
"import urllib.request\n",
"\n",
"from collections import Counter, defaultdict, namedtuple, deque\n",
"from functools import lru_cache\n",
"from itertools import permutations, combinations, chain, cycle, product, islice, count as count_from\n",
"from heapq import heappop, heappush\n",
"\n",
"identity = lambda x: x\n",
"letters = 'abcdefghijklmnopqrstuvwxyz'\n",
"\n",
"cat = ''.join\n",
"\n",
"Ø = frozenset() # Empty set\n",
"inf = float('inf')\n",
"BIG = 10 ** 999\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",
"\n",
"################ Functions on Iterables\n",
"\n",
"def first(iterable, default=None): return next(iter(iterable), default)\n",
"\n",
"def first_true(iterable, pred=None, default=None):\n",
" \"\"\"Returns the first true value in the iterable.\n",
" If no true value is found, returns *default*\n",
" If *pred* is not None, returns the first item\n",
" for which pred(item) is true.\"\"\"\n",
" # first_true([a,b,c], default=x) --> a or b or c or x\n",
" # first_true([a,b], fn, x) --> a if fn(a) else b if fn(b) else x\n",
" return next(filter(pred, iterable), default)\n",
"\n",
"def nth(iterable, n, default=None):\n",
" \"Returns the nth item of iterable, or a default value\"\n",
" return next(islice(iterable, n, None), default)\n",
"\n",
"def upto(iterable, maxval):\n",
" \"From a monotonically increasing iterable, generate all the values <= maxval.\"\n",
" # Why <= maxval rather than < maxval? In part because that's how Ruby's upto does it.\n",
" return takewhile(lambda x: x <= maxval, iterable)\n",
"\n",
"def groupby(iterable, key=identity):\n",
" \"Return a dict of {key(item): [items...]} grouping all items in iterable by keys.\"\n",
" groups = defaultdict(list)\n",
" for item in iterable:\n",
" groups[key(item)].append(item)\n",
" return groups\n",
"\n",
"def grouper(iterable, n, fillvalue=None):\n",
" \"\"\"Collect data into fixed-length chunks:\n",
" grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx\"\"\"\n",
" args = [iter(iterable)] * n\n",
" return zip_longest(*args, fillvalue=fillvalue)\n",
"\n",
"def overlapping(iterable, n):\n",
" \"\"\"Generate all (overlapping) n-element subsequences of iterable.\n",
" overlapping('ABCDEFG', 3) --> ABC BCD CDE DEF EFG\"\"\"\n",
" if isinstance(iterable, abc.Sequence):\n",
" yield from (iterable[i:i+n] for i in range(len(iterable) + 1 - n))\n",
" else:\n",
" result = deque(maxlen=n)\n",
" for x in iterable:\n",
" result.append(x)\n",
" if len(result) == n:\n",
" yield tuple(result)\n",
" \n",
"def pairwise(iterable):\n",
" \"s -> (s0,s1), (s1,s2), (s2, s3), ...\"\n",
" return overlapping(iterable, 2)\n",
"\n",
"def sequence(iterable, type=tuple):\n",
" \"Coerce iterable to sequence: leave it alone if it is already a sequence, else make it of type.\"\n",
" return iterable if isinstance(iterable, abc.Sequence) else type(iterable)\n",
"\n",
"def join(iterable, sep=''):\n",
" \"Join the items in iterable, converting each to a string first.\"\n",
" return sep.join(map(str, iterable))\n",
" \n",
"def powerset(iterable):\n",
" \"Yield all subsets of items.\"\n",
" items = list(iterable)\n",
" for r in range(len(items)+1):\n",
" for c in combinations(items, r):\n",
" yield c\n",
" \n",
"def quantify(iterable, pred=bool):\n",
" \"Count how many times the predicate is true.\"\n",
" return sum(map(pred, iterable))\n",
"\n",
"def shuffled(iterable):\n",
" \"Create a new list out of iterable, and shuffle it.\"\n",
" new = list(iterable)\n",
" random.shuffle(new)\n",
" return new\n",
" \n",
"flatten = chain.from_iterable\n",
" \n",
"class Set(frozenset):\n",
" \"A frozenset, but with a prettier printer.\"\n",
" def __repr__(self): return '{' + join(sorted(self), ', ') + '}'\n",
" \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",
" return typ(sorted(items))\n",
" \n",
"################ Math\n",
" \n",
"def transpose(matrix): return tuple(zip(*matrix))\n",
"\n",
"def isqrt(n):\n",
" \"Integer square root (rounds down).\"\n",
" 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",
" 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",
" m = (1.0 if step >= 0 else -1.0)\n",
" while start * m <= end * m:\n",
" yield start\n",
" start += step\n",
" \n",
"def multiply(numbers):\n",
" \"Multiply all the numbers together.\"\n",
" result = 1\n",
" for n in numbers:\n",
" result *= n\n",
" return result\n",
"\n",
"################ 2-D points implemented using (x, y) tuples\n",
"\n",
"def X(point): x, y = point; return x\n",
"def Y(point): x, y = point; return y\n",
"\n",
"def neighbors4(point): \n",
" \"The four neighboring squares.\"\n",
" x, y = point\n",
" return ( (x, y-1),\n",
" (x-1, y), (x+1, y), \n",
" (x, y+1))\n",
"\n",
"def neighbors8(point): \n",
" \"The eight neighboring squares.\"\n",
" 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",
"\n",
"def cityblock_distance(p, q=(0, 0)): \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",
" \"Hypotenuse distance between two points.\"\n",
" return math.hypot(X(p) - X(q), Y(p) - Y(q))\n",
"\n",
"################ Debugging \n",
"\n",
"def trace1(f):\n",
" \"Print a trace of the input and output of a function on one line.\"\n",
" def traced_f(*args):\n",
" result = f(*args)\n",
" print('{}({}) = {}'.format(f.__name__, ', '.join(map(str, args)), result))\n",
" return result\n",
" return traced_f\n",
"\n",
"def grep(pattern, iterable):\n",
" \"Print lines from iterable that match pattern.\"\n",
" for line in iterable:\n",
" if re.search(pattern, line):\n",
" print(line)\n",
"\n",
"################ A* and Breadth-First Search (we track states, not actions)\n",
"\n",
"def Astar(start, moves_func, h_func, cost_func=lambda s, s2: 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",
" path_cost = {start: 0} # The cost of the best path to a state.\n",
" Path = lambda s: ([] if (s is None) else Path(previous[s]) + [s])\n",
" while frontier:\n",
" (f, s) = heappop(frontier)\n",
" if h_func(s) == 0:\n",
" return Path(s)\n",
" for s2 in moves_func(s):\n",
" g = path_cost[s] + cost_func(s, s2)\n",
" if s2 not in path_cost or g < path_cost[s2]:\n",
" heappush(frontier, (g + h_func(s2), s2))\n",
" path_cost[s2] = g\n",
" previous[s2] = s\n",
"\n",
"def bfs(start, moves_func, goals):\n",
" \"Breadth-first search\"\n",
" goal_func = (goals if callable(goals) else lambda s: s in goals)\n",
" return Astar(start, moves_func, lambda s: (0 if goal_func(s) else 1))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}