solution.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #!/usr/bin/env python3
  2. import sys
  3. import re
  4. class Node:
  5. def __init__(self, left = None, right = None, value = None):
  6. self.left = left
  7. self.right = right
  8. self.value = value
  9. self.parent = None
  10. def __str__(self):
  11. return str(self.value) if self.value != None else f"[{str(self.left)}, {str(self.right)}]"
  12. def insert(self, node):
  13. if not self.left:
  14. self.left = node
  15. self.left.parent = self
  16. else:
  17. self.right = node
  18. self.right.parent = self
  19. def is_leaf(self):
  20. return self.left == None and self.right == None
  21. def is_left(self):
  22. return self.parent and self.parent.left == self
  23. def is_right(self):
  24. return self.parent and self.parent.right == self
  25. def parse_snailfishes(str):
  26. stack = [Node()]
  27. for c in str:
  28. if c == '[':
  29. stack.append(Node())
  30. continue
  31. if c == ']':
  32. node = stack.pop()
  33. stack[-1].insert(node)
  34. continue
  35. if c == ',':
  36. continue
  37. # if none apply insert as number
  38. stack[-1].insert(Node(value=int(c)))
  39. return stack.pop()
  40. def explode(node, value, left):
  41. #print(f'@ {node}')
  42. #print(f'@ {node.parent}')
  43. current = node
  44. while current.parent != None and ((current.is_left() and current.parent.right.value != None) or (current.is_right() and current.parent.left.value != None)):
  45. current = current.parent
  46. current = current.left if left else current.right
  47. while current.right if left else current.left != None:
  48. current = current.right if left else current.left
  49. #print(f'reached node {current} ({"left" if left else "right"})')
  50. if current.value != None:
  51. current.value += value
  52. return True
  53. def reduce_snailfishes(node, level = 1):
  54. current = node
  55. reduced = False
  56. #print(f'level {level}')
  57. if level > 3 and current.left.is_leaf() and current.right.is_leaf():
  58. print(f'exploding {current} distributing {current.left} and {current.right}')
  59. # search left spot
  60. reduced = reduced or explode(current, current.left.value, True)
  61. reduced = reduced or explode(current, current.right.value, False)
  62. # search right spot
  63. if current.is_left():
  64. current.parent.left = Node(value=0)
  65. if current.is_right():
  66. current.parent.right = Node(value=0)
  67. #explode_right(current, current.right)
  68. return reduced
  69. if not current.left.is_leaf():
  70. reduced = reduced or reduce_snailfishes(current.left, level + 1)
  71. if not current.right.is_leaf():
  72. reduced = reduced or reduce_snailfishes(current.right, level + 1)
  73. return reduced
  74. def add_snailfishes(node1, node2):
  75. print(f'adding {node1} and {node2}')
  76. node = Node(node1, node2)
  77. node.left.parent = node
  78. node.right.parent = node
  79. print(f'into {node}')
  80. while reduce_snailfishes(node):
  81. print(f'reducing again {node}')
  82. print(f'reduced to {node}')
  83. numbers = []
  84. for line in sys.stdin:
  85. print(f"new line: ", line.rstrip('\n'))
  86. numbers.append(parse_snailfishes(line.rstrip('\n')[1:-1]))
  87. print([str(n) for n in numbers])
  88. node1 = numbers[0]
  89. for i in range(1, len(numbers) * 0):
  90. node2 = numbers[i]
  91. add_snailfishes(node1, node2)
  92. node1 = node2
  93. add_snailfishes(numbers[3], numbers[4])