1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Monkey = Struct.new(:id, :items, :operation, :test, :t, :f) do
  def throw_to(item)
    (item % test).zero? ? t : f
  end
end

MONKEY_RE = /Monkey (?<id>\d+):
  Starting items: (?<items>(?~\n))
  Operation: new = (?<op>(?~\n))
  Test: divisible by (?<test>\d+)
    If true: throw to monkey (?<t>\d+)
    If false: throw to monkey (?<f>\d+)/m

monkeys = ARGF.read.split("\n\n").map {|monkey|
  md = MONKEY_RE.match(monkey)
  fail if md.nil?

  Monkey.new(
    md[:id].to_i,
    md[:items].split(", ").map(&:to_i),
    md[:op],
    md[:test].to_i,
    md[:t].to_i,
    md[:f].to_i,
  )
}

max_worry = monkeys.map(&:test).inject(:*)

inspections = Hash.new(0)
# 20.times do
10_000.times do
  monkeys.each do |monkey|
    until monkey.items.empty?
      inspections[monkey.id] += 1

      item = monkey.items.shift
      old = item
      item = eval(monkey.operation)
      # item /= 3
      item %= max_worry
      to = monkey.throw_to(item)
      monkeys[to].items << item
    end
  end
end

p inspections.values.max(2).inject(:*)