diff --git a/inputs/11.small.txt b/inputs/11.small.txt new file mode 100644 index 0000000..30e09e5 --- /dev/null +++ b/inputs/11.small.txt @@ -0,0 +1,27 @@ +Monkey 0: + Starting items: 79, 98 + Operation: new = old * 19 + Test: divisible by 23 + If true: throw to monkey 2 + If false: throw to monkey 3 + +Monkey 1: + Starting items: 54, 65, 75, 74 + Operation: new = old + 6 + Test: divisible by 19 + If true: throw to monkey 2 + If false: throw to monkey 0 + +Monkey 2: + Starting items: 79, 60, 97 + Operation: new = old * old + Test: divisible by 13 + If true: throw to monkey 1 + If false: throw to monkey 3 + +Monkey 3: + Starting items: 74 + Operation: new = old + 3 + Test: divisible by 17 + If true: throw to monkey 0 + If false: throw to monkey 1 diff --git a/inputs/11.txt b/inputs/11.txt new file mode 100644 index 0000000..ecdc524 --- /dev/null +++ b/inputs/11.txt @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 89, 73, 66, 57, 64, 80 + Operation: new = old * 3 + Test: divisible by 13 + If true: throw to monkey 6 + If false: throw to monkey 2 + +Monkey 1: + Starting items: 83, 78, 81, 55, 81, 59, 69 + Operation: new = old + 1 + Test: divisible by 3 + If true: throw to monkey 7 + If false: throw to monkey 4 + +Monkey 2: + Starting items: 76, 91, 58, 85 + Operation: new = old * 13 + Test: divisible by 7 + If true: throw to monkey 1 + If false: throw to monkey 4 + +Monkey 3: + Starting items: 71, 72, 74, 76, 68 + Operation: new = old * old + Test: divisible by 2 + If true: throw to monkey 6 + If false: throw to monkey 0 + +Monkey 4: + Starting items: 98, 85, 84 + Operation: new = old + 7 + Test: divisible by 19 + If true: throw to monkey 5 + If false: throw to monkey 7 + +Monkey 5: + Starting items: 78 + Operation: new = old + 8 + Test: divisible by 5 + If true: throw to monkey 3 + If false: throw to monkey 0 + +Monkey 6: + Starting items: 86, 70, 60, 88, 88, 78, 74, 83 + Operation: new = old + 4 + Test: divisible by 11 + If true: throw to monkey 1 + If false: throw to monkey 2 + +Monkey 7: + Starting items: 81, 58 + Operation: new = old + 5 + Test: divisible by 17 + If true: throw to monkey 3 + If false: throw to monkey 5 diff --git a/src/main.rs b/src/main.rs index e891f58..5327078 100644 --- a/src/main.rs +++ b/src/main.rs @@ -262,9 +262,152 @@ solutions! { let cmds = input.lines().map(Cmd::from_str).collect(); Screen::new().draw(cmds).to_string().into() } + ], + [ + // day 11 part 1 + |input| { + let monkeys = input.split("\n\n").map(|s| Monkey::from_str(s, false)).collect(); + run_rounds(monkeys, 20).into() + }, + // day 11 part 2 + |input| { + let monkeys = input.split("\n\n").map(|s| Monkey::from_str(s, true)).collect(); + run_rounds(monkeys, 10000).into() + } ] } +fn run_rounds(mut monkeys: Vec, n: usize) -> u64 { + let mod_factor: usize = monkeys.iter().map(|m| m.test).product(); + let mut counts = vec![0; monkeys.len()]; + for round in 1..=n { + let next = run_round(&mut monkeys, mod_factor); + counts = next.iter().zip(counts).map(|(x, y)| x + y).collect(); + if round % 1000 == 0 || round == 20 || round == 1 {} + } + counts.sort(); + counts[counts.len() - 1] * counts[counts.len() - 2] +} + +fn run_round(monkeys: &mut Vec, mod_factor: usize) -> Vec { + let mut inspects = vec![]; + for i in 0..monkeys.len() { + let monkey = &mut monkeys[i]; + let throws = monkey.take_turn(mod_factor); + inspects.push(throws.len() as u64); + for (to, item) in throws { + monkeys[to].items.push(item) + } + } + inspects +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +enum OpType { + Add, + Mul, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct Op { + op_type: OpType, + operand: Option, +} + +impl Op { + fn operand(s: &str) -> Option { + match s { + "old" => None, + _ => Some(s.parse::().unwrap()), + } + } + + fn from_str(s: &str) -> Self { + let (op_type, y) = s.split_once(' ').unwrap(); + Self { + op_type: match op_type { + "+" => OpType::Add, + "*" => OpType::Mul, + _ => unreachable!("whoa"), + }, + operand: Self::operand(y), + } + } + + fn apply(&self, old: usize) -> usize { + let operand = self.operand.unwrap_or(old); + match self.op_type { + OpType::Add => old.wrapping_add(operand), + OpType::Mul => old.wrapping_mul(operand), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct Monkey { + items: Vec, + operation: Op, + test: usize, + throw_true: usize, + throw_false: usize, + part_two: bool, +} + +impl Monkey { + fn from_str(s: &str, part_two: bool) -> Self { + let (_, s) = s.split_once('\n').unwrap(); + let (items, s) = s.split_once('\n').unwrap(); + let (operation, s) = s.split_once('\n').unwrap(); + let (test, s) = s.split_once('\n').unwrap(); + let (throw_true, throw_false) = s.split_once('\n').unwrap(); + Monkey { + items: items + .strip_prefix(" Starting items: ") + .unwrap() + .split(", ") + .map(|n| n.parse::().unwrap()) + .collect(), + operation: Op::from_str(operation.strip_prefix(" Operation: new = old ").unwrap()), + test: test + .strip_prefix(" Test: divisible by ") + .unwrap() + .parse::() + .unwrap(), + throw_true: throw_true + .strip_prefix(" If true: throw to monkey ") + .unwrap() + .parse::() + .unwrap(), + throw_false: throw_false + .strip_prefix(" If false: throw to monkey ") + .unwrap() + .trim() + .parse::() + .unwrap(), + part_two, + } + } + + fn take_turn(&mut self, mod_factor: usize) -> Vec<(usize, usize)> { + self.items + .drain(..) + .map(|item| { + let level = self.operation.apply(item); + let level = if self.part_two { + level % mod_factor + } else { + level / 3 + }; + if level % self.test == 0 { + (self.throw_true, level) + } else { + (self.throw_false, level) + } + }) + .collect() + } +} + struct Screen { x: isize, cycle: isize,