···11+import os # NOQA
22+import sys # NOQA
33+import re # NOQA
44+import math # NOQA
55+import fileinput
66+from string import ascii_uppercase, ascii_lowercase # NOQA
77+from collections import Counter, defaultdict, deque, namedtuple # NOQA
88+from itertools import count, product, permutations, combinations, combinations_with_replacement # NOQA
99+1010+from utils import parse_line, parse_nums, mul, all_unique, factors, memoize, primes # NOQA
1111+from utils import chunks, gcd, lcm, print_grid, min_max_xy # NOQA
1212+from utils import new_table, transposed, rotated # NOQA
1313+from utils import md5, sha256, knot_hash # NOQA
1414+from utils import VOWELS, CONSONANTS # NOQA
1515+from utils import Point, DIRS, DIRS_4, DIRS_8 # NOQA
1616+1717+# Itertools Functions:
1818+# product('ABCD', repeat=2) AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
1919+# permutations('ABCD', 2) AB AC AD BA BC BD CA CB CD DA DB DC
2020+# combinations('ABCD', 2) AB AC AD BC BD CD
2121+# combinations_with_replacement('ABCD', 2) AA AB AC AD BB BC BD CC CD DD
2222+2323+total = 0
2424+result = []
2525+table = new_table(None, width=2, height=4)
2626+2727+for i, line in enumerate(fileinput.input()):
2828+ line = line.strip()
2929+ nums = parse_nums(line)
3030+ data = parse_line(r'', line)
3131+3232+ if i == 0:
3333+ print(data)
+287
2020/utils.py
···11+import re
22+import math
33+import hashlib
44+import operator
55+from functools import total_ordering
66+77+88+LETTERS = [x for x in 'abcdefghijklmnopqrstuvwxyz']
99+VOWELS = {'a', 'e', 'i', 'o', 'u'}
1010+CONSONANTS = set(x for x in LETTERS if x not in VOWELS)
1111+1212+1313+def parse_line(regex, line):
1414+ ret = []
1515+ for match in re.match(regex, line).groups():
1616+ try:
1717+ ret.append(int(match))
1818+ except ValueError:
1919+ ret.append(match)
2020+2121+ return ret
2222+2323+2424+def parse_nums(line, negatives=True):
2525+ num_re = r'-?\d+' if negatives else r'\d+'
2626+ return [int(n) for n in re.findall(num_re, line)]
2727+2828+2929+def new_table(val, width, height):
3030+ return [[val for _ in range(width)] for _ in range(height)]
3131+3232+3333+def transposed(matrix):
3434+ """Returns the transpose of the given matrix."""
3535+ return [list(r) for r in zip(*matrix)]
3636+3737+3838+def rotated(matrix):
3939+ """Returns the given matrix rotated 90 degrees clockwise."""
4040+ return [list(r) for r in zip(*matrix[::-1])]
4141+4242+4343+def mul(lst):
4444+ """Like sum(), but for multiplication."""
4545+ return reduce(operator.mul, lst, 1) # NOQA
4646+4747+4848+def chunks(l, n):
4949+ """Yield successive n-sized chunks from l."""
5050+ for i in range(0, len(l), n):
5151+ yield l[i:i + n]
5252+5353+5454+def all_unique(lst):
5555+ return len(lst) == len(set(lst))
5656+5757+5858+def factors(n):
5959+ """Returns the factors of n."""
6060+ return sorted(
6161+ x for tup in (
6262+ [i, n // i] for i in range(1, int(n ** 0.5) + 1)
6363+ if n % i == 0)
6464+ for x in tup)
6565+6666+6767+def gcd(a,b):
6868+ """Compute the greatest common divisor of a and b"""
6969+ while b > 0:
7070+ a, b = b, a % b
7171+ return a
7272+7373+7474+def lcm(a, b):
7575+ """Compute the lowest common multiple of a and b"""
7676+ return a * b / gcd(a, b)
7777+7878+7979+def min_max_xy(points):
8080+ if len(points) == 0:
8181+ return None, None, None, None
8282+ if type(points[0]) == tuple:
8383+ min_x = min(p[0] for p in points)
8484+ max_x = max(p[0] for p in points)
8585+ min_y = min(p[1] for p in points)
8686+ max_y = max(p[1] for p in points)
8787+ else:
8888+ min_x = min(p.x for p in points)
8989+ max_x = max(p.x for p in points)
9090+ min_y = min(p.y for p in points)
9191+ max_y = max(p.y for p in points)
9292+9393+ return min_x, max_x, min_y, max_y
9494+9595+9696+def print_grid(grid, f=None):
9797+ if f is None:
9898+ f = lambda x: x # NOQA
9999+100100+ if type(grid) is dict:
101101+ positions = grid.keys()
102102+ min_x, max_x, min_y, max_y = min_max_xy(positions)
103103+ if type(positions[0]) is tuple:
104104+ for y in range(min_y, max_y + 1):
105105+ print ''.join(f(grid.get((x, y), ' ')) for x in range(min_x, max_x + 1))
106106+ else:
107107+ # (x, y) => point
108108+ for y in range(min_y, max_y + 1):
109109+ print ''.join(f(grid.get(Point(x, y), ' ')) for x in range(min_x, max_x + 1))
110110+ else:
111111+ for y in range(len(grid)):
112112+ print ''.join(f(grid[y][x]) for x in range(len(grid[0])))
113113+114114+115115+def memoize(f):
116116+ """Simple dictionary-based memoization decorator"""
117117+ cache = {}
118118+119119+ def _mem_fn(*args):
120120+ if args not in cache:
121121+ cache[args] = f(*args)
122122+ return cache[args]
123123+124124+ _mem_fn.cache = cache
125125+ return _mem_fn
126126+127127+128128+def _eratosthenes(n):
129129+ """http://stackoverflow.com/a/3941967/239076"""
130130+ # Initialize list of primes
131131+ _primes = [True] * n
132132+133133+ # Set 0 and 1 to non-prime
134134+ _primes[0] = _primes[1] = False
135135+136136+ for i, is_prime in enumerate(_primes):
137137+ if is_prime:
138138+ yield i
139139+140140+ # Mark factors as non-prime
141141+ for j in xrange(i * i, n, i): # NOQA
142142+ _primes[j] = False
143143+144144+145145+def primes(n):
146146+ """Return a list of primes from [2, n)"""
147147+ return list(_eratosthenes(n))
148148+149149+150150+def md5(msg):
151151+ m = hashlib.md5()
152152+ m.update(msg)
153153+ return m.hexdigest()
154154+155155+156156+def sha256(msg):
157157+ s = hashlib.sha256()
158158+ s.update(msg)
159159+ return s.hexdigest()
160160+161161+162162+def knot_hash(msg):
163163+ lengths = [ord(x) for x in msg] + [17, 31, 73, 47, 23]
164164+ sparse = range(0, 256)
165165+ pos = 0
166166+ skip = 0
167167+168168+ for _ in range(64):
169169+ for l in lengths:
170170+ for i in range(l // 2):
171171+ x = (pos + i) % len(sparse)
172172+ y = (pos + l - i - 1) % len(sparse)
173173+ sparse[x], sparse[y] = sparse[y], sparse[x]
174174+175175+ pos = pos + l + skip % len(sparse)
176176+ skip += 1
177177+178178+ hash_val = 0
179179+180180+ for i in range(16):
181181+ res = 0
182182+ for j in range(0, 16):
183183+ res ^= sparse[(i * 16) + j]
184184+185185+ hash_val += res << ((16 - i - 1) * 8)
186186+187187+ return '%032x' % hash_val
188188+189189+190190+HEX_DIRS = {
191191+ 'N': (1, -1, 0),
192192+ 'NE': (1, 0, -1),
193193+ 'SE': (0, 1, -1),
194194+ 'S': (-1, 1, 0),
195195+ 'SW': (-1, 0, 1),
196196+ 'NW': (0, -1, 1),
197197+}
198198+199199+200200+def hex_distance(x, y, z):
201201+ """Returns a given hex point's distance from the origin."""
202202+ return (abs(x) + abs(y) + abs(z)) // 2
203203+204204+205205+@total_ordering
206206+class Point:
207207+ """Simple 2-dimensional point."""
208208+ def __init__(self, x, y):
209209+ self.x = x
210210+ self.y = y
211211+212212+ def __add__(self, other):
213213+ return Point(self.x + other.x, self.y + other.y)
214214+215215+ def __sub__(self, other):
216216+ return Point(self.x - other.x, self.y - other.y)
217217+218218+ def __mul__(self, n):
219219+ return Point(self.x * n, self.y * n)
220220+221221+ def __div__(self, n):
222222+ return Point(self.x / n, self.y / n)
223223+224224+ def __neg__(self):
225225+ return Point(-self.x, -self.y)
226226+227227+ def __eq__(self, other):
228228+ return self.x == other.x and self.y == other.y
229229+230230+ def __ne__(self, other):
231231+ return not self == other
232232+233233+ def __lt__(self, other):
234234+ return self.length < other.length
235235+236236+ def __str__(self):
237237+ return "({}, {})".format(self.x, self.y)
238238+239239+ def __repr__(self):
240240+ return "Point({}, {})".format(self.x, self.y)
241241+242242+ def __hash__(self):
243243+ return hash(tuple((self.x, self.y)))
244244+245245+ def dist(self, other):
246246+ return math.sqrt((self.x - other.x) ** 2 + (self.y - other.y) ** 2)
247247+248248+ def dist_manhattan(self, other):
249249+ return abs(self.x - other.x) + abs(self.y - other.y)
250250+251251+ def angle(self, to=None):
252252+ if to is None:
253253+ return math.atan2(self.y, self.x)
254254+ return math.atan2(self.y - to.y, self.x - to.x)
255255+256256+ @property
257257+ def manhattan(self):
258258+ return abs(self.x) + abs(self.y)
259259+260260+ @property
261261+ def length(self):
262262+ return math.sqrt(self.x ** 2 + self.y ** 2)
263263+264264+ def neighbours_4(self):
265265+ return [self + p for p in DIRS_4]
266266+267267+ def neighbours_8(self):
268268+ return [self + p for p in DIRS_8]
269269+270270+271271+DIRS_4 = DIRS = [
272272+ Point(0, 1), # north
273273+ Point(1, 0), # east
274274+ Point(0, -1), # south
275275+ Point(-1, 0), # west
276276+]
277277+278278+DIRS_8 = [
279279+ Point(0, 1), # N
280280+ Point(1, 1), # NE
281281+ Point(1, 0), # E
282282+ Point(1, -1), # SE
283283+ Point(0, -1), # S
284284+ Point(-1, -1), # SW
285285+ Point(-1, 0), # W
286286+ Point(-1, 1), # NW
287287+]