#[path = "../lib.rs"] mod lib; struct Monkey { items: Vec, op_add: u64, op_add_self: bool, op_mul: u64, op_mul_self: bool, div: u64, if_true: usize, if_false: usize, } fn cut_prefix(line: &String, prefix: &'static str) -> Option { if line.starts_with(prefix) { return Some(line[prefix.len()..].to_string()); } else { return None; } } fn get_monkeys() -> Vec { let mut monkeys = vec![]; let mut monkey = Monkey { items: vec![], op_add: 0, op_add_self: false, op_mul: 1, op_mul_self: false, div: 1, if_true: 0, if_false: 0, }; for line in lib::iter_input() { if line.starts_with("Monkey ") { } else if let Some(rest) = cut_prefix(&line, " Starting items: ") { for s in rest.split(", ") { let i = s.parse::().unwrap(); monkey.items.push(i); } } else if let Some(rest) = cut_prefix(&line, " Operation: new = old ") { match lib::split_once(rest.as_str(), ' ').unwrap() { ("+", "old") => { monkey.op_add_self = true; }, ("*", "old") => { monkey.op_mul_self = true; }, ("+", s) => { monkey.op_add = s.parse().unwrap(); }, ("*", s) => { monkey.op_mul = s.parse().unwrap(); }, _ => unreachable!(), } } else if let Some(rest) = cut_prefix(&line, " Test: divisible by ") { monkey.div = rest.parse().unwrap(); } else if let Some(rest) = cut_prefix(&line, " If true: throw to monkey ") { monkey.if_true = rest.parse().unwrap(); } else if let Some(rest) = cut_prefix(&line, " If false: throw to monkey ") { monkey.if_false = rest.parse().unwrap(); } else if line == "" { // I cheated slightly by adding a blank line to the end of the input monkeys.push(monkey); monkey = Monkey { items: vec![], op_add: 0, op_add_self: false, op_mul: 1, op_mul_self: false, div: 1, if_true: 0, if_false: 0, }; } else { unreachable!(); } } return monkeys; } fn run(rounds: usize, damper: u64) -> u64 { let mut monkeys = get_monkeys(); let mut counts = vec![0; monkeys.len()]; // this keeps the values bounded without changing the results let total_div: u64 = monkeys.iter().map(|m| m.div).product(); for _ in 0..rounds { for i in 0..monkeys.len() { while !monkeys[i].items.is_empty() { let mut value = monkeys[i].items.remove(0); value += if monkeys[i].op_add_self { value } else { monkeys[i].op_add }; value *= if monkeys[i].op_mul_self { value } else { monkeys[i].op_mul }; value /= damper; value %= total_div; let other = if value % monkeys[i].div == 0 { monkeys[i].if_true } else { monkeys[i].if_false }; monkeys[other].items.push(value); counts[i] += 1; } } } counts.sort(); return counts.into_iter().rev().take(2).product(); } fn main() { println!("part1: {}", run(20, 3)); println!("part2: {}", run(10000, 1)); }