105 lines
3.0 KiB
Python
105 lines
3.0 KiB
Python
|
import shared
|
||
|
import itertools
|
||
|
import json
|
||
|
import math
|
||
|
from functools import reduce
|
||
|
|
||
|
red = lambda word: f"\u001b[31m{word}\u001b[0m"
|
||
|
yellow = lambda word: f"\u001b[33m{word}\u001b[0m"
|
||
|
blue = lambda word: f"\u001b[34m{word}\u001b[0m"
|
||
|
green = lambda word: f"\u001b[32m{word}\u001b[0m"
|
||
|
|
||
|
class Snailfish:
|
||
|
def __init__(self):
|
||
|
self.load()
|
||
|
|
||
|
def load(self):
|
||
|
snailfish = []
|
||
|
with open(shared.get_fname(18), "r") as f:
|
||
|
for line in f.readlines():
|
||
|
snailfish.append(json.loads(line.rstrip()))
|
||
|
print(snailfish[-1])
|
||
|
self.snailfish = snailfish
|
||
|
|
||
|
def run(self):
|
||
|
reduced = reduce(self.add, self.snailfish)
|
||
|
print(green(reduced))
|
||
|
self.magnitude_sum = self.magnitude(reduced)
|
||
|
permutations = itertools.permutations(self.snailfish, 2)
|
||
|
self.magnitude_max = 0
|
||
|
for a,b in permutations:
|
||
|
print(red(a), yellow(b))
|
||
|
fish_sum = self.add(a,b)
|
||
|
print("\t", blue(fish_sum))
|
||
|
mag = self.magnitude(fish_sum)
|
||
|
if mag > self.magnitude_max:
|
||
|
self.magnitude_max = mag
|
||
|
print()
|
||
|
|
||
|
def add_left(self, fish, value):
|
||
|
if value is None:
|
||
|
return fish
|
||
|
if isinstance(fish, int):
|
||
|
return fish + value
|
||
|
return [self.add_left(fish[0], value), fish[1]]
|
||
|
|
||
|
def add_right(self, fish, value):
|
||
|
if value is None:
|
||
|
return fish
|
||
|
if isinstance(fish, int):
|
||
|
return fish + value
|
||
|
return [fish[0], self.add_right(fish[1], value)]
|
||
|
|
||
|
def explode(self, fish, depth=4):
|
||
|
if isinstance(fish, int):
|
||
|
return False, None, fish, None
|
||
|
if depth == 0:
|
||
|
return True, fish[0], 0, fish[1]
|
||
|
x, y = fish
|
||
|
exploded, left, x, right = self.explode(x, depth - 1)
|
||
|
if exploded:
|
||
|
return True, left, [x, self.add_left(y, right)], None
|
||
|
exploded, left, y, right = self.explode(y, depth - 1)
|
||
|
if exploded:
|
||
|
return True, None, [self.add_right(x, left), y], right
|
||
|
return False, None, fish, None
|
||
|
|
||
|
def split(self, fish):
|
||
|
if isinstance(fish, int):
|
||
|
if fish >= 10:
|
||
|
return True, [fish // 2, math.ceil(fish / 2)]
|
||
|
return False, fish
|
||
|
x, y = fish
|
||
|
split, x = self.split(x)
|
||
|
if split:
|
||
|
return True, [x, y]
|
||
|
split, y = self.split(y)
|
||
|
return split, [x, y]
|
||
|
|
||
|
def add(self, x, y):
|
||
|
fish = [x, y]
|
||
|
while True:
|
||
|
exploded, _, fish, _ = self.explode(fish)
|
||
|
if exploded:
|
||
|
continue
|
||
|
split, fish = self.split(fish)
|
||
|
if not split:
|
||
|
break
|
||
|
return fish
|
||
|
|
||
|
def magnitude(self, fish):
|
||
|
if isinstance(fish, int):
|
||
|
return fish
|
||
|
return 3 * self.magnitude(fish[0]) + 2 * self.magnitude(fish[1])
|
||
|
|
||
|
|
||
|
def main():
|
||
|
s = Snailfish()
|
||
|
s.run()
|
||
|
print('part1: sum', s.magnitude_sum)
|
||
|
print('part2: max', s.magnitude_max)
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|