diff options
Diffstat (limited to '2021/day18/18.py')
-rw-r--r-- | 2021/day18/18.py | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/2021/day18/18.py b/2021/day18/18.py new file mode 100644 index 0000000..88ebf5e --- /dev/null +++ b/2021/day18/18.py @@ -0,0 +1,132 @@ +from math import ceil + +class SnailfishItem: + def __init__(self, parent, contents): + self.parent = parent + self.atomic = not isinstance(contents, list) + if not self.atomic: + if isinstance(contents[0], SnailfishItem): + self.left = contents[0] + self.left.parent = self + else: + self.left = SnailfishItem(self, contents[0]) + if isinstance(contents[1], SnailfishItem): + self.right = contents[1] + self.right.parent = self + else: + self.right = SnailfishItem(self, contents[1]) + else: + self.contents = contents + + def __str__(self): + if self.atomic: + return str(self.contents) + else: + return "[%s, %s]" % (str(self.left), str(self.right)) + + def add(self, other): + if self.atomic and other.atomic: + self.contents += other.contents + else: + if self.atomic: + self.left = SnailfishItem(self, self.contents) + else: + self.left = SnailfishItem(self, [self.left, self.right]) + self.atomic = False + self.right = other + other.parent = self + self.contents = None + while self.reduce(): + pass + + def check_explodes(self, n=0): + if self.atomic: + return False + elif n < 4: + return self.left.check_explodes(n+1) or self.right.check_explodes(n+1) + + self.explode_left() + self.explode_right() + + self.atomic = True + self.contents = 0 + self.left = None + self.right = None + + return True + + def check_splits(self): + if not self.atomic: + return self.left.check_splits() or self.right.check_splits() + elif self.contents < 10: + return False + + self.atomic = False + self.left = SnailfishItem(self, self.contents // 2) + self.right = SnailfishItem(self, ceil(self.contents / 2)) + self.contents = None + return True + + def reduce(self, n=0): + if not self.atomic: + return self.check_explodes(n) or self.check_splits() + else: + return self.check_splits() + + def explode_left(self): + last_node = self + node = self.parent + while node != None and node.left == last_node: + last_node = node + node = last_node.parent + + if node == None: + return # leftmost element of tree + + node = node.left + while not node.atomic: + node = node.right + + node.add(self.left) + + def explode_right(self): + last_node = self + node = self.parent + while node != None and node.right == last_node: + last_node = node + node = last_node.parent + + if node == None: + return # rightmost element of tree + + node = node.right + while not node.atomic: + node = node.left + + node.add(self.right) + + def magnitude(self): + if self.atomic: + return self.contents + else: + return (3 * self.left.magnitude()) + (2 * self.right.magnitude()) + +lines = open("./input").read().strip().split("\n") +val = SnailfishItem(None, eval(lines[0])) # cope, seethe, mald, etc. +for line in lines[1:]: + val.add(SnailfishItem(None, eval(line))) + +print("Part 1: %d" % val.magnitude()) + +max_mag = 0 +for x_str in lines: + for y_str in lines: + if x_str == y_str: + continue + x = SnailfishItem(None, eval(x_str)) + x.add(SnailfishItem(None, eval(y_str))) + + if x.magnitude() > max_mag: + max_mag = x.magnitude() + +print("Part 2: %d" % max_mag) |