|
@@ -0,0 +1,46 @@
|
|
1
|
+import string
|
|
2
|
+from functools import partial
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+def spin(amount, line):
|
|
6
|
+ return line[-amount:] + line[:-amount]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+def exchange(p1, p2, line):
|
|
10
|
+ line[p1], line[p2] = line[p2], line[p1]
|
|
11
|
+ return line
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+def partner(n1, n2, line):
|
|
15
|
+ p1, p2 = line.index(n1), line.index(n2)
|
|
16
|
+ line[p1], line[p2] = line[p2], line[p1]
|
|
17
|
+ return line
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+def dance(reps, moves):
|
|
21
|
+ line = list(string.ascii_lowercase[:16])
|
|
22
|
+ # Maintain a history to try and find cycles. If we ever generate the same line twice
|
|
23
|
+ # then all of the remainder will just cycle between those two lines.
|
|
24
|
+ history = []
|
|
25
|
+ for i in range(reps):
|
|
26
|
+ for move in moves:
|
|
27
|
+ line = move(line)
|
|
28
|
+ if line in history:
|
|
29
|
+ start = history.index(line)
|
|
30
|
+ cycle = len(history) - start
|
|
31
|
+ return ''.join(history[start + (reps - i - 1) % cycle])
|
|
32
|
+ history.append(line[:]) # NB: Copy of the line, so it doesn't get mutated next cycle...
|
|
33
|
+ return ''.join(line)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+instructions = {
|
|
37
|
+ 's': lambda r: partial(spin, int(r)),
|
|
38
|
+ 'x': lambda r: partial(exchange, *map(int, r.split('/'))),
|
|
39
|
+ 'p': lambda r: partial(partner, *r.split('/'))
|
|
40
|
+}
|
|
41
|
+
|
|
42
|
+with open('data/16.txt', 'r') as file:
|
|
43
|
+ # Pre-parse the list of moves into function calls to save string-fiddling lots of times
|
|
44
|
+ moves = list(map(lambda line: instructions[line[0]](line[1:]), file.readline().strip().split(',')))
|
|
45
|
+ print(f'Part one: {dance(1, moves)}')
|
|
46
|
+ print(f'Part two: {dance(1000000000, moves)}')
|