from tools.aoc import AOCDay from typing import Any class Node: def __init__(self, node_id: int, value: int): self.node_id = node_id self.value = value self.left = None self.right = None self.was_moved = False def __str__(self): return f"Node(id={self.node_id}; value={self.value}; moved={self.was_moved}; left={self.left.node_id}; right={self.right.node_id})" def __len__(self): ptr = self length = 0 while ptr.right != self: length += 1 ptr = ptr.right return length + 1 def llistprint(llist: Node) -> None: ptr = llist print("[", end="") while ptr.right != llist: print(f"{ptr.value}, ", end="") ptr = ptr.right print(f"{ptr.value}]") def mix(head: Node) -> Node: ptr = head list_len = len(head) for i in range(list_len): cur_val = ptr.value cur_ptr = ptr cur_ptr.was_moved = True ptr = ptr.right while ptr.was_moved and i < list_len - 1: ptr = ptr.right if cur_val == 0: continue if cur_ptr == head: head = cur_ptr.right cur_ptr.left.right = cur_ptr.right cur_ptr.right.left = cur_ptr.left target_ptr = cur_ptr if cur_val > 0: cur_val = cur_val % list_len + cur_val // list_len else: cur_val = -(abs(cur_val) % list_len + abs(cur_val) // list_len) for _ in range(abs(cur_val)): if cur_val < 0: target_ptr = target_ptr.left else: target_ptr = target_ptr.right if cur_val < 0: cur_ptr.left = target_ptr.left cur_ptr.right = target_ptr target_ptr.left.right = cur_ptr target_ptr.left = cur_ptr else: cur_ptr.left = target_ptr cur_ptr.right = target_ptr.right target_ptr.right.left = cur_ptr target_ptr.right = cur_ptr return head class Day(AOCDay): inputs = [ [ (3, "input20_test"), (4, "input20_test2"), (10763, "input20"), ], [ (1623178306, "input20_test"), (None, "input20"), ] ] def get_inp_llist(self, mul: int = 1) -> Node: head = None tail = None for i, x in enumerate(self.getInput(int)): n = Node(i, x * mul) if head is None: head = n tail = n else: tail.right = n n.left = tail tail = n tail.right = head head.left = tail return head def part1(self) -> Any: ptr = self.get_inp_llist() ptr = mix(ptr) while ptr.value != 0: ptr = ptr.right val_sum = 0 for _ in range(3): for _ in range(1000): ptr = ptr.right val_sum += ptr.value return val_sum def part2(self) -> Any: key = 811589153 ptr = self.get_inp_llist(key) for _ in range(10): llistprint(ptr) ptr = mix(ptr) llistprint(ptr) return "" if __name__ == '__main__': day = Day(2022, 20) day.run(verbose=True)