123456789101112131415161718192021222324252627282930313233343536373839404142434445 |
- import string
- from functools import partial, reduce
-
-
- def spin(amount, line):
- return line[-amount:] + line[:-amount]
-
-
- def exchange(p1, p2, line):
- line[p1], line[p2] = line[p2], line[p1]
- return line
-
-
- def partner(n1, n2, line):
- p1, p2 = line.index(n1), line.index(n2)
- line[p1], line[p2] = line[p2], line[p1]
- return line
-
-
- def dance(reps, moves):
- line = list(string.ascii_lowercase[:16])
- # Maintain a history to try and find cycles. If we ever generate the same line twice
- # then all of the remainder will just cycle between those two lines.
- history = []
- for i in range(reps):
- line = reduce(lambda v, m: m(v), moves, line)
- if line in history:
- start = history.index(line)
- cycle = len(history) - start
- return ''.join(history[start + (reps - i - 1) % cycle])
- history.append(line[:]) # NB: Copy of the line, so it doesn't get mutated next cycle...
- return ''.join(line)
-
-
- instructions = {
- 's': lambda r: partial(spin, int(r)),
- 'x': lambda r: partial(exchange, *map(int, r.split('/'))),
- 'p': lambda r: partial(partner, *r.split('/'))
- }
-
- with open('data/16.txt', 'r') as file:
- # Pre-parse the list of moves into function calls to save string-fiddling lots of times
- moves = list(map(lambda line: instructions[line[0]](line[1:]), file.readline().strip().split(',')))
- print(f'Part one: {dance(1, moves)}')
- print(f'Part two: {dance(1000000000, moves)}')
|