-
Notifications
You must be signed in to change notification settings - Fork 0
/
8.py
59 lines (44 loc) · 1.48 KB
/
8.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import itertools as it
from math import lcm
DEBUG = 0
# N = [line.strip() for line in open('./in/8.test.txt').readlines()]
# N = [line.strip() for line in open('./in/8.test.2.txt').readlines()]
# N = [line.strip() for line in open('./in/8.test.3.txt').readlines()]
N = [line.strip() for line in open('./in/8.txt').readlines()]
pattern, _, *lines = N
tree = {
a: (b[1:-1], c[:-1]) for a, _, b, c in map(str.split, lines)
}
GOAL = 'ZZZ'
def part_1():
START = 'AAA'
curr = START
for i, dirn in enumerate(it.cycle(pattern)):
if curr == GOAL:
return i
curr = tree[curr][dirn == 'R']
def part_2():
pointers = [node for node in tree if node.endswith('A')]
start = pointers[:]
offsets = [0 for _ in pointers]
cycle_lengths = [0 for _ in pointers]
# discovered invariant:
# each pointer only cycles through
# *one* node with a Z
for i, dirn in enumerate(it.cycle(pattern)):
for j, node in enumerate(pointers):
if node.endswith('Z'):
if offsets[j] == 0:
offsets[j] = i
elif cycle_lengths[j] == 0:
cycle_lengths[j] = i - offsets[j]
if all(cycle_lengths):
break
pointers = [tree[curr][dirn == 'R'] for curr in pointers]
DEBUG and print(i, cycle_lengths)
return lcm(*cycle_lengths)
if __name__ == '__main__':
print('--- Part 1 ---')
print(part_1())
print('\n--- Part 2 ---')
print(part_2())