···11+import fileinput
22+33+44+class Node:
55+ def __init__(self, i, val):
66+ self.i = i
77+ self.val = val
88+ self.back = None
99+ self.next = None
1010+1111+1212+# Parse problem input.
1313+INPUT = [int(x) for x in fileinput.input()]
1414+1515+1616+def construct_problem(problem_input, decryption_key=1):
1717+ numbers = []
1818+ first = None
1919+ last = None
2020+ zero = None
2121+ for i, num in enumerate(problem_input):
2222+ node = Node(i, num * decryption_key)
2323+2424+ if num == 0:
2525+ zero = node
2626+2727+ if first is None:
2828+ first = node
2929+ else:
3030+ node.back = last
3131+3232+ if last is not None:
3333+ last.next = node
3434+3535+ last = node
3636+ numbers.append(node)
3737+3838+ last.next = first
3939+ first.back = last
4040+4141+ return numbers, zero
4242+4343+4444+def move_number(node, mod):
4545+ n = node.val % mod
4646+ if n == 0:
4747+ return
4848+4949+ # Keep track of old parent/child.
5050+ parent = node.back
5151+ child = node.next
5252+5353+ # Find the next location.
5454+ curr = node
5555+ for _ in range(n):
5656+ curr = curr.next
5757+5858+ # Point new parent/child to node and vice versa.
5959+ desc = curr.next
6060+6161+ desc.back = node
6262+ curr.next = node
6363+ node.back = curr
6464+ node.next = desc
6565+6666+ # Put the old parent/child together.
6767+ parent.next = child
6868+ child.back = parent
6969+7070+7171+def mix(numbers):
7272+ for n in numbers:
7373+ move_number(n, len(numbers) - 1)
7474+7575+7676+def get_grove_coordinates(curr):
7777+ vals = []
7878+ for i in range(3):
7979+ for _ in range(1000):
8080+ curr = curr.next
8181+8282+ vals.append(curr.val)
8383+8484+ return sum(vals)
8585+8686+8787+# Solve part 1.
8888+numbers, zero = construct_problem(INPUT)
8989+mix(numbers)
9090+print("Part 1:", get_grove_coordinates(zero))
9191+9292+# Solve part 2.
9393+numbers, zero = construct_problem(INPUT, decryption_key=811589153)
9494+for _ in range(10): mix(numbers)
9595+print("Part 2:", get_grove_coordinates(zero))
9696+