···11+import os # NOQA
22+import sys # NOQA
33+import re # NOQA
44+import math # NOQA
55+import fileinput
66+from collections import Counter, defaultdict, deque, namedtuple # NOQA
77+from itertools import count, product, permutations, combinations, combinations_with_replacement # NOQA
88+99+from utils import parse_line, mul, all_unique, factors, memoize, primes # NOQA
1010+from utils import new_table, transposed, rotated # NOQA
1111+from utils import md5, sha256, knot_hash # NOQA
1212+from utils import Point, DIRS, DIRS_4, DIRS_8 # NOQA
1313+1414+# Itertools Functions:
1515+# product('ABCD', repeat=2) AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
1616+# permutations('ABCD', 2) AB AC AD BA BC BD CA CB CD DA DB DC
1717+# combinations('ABCD', 2) AB AC AD BC BD CD
1818+# combinations_with_replacement('ABCD', 2) AA AB AC AD BB BC BD CC CD DD
1919+2020+total = 0
2121+result = []
2222+table = new_table(None, width=2, height=4)
2323+2424+for i, line in enumerate(fileinput.input()):
2525+ line = line.strip()
2626+ data = parse_line(r'', line)
2727+2828+ if i == 0:
2929+ print(data)
+208
2018/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 new_table(val, width, height):
2525+ return [[val for _ in range(width)] for _ in range(height)]
2626+2727+2828+def transposed(matrix):
2929+ """Returns the transpose of the given matrix."""
3030+ return [list(r) for r in zip(*matrix)]
3131+3232+3333+def rotated(matrix):
3434+ """Returns the given matrix rotated 90 degrees clockwise."""
3535+ return [list(r) for r in zip(*matrix[::-1])]
3636+3737+3838+def mul(lst):
3939+ """Like sum(), but for multiplication."""
4040+ return reduce(operator.mul, lst, 1) # NOQA
4141+4242+4343+def chunks(l, n):
4444+ """Yield successive n-sized chunks from l."""
4545+ for i in range(0, len(l), n):
4646+ yield l[i:i + n]
4747+4848+4949+def all_unique(lst):
5050+ return len(lst) == len(set(lst))
5151+5252+5353+def factors(n):
5454+ """Returns the factors of n."""
5555+ return sorted(
5656+ x for tup in (
5757+ [i, n // i] for i in range(1, int(n ** 0.5) + 1)
5858+ if n % i == 0)
5959+ for x in tup)
6060+6161+6262+def memoize(f):
6363+ """Simple dictionary-based memoization decorator"""
6464+ cache = {}
6565+6666+ def _mem_fn(*args):
6767+ if args not in cache:
6868+ cache[args] = f(*args)
6969+ return cache[args]
7070+7171+ _mem_fn.cache = cache
7272+ return _mem_fn
7373+7474+7575+def _eratosthenes(n):
7676+ """http://stackoverflow.com/a/3941967/239076"""
7777+ # Initialize list of primes
7878+ _primes = [True] * n
7979+8080+ # Set 0 and 1 to non-prime
8181+ _primes[0] = _primes[1] = False
8282+8383+ for i, is_prime in enumerate(_primes):
8484+ if is_prime:
8585+ yield i
8686+8787+ # Mark factors as non-prime
8888+ for j in xrange(i * i, n, i): # NOQA
8989+ _primes[j] = False
9090+9191+9292+def primes(n):
9393+ """Return a list of primes from [2, n)"""
9494+ return list(_eratosthenes(n))
9595+9696+9797+def md5(msg):
9898+ m = hashlib.md5()
9999+ m.update(msg)
100100+ return m.hexdigest()
101101+102102+103103+def sha256(msg):
104104+ s = hashlib.sha256()
105105+ s.update(msg)
106106+ return s.hexdigest()
107107+108108+109109+def knot_hash(msg):
110110+ lengths = [ord(x) for x in msg] + [17, 31, 73, 47, 23]
111111+ sparse = range(0, 256)
112112+ pos = 0
113113+ skip = 0
114114+115115+ for _ in range(64):
116116+ for l in lengths:
117117+ for i in range(l // 2):
118118+ x = (pos + i) % len(sparse)
119119+ y = (pos + l - i - 1) % len(sparse)
120120+ sparse[x], sparse[y] = sparse[y], sparse[x]
121121+122122+ pos = pos + l + skip % len(sparse)
123123+ skip += 1
124124+125125+ hash_val = 0
126126+127127+ for i in range(16):
128128+ res = 0
129129+ for j in range(0, 16):
130130+ res ^= sparse[(i * 16) + j]
131131+132132+ hash_val += res << ((16 - i - 1) * 8)
133133+134134+ return '%032x' % hash_val
135135+136136+137137+@total_ordering
138138+class Point:
139139+ """Simple 2-dimensional point."""
140140+ def __init__(self, x, y):
141141+ self.x = x
142142+ self.y = y
143143+144144+ def __add__(self, other):
145145+ return Point(self.x + other.x, self.y + other.y)
146146+147147+ def __sub__(self, other):
148148+ return Point(self.x - other.x, self.y - other.y)
149149+150150+ def __mul__(self, n):
151151+ return Point(self.x * n, self.y * n)
152152+153153+ def __div__(self, n):
154154+ return Point(self.x / n, self.y / n)
155155+156156+ def __neg__(self):
157157+ return Point(-self.x, -self.y)
158158+159159+ def __eq__(self, other):
160160+ return self.x == other.x and self.y == other.y
161161+162162+ def __ne__(self, other):
163163+ return not self == other
164164+165165+ def __lt__(self, other):
166166+ return self.manhattan < other.manhattan
167167+168168+ def __str__(self):
169169+ return "({}, {})".format(self.x, self.y)
170170+171171+ def __repr__(self):
172172+ return "Point({}, {})".format(self.x, self.y)
173173+174174+ def __hash__(self):
175175+ return hash(tuple((self.x, self.y)))
176176+177177+ @property
178178+ def manhattan(self):
179179+ return abs(self.x) + abs(self.y)
180180+181181+ @property
182182+ def distance(self):
183183+ return math.sqrt(self.x ** 2 + self.y ** 2)
184184+185185+ def neighbours_4(self):
186186+ return [self + p for p in DIRS_4]
187187+188188+ def neighbours_8(self):
189189+ return [self + p for p in DIRS_8]
190190+191191+192192+DIRS_4 = DIRS = [
193193+ Point(0, 1), # north
194194+ Point(1, 0), # east
195195+ Point(0, -1), # south
196196+ Point(-1, 0), # west
197197+]
198198+199199+DIRS_8 = [
200200+ Point(0, 1), # N
201201+ Point(1, 1), # NE
202202+ Point(1, 0), # E
203203+ Point(1, -1), # SE
204204+ Point(0, -1), # S
205205+ Point(-1, -1), # SW
206206+ Point(-1, 0), # W
207207+ Point(-1, 1), # NW
208208+]