from functools import reduce as freduce from itertools import permutations class Regular: __slots__ = ['data'] def __init__(self, x): self.data = x def __str__(self): return f'r{self.data}' __repr__ = __str__ def __eq__(self, other): if isinstance(other, Regular): return self.data == other.data if isinstance(other, int): return self.data == other return False def load_file(filename='input'): with open(filename) as f: for line in f: yield line.strip() def add(x, y): return reduce(add_numbers(x, y)) def reduce(x): while True: if can_explode(x): x = explode(x) continue if can_split(x): x = split(x) continue break return x def can_split(x): try: return next(filter(lambda k: k.data>=10, numbers(x))) except StopIteration: return False def is_int(x): return isinstance(x, int) def is_regular(x): return isinstance(x, Regular) def is_pair(x): return isinstance(x, list) def magnitude(x): if is_regular(x): return x.data return 3*magnitude(first(x)) + 2*magnitude(second(x)) def numbers(x): if is_regular(x): yield x elif is_pair(x): yield from numbers(first(x)) yield from numbers(second(x)) def height(x, h=0): if is_regular(first(x)) and is_regular(second(x)): yield h, x if is_pair(first(x)): yield from height(first(x), h+1) if is_pair(second(x)): yield from height(second(x), h+1) def can_explode(x): try: return next(filter(lambda k: k[0]==4, height(x))) except StopIteration: return None def explode(where): what = can_explode(where)[1] replace_once(where, what, Regular(-1)) k = list(numbers(where)) i = k.index(Regular(-1)) if i-1>=0: k[i-1].data += what[0].data if i+1