#!/usr/bin/env python3 from pathlib import Path def parse(line): if ',' not in line: return int(line) line = line[1:-1] level = 0 split_idx = 0 for i, c in enumerate(line): if '[' == c: level += 1 elif ']' == c: level -= 1 elif 0 == level and ',' == c: split_idx = i break left = parse(line[:split_idx]) right = parse(line[split_idx + 1:]) return (left, right) def explode_to_left(n, l): (left, right) = n res = True if type(right) == int: right = right + l else: res, right = explode_to_left(right, l) if not res: if type(left) == int: left = left + l res = True else: res, left = explode_to_left(left, l) if not res: res = False return res, (left, right) def explode_to_right(n, r): (left, right) = n res = True if type(left) == int: left = left + r else: res, left = explode_to_right(left, r) if not res: if type(right) == int: right = right + r res = True else: res, right = explode_to_right(right, r) if not res: res = False return res, (left, right) def explode(n, lvl=0): if type(n) is int: return False, n, None, None (left, right) = n if lvl == 4 and type(left) is int and type(right) is int: return True, 0, left, right else: res, left, l, r = explode(left, lvl+1) if not res: res, right, l, r = explode(right, lvl+1) if not res: return False, n, None, None else: if l: if type(left) is int: left = left + l l = None else: res, left = explode_to_left(left, l) if res: l = None return True, (left, right), l, r else: if r: if type(right) is int: right = right + r r = None else: res, right = explode_to_right(right, r) if res: r = None return True, (left, right), l, r def split(n): if type(n) is int: if 10 <= n: return True, (n // 2, (n + 1) // 2) else: return False, n (left, right) = n res, left = split(left) if not res: res, right = split(right) return res, (left, right) def magnitude(n): m = 0 (left, right) = n if type(left) is int: m += 3 * left else: m += 3 * magnitude(left) if type(right) is int: m += 2 * right else: m += 2 * magnitude(right) return m def part_1(input): result = 0 n = None for line in input: line = line.rstrip() if not n: n = parse(line) continue n = (n, parse(line)) res = True while res: while res: res, n, _, _ = explode(n) res, n = split(n) result = magnitude(n) print("Part 1 result:", result) def part_2(input): result = 0 nbrs = [] for line in input: line = line.rstrip() nbrs.append(parse(line)) for n1 in nbrs: for n2 in nbrs: if n1 == n2: continue n = (n1, n2) res = True while res: while res: res, n, _, _ = explode(n) res, n = split(n) result = max(result, magnitude(n)) print("Part 2 result:", result) input = list() p = Path(__file__).with_name('input.txt') with open(p) as f: input = f.readlines() part_1(input) part_2(input)