|
@@ -0,0 +1,33 @@
|
|
1
|
+#!/usr/bin/python3
|
|
2
|
+
|
|
3
|
+import functools
|
|
4
|
+import hashlib
|
|
5
|
+import itertools
|
|
6
|
+import re
|
|
7
|
+
|
|
8
|
+salt = 'cuanljph'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+@functools.lru_cache(maxsize=1024)
|
|
12
|
+def md5(index):
|
|
13
|
+ return hashlib.md5((salt + str(index)).encode('UTF-8')).hexdigest()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+@functools.lru_cache(maxsize=1024)
|
|
17
|
+def stretched(index):
|
|
18
|
+ key = salt + str(index)
|
|
19
|
+ for _ in range(2017): key = hashlib.md5(key.encode('UTF-8')).hexdigest()
|
|
20
|
+ return key
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+@functools.lru_cache(maxsize=1024)
|
|
24
|
+def trip(index, fn):
|
|
25
|
+ return tripmatcher.search(fn(index))
|
|
26
|
+
|
|
27
|
+tripmatcher = re.compile(r'(.)\1{2}')
|
|
28
|
+matches = lambda fn: ((i, fn(i)) for i in itertools.count()
|
|
29
|
+ if trip(i, fn) and any(trip(i, fn).group(1) * 5 in fn(n)
|
|
30
|
+ for n in range(i + 1, i + 1000)))
|
|
31
|
+
|
|
32
|
+print("Part one: %s" % next(itertools.islice(matches(md5), 63, 64))[0])
|
|
33
|
+print("Part two: %s" % next(itertools.islice(matches(stretched), 63, 64))[0])
|