Advertisement
Guest User

AoC 2022 - Day 21

a guest
Dec 27th, 2022
327
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.34 KB | None | 0 0
  1. """
  2. Advent of Code 2022 Day 21
  3. """
  4. import re
  5. import sys
  6. from typing import Iterable
  7.  
  8. from advent_tools import get_daily_input
  9.  
  10. DAY = 21
  11.  
  12. TEST = sys.argv[1] == "test" if len(sys.argv) > 1 else False
  13.  
  14. TEST_DATA = """
  15. root: pppw + sjmn
  16. dbpl: 5
  17. cczh: sllz + lgvd
  18. zczc: 2
  19. ptdq: humn - dvpt
  20. dvpt: 3
  21. lfqf: 4
  22. humn: 5
  23. ljgn: 2
  24. sjmn: drzm * dbpl
  25. sllz: 4
  26. pppw: cczh / lfqf
  27. lgvd: ljgn * ptdq
  28. drzm: hmdt - zczc
  29. hmdt: 32
  30. """
  31.  
  32. if TEST:
  33.     def get_daily_input(_):
  34.         for line in TEST_DATA.strip().split("\n"):
  35.             yield line.strip("\n")
  36.  
  37.  
  38. class MonkeyMathSolver:
  39.     operations: dict[str, callable] = {
  40.         "+": lambda a, b: a + b,
  41.         "-": lambda a, b: a - b,
  42.         "*": lambda a, b: a * b,
  43.         "/": lambda a, b: a // b,
  44.     }
  45.  
  46.     inverse_right: dict[str, callable] = {
  47.         "+": lambda a, b: a - b,
  48.         "-": lambda a, b: a + b,
  49.         "*": lambda a, b: a // b,
  50.         "/": lambda a, b: a * b,
  51.     }
  52.  
  53.     inverse_left: dict[str, callable] = {
  54.         "+": lambda a, b: a - b,
  55.         "-": lambda a, b: (a - b) * -1,
  56.         "*": lambda a, b: a // b,
  57.         "/": lambda a, b: b // a,
  58.     }
  59.  
  60.     def __init__(self, input_data: Iterable[str]):
  61.         self.data: dict[str, [str | int]] = {}
  62.         for line in input_data:
  63.             name, value = line.split(": ")
  64.             self.data[name] = int(value) if value.isnumeric() else value
  65.  
  66.     def resolve_root(self, data: dict[str, [str | int]] = None,
  67.                      key: str = "root") -> int | str:
  68.         if not data:
  69.             data = self.data
  70.         if type(data[key]) == int:
  71.             return data[key]
  72.         else:
  73.             v1, op, v2 = data[key].split(" ")
  74.             if data.get(v1):
  75.                 v1 = self.resolve_root(data, v1)
  76.             if data.get(v2):
  77.                 v2 = self.resolve_root(data, v2)
  78.             if type(v1) == int and type(v2) == int:
  79.                 return self.operations[op](v1, v2)
  80.             else:
  81.                 return f"({v1} {op} {v2})"
  82.  
  83.     def solve_for(self, key: str = "humn"):
  84.         data = self.data.copy()
  85.         data["root"] = re.sub(r"[+\-*/]", "=", data["root"])
  86.         del (data[key])
  87.         left, right = self.resolve_root(data)[1:-1].split(" = ")
  88.  
  89.         if left.isnumeric():
  90.             left, right = right, int(left)
  91.         elif right.isnumeric():
  92.             right = int(right)
  93.  
  94.         while left != key:
  95.             if left.startswith("(") and left.endswith(")"):
  96.                 left = left[1:-1]
  97.             elif left.startswith(("(", key)):
  98.                 v1, op, v2 = re.search(r"^(.+) ([+\-*/]) (\d+)$", left).groups()
  99.                 left = v1
  100.                 right = self.inverse_right[op](right, int(v2))
  101.             elif left.endswith((")", key)):
  102.                 v1, op, v2 = re.search(r"^(\d+) ([+\-*/]) (.+)$", left).groups()
  103.                 left = v2
  104.                 right = self.inverse_left[op](right, int(v1))
  105.             else:
  106.                 return f"{left} = {right}"
  107.  
  108.         return right
  109.  
  110.  
  111. def part_1() -> int:
  112.     mms = MonkeyMathSolver(get_daily_input(DAY))
  113.     return mms.resolve_root()
  114.  
  115.  
  116. def part_2() -> int | str:
  117.     mms = MonkeyMathSolver(get_daily_input(DAY))
  118.     return mms.solve_for()
  119.  
  120.  
  121. def main():
  122.     print(f"Part 1: {part_1()}")
  123.     print(f"Part 2: {part_2()}")
  124.  
  125.  
  126. if __name__ == "__main__":
  127.     main()
  128.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement