advent-of-code/2021/python/day18.py

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()