Added 2021 (python)

This commit is contained in:
Karma Riuk
2023-08-02 11:46:44 +02:00
parent 410815acf8
commit 11600f7ba9
82 changed files with 8693 additions and 0 deletions

100
2021/18/input Normal file
View File

@ -0,0 +1,100 @@
[[[0,[6,6]],[[7,2],[6,2]]],[[[9,4],[5,8]],6]]
[[[4,9],6],[[[0,1],[8,5]],[3,[7,6]]]]
[[1,7],[[[1,3],2],[[6,8],8]]]
[4,[[6,[6,0]],[[4,9],5]]]
[[3,8],[[0,6],1]]
[[2,2],[[[2,3],[2,9]],[[9,6],[4,9]]]]
[[[3,4],[[7,7],[7,8]]],[[0,2],6]]
[[[[4,4],[3,3]],[[9,0],4]],[8,[7,[6,6]]]]
[[[9,9],8],1]
[2,[[7,[1,9]],[9,2]]]
[[[[6,0],[8,2]],[[9,0],[8,7]]],[3,[6,[8,8]]]]
[[[8,[9,2]],[1,4]],[[2,2],[[1,0],5]]]
[[[9,[0,3]],[4,[2,3]]],[[8,[0,1]],[[4,8],[5,4]]]]
[[[2,0],[1,7]],[[3,[0,7]],[[7,6],0]]]
[[[1,[5,1]],[[0,3],9]],[[3,8],[[5,3],1]]]
[[[[4,5],2],[[7,7],[4,8]]],[3,[3,[6,5]]]]
[[[[4,4],4],[[5,0],2]],[9,[[0,7],5]]]
[[2,[[8,0],9]],0]
[[[[0,5],[1,0]],[0,[5,1]]],[[[0,8],[6,0]],[6,[3,9]]]]
[[[[2,4],[5,5]],[4,7]],[[[5,6],[9,5]],1]]
[[[4,[5,1]],[[6,7],1]],[1,[[5,9],4]]]
[[0,6],[[9,3],[4,2]]]
[7,[[[2,4],[3,4]],[2,0]]]
[0,[6,7]]
[[[0,2],[[7,2],7]],[[[6,3],[2,0]],[[8,6],[7,9]]]]
[[[7,[0,5]],7],[[2,3],[3,3]]]
[[2,[0,[4,5]]],[[4,[7,9]],[[5,6],4]]]
[[[5,4],0],[5,[[7,1],[7,6]]]]
[[0,3],[[[5,2],5],[[8,5],[2,8]]]]
[[[0,[8,9]],[[3,1],2]],[[3,[7,1]],7]]
[[[[9,7],[5,5]],[[2,4],1]],[[1,3],[[4,0],[9,1]]]]
[[[0,9],4],0]
[[[[8,8],9],[[8,2],3]],[[2,[7,4]],[9,1]]]
[[[1,2],8],[[[4,4],2],[2,4]]]
[[6,[7,[2,1]]],[[2,1],3]]
[0,[[[7,8],0],[5,[8,5]]]]
[[[2,8],6],[6,[[1,1],[1,2]]]]
[[[[3,9],2],[7,[4,9]]],[[[5,3],3],[[7,3],5]]]
[[2,[4,[3,2]]],[[4,9],6]]
[[[[1,1],[0,5]],[1,[4,9]]],[[6,[5,7]],[[1,6],[7,2]]]]
[0,[0,[[8,5],8]]]
[[[1,[2,5]],8],[[3,[0,2]],4]]
[[[4,3],0],[[[6,9],[7,2]],[[1,9],8]]]
[[[[7,1],0],[7,5]],[6,2]]
[[[9,[6,5]],6],[[5,5],[[4,6],2]]]
[[[[3,0],[5,5]],2],[7,[9,[8,5]]]]
[9,[[9,7],[3,3]]]
[[[0,0],4],[7,[[5,8],[2,7]]]]
[[[[9,2],4],[[0,1],[4,1]]],[[4,[6,5]],5]]
[8,[[[5,2],8],[6,0]]]
[[[[9,6],2],9],[5,[[5,3],5]]]
[[[8,[8,0]],[7,[3,3]]],[[[8,8],[5,5]],[[1,3],3]]]
[[[2,3],4],[[[8,8],[1,4]],5]]
[[[[3,7],9],6],[[5,[4,1]],4]]
[[[3,4],[[5,3],4]],[[2,[4,2]],[[0,7],5]]]
[0,9]
[[2,[[9,1],[3,4]]],[[[5,7],[6,6]],[5,[3,6]]]]
[[[[7,2],7],[[8,7],9]],[9,[[7,0],[3,4]]]]
[[[[8,3],[0,2]],0],[5,[[9,9],1]]]
[[[1,5],[[3,9],[5,6]]],[6,[2,[2,4]]]]
[[[[1,6],7],[8,9]],[[[6,7],8],1]]
[[5,[[1,3],[1,8]]],[8,1]]
[[[[4,6],9],[[3,0],[2,4]]],3]
[[[[6,6],[9,8]],[4,7]],[[6,8],1]]
[[[9,[7,8]],[4,[0,3]]],[[8,[8,1]],8]]
[4,0]
[[[[1,8],[6,9]],[[1,5],[6,1]]],[[1,9],[0,1]]]
[[[[1,8],[1,8]],[[6,2],[8,6]]],[[[6,8],3],[[8,0],[7,3]]]]
[8,9]
[[2,8],2]
[[4,[[7,0],[1,8]]],1]
[[5,0],[[[3,4],0],3]]
[[[[7,5],2],6],[[9,2],[[5,0],[7,5]]]]
[[8,[[0,0],[3,7]]],[1,6]]
[[[[5,2],[5,1]],[8,6]],[2,[9,[5,4]]]]
[[[6,[3,3]],[[0,4],0]],[[4,4],[[3,6],6]]]
[[7,[[4,9],[9,7]]],[3,[[8,7],9]]]
[[[[3,3],9],[8,[7,2]]],[[3,9],8]]
[[[0,[9,2]],1],[6,[[9,7],8]]]
[[5,[0,1]],[8,7]]
[[[[0,7],5],8],[[[0,0],[7,1]],[2,[6,9]]]]
[[5,[[3,3],7]],[[[1,3],[5,4]],[[0,8],[2,2]]]]
[[[[7,4],5],[[9,1],[5,5]]],[[0,8],[0,[6,4]]]]
[[0,[[9,5],[4,3]]],[[[2,7],[4,7]],6]]
[[7,[[3,2],[7,9]]],[[[8,6],[1,8]],[5,[5,6]]]]
[[0,[[3,3],0]],[[[5,2],[2,4]],[6,8]]]
[[[6,[5,6]],9],[[[5,2],7],[[8,7],[2,4]]]]
[[[[7,2],[8,2]],5],[[[4,5],[0,7]],6]]
[[[[6,1],4],6],[[4,[7,8]],3]]
[[[[2,6],[5,0]],5],[[3,[5,4]],[[2,3],[8,6]]]]
[[4,[[1,3],[1,3]]],[[[5,1],2],[[7,3],[9,6]]]]
[[8,[6,[0,0]]],[[[4,4],9],[6,2]]]
[[9,7],7]
[[[3,1],[[0,3],[5,2]]],3]
[[1,5],[4,[0,[3,6]]]]
[[[[4,9],[6,5]],[8,4]],2]
[[[7,[1,5]],4],[[3,[4,6]],[7,[4,3]]]]
[[[0,[5,7]],[[8,7],[2,6]]],[[4,5],5]]
[[[2,3],[[9,5],[9,3]]],[[[2,5],9],[[9,1],8]]]
[[[[4,4],4],[[4,0],9]],[[[5,3],1],[3,[7,6]]]]

184
2021/18/prog.py Normal file
View File

@ -0,0 +1,184 @@
VERBOSE = True
def verbose(s = "", *args, **kwargs):
if VERBOSE:
print(s, *args, **kwargs)
def get_input(sample = False, part = 1):
import json
with open(f'sample_p{part}' if sample else 'input', 'r') as f:
return [parse(json.loads(line.strip())) for line in f.readlines()]
class Pair:
def __init__(self, left, right, parent = None) -> None:
self.left = left
self.right = right
self.parent = parent
def left_most(self) -> int:
if isinstance(self.left, int):
return self.left
return self.left.left_most()
def left_most_pair(self):
if isinstance(self.left, int):
return self
return self.left.left_most_pair()
def right_most(self) -> int:
if isinstance(self.right, int):
return self.right
return self.right.right_most()
def right_most_pair(self):
if isinstance(self.right, int):
return self
return self.right.right_most_pair()
def explode(self):
if not (isinstance(self.left, int) and isinstance(self.left, int)):
raise ValueError("Both children must be ints to explode")
cur = self
while cur.parent != None and cur.parent.left is cur:
cur = cur.parent
if cur.parent != None:
if isinstance(cur.parent.left, int):
cur.parent.left += self.left
else:
cur.parent.left.right_most_pair().right += self.left
cur = self
while cur.parent != None and cur.parent.right is cur:
cur = cur.parent
if cur.parent != None:
if isinstance(cur.parent.right, int):
cur.parent.right += self.right
else:
cur.parent.right.left_most_pair().left += self.right
if self.parent != None:
if self.parent.left == self:
self.parent.left = 0
else:
self.parent.right = 0
def split_left(self):
self.left = Pair(self.left // 2, self.left // 2 + self.left % 2, self)
def split_right(self):
self.right = Pair(self.right // 2, self.right // 2 + self.right % 2, self)
def __repr__(self) -> str:
return str(self)
def __str__(self) -> str:
return f"[{str(self.left)}, {str(self.right)}]"
def __eq__(self, __o) -> bool:
try:
return self.left == __o.left and self.right == __o.right
except Exception as e:
return False
def list(self) -> str:
return [
self.left if isinstance(self.left, int) else self.left.list(),
self.right if isinstance(self.right, int) else self.right.list()
]
def __add__(self, __o):
new = Pair(self, __o)
self.parent = new
__o.parent = new
new.reduce()
return new
def reduce(self):
reduce_again = False
while True:
lvl = 0
old_queue = []
queue = [self]
new_queue = []
while len(queue) != 0 and lvl <= 4:
lvl += 1
for n in queue:
if not isinstance(n.left, int):
new_queue.append(n.left)
if not isinstance(n.right, int):
new_queue.append(n.right)
old_queue = queue[:]
queue = new_queue[:]
new_queue = []
queue = old_queue[:]
if lvl <= 4:
break
queue[0].left_most_pair().explode()
# verbose(f"{lvl = }, {queue = }")
# if lvl > 4 and len(queue) > 0:
# verbose(f"needing to explode some stuff, {queue = }")
# reduce_again = True
# for n in queue:
# n.explode()
# else:
# break
queue = [self]
new_queue = []
while len(queue) != 0:
lvl += 1
for n in queue:
if isinstance(n.left, int):
if n.left >= 10:
verbose(f"splitting left of {n}")
reduce_again = True
n.split_left()
else:
new_queue.append(n.left)
if isinstance(n.right, int):
if n.right >= 10:
verbose(f"splitting right of {n}")
reduce_again = True
n.split_right()
else:
new_queue.append(n.right)
queue = new_queue[:]
new_queue = []
if reduce_again:
self.reduce()
def mag(self):
res = 0
res += 3 * (self.left if isinstance(self.left, int) else self.left.mag())
res += 2 * (self.right if isinstance(self.right, int) else self.right.mag())
return res
def parse(arr, parent = None):
ret = Pair(None, None, parent)
ret.left = arr[0] if isinstance(arr[0], int) else parse(arr[0], ret)
ret.right = arr[1] if isinstance(arr[1], int) else parse(arr[1], ret)
return ret
def result(inp, part = 1, partial = False):
partial_res = inp[0]
for p in inp[1:]:
verbose(f"adding {partial_res} and {p}")
partial_res += p
verbose()
if partial:
return partial_res
return partial_res.mag()
if __name__ == "__main__":
VERBOSE = False
print(result(get_input(), part = 1))

4
2021/18/sample_p1 Normal file
View File

@ -0,0 +1,4 @@
[1,1]
[2,2]
[3,3]
[4,4]

5
2021/18/sample_p2 Normal file
View File

@ -0,0 +1,5 @@
[1,1]
[2,2]
[3,3]
[4,4]
[5,5]

6
2021/18/sample_p3 Normal file
View File

@ -0,0 +1,6 @@
[1,1]
[2,2]
[3,3]
[4,4]
[5,5]
[6,6]

10
2021/18/sample_p4 Normal file
View File

@ -0,0 +1,10 @@
[[[0,[4,5]],[0,0]],[[[4,5],[2,6]],[9,5]]]
[7,[[[3,7],[4,3]],[[6,3],[8,8]]]]
[[2,[[0,8],[3,4]]],[[[6,7],1],[7,[1,6]]]]
[[[[2,4],7],[6,[0,5]]],[[[6,8],[2,8]],[[2,1],[4,5]]]]
[7,[5,[[3,8],[1,4]]]]
[[2,[2,2]],[8,[8,1]]]
[2,9]
[1,[[[9,3],9],[[9,0],[0,7]]]]
[[[5,[7,4]],7],1]
[[[[4,2],2],6],[8,7]]

10
2021/18/sample_p5 Normal file
View File

@ -0,0 +1,10 @@
[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]]
[[[5,[2,8]],4],[5,[[9,9],0]]]
[6,[[[6,2],[5,6]],[[7,6],[4,7]]]]
[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]]
[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]]
[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]]
[[[[5,4],[7,7]],8],[[8,3],8]]
[[9,3],[[9,9],[6,[4,9]]]]
[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]]
[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]

108
2021/18/test.py Normal file
View File

@ -0,0 +1,108 @@
from prog import *
import unittest
class Tests(unittest.TestCase):
def test_eq(self):
for l in [
[1,2],
[[1, 2], 3],
[[[[[9,8],1],2],3],4],
[[[[0,9],2],3],4],
[7,[6,[5,[4,[3,2]]]]],
[7,[6,[5,[7,0]]]],
[[6,[5,[4,[3,2]]]],1],
[[6,[5,[7,0]]],3],
[[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]],
[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]],
[[3,[2,[8,0]]],[9,[5,[7,0]]]],
[[[[[4,3],4],4],[7,[[8,4],9]]],[1,1]],
[[[[0,7],4],[7,[[8,4],9]]],[1,1]],
[[[[0,7],4],[15,[0,13]]],[1,1]],
[[[[0,7],4],[[7,8],[0,13]]],[1,1]],
[[[[0,7],4],[[7,8],[0,[6,7]]]],[1,1]],
[[[[0,7],4],[[7,8],[6,0]]],[8,1]],
]:
l1 = parse(l)
l2 = parse(l)
with self.subTest(l=l, l1=l1, l2=l2):
self.assertEqual(l1, l2)
def test_parse(self):
for l in [
[1,2],
[[1, 2], 3],
[[[[[9,8],1],2],3],4],
[[[[0,9],2],3],4],
[7,[6,[5,[4,[3,2]]]]],
[7,[6,[5,[7,0]]]],
[[6,[5,[4,[3,2]]]],1],
[[6,[5,[7,0]]],3],
[[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]],
[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]],
[[3,[2,[8,0]]],[9,[5,[7,0]]]],
[[[[[4,3],4],4],[7,[[8,4],9]]],[1,1]],
[[[[0,7],4],[7,[[8,4],9]]],[1,1]],
[[[[0,7],4],[15,[0,13]]],[1,1]],
[[[[0,7],4],[[7,8],[0,13]]],[1,1]],
[[[[0,7],4],[[7,8],[0,[6,7]]]],[1,1]],
[[[[0,7],4],[[7,8],[6,0]]],[8,1]],
]:
with self.subTest(l=l):
self.assertEqual(parse(l).list(), l)
def test_explode(self):
t1 = parse([[[[[9,8],1],2],3],4])
t1.left_most_pair().explode()
t2 = parse([[[[0,9],2],3],4])
self.assertEqual(t1, t2)
t1 = parse([7,[6,[5,[4,[3,2]]]]])
t1.right_most_pair().explode()
t2 = parse([7,[6,[5,[7,0]]]])
self.assertEqual(t1, t2)
t1 = parse([[6,[5,[4,[3,2]]]],1])
t1.left.right_most_pair().explode()
t2 = parse([[6,[5,[7,0]]],3])
self.assertEqual(t1, t2)
t1 = parse([[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]])
t1.left.right_most_pair().explode()
t2 = parse([[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]])
self.assertEqual(t1, t2)
t1 = parse([[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]])
t1.right_most_pair().explode()
t2 = parse([[3,[2,[8,0]]],[9,[5,[7,0]]]])
self.assertEqual(t1, t2)
def test_add_and_reduce(self):
self.assertEqual(parse([[[[4,3],4],4],[7,[[8,4],9]]]) + parse([1, 1]), parse([[[[0,7],4],[[7,8],[6,0]]],[8,1]]))
self.assertEqual(parse([[[0,[4,5]],[0,0]],[[[4,5],[2,6]],[9,5]]]) + parse([7,[[[3,7],[4,3]],[[6,3],[8,8]]]]), parse([[[[4,0],[5,4]],[[7,7],[6,0]]],[[8,[7,7]],[[7,9],[5,0]]]]))
def test_mag(self):
self.assertEqual(parse([9, 1]).mag(), 29)
self.assertEqual(parse([1, 9]).mag(), 21)
self.assertEqual(parse([[9, 1], [1, 9]]).mag(), 129)
self.assertEqual(parse([[1,2],[[3,4],5]]).mag(), 143)
self.assertEqual(parse([[[[0,7],4],[[7,8],[6,0]]],[8,1]]).mag(), 1384)
self.assertEqual(parse([[[[1,1],[2,2]],[3,3]],[4,4]]).mag(), 445)
self.assertEqual(parse([[[[3,0],[5,3]],[4,4]],[5,5]]).mag(), 791)
self.assertEqual(parse([[[[5,0],[7,4]],[5,5]],[6,6]]).mag(), 1137)
self.assertEqual(parse([[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]).mag(), 3488)
# def test_part1_partial(self):
# self.assertEqual(result(get_input(sample = True), partial = True), parse([[[[1,1],[2,2]],[3,3]],[4,4]]))
# self.assertEqual(result(get_input(sample = True, part = 2), partial = True), parse([[[[3,0],[5,3]],[4,4]],[5,5]]))
# self.assertEqual(result(get_input(sample = True, part = 3), partial = True), parse([[[[5,0],[7,4]],[5,5]],[6,6]]))
# self.assertEqual(result(get_input(sample = True, part = 4), partial = True), parse([[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]))
# self.assertEqual(result(get_input(sample = True, part = 5), partial = True), parse([[[[6,6],[7,6]],[[7,7],[7,0]]],[[[7,7],[7,7]],[[7,8],[9,9]]]]))
# def test_part1(self):
# self.assertEqual(result(get_input(sample = True, part = 5)), 4140)
# def test_part2(self):
# self.assertEqual(result(get_input(sample = True), part = 2), 5)