Created
December 18, 2021 09:21
-
-
Save serjflint/264a059714ec570cbce5de29ce547500 to your computer and use it in GitHub Desktop.
Day 18 Try 2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import copy | |
import functools | |
import typing as tp | |
Value = tp.Union[int, tp.List] | |
Pair = tp.List[Value] | |
def loader(lines: tp.Iterable[str]): | |
for line in lines: | |
if not line: | |
break | |
yield line | |
def parse(line: str) -> Pair: | |
val, _pos = parse_rec(line, 0) | |
return val | |
def parse_rec(line: str, pos: int) -> tp.Tuple[Pair, int]: | |
assert line[pos] == "[" | |
pos += 1 | |
left_val, pos = parse_val(line, pos) | |
assert line[pos] == "," | |
pos += 1 | |
right_val, pos = parse_val(line, pos) | |
assert line[pos] == "]" | |
pos += 1 | |
return [left_val, right_val], pos | |
def parse_val(line, pos) -> tp.Tuple[Value, int]: | |
if line[pos] == "[": | |
val, pos = parse_rec(line, pos) | |
else: | |
val = str() | |
while line[pos].isdigit(): | |
val += line[pos] | |
pos += 1 | |
val = [int(val)] | |
return val, pos | |
def explode(p: Pair) -> bool: | |
return explode_rec(p, 0, [], []) | |
def descend(val: Value, index: int): | |
while len(val) == 2: | |
val = val[index] | |
return val | |
def explode_rec( | |
val: Value, level: int, left: tp.Optional[Value], right: tp.Optional[Value] | |
): | |
if len(val) == 1: | |
return False | |
if level >= 4: | |
if left: | |
left[0] += val[0][0] | |
if right: | |
right[0] += val[1][0] | |
val[:] = [0] | |
return True | |
return ( | |
explode_rec(val[0], level + 1, left, descend(val[1], 0)) | |
or | |
explode_rec(val[1], level + 1, descend(val[0], 1), right) | |
) | |
def split(val: Value): | |
if len(val) == 1: | |
return False | |
return split_val(val, 0) or split_val(val, 1) | |
def split_val(val: Value, index: int): | |
saved = val[index][0] | |
if len(val[index]) == 1: | |
if saved > 9: | |
half = saved // 2 | |
val[index] = [[half], [saved - half]] | |
return True | |
return False | |
return split(val[index]) | |
def simplify(val): | |
cond = True | |
while cond: | |
cond = False | |
if explode(val): | |
cond = True | |
continue | |
if split(val): | |
cond = True | |
continue | |
return val | |
def add(a: Pair, b: Pair) -> Pair: | |
a, b = copy.deepcopy(a), copy.deepcopy(b) | |
return simplify([a, b]) | |
def magnitude(val: Value): | |
if len(val) == 1: | |
return val[0] | |
return 3 * magnitude(val[0]) + 2 * magnitude(val[1]) | |
def task_1(lines: tp.Iterable[str]) -> int: | |
snailfish_numbers = [parse(line) for line in loader(lines)] | |
result = functools.reduce(add, snailfish_numbers) | |
m = magnitude(result) | |
return m | |
def task_2(lines: tp.Iterable[str]) -> int: | |
snailfish_numbers = [parse(line) for line in loader(lines)] | |
max_magnitude = 0 | |
for x in range(len(snailfish_numbers)): | |
for y in range(len(snailfish_numbers)): | |
if x == y: | |
continue | |
result = add(snailfish_numbers[x], snailfish_numbers[y]) | |
m = magnitude(result) | |
max_magnitude = max(max_magnitude, m) | |
return max_magnitude |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment