Advertisement
Guest User

Advent of Code 2021 Day 18

a guest
Dec 18th, 2021
158
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.37 KB | None | 0 0
  1. from ast import literal_eval
  2. from collections import deque
  3. from itertools import combinations
  4. from math import ceil
  5.  
  6.  
  7. def parse_input(filepath):
  8.     with open(filepath, "r") as f:
  9.         snailfish_numbers = [line.strip() for line in f.readlines()]
  10.     return snailfish_numbers
  11.  
  12.  
  13. def explode(num):
  14.     new_num: deque[str] = deque()
  15.     depth = -1
  16.     num_len = len(num)
  17.     ptr = 0
  18.     exploded = False
  19.     right_applied = False
  20.     right = None
  21.     while ptr < num_len:
  22.         if num[ptr] == "[":
  23.             new_num.append(num[ptr])
  24.             depth += 1
  25.             ptr += 1
  26.         elif num[ptr] == "]":
  27.             if depth >= 4 and not exploded:
  28.                 exploded = True
  29.                 temp = deque()
  30.                 while new_num[-1] != "[":
  31.                     temp.appendleft(new_num.pop())
  32.                 new_num.pop()
  33.                 temp = ''.join(temp).split(",")
  34.                 left, right = int(temp[0]), int(temp[1])
  35.                 # Iterate left and find a number to add left to??
  36.                 new_num_left = deque()
  37.                 while new_num:
  38.                     left_val = new_num.pop()
  39.                     if left_val.isnumeric():
  40.                         left_val = str(int(left) + int(left_val))
  41.                         new_num.append(left_val)
  42.                         break
  43.                     else:
  44.                         new_num_left.appendleft(left_val)
  45.                 new_num.extend(new_num_left)
  46.                 new_num.append("0")
  47.             else:
  48.                 new_num.append(num[ptr])
  49.             ptr += 1
  50.             depth -= 1
  51.         elif num[ptr] == ",":
  52.             new_num.append(num[ptr])
  53.             ptr += 1
  54.         else:
  55.             inner_num = []
  56.             while num[ptr].isnumeric():
  57.                 inner_num.append(num[ptr])
  58.                 ptr += 1
  59.             next_num = "".join(inner_num)
  60.             if right and not right_applied:
  61.                 next_num = str(int(next_num) + int(right))
  62.                 right_applied = True
  63.             new_num.append(next_num)
  64.     return "".join(new_num)
  65.  
  66.  
  67. def split(num) -> str:
  68.     new_num: deque[str] = deque()
  69.     num_len = len(num)
  70.     ptr = 0
  71.     num_split = False
  72.     while ptr < num_len:
  73.         if num[ptr] in "[,]":
  74.             new_num.append(num[ptr])
  75.             ptr += 1
  76.         else:
  77.             inner_num = []
  78.             while num[ptr].isnumeric():
  79.                 inner_num.append(num[ptr])
  80.                 ptr += 1
  81.             next_num = "".join(inner_num)
  82.             if not num_split and int(next_num) >= 10:
  83.                 next_num = int(next_num)
  84.                 left = next_num // 2
  85.                 right = ceil(next_num / 2)
  86.                 new_num.append(f"[{str(left)},{str(right)}]")
  87.                 num_split = True
  88.             else:
  89.                 new_num.append(next_num)
  90.     return "".join(new_num)
  91.  
  92.  
  93. def reduce(num):
  94.     while True:
  95.         exploded_num = explode(num)
  96.         if exploded_num != num:
  97.             num = exploded_num
  98.             continue
  99.         split_num = split(num)
  100.         if split_num != num:
  101.             num = split_num
  102.             continue
  103.         return num
  104.  
  105.  
  106. def add(num1, num2):
  107.     new_num = f"[{num1},{num2}]"
  108.     reduced_num = reduce(new_num)
  109.     return reduced_num
  110.  
  111.  
  112. def calculate_magnitude(num):
  113.     if isinstance(num,str):
  114.         num = literal_eval(num)
  115.     match (isinstance(num[0], int), isinstance(num[1], int)):
  116.         case (True, True):
  117.             return num[0] * 3 + num[1] * 2
  118.         case (True, False):
  119.             return 3 * num[0] + 2 * calculate_magnitude(num[1])
  120.         case (False, True):
  121.             return 3 * calculate_magnitude(num[0]) + 2 * num[1]
  122.         case (False, False):
  123.             return 3 * calculate_magnitude(num[0]) + 2 * calculate_magnitude(num[1])
  124.  
  125.  
  126. def part_a():
  127.     fp = r"data/day18.txt"
  128.     data = parse_input(fp)
  129.     l, *r = data
  130.     for n in r:
  131.         l = add(l, n)
  132.     m = calculate_magnitude(l)
  133.     return m
  134.  
  135.  
  136. def part_b():
  137.     fp = r"data/day18.txt"
  138.     data = parse_input(fp)
  139.     data = parse_input(fp)
  140.     max_magnitude = float("-inf")
  141.     for a, b in combinations(data, 2):
  142.         c = calculate_magnitude(add(a, b))
  143.         d = calculate_magnitude(add(b, a))
  144.         max_magnitude = max(max_magnitude, c, d)
  145.     return max_magnitude
  146.  
  147.  
  148. if __name__ == '__main__':
  149.     print(part_a())
  150.     print(part_b())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement