18_snailfish.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #!/usr/bin/env python3
  2. import sys
  3. from ast import literal_eval
  4. from functools import reduce
  5. from itertools import permutations
  6. class Number:
  7. def __init__(self, value, left, right):
  8. self.prev = self.next = None
  9. self.value = value
  10. self.left = left
  11. self.right = right
  12. @classmethod
  13. def maybe_pair(cls, maybe_list):
  14. if isinstance(maybe_list, int):
  15. return cls(maybe_list, None, None)
  16. left, right = map(cls.maybe_pair, maybe_list)
  17. return cls(None, left, right)
  18. @classmethod
  19. def fromlist(cls, list_num):
  20. root = cls.maybe_pair(list_num)
  21. prev = None
  22. for node in root.numbers():
  23. if prev:
  24. prev.next = node
  25. node.prev = prev
  26. prev = node
  27. return root
  28. def isnum(self):
  29. return self.value is not None
  30. def numbers(self):
  31. if self.isnum():
  32. yield self
  33. else:
  34. yield from self.left.numbers()
  35. yield from self.right.numbers()
  36. def __repr__(self):
  37. if self.value is not None:
  38. return repr(self.value)
  39. return '[%s,%s]' % (self.left, self.right)
  40. def first(self):
  41. return self if self.isnum() else self.left.first()
  42. def last(self):
  43. return self if self.isnum() else self.right.last()
  44. def add(self, other):
  45. new = self.__class__(None, self, other)
  46. l = self.last()
  47. r = other.first()
  48. l.next = r
  49. r.prev = l
  50. new.reduce()
  51. return new
  52. def explode(self, depth):
  53. if self.isnum():
  54. return False
  55. if self.left.isnum() and self.right.isnum() and depth >= 4:
  56. self.prev = self.left.prev
  57. self.next = self.right.next
  58. if self.left.prev:
  59. self.left.prev.value += self.left.value
  60. self.left.prev.next = self
  61. if self.right.next:
  62. self.right.next.value += self.right.value
  63. self.right.next.prev = self
  64. self.left = self.right = None
  65. self.value = 0
  66. return True
  67. return self.left.explode(depth + 1) or self.right.explode(depth + 1)
  68. def split(self):
  69. if not self.isnum():
  70. return self.left.split() or self.right.split()
  71. if self.value < 10:
  72. return False
  73. half, odd = divmod(self.value, 2)
  74. self.left = self.__class__(half, None, None)
  75. self.right = self.__class__(half + odd, None, None)
  76. if self.prev:
  77. self.prev.next = self.left
  78. if self.next:
  79. self.next.prev = self.right
  80. self.left.prev = self.prev
  81. self.left.next = self.right
  82. self.right.prev = self.left
  83. self.right.next = self.next
  84. self.value = self.prev = self.next = None
  85. return True
  86. def reduce(self):
  87. if not self.isnum() or self.split():
  88. if self.explode(0) or self.split():
  89. self.reduce()
  90. def magnitude(self):
  91. if self.isnum():
  92. return self.value
  93. return 3 * self.left.magnitude() + 2 * self.right.magnitude()
  94. nums = list(map(literal_eval, sys.stdin))
  95. print(reduce(Number.add, map(Number.fromlist, nums)).magnitude())
  96. print(max(Number.fromlist(x).add(Number.fromlist(y)).magnitude()
  97. for x, y in permutations(nums, 2)))