balt.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import os, argparse
  2. from typing import List
  3. DEBUG = False
  4. #DEBUG = True
  5. def debug_print(s):
  6. if DEBUG:
  7. print(f"DEBUG: {s}")
  8. def solve_task(lines):
  9. monkeys = []
  10. current_monkey = []
  11. for line in lines:
  12. if len(line) == 0:
  13. monkeys.append(Monkey.from_line(current_monkey))
  14. current_monkey = []
  15. else:
  16. current_monkey.append(line)
  17. if(len(current_monkey) != 0):
  18. monkeys.append(Monkey.from_line(current_monkey))
  19. for i, monkey in enumerate(monkeys):
  20. print(f"Monkey {i}:")
  21. print(f"{monkey}\n")
  22. game = KeepAwayGame(monkeys)
  23. game.do_rounds(10000)
  24. for i, monkey in enumerate(monkeys):
  25. print(f"Monkey {i} inspected items : {monkey.items_inspected} times.")
  26. print(f"Monkey business: {game.monkey_business()}")
  27. class Monkey:
  28. def __init__(self, items, operation, modulo, true_monkey, false_monkey) -> None:
  29. self._items = items
  30. self._operation = operation
  31. self._modulo = modulo
  32. self._true_monkey = true_monkey
  33. self._false_monkey = false_monkey
  34. self.items_inspected = 0
  35. def __str__(self):
  36. to_return = f" Items: {str(self._items)[1:-1]}\n"
  37. to_return += f" Operation: {self._operation}\n"
  38. to_return += f" Test: divisible by {self._modulo}\n"
  39. to_return += f" If true: throw to monkey {self._true_monkey}\n"
  40. to_return += f" If false: throw to monkey {self._false_monkey}"
  41. return to_return
  42. def give(self, item):
  43. self._items.append(item)
  44. def take_round(self, throw_function):
  45. while len(self._items):
  46. item = self._items.pop(0)
  47. #debug_print(f" Monkey inspects an item with a worry level of {item}.")
  48. self.items_inspected += 1
  49. item = self._operation(item)
  50. debug_print(f" New worry level: {item}.")
  51. #item = item // 3
  52. #debug_print(f" Monkey gets bored with item. Worry level is divided by 3 to {item}.")
  53. if (item % self._modulo) == 0:
  54. debug_print(f" Test: true")
  55. throw_function(self._true_monkey, item)
  56. #debug_print(f" Item with worry level {item} is thrown to monkey {self._true_monkey}.")
  57. else:
  58. #debug_print(f" Test: false")
  59. throw_function(self._false_monkey, item)
  60. #debug_print(f" Item with worry level {item} is thrown to monkey {self._false_monkey}.")
  61. def from_line(lines) -> None:
  62. starting_items = [int(i) for i in lines[1].split(':')[1].split(',')]
  63. operation = Monkey.create_operation_from_line(lines[2])
  64. modulo = int(lines[3].split("by")[1])
  65. iftrue = int(lines[4].split("monkey")[1])
  66. iffalse = int(lines[5].split("monkey")[1])
  67. return Monkey(starting_items, operation, modulo, iftrue, iffalse)
  68. def create_operation_from_line(line):
  69. operation = line.split(':')[1].strip()
  70. global_dir = {}
  71. exec(f"""def func(old):
  72. {operation}
  73. return new""", global_dir)
  74. return global_dir["func"]
  75. class KeepAwayGame:
  76. def __init__(self, monkeys: List[Monkey]) -> None:
  77. self.monkeys = monkeys
  78. self.global_modulo = 1
  79. for monkey in monkeys:
  80. self.global_modulo *= monkey._modulo
  81. print(f"Game initialized with global modulo: {self.global_modulo}")
  82. def do_rounds(self, n = 1):
  83. for round in range(n):
  84. debug_print(f"Round {round}")
  85. for i, monkey in enumerate(self.monkeys):
  86. debug_print(f"Monkey {i}:")
  87. monkey.take_round(self.throw)
  88. def monkey_business(self):
  89. inspections = [m.items_inspected for m in self.monkeys]
  90. inspections.sort()
  91. return inspections[-1] * inspections[-2]
  92. def throw(self, recipient, worry_level):
  93. worry_level = worry_level % self.global_modulo
  94. self.monkeys[recipient].give(worry_level)
  95. def read_lines(filename):
  96. lines = []
  97. with open(filename) as infile:
  98. for raw_line in infile:
  99. line = raw_line.rstrip()
  100. lines.append(line)
  101. return lines
  102. def parse_arguments():
  103. parser = argparse.ArgumentParser(description="Script that solves the case",epilog="Have a nice day!")
  104. parser.add_argument('filename', nargs='?', default="example.txt", help='Input file')
  105. args = parser.parse_args()
  106. return args
  107. def main():
  108. args = parse_arguments()
  109. lines = read_lines(args.filename)
  110. solve_task(lines)
  111. if __name__ == "__main__":
  112. main()