solution.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #!/usr/bin/python3
  2. import sys
  3. import re
  4. import math
  5. from dataclasses import dataclass
  6. from typing import Callable
  7. @dataclass
  8. class Monkey:
  9. items: list
  10. operator: Callable[[int, int], int]
  11. has_num_arg: bool
  12. num_arg: int
  13. div_by: int
  14. to1: int
  15. to2: int
  16. reduce_worry_level: bool
  17. coeff: int = 0
  18. inspections: int = 0
  19. def turn(self):
  20. #print(self.items, '-> ', end='')
  21. throws = []
  22. for i in range(len(self.items)):
  23. # increase inspections
  24. self.inspections += 1
  25. # apply operation
  26. self.items[i] = self.operator(self.items[i], self.num_arg if self.has_num_arg else self.items[i])
  27. # keep worry levels small
  28. if self.reduce_worry_level:
  29. self.items[i] //= 3
  30. else:
  31. self.items[i] %= self.coeff
  32. # pick target
  33. target = self.to1 if (self.items[i] % self.div_by == 0) else self.to2
  34. # construct list transformations
  35. throws.append((self.items[i], target))
  36. self.items.clear()
  37. #print(throws)
  38. return throws
  39. def add(a, b): return a + b
  40. def mul(a, b): return a * b
  41. def business(monkeys):
  42. for monkey in monkeys:
  43. throws = monkey.turn()
  44. for level, target in throws:
  45. monkeys[target].items.append(level)
  46. def solution(rounds, reduce_worry_level):
  47. monkeys = []
  48. for line in sys.stdin:
  49. if 'Monkey' in line:
  50. starting_items = next(sys.stdin)
  51. operation_string = next(sys.stdin)
  52. test = next(sys.stdin)
  53. test_true = next(sys.stdin)
  54. test_false = next(sys.stdin)
  55. items = [int(i) for i in starting_items.strip().split(': ')[1].split(', ')]
  56. operation_params = sorted(re.match(r'^Operation: new = (old|-?[0-9]+) ([\*\+]) (old|-?[0-9]+)', operation_string.strip()).groups())
  57. operator = add if operation_params[0] == '+' else mul
  58. num_arg = int(operation_params[1]) if operation_params[1] != 'old' else 0
  59. has_num_arg = operation_params[1] != 'old'
  60. div_by = int(test.strip().split(' ')[-1])
  61. to1 = int(test_true.strip().split(' ')[-1])
  62. to2 = int(test_false.strip().split(' ')[-1])
  63. monkeys.append(Monkey(items, operator, has_num_arg, num_arg, div_by, to1, to2, reduce_worry_level))
  64. if not reduce_worry_level:
  65. coeff = 1
  66. for monkey in monkeys:
  67. coeff *= monkey.div_by
  68. for monkey in monkeys:
  69. monkey.coeff = coeff
  70. for _ in range(rounds):
  71. business(monkeys)
  72. inspections = []
  73. for monkey in monkeys:
  74. inspections.append(monkey.inspections)
  75. max1, max2 = sorted(inspections)[-2:]
  76. print(f'max. 2 inspection counts ({max1}, {max2}) yield total monkey business of {max1 * max2}')
  77. if sys.argv[1] in '1':
  78. solution(20, True)
  79. else:
  80. solution(10000, False)