/ Python / 2021 / 18.py
18.py
  1  from lib import *
  2  
  3  input = read_input(2021, 18)
  4  
  5  lines = input.splitlines()
  6  
  7  parent = lambda n: n >> 1
  8  left = lambda n: n << 1
  9  right = lambda n: n << 1 | 1
 10  
 11  
 12  def parse(lst):
 13      out = [None] * 64
 14  
 15      def fill(l, n):
 16          if not isinstance(l, list):
 17              out[n] = l
 18          else:
 19              fill(l[0], left(n))
 20              fill(l[1], right(n))
 21  
 22      fill(lst, 1)
 23      return out
 24  
 25  
 26  def explode(lst):
 27      def move_up(i, x):
 28          while lst[i] is None:
 29              i = parent(i)
 30  
 31          lst[i] += x
 32  
 33      for n in range(1 << 4, 1 << 5):
 34          if lst[n] is not None:
 35              continue
 36  
 37          l = lst[a := left(n)]
 38          r = lst[b := right(n)]
 39          if l is None and r is None:
 40              continue
 41  
 42          lst[a] = None
 43          lst[b] = None
 44          lst[n] = 0
 45  
 46          if a - 1 >= 1 << 5:
 47              move_up(a - 1, l)
 48          if b + 1 < 1 << 6:
 49              move_up(b + 1, r)
 50  
 51          return True
 52  
 53      return False
 54  
 55  
 56  def split(lst, n=1):
 57      if (x := lst[n]) is None:
 58          return split(lst, left(n)) or split(lst, right(n))
 59  
 60      if x < 10:
 61          return False
 62  
 63      k = x >> 1
 64      lst[n] = None
 65      lst[left(n)] = k
 66      lst[right(n)] = x - k
 67      return True
 68  
 69  
 70  def add(a, b):
 71      out = [None, None]
 72      for i in range(6):
 73          out += a[1 << i : 1 << i + 1]
 74          out += b[1 << i : 1 << i + 1]
 75  
 76      while explode(out) or split(out):
 77          pass
 78  
 79      return out
 80  
 81  
 82  def magnitude(lst, n=1):
 83      if lst[n] is not None:
 84          return lst[n]
 85  
 86      return 3 * magnitude(lst, left(n)) + 2 * magnitude(lst, right(n))
 87  
 88  
 89  def mk_list(lst, n=1):
 90      if lst[n] is not None:
 91          return lst[n]
 92  
 93      return [mk_list(lst, left(n)), mk_list(lst, right(n))]
 94  
 95  
 96  print(magnitude(reduce(add, (parse(ast.literal_eval(line)) for line in lines))))
 97  
 98  
 99  out = 0
100  
101  for a in lines:
102      for b in lines:
103          if a == b:
104              continue
105  
106          out = max(out, magnitude(add(parse(ast.literal_eval(a)), parse(ast.literal_eval(b)))))
107  
108  print(out)