diff --git a/day18.py b/day18.py index 27425ad..62c8ca1 100644 --- a/day18.py +++ b/day18.py @@ -1,9 +1,16 @@ +import re from itertools import combinations from math import ceil from tools.aoc import AOCDay from typing import Any +re_pair = re.compile(r"\[(\d+),(\d+)\]") +re_lnum = re.compile(r".*[^\d](\d+)") +re_rnum = re.compile(r"(\d+)") +re_bignum = re.compile(r"(\d\d+)") + + class Snailfish: def __init__(self, fish_str: str): self.pairs = fish_str @@ -21,72 +28,46 @@ class Snailfish: elif c == "[": open_count += 1 if open_count == 5: - index_explode = i - while self.pairs[index_explode + 1] == "[" or self.pairs[index_explode + 3] == "[": - if self.pairs[index_explode + 1] == "[": - index_explode += 1 - if self.pairs[index_explode + 3] == "[": - index_explode += 3 - explode_pair = self.pairs[index_explode:self.pairs.index("]", index_explode) + 1] - explode_left, explode_right = map(int, explode_pair[1:-1].split(",")) - old_number_left = "" - old_number_right = "" - new_number_left = "" - new_number_right = "" - index_left = index_explode - index_right = index_explode + len(explode_pair) - for i_left in range(index_explode, 0, -1): - if self.pairs[i_left] not in ['[', ']', ',']: - il_add = 0 - while self.pairs[i_left - il_add - 1] in "0123456789": - il_add += 1 - index_left = i_left - il_add - old_number_left = self.pairs[i_left - il_add:i_left + 1] - new_number_left = str(int(old_number_left) + explode_left) - break - for i_right in range(index_explode + len(explode_pair), len(self.pairs)): - if self.pairs[i_right] not in ['[', ']', ',']: - ir_add = 0 - while self.pairs[i_right + ir_add + 1] in "0123456789": - ir_add += 1 - index_right = i_right - old_number_right = self.pairs[i_right:i_right + ir_add + 1] - new_number_right = str(int(old_number_right) + explode_right) - break - new_pairs = "" - if index_left != index_explode: - new_pairs += self.pairs[:index_left] + new_number_left + self.pairs[index_left + len(old_number_left):index_explode] - else: - new_pairs = self.pairs[:index_explode] - new_pairs += "0" - if index_right != index_explode + len(explode_pair): - new_pairs += self.pairs[index_explode + len(explode_pair):index_right] + new_number_right + self.pairs[index_right + len(old_number_right):] - else: - new_pairs += self.pairs[index_explode + len(explode_pair):] - self.pairs = new_pairs + explode_pair_match = re_pair.search(self.pairs, i) + index_l, index_r = explode_pair_match.span() + explode_left, explode_right = map(int, explode_pair_match.groups()) + lnum_old = rnum_old = lnum_new = rnum_new = "" + lnum_index = index_l + rnum_index = index_r + + if left_num := re_lnum.search(self.pairs[:index_l]): + lnum_old = left_num.groups()[0] + lnum_new = str(int(lnum_old) + explode_left) + lnum_index = left_num.span()[1] - len(lnum_old) + + if right_num := re_rnum.search(self.pairs, index_r): + rnum_old = right_num.groups()[0] + rnum_new = str(int(rnum_old) + explode_right) + rnum_index = right_num.span()[0] + + self.pairs = "".join([ + self.pairs[:lnum_index], + lnum_new, + self.pairs[lnum_index + len(lnum_old):index_l], + "0", + self.pairs[index_r:rnum_index], + rnum_new, + self.pairs[rnum_index + len(rnum_old):] + ]) return True - for i in range(1, len(self.pairs)): - if self.pairs[i - 1] not in ["[", "]", ","] and self.pairs[i] not in ["[", "]", ","]: - number = int(self.pairs[i-1:i+1]) - self.pairs = self.pairs.replace(str(number), "[%d,%d]" % (number // 2, int(ceil(number / 2))), 1) - return True + if big_num_match := re_bignum.search(self.pairs): + num = int(big_num_match.group()) + self.pairs = self.pairs.replace(big_num_match.group(), "[%d,%d]" % (num // 2, int(ceil(num / 2))), 1) + return True return False def getMagnitude(self) -> int: pairs = self.pairs - while "[" in pairs: - for i in range(len(pairs)): - if pairs[i] == "]": - r = i + 1 - l = i - 1 - while pairs[l] != "[": - l -= 1 - replace_pair = pairs[l:r] - num1, num2 = map(int, replace_pair[1:-1].split(",")) - pairs = pairs.replace(replace_pair, str(num1 * 3 + num2 * 2)) - break + while re_pair.search(pairs): + for num1, num2 in re_pair.findall(pairs): + pairs = pairs.replace("[%s,%s]" % (num1, num2), str(int(num1) * 3 + int(num2) * 2)) return int(pairs)