|
| 1 | +use regex::Regex; |
| 2 | +use std::collections::VecDeque; |
| 3 | +use std::io::Read; |
| 4 | + |
| 5 | +enum Operation { |
| 6 | + Add(u64), |
| 7 | + Mult(u64), |
| 8 | + Square, |
| 9 | +} |
| 10 | + |
| 11 | +struct Monkey { |
| 12 | + items: VecDeque<u64>, |
| 13 | + op: Operation, |
| 14 | + divisor: u64, |
| 15 | + t: usize, |
| 16 | + f: usize, |
| 17 | + inspections: u64, |
| 18 | +} |
| 19 | + |
| 20 | +fn main() { |
| 21 | + let mut input = String::new(); |
| 22 | + std::io::stdin().read_to_string(&mut input).unwrap(); |
| 23 | + |
| 24 | + let re = Regex::new(concat!( |
| 25 | + r"(?m)^Monkey (\d+):\n Starting items: (\d+(?:, \d+)*)\n Operation: new = old (?:\* (?:(\d+)|(old))|\+ ", |
| 26 | + r"(\d+))\n Test: divisible by (\d+)\n If true: throw to monkey (\d+)\n If false: throw to monkey (\d+)$", |
| 27 | + )).unwrap(); |
| 28 | + |
| 29 | + let mut monkeys: Vec<_> = re.captures_iter(&input).enumerate().map(|(n, m)| { |
| 30 | + assert_eq!(m[1].parse::<usize>().unwrap(), n); |
| 31 | + |
| 32 | + Monkey { |
| 33 | + items: m[2].split(", ").map(|num| num.parse().unwrap()).collect(), |
| 34 | + op: if let Some(factor) = m.get(3) { |
| 35 | + Operation::Mult(factor.as_str().parse().unwrap()) |
| 36 | + } else if let Some(_) = m.get(4) { |
| 37 | + Operation::Square |
| 38 | + } else if let Some(term) = m.get(5) { |
| 39 | + Operation::Add(term.as_str().parse().unwrap()) |
| 40 | + } else { |
| 41 | + panic!() |
| 42 | + }, |
| 43 | + divisor: m[6].parse().unwrap(), |
| 44 | + t: m[7].parse().unwrap(), |
| 45 | + f: m[8].parse().unwrap(), |
| 46 | + inspections: 0, |
| 47 | + } |
| 48 | + }).collect(); |
| 49 | + let modulo = monkeys.iter().fold(1, |acc, monkey| |
| 50 | + if acc % monkey.divisor == 0 { acc } else { acc * monkey.divisor } |
| 51 | + ); |
| 52 | + |
| 53 | + for _ in 0..10000 { |
| 54 | + for i in 0..monkeys.len() { |
| 55 | + while let Some(item) = monkeys[i].items.pop_front() { |
| 56 | + let monkey = &monkeys[i]; |
| 57 | + let item = match monkey.op { |
| 58 | + Operation::Mult(factor) => item * factor, |
| 59 | + Operation::Square => item * item, |
| 60 | + Operation::Add(term) => item + term, |
| 61 | + } % modulo; |
| 62 | + let target = if item % monkey.divisor == 0 { monkey.t } else { monkey.f }; |
| 63 | + monkeys[i].inspections += 1; |
| 64 | + monkeys[target].items.push_back(item); |
| 65 | + } |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + let mut top = [0; 2]; |
| 70 | + for monkey in &monkeys { |
| 71 | + let i = top.iter_mut().min().unwrap(); |
| 72 | + if monkey.inspections > *i { |
| 73 | + *i = monkey.inspections; |
| 74 | + } |
| 75 | + } |
| 76 | + println!("{}", top.iter().product::<u64>()); |
| 77 | +} |
0 commit comments