Advertisement
Arham-4

AoC Day 18

Dec 18th, 2021 (edited)
1,424
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.36 KB | None | 0 0
  1. import json
  2. import math
  3.  
  4.  
  5. class Number:
  6.     def __init__(self, value):
  7.         self.value = value
  8.         self.left = None
  9.         self.right = None
  10.  
  11.     def __repr__(self):
  12.         return str(self.value)
  13.  
  14.  
  15. def depth(pairs):
  16.     if isinstance(pairs, list):
  17.         res = 1 + max(depth(pair) for pair in pairs)
  18.         return res
  19.     else:
  20.         return 0
  21.  
  22.  
  23. def convert_numbers(item):
  24.     for l in range(len(item)):
  25.         if isinstance(item[l], int):
  26.             item[l] = Number(item[l])
  27.         elif isinstance(item[l], list):
  28.             convert_numbers(item[l])
  29.  
  30.  
  31. def make_neighbors(item):
  32.     aggregated = []
  33.  
  34.     def visit_all(item):
  35.         for l in range(len(item)):
  36.             if isinstance(item[l], Number):
  37.                 aggregated.append(item[l])
  38.             elif isinstance(item[l], list):
  39.                 visit_all(item[l])
  40.  
  41.     visit_all(item)
  42.  
  43.     aggregated[0].right = aggregated[1]
  44.     aggregated[-1].left = aggregated[-2]
  45.     for i in range(1, len(aggregated) - 1):
  46.         aggregated[i].left = aggregated[i - 1]
  47.         aggregated[i].right = aggregated[i + 1]
  48.  
  49.  
  50. def read_line(line):
  51.     line_to_list = json.loads(line)
  52.     for l in range(len(line_to_list)):
  53.         convert_numbers(line_to_list)
  54.     return line_to_list
  55.  
  56.  
  57. def split(pairs):
  58.     for l in range(len(pairs)):
  59.         if isinstance(pairs[l], Number):
  60.             previous_number = pairs[l]
  61.  
  62.             if pairs[l].value >= 10:
  63.                 half = pairs[l].value / 2
  64.                 pairs[l] = [Number(int(math.floor(half))), Number(int(math.ceil(half)))]
  65.  
  66.                 pairs[l][0].left = previous_number.left
  67.                 pairs[l][0].right = pairs[l][1]
  68.                 if previous_number.left is not None:
  69.                     previous_number.left.right = pairs[l][0]
  70.  
  71.                 pairs[l][1].left = pairs[l][0]
  72.                 pairs[l][1].right = previous_number.right
  73.                 if previous_number.right is not None:
  74.                     previous_number.right.left = pairs[l][1]
  75.  
  76.                 return True
  77.         elif isinstance(pairs[l], list):
  78.             if split(pairs[l]):
  79.                 return True
  80.     return False
  81.  
  82.  
  83. def is_number_pair(pairs):
  84.     for item in pairs:
  85.         if isinstance(item, list):
  86.             return False
  87.     return True
  88.  
  89.  
  90. def explode(pairs, depth):
  91.     if isinstance(pairs, list):
  92.         if depth >= 3:
  93.             for i in range(len(pairs)):
  94.                 layer3 = pairs[i]
  95.                 if isinstance(pairs[i], list):
  96.                     if is_number_pair(pairs[i]):
  97.                         pairs.remove(layer3)
  98.  
  99.                         replacement = Number(0)
  100.                         if layer3[0].left is not None:
  101.                             replacement.left = layer3[0].left
  102.  
  103.                             layer3[0].left.value += layer3[0].value
  104.                             layer3[0].left.right = replacement
  105.  
  106.                         if layer3[1].right is not None:
  107.                             replacement.right = layer3[1].right
  108.  
  109.                             layer3[1].right.value += layer3[1].value
  110.                             layer3[1].right.left = replacement
  111.  
  112.                         pairs.insert(i, replacement)
  113.                         return True
  114.                     elif explode(pairs[i], depth + 1):
  115.                         return True
  116.         else:
  117.             for item in pairs:
  118.                 if explode(item, depth + 1):
  119.                     return True
  120.     return False
  121.  
  122. def reduce(pairs):
  123.     if depth(pairs) > 4:
  124.         while depth(pairs) > 4:
  125.             for i in range(len(pairs)):
  126.                 pair = pairs[i]
  127.                 if depth(pair) >= 4:
  128.                     reduce(pair)
  129.     elif depth(pairs) == 4:
  130.         while True:
  131.             if explode(pairs, 1):
  132.                 pass
  133.             elif split(pairs):
  134.                 pass
  135.             else:
  136.                 break
  137.  
  138.  
  139. def magnitude(pairs):
  140.     if isinstance(pairs, Number):
  141.         return pairs.value
  142.     return magnitude(pairs[0]) * 3 + magnitude(pairs[1]) * 2
  143.  
  144.  
  145. def solution(inp):
  146.     pairs = read_line(inp[0])
  147.  
  148.     for i in range(1, len(inp)):
  149.         pairs = [pairs, read_line(inp[i])]
  150.         make_neighbors(pairs)
  151.  
  152.         reduce(pairs)
  153.  
  154.     return magnitude(pairs)
  155.  
  156.  
  157. def result(inp):
  158.     return solution(inp)
  159.  
  160.  
  161. def test(example_inp):
  162.     assert result(example_inp) == 3488
  163.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement