Compare commits
4 commits
87dd721d47
...
8bf78654a5
Author | SHA1 | Date | |
---|---|---|---|
Bruno BELANYI | 8bf78654a5 | ||
Bruno BELANYI | c0bf6fe213 | ||
Bruno BELANYI | 2be3cf4327 | ||
Bruno BELANYI | 38902d9a64 |
208
2021/d18/ex1/ex1.py
Executable file
208
2021/d18/ex1/ex1.py
Executable file
|
@ -0,0 +1,208 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import itertools
|
||||||
|
import sys
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Iterator, List, Optional, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Tree:
|
||||||
|
parent: Optional["Pair"]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Pair(Tree):
|
||||||
|
left: Tree
|
||||||
|
right: Tree
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Num(Tree):
|
||||||
|
val: int
|
||||||
|
|
||||||
|
|
||||||
|
# True means left, False means right
|
||||||
|
Path = List[bool]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(input: List[str]) -> int:
|
||||||
|
def make_pair(left: Tree, right: Tree, parent: Optional[Pair] = None) -> Pair:
|
||||||
|
pair = Pair(parent=parent, left=left, right=right)
|
||||||
|
pair.left.parent = pair
|
||||||
|
pair.right.parent = pair
|
||||||
|
return pair
|
||||||
|
|
||||||
|
def make_num(val: int, parent: Optional[Pair] = None) -> Num:
|
||||||
|
return Num(parent=parent, val=val)
|
||||||
|
|
||||||
|
# FIXME: remove this
|
||||||
|
def debug(tree: Tree) -> str:
|
||||||
|
if isinstance(tree, Pair):
|
||||||
|
return f"[{debug(tree.left)},{debug(tree.right)}]"
|
||||||
|
assert isinstance(tree, Num)
|
||||||
|
return str(tree.val)
|
||||||
|
|
||||||
|
def parse() -> List[Tree]:
|
||||||
|
def parse_snailfish_number(line: str) -> Tree:
|
||||||
|
def parse_index(input: str, index: int = 0) -> Tuple[int, Tree]:
|
||||||
|
if input[index] == "[":
|
||||||
|
left_index, left = parse_index(input, index + 1)
|
||||||
|
assert input[left_index] == "," # Sanity check
|
||||||
|
right_index, right = parse_index(input, left_index + 1)
|
||||||
|
assert input[right_index] == "]" # Sanity check
|
||||||
|
return right_index + 1, make_pair(left, right)
|
||||||
|
res = 0
|
||||||
|
for i in itertools.count(index):
|
||||||
|
if i < len(input) and input[i] in set(str(i) for i in range(10)):
|
||||||
|
res = res * 10 + int(input[i])
|
||||||
|
else:
|
||||||
|
return i, make_num(res)
|
||||||
|
assert False # Sanity check
|
||||||
|
|
||||||
|
__, res = parse_index(line)
|
||||||
|
return res
|
||||||
|
|
||||||
|
return [parse_snailfish_number(line) for line in input]
|
||||||
|
|
||||||
|
def explosion_path(number: Tree) -> Optional[Path]:
|
||||||
|
def dfs(number: Pair, path: Path = []) -> Optional[Path]:
|
||||||
|
if (
|
||||||
|
len(path) >= 4
|
||||||
|
and isinstance(number.left, Num)
|
||||||
|
and isinstance(number.right, Num)
|
||||||
|
):
|
||||||
|
return path
|
||||||
|
if isinstance(number.left, Pair):
|
||||||
|
left_path = dfs(number.left, path + [True])
|
||||||
|
if left_path is not None:
|
||||||
|
return left_path
|
||||||
|
if isinstance(number.right, Pair):
|
||||||
|
right_path = dfs(number.right, path + [False])
|
||||||
|
if right_path is not None:
|
||||||
|
return right_path
|
||||||
|
return None
|
||||||
|
|
||||||
|
assert isinstance(number, Pair) # Sanity check
|
||||||
|
return dfs(number)
|
||||||
|
|
||||||
|
def split_path(number: Tree) -> Optional[Path]:
|
||||||
|
def dfs(number: Pair, path: Path = []) -> Optional[Path]:
|
||||||
|
if isinstance(number.left, Num):
|
||||||
|
if number.left.val >= 10:
|
||||||
|
return path + [True]
|
||||||
|
else:
|
||||||
|
assert isinstance(number.left, Pair) # Sanity check
|
||||||
|
if (left_path := dfs(number.left, path + [True])) is not None:
|
||||||
|
return left_path
|
||||||
|
if isinstance(number.right, Num):
|
||||||
|
if number.right.val >= 10:
|
||||||
|
return path + [False]
|
||||||
|
else:
|
||||||
|
assert isinstance(number.right, Pair) # Sanity check
|
||||||
|
if (right_path := dfs(number.right, path + [False])) is not None:
|
||||||
|
return right_path
|
||||||
|
return None
|
||||||
|
|
||||||
|
assert isinstance(number, Pair) # Sanity check
|
||||||
|
return dfs(number)
|
||||||
|
|
||||||
|
def explode(number: Tree, path: Path) -> Tree:
|
||||||
|
def walk(number: Tree, reverse: bool) -> Iterator[Tree]:
|
||||||
|
if isinstance(number, Num):
|
||||||
|
yield number
|
||||||
|
else:
|
||||||
|
assert isinstance(number, Pair) # Sanity check
|
||||||
|
first, second = (
|
||||||
|
(number.right, number.left)
|
||||||
|
if reverse
|
||||||
|
else (number.left, number.right)
|
||||||
|
)
|
||||||
|
yield from walk(first, reverse)
|
||||||
|
yield number
|
||||||
|
yield from walk(second, reverse)
|
||||||
|
|
||||||
|
def next_num(number: Tree, reverse: bool) -> Optional[Num]:
|
||||||
|
if number.parent is None:
|
||||||
|
return None
|
||||||
|
sibling = number.parent.left if reverse else number.parent.right
|
||||||
|
if number is sibling:
|
||||||
|
return next_num(number.parent, reverse)
|
||||||
|
for node in walk(sibling, reverse=reverse):
|
||||||
|
if isinstance(node, Num):
|
||||||
|
return node
|
||||||
|
return None
|
||||||
|
|
||||||
|
assert isinstance(number, Pair) # Sanity check
|
||||||
|
|
||||||
|
if len(path) == 0:
|
||||||
|
p, n = next_num(number, reverse=True), next_num(number, reverse=False)
|
||||||
|
if p is not None:
|
||||||
|
assert isinstance(number.left, Num) # Safety check
|
||||||
|
p.val += number.left.val
|
||||||
|
if n is not None:
|
||||||
|
assert isinstance(number.right, Num) # Safety check
|
||||||
|
n.val += number.right.val
|
||||||
|
return make_num(0)
|
||||||
|
|
||||||
|
parent, left, right = number.parent, number.left, number.right
|
||||||
|
if path[0]:
|
||||||
|
left = explode(number.left, path[1:])
|
||||||
|
else:
|
||||||
|
right = explode(number.right, path[1:])
|
||||||
|
|
||||||
|
return make_pair(parent=parent, left=left, right=right)
|
||||||
|
|
||||||
|
def split(number: Tree, path: Path) -> Tree:
|
||||||
|
def split_int(num: int, parent: Optional[Pair]) -> Tree:
|
||||||
|
assert num >= 0 # Sanity check
|
||||||
|
left = num // 2
|
||||||
|
right = num - left
|
||||||
|
res = make_pair(left=make_num(left), right=make_num(right), parent=parent)
|
||||||
|
return res
|
||||||
|
|
||||||
|
if len(path) == 0:
|
||||||
|
assert isinstance(number, Num) # Sanity check
|
||||||
|
return split_int(number.val, number.parent)
|
||||||
|
|
||||||
|
assert isinstance(number, Pair) # Sanity check
|
||||||
|
|
||||||
|
parent, left, right = number.parent, number.left, number.right
|
||||||
|
if path[0]:
|
||||||
|
left = split(number.left, path[1:])
|
||||||
|
else:
|
||||||
|
right = split(number.right, path[1:])
|
||||||
|
|
||||||
|
return make_pair(parent=parent, left=left, right=right)
|
||||||
|
|
||||||
|
def reduce(number: Tree) -> Tree:
|
||||||
|
path = explosion_path(number)
|
||||||
|
if path is not None:
|
||||||
|
return reduce(explode(number, path))
|
||||||
|
path = split_path(number)
|
||||||
|
if path is not None:
|
||||||
|
return reduce(split(number, path))
|
||||||
|
return number
|
||||||
|
|
||||||
|
def add(left: Tree, right: Tree) -> Tree:
|
||||||
|
return reduce(make_pair(left=left, right=right))
|
||||||
|
|
||||||
|
def magnitude(number: Tree) -> int:
|
||||||
|
if isinstance(number, Num):
|
||||||
|
return number.val
|
||||||
|
assert isinstance(number, Pair) # Safety check
|
||||||
|
return 3 * magnitude(number.left) + 2 * magnitude(number.right)
|
||||||
|
|
||||||
|
numbers = parse()
|
||||||
|
result = functools.reduce(add, numbers)
|
||||||
|
return magnitude(result)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
input = [line.strip() for line in sys.stdin.readlines()]
|
||||||
|
print(solve(input))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
100
2021/d18/ex1/input
Normal file
100
2021/d18/ex1/input
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
[[3,[8,[2,1]]],[[[0,6],[0,2]],3]]
|
||||||
|
[[[1,[8,5]],[[3,9],0]],2]
|
||||||
|
[5,[[5,[3,8]],[7,4]]]
|
||||||
|
[1,[[[0,4],[8,5]],6]]
|
||||||
|
[[[1,[0,3]],2],[2,[0,[7,9]]]]
|
||||||
|
[[[4,[4,4]],[[7,2],[7,1]]],9]
|
||||||
|
[5,[4,4]]
|
||||||
|
[[0,[[2,6],[8,9]]],[[4,5],2]]
|
||||||
|
[[[8,2],0],3]
|
||||||
|
[[9,0],[3,3]]
|
||||||
|
[[[[5,2],2],5],5]
|
||||||
|
[[[1,6],[[0,4],[7,7]]],[[1,4],[[6,5],5]]]
|
||||||
|
[[[[4,1],[4,1]],[2,[5,5]]],[1,[0,[0,6]]]]
|
||||||
|
[[[[1,5],1],[8,4]],[9,[3,4]]]
|
||||||
|
[[1,[3,3]],[[[7,4],[8,1]],2]]
|
||||||
|
[3,[[[2,1],4],[5,4]]]
|
||||||
|
[6,[[0,[1,9]],[[4,0],8]]]
|
||||||
|
[5,[7,[7,[8,8]]]]
|
||||||
|
[[[[6,2],[5,8]],[5,[3,1]]],[[7,9],[[2,0],6]]]
|
||||||
|
[[[7,[7,9]],[5,7]],[[[9,3],[6,9]],[[1,2],[2,3]]]]
|
||||||
|
[[[[4,1],2],[1,[6,6]]],[[[2,2],[8,8]],4]]
|
||||||
|
[[[[3,7],4],8],[6,[[0,2],3]]]
|
||||||
|
[[[[1,8],2],3],[[9,[1,7]],[[0,0],[6,8]]]]
|
||||||
|
[[[9,[5,2]],7],[[8,6],[8,[1,2]]]]
|
||||||
|
[[[7,[1,0]],[[6,0],[8,4]]],[[[7,8],5],[3,[1,2]]]]
|
||||||
|
[[[[2,5],9],[[8,2],0]],0]
|
||||||
|
[0,[[[7,5],[4,1]],[5,[6,6]]]]
|
||||||
|
[[[[3,6],2],[[1,1],[6,6]]],0]
|
||||||
|
[[[[0,9],[2,5]],[2,[3,2]]],[6,3]]
|
||||||
|
[3,[[9,[1,4]],[[0,8],[4,6]]]]
|
||||||
|
[1,[[5,[5,9]],[9,0]]]
|
||||||
|
[[[6,8],4],[[[6,6],2],[[3,9],2]]]
|
||||||
|
[5,[[[7,5],[4,8]],0]]
|
||||||
|
[[9,[6,6]],[9,[[6,8],[6,4]]]]
|
||||||
|
[[[4,8],[0,[2,8]]],[7,[[4,5],[1,6]]]]
|
||||||
|
[[[6,[8,6]],2],[[[2,9],[2,4]],[0,2]]]
|
||||||
|
[[[0,[5,6]],[[3,8],3]],[[3,1],7]]
|
||||||
|
[[1,[8,1]],[1,[6,[7,1]]]]
|
||||||
|
[[[5,[9,6]],[3,5]],2]
|
||||||
|
[[3,7],[[[2,5],[4,1]],[3,[5,6]]]]
|
||||||
|
[[8,7],[[9,6],3]]
|
||||||
|
[[[[4,2],[4,8]],[7,[4,5]]],2]
|
||||||
|
[[[[6,7],6],3],[[[6,7],4],0]]
|
||||||
|
[[[0,1],[[9,1],[2,9]]],9]
|
||||||
|
[[[[8,5],[5,8]],[0,7]],[0,[8,[3,2]]]]
|
||||||
|
[[4,[[6,5],[1,9]]],[[[0,0],1],6]]
|
||||||
|
[[[[9,5],9],[2,[6,3]]],[[2,9],[6,9]]]
|
||||||
|
[[[7,[5,0]],1],[7,[[8,7],3]]]
|
||||||
|
[[[2,4],2],[[[3,0],6],[[0,2],[9,2]]]]
|
||||||
|
[[1,[[7,3],[4,3]]],[[[3,9],[1,1]],[3,6]]]
|
||||||
|
[[[[4,7],7],[[7,1],[2,3]]],[1,[[7,6],[5,6]]]]
|
||||||
|
[[0,[5,2]],0]
|
||||||
|
[[[[6,6],[4,8]],8],[[0,[7,4]],8]]
|
||||||
|
[[4,[7,2]],[[[0,8],1],[9,5]]]
|
||||||
|
[0,0]
|
||||||
|
[[[[3,7],6],3],[3,[[3,3],1]]]
|
||||||
|
[[[6,5],7],[[3,5],[[6,4],[4,9]]]]
|
||||||
|
[[4,[[7,9],9]],9]
|
||||||
|
[5,[8,[[7,4],1]]]
|
||||||
|
[[[[2,4],[5,7]],8],[[[7,6],[6,9]],[[3,9],[6,4]]]]
|
||||||
|
[[[4,8],3],[[[3,9],7],0]]
|
||||||
|
[0,[8,[[4,2],3]]]
|
||||||
|
[[[[0,1],[5,8]],[7,2]],[2,4]]
|
||||||
|
[[6,[8,[1,9]]],[[[6,5],[8,1]],[7,[6,4]]]]
|
||||||
|
[[9,3],[5,[0,6]]]
|
||||||
|
[[2,[7,[2,0]]],[[2,1],[5,5]]]
|
||||||
|
[[[0,[7,0]],[[0,4],[4,9]]],[8,[[6,1],[6,3]]]]
|
||||||
|
[[[[5,7],[3,2]],[0,[5,0]]],[[0,[1,6]],3]]
|
||||||
|
[[[[6,3],[9,5]],[9,9]],[[5,[8,3]],[[0,0],[0,3]]]]
|
||||||
|
[[6,[4,9]],[[[9,9],[8,4]],4]]
|
||||||
|
[0,[2,5]]
|
||||||
|
[[[[7,9],[1,2]],[3,3]],[[[7,2],7],[[1,6],0]]]
|
||||||
|
[[[[8,0],2],8],[[[1,5],9],9]]
|
||||||
|
[[[0,[6,9]],4],[[[4,8],5],4]]
|
||||||
|
[[6,[[0,3],4]],[0,[[8,3],1]]]
|
||||||
|
[[[1,2],[2,[3,3]]],[6,7]]
|
||||||
|
[[0,[[7,4],5]],[3,[[8,2],0]]]
|
||||||
|
[[[[0,1],[1,7]],[[2,7],[5,9]]],[[[7,0],0],[8,1]]]
|
||||||
|
[[6,4],[3,0]]
|
||||||
|
[[[[6,6],4],[5,1]],[7,3]]
|
||||||
|
[[[[9,2],3],[8,[4,8]]],7]
|
||||||
|
[[5,[[2,2],[9,2]]],[[[1,8],0],[8,[6,3]]]]
|
||||||
|
[2,[[0,0],[0,[9,9]]]]
|
||||||
|
[[4,4],[[6,5],[6,5]]]
|
||||||
|
[[[[9,1],2],4],5]
|
||||||
|
[[[[2,1],[3,1]],[[2,6],9]],5]
|
||||||
|
[[[9,[0,6]],7],[[8,3],[[8,1],2]]]
|
||||||
|
[[[6,[0,0]],[2,[0,0]]],[[[0,4],8],3]]
|
||||||
|
[[[[4,1],[2,9]],[6,5]],3]
|
||||||
|
[[9,[[9,4],8]],[[[5,5],3],[[3,4],4]]]
|
||||||
|
[8,[9,[[0,3],1]]]
|
||||||
|
[9,[[[6,0],4],9]]
|
||||||
|
[[6,[2,9]],[[[2,7],[5,3]],0]]
|
||||||
|
[[[4,1],5],[8,[[0,7],4]]]
|
||||||
|
[[[[2,5],5],[[8,2],[8,9]]],[[9,6],[[0,3],[2,3]]]]
|
||||||
|
[6,1]
|
||||||
|
[[1,7],4]
|
||||||
|
[[8,7],0]
|
||||||
|
[[[[5,4],7],5],[[[6,1],5],[5,[5,5]]]]
|
||||||
|
[[[6,[1,5]],[0,[7,0]]],[[[1,5],3],[5,[1,0]]]]
|
211
2021/d18/ex2/ex2.py
Executable file
211
2021/d18/ex2/ex2.py
Executable file
|
@ -0,0 +1,211 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import itertools
|
||||||
|
import sys
|
||||||
|
from copy import deepcopy
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Iterator, List, Optional, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Tree:
|
||||||
|
parent: Optional["Pair"]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Pair(Tree):
|
||||||
|
left: Tree
|
||||||
|
right: Tree
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Num(Tree):
|
||||||
|
val: int
|
||||||
|
|
||||||
|
|
||||||
|
# True means left, False means right
|
||||||
|
Path = List[bool]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(input: List[str]) -> int:
|
||||||
|
def make_pair(left: Tree, right: Tree, parent: Optional[Pair] = None) -> Pair:
|
||||||
|
pair = Pair(parent=parent, left=left, right=right)
|
||||||
|
pair.left.parent = pair
|
||||||
|
pair.right.parent = pair
|
||||||
|
return pair
|
||||||
|
|
||||||
|
def make_num(val: int, parent: Optional[Pair] = None) -> Num:
|
||||||
|
return Num(parent=parent, val=val)
|
||||||
|
|
||||||
|
# FIXME: remove this
|
||||||
|
def debug(tree: Tree) -> str:
|
||||||
|
if isinstance(tree, Pair):
|
||||||
|
return f"[{debug(tree.left)},{debug(tree.right)}]"
|
||||||
|
assert isinstance(tree, Num)
|
||||||
|
return str(tree.val)
|
||||||
|
|
||||||
|
def parse() -> List[Tree]:
|
||||||
|
def parse_snailfish_number(line: str) -> Tree:
|
||||||
|
def parse_index(input: str, index: int = 0) -> Tuple[int, Tree]:
|
||||||
|
if input[index] == "[":
|
||||||
|
left_index, left = parse_index(input, index + 1)
|
||||||
|
assert input[left_index] == "," # Sanity check
|
||||||
|
right_index, right = parse_index(input, left_index + 1)
|
||||||
|
assert input[right_index] == "]" # Sanity check
|
||||||
|
return right_index + 1, make_pair(left, right)
|
||||||
|
res = 0
|
||||||
|
for i in itertools.count(index):
|
||||||
|
if i < len(input) and input[i] in set(str(i) for i in range(10)):
|
||||||
|
res = res * 10 + int(input[i])
|
||||||
|
else:
|
||||||
|
return i, make_num(res)
|
||||||
|
assert False # Sanity check
|
||||||
|
|
||||||
|
__, res = parse_index(line)
|
||||||
|
return res
|
||||||
|
|
||||||
|
return [parse_snailfish_number(line) for line in input]
|
||||||
|
|
||||||
|
def explosion_path(number: Tree) -> Optional[Path]:
|
||||||
|
def dfs(number: Pair, path: Path = []) -> Optional[Path]:
|
||||||
|
if (
|
||||||
|
len(path) >= 4
|
||||||
|
and isinstance(number.left, Num)
|
||||||
|
and isinstance(number.right, Num)
|
||||||
|
):
|
||||||
|
return path
|
||||||
|
if isinstance(number.left, Pair):
|
||||||
|
left_path = dfs(number.left, path + [True])
|
||||||
|
if left_path is not None:
|
||||||
|
return left_path
|
||||||
|
if isinstance(number.right, Pair):
|
||||||
|
right_path = dfs(number.right, path + [False])
|
||||||
|
if right_path is not None:
|
||||||
|
return right_path
|
||||||
|
return None
|
||||||
|
|
||||||
|
assert isinstance(number, Pair) # Sanity check
|
||||||
|
return dfs(number)
|
||||||
|
|
||||||
|
def split_path(number: Tree) -> Optional[Path]:
|
||||||
|
def dfs(number: Pair, path: Path = []) -> Optional[Path]:
|
||||||
|
if isinstance(number.left, Num):
|
||||||
|
if number.left.val >= 10:
|
||||||
|
return path + [True]
|
||||||
|
else:
|
||||||
|
assert isinstance(number.left, Pair) # Sanity check
|
||||||
|
if (left_path := dfs(number.left, path + [True])) is not None:
|
||||||
|
return left_path
|
||||||
|
if isinstance(number.right, Num):
|
||||||
|
if number.right.val >= 10:
|
||||||
|
return path + [False]
|
||||||
|
else:
|
||||||
|
assert isinstance(number.right, Pair) # Sanity check
|
||||||
|
if (right_path := dfs(number.right, path + [False])) is not None:
|
||||||
|
return right_path
|
||||||
|
return None
|
||||||
|
|
||||||
|
assert isinstance(number, Pair) # Sanity check
|
||||||
|
return dfs(number)
|
||||||
|
|
||||||
|
def explode(number: Tree, path: Path) -> Tree:
|
||||||
|
def walk(number: Tree, reverse: bool) -> Iterator[Tree]:
|
||||||
|
if isinstance(number, Num):
|
||||||
|
yield number
|
||||||
|
else:
|
||||||
|
assert isinstance(number, Pair) # Sanity check
|
||||||
|
first, second = (
|
||||||
|
(number.right, number.left)
|
||||||
|
if reverse
|
||||||
|
else (number.left, number.right)
|
||||||
|
)
|
||||||
|
yield from walk(first, reverse)
|
||||||
|
yield number
|
||||||
|
yield from walk(second, reverse)
|
||||||
|
|
||||||
|
def next_num(number: Tree, reverse: bool) -> Optional[Num]:
|
||||||
|
if number.parent is None:
|
||||||
|
return None
|
||||||
|
sibling = number.parent.left if reverse else number.parent.right
|
||||||
|
if number is sibling:
|
||||||
|
return next_num(number.parent, reverse)
|
||||||
|
for node in walk(sibling, reverse=reverse):
|
||||||
|
if isinstance(node, Num):
|
||||||
|
return node
|
||||||
|
return None
|
||||||
|
|
||||||
|
assert isinstance(number, Pair) # Sanity check
|
||||||
|
|
||||||
|
if len(path) == 0:
|
||||||
|
p, n = next_num(number, reverse=True), next_num(number, reverse=False)
|
||||||
|
if p is not None:
|
||||||
|
assert isinstance(number.left, Num) # Safety check
|
||||||
|
p.val += number.left.val
|
||||||
|
if n is not None:
|
||||||
|
assert isinstance(number.right, Num) # Safety check
|
||||||
|
n.val += number.right.val
|
||||||
|
return make_num(0)
|
||||||
|
|
||||||
|
parent, left, right = number.parent, number.left, number.right
|
||||||
|
if path[0]:
|
||||||
|
left = explode(number.left, path[1:])
|
||||||
|
else:
|
||||||
|
right = explode(number.right, path[1:])
|
||||||
|
|
||||||
|
return make_pair(parent=parent, left=left, right=right)
|
||||||
|
|
||||||
|
def split(number: Tree, path: Path) -> Tree:
|
||||||
|
def split_int(num: int, parent: Optional[Pair]) -> Tree:
|
||||||
|
assert num >= 0 # Sanity check
|
||||||
|
left = num // 2
|
||||||
|
right = num - left
|
||||||
|
res = make_pair(left=make_num(left), right=make_num(right), parent=parent)
|
||||||
|
return res
|
||||||
|
|
||||||
|
if len(path) == 0:
|
||||||
|
assert isinstance(number, Num) # Sanity check
|
||||||
|
return split_int(number.val, number.parent)
|
||||||
|
|
||||||
|
assert isinstance(number, Pair) # Sanity check
|
||||||
|
|
||||||
|
parent, left, right = number.parent, number.left, number.right
|
||||||
|
if path[0]:
|
||||||
|
left = split(number.left, path[1:])
|
||||||
|
else:
|
||||||
|
right = split(number.right, path[1:])
|
||||||
|
|
||||||
|
return make_pair(parent=parent, left=left, right=right)
|
||||||
|
|
||||||
|
def reduce(number: Tree) -> Tree:
|
||||||
|
path = explosion_path(number)
|
||||||
|
if path is not None:
|
||||||
|
return reduce(explode(number, path))
|
||||||
|
path = split_path(number)
|
||||||
|
if path is not None:
|
||||||
|
return reduce(split(number, path))
|
||||||
|
return number
|
||||||
|
|
||||||
|
def add(left: Tree, right: Tree) -> Tree:
|
||||||
|
return reduce(make_pair(left=left, right=right))
|
||||||
|
|
||||||
|
def magnitude(number: Tree) -> int:
|
||||||
|
if isinstance(number, Num):
|
||||||
|
return number.val
|
||||||
|
assert isinstance(number, Pair) # Safety check
|
||||||
|
return 3 * magnitude(number.left) + 2 * magnitude(number.right)
|
||||||
|
|
||||||
|
numbers = parse()
|
||||||
|
return max(
|
||||||
|
magnitude(add(deepcopy(l), deepcopy(r)))
|
||||||
|
for l, r in itertools.permutations(numbers, 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
input = [line.strip() for line in sys.stdin.readlines()]
|
||||||
|
print(solve(input))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
100
2021/d18/ex2/input
Normal file
100
2021/d18/ex2/input
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
[[3,[8,[2,1]]],[[[0,6],[0,2]],3]]
|
||||||
|
[[[1,[8,5]],[[3,9],0]],2]
|
||||||
|
[5,[[5,[3,8]],[7,4]]]
|
||||||
|
[1,[[[0,4],[8,5]],6]]
|
||||||
|
[[[1,[0,3]],2],[2,[0,[7,9]]]]
|
||||||
|
[[[4,[4,4]],[[7,2],[7,1]]],9]
|
||||||
|
[5,[4,4]]
|
||||||
|
[[0,[[2,6],[8,9]]],[[4,5],2]]
|
||||||
|
[[[8,2],0],3]
|
||||||
|
[[9,0],[3,3]]
|
||||||
|
[[[[5,2],2],5],5]
|
||||||
|
[[[1,6],[[0,4],[7,7]]],[[1,4],[[6,5],5]]]
|
||||||
|
[[[[4,1],[4,1]],[2,[5,5]]],[1,[0,[0,6]]]]
|
||||||
|
[[[[1,5],1],[8,4]],[9,[3,4]]]
|
||||||
|
[[1,[3,3]],[[[7,4],[8,1]],2]]
|
||||||
|
[3,[[[2,1],4],[5,4]]]
|
||||||
|
[6,[[0,[1,9]],[[4,0],8]]]
|
||||||
|
[5,[7,[7,[8,8]]]]
|
||||||
|
[[[[6,2],[5,8]],[5,[3,1]]],[[7,9],[[2,0],6]]]
|
||||||
|
[[[7,[7,9]],[5,7]],[[[9,3],[6,9]],[[1,2],[2,3]]]]
|
||||||
|
[[[[4,1],2],[1,[6,6]]],[[[2,2],[8,8]],4]]
|
||||||
|
[[[[3,7],4],8],[6,[[0,2],3]]]
|
||||||
|
[[[[1,8],2],3],[[9,[1,7]],[[0,0],[6,8]]]]
|
||||||
|
[[[9,[5,2]],7],[[8,6],[8,[1,2]]]]
|
||||||
|
[[[7,[1,0]],[[6,0],[8,4]]],[[[7,8],5],[3,[1,2]]]]
|
||||||
|
[[[[2,5],9],[[8,2],0]],0]
|
||||||
|
[0,[[[7,5],[4,1]],[5,[6,6]]]]
|
||||||
|
[[[[3,6],2],[[1,1],[6,6]]],0]
|
||||||
|
[[[[0,9],[2,5]],[2,[3,2]]],[6,3]]
|
||||||
|
[3,[[9,[1,4]],[[0,8],[4,6]]]]
|
||||||
|
[1,[[5,[5,9]],[9,0]]]
|
||||||
|
[[[6,8],4],[[[6,6],2],[[3,9],2]]]
|
||||||
|
[5,[[[7,5],[4,8]],0]]
|
||||||
|
[[9,[6,6]],[9,[[6,8],[6,4]]]]
|
||||||
|
[[[4,8],[0,[2,8]]],[7,[[4,5],[1,6]]]]
|
||||||
|
[[[6,[8,6]],2],[[[2,9],[2,4]],[0,2]]]
|
||||||
|
[[[0,[5,6]],[[3,8],3]],[[3,1],7]]
|
||||||
|
[[1,[8,1]],[1,[6,[7,1]]]]
|
||||||
|
[[[5,[9,6]],[3,5]],2]
|
||||||
|
[[3,7],[[[2,5],[4,1]],[3,[5,6]]]]
|
||||||
|
[[8,7],[[9,6],3]]
|
||||||
|
[[[[4,2],[4,8]],[7,[4,5]]],2]
|
||||||
|
[[[[6,7],6],3],[[[6,7],4],0]]
|
||||||
|
[[[0,1],[[9,1],[2,9]]],9]
|
||||||
|
[[[[8,5],[5,8]],[0,7]],[0,[8,[3,2]]]]
|
||||||
|
[[4,[[6,5],[1,9]]],[[[0,0],1],6]]
|
||||||
|
[[[[9,5],9],[2,[6,3]]],[[2,9],[6,9]]]
|
||||||
|
[[[7,[5,0]],1],[7,[[8,7],3]]]
|
||||||
|
[[[2,4],2],[[[3,0],6],[[0,2],[9,2]]]]
|
||||||
|
[[1,[[7,3],[4,3]]],[[[3,9],[1,1]],[3,6]]]
|
||||||
|
[[[[4,7],7],[[7,1],[2,3]]],[1,[[7,6],[5,6]]]]
|
||||||
|
[[0,[5,2]],0]
|
||||||
|
[[[[6,6],[4,8]],8],[[0,[7,4]],8]]
|
||||||
|
[[4,[7,2]],[[[0,8],1],[9,5]]]
|
||||||
|
[0,0]
|
||||||
|
[[[[3,7],6],3],[3,[[3,3],1]]]
|
||||||
|
[[[6,5],7],[[3,5],[[6,4],[4,9]]]]
|
||||||
|
[[4,[[7,9],9]],9]
|
||||||
|
[5,[8,[[7,4],1]]]
|
||||||
|
[[[[2,4],[5,7]],8],[[[7,6],[6,9]],[[3,9],[6,4]]]]
|
||||||
|
[[[4,8],3],[[[3,9],7],0]]
|
||||||
|
[0,[8,[[4,2],3]]]
|
||||||
|
[[[[0,1],[5,8]],[7,2]],[2,4]]
|
||||||
|
[[6,[8,[1,9]]],[[[6,5],[8,1]],[7,[6,4]]]]
|
||||||
|
[[9,3],[5,[0,6]]]
|
||||||
|
[[2,[7,[2,0]]],[[2,1],[5,5]]]
|
||||||
|
[[[0,[7,0]],[[0,4],[4,9]]],[8,[[6,1],[6,3]]]]
|
||||||
|
[[[[5,7],[3,2]],[0,[5,0]]],[[0,[1,6]],3]]
|
||||||
|
[[[[6,3],[9,5]],[9,9]],[[5,[8,3]],[[0,0],[0,3]]]]
|
||||||
|
[[6,[4,9]],[[[9,9],[8,4]],4]]
|
||||||
|
[0,[2,5]]
|
||||||
|
[[[[7,9],[1,2]],[3,3]],[[[7,2],7],[[1,6],0]]]
|
||||||
|
[[[[8,0],2],8],[[[1,5],9],9]]
|
||||||
|
[[[0,[6,9]],4],[[[4,8],5],4]]
|
||||||
|
[[6,[[0,3],4]],[0,[[8,3],1]]]
|
||||||
|
[[[1,2],[2,[3,3]]],[6,7]]
|
||||||
|
[[0,[[7,4],5]],[3,[[8,2],0]]]
|
||||||
|
[[[[0,1],[1,7]],[[2,7],[5,9]]],[[[7,0],0],[8,1]]]
|
||||||
|
[[6,4],[3,0]]
|
||||||
|
[[[[6,6],4],[5,1]],[7,3]]
|
||||||
|
[[[[9,2],3],[8,[4,8]]],7]
|
||||||
|
[[5,[[2,2],[9,2]]],[[[1,8],0],[8,[6,3]]]]
|
||||||
|
[2,[[0,0],[0,[9,9]]]]
|
||||||
|
[[4,4],[[6,5],[6,5]]]
|
||||||
|
[[[[9,1],2],4],5]
|
||||||
|
[[[[2,1],[3,1]],[[2,6],9]],5]
|
||||||
|
[[[9,[0,6]],7],[[8,3],[[8,1],2]]]
|
||||||
|
[[[6,[0,0]],[2,[0,0]]],[[[0,4],8],3]]
|
||||||
|
[[[[4,1],[2,9]],[6,5]],3]
|
||||||
|
[[9,[[9,4],8]],[[[5,5],3],[[3,4],4]]]
|
||||||
|
[8,[9,[[0,3],1]]]
|
||||||
|
[9,[[[6,0],4],9]]
|
||||||
|
[[6,[2,9]],[[[2,7],[5,3]],0]]
|
||||||
|
[[[4,1],5],[8,[[0,7],4]]]
|
||||||
|
[[[[2,5],5],[[8,2],[8,9]]],[[9,6],[[0,3],[2,3]]]]
|
||||||
|
[6,1]
|
||||||
|
[[1,7],4]
|
||||||
|
[[8,7],0]
|
||||||
|
[[[[5,4],7],5],[[[6,1],5],[5,[5,5]]]]
|
||||||
|
[[[6,[1,5]],[0,[7,0]]],[[[1,5],3],[5,[1,0]]]]
|
Loading…
Reference in a new issue