diff --git a/2022/inputs/11.txt b/2022/inputs/11.txt new file mode 100644 index 0000000..7b193fa --- /dev/null +++ b/2022/inputs/11.txt @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 84, 66, 62, 69, 88, 91, 91 + Operation: new = old * 11 + Test: divisible by 2 + If true: throw to monkey 4 + If false: throw to monkey 7 + +Monkey 1: + Starting items: 98, 50, 76, 99 + Operation: new = old * old + Test: divisible by 7 + If true: throw to monkey 3 + If false: throw to monkey 6 + +Monkey 2: + Starting items: 72, 56, 94 + Operation: new = old + 1 + Test: divisible by 13 + If true: throw to monkey 4 + If false: throw to monkey 0 + +Monkey 3: + Starting items: 55, 88, 90, 77, 60, 67 + Operation: new = old + 2 + Test: divisible by 3 + If true: throw to monkey 6 + If false: throw to monkey 5 + +Monkey 4: + Starting items: 69, 72, 63, 60, 72, 52, 63, 78 + Operation: new = old * 13 + Test: divisible by 19 + If true: throw to monkey 1 + If false: throw to monkey 7 + +Monkey 5: + Starting items: 89, 73 + Operation: new = old + 5 + Test: divisible by 17 + If true: throw to monkey 2 + If false: throw to monkey 0 + +Monkey 6: + Starting items: 78, 68, 98, 88, 66 + Operation: new = old + 6 + Test: divisible by 11 + If true: throw to monkey 2 + If false: throw to monkey 5 + +Monkey 7: + Starting items: 70 + Operation: new = old + 7 + Test: divisible by 5 + If true: throw to monkey 1 + If false: throw to monkey 3 diff --git a/2022/src/day11.rs b/2022/src/day11.rs index b18a9d3..c013b57 100644 --- a/2022/src/day11.rs +++ b/2022/src/day11.rs @@ -18,13 +18,13 @@ use crate::common::parse_input; #[derive(Debug, Copy, Clone)] enum Operation { - Mul(u32), - Add(u32), + Mul(u64), + Add(u64), Square, } impl Operation { - fn transform(self, worry: u32) -> u32 { + fn transform(self, worry: u64) -> u64 { match self { Operation::Mul(val) => worry * val, Operation::Add(val) => worry + val, @@ -35,15 +35,15 @@ impl Operation { #[derive(Debug)] struct Monkey { - items: Vec, + items: Vec, operation: Operation, - test_mod: u32, + test_mod: u64, targets: [usize; 2], inspected: usize, } impl Monkey { - fn handle_items(&mut self, drains: &mut [Vec; 2]) { + fn handle_items(&mut self, drains: &mut [Vec; 2]) { self.inspected += self.items.len(); for item in self.items.drain(..) { @@ -54,6 +54,18 @@ impl Monkey { drains[(new_val % self.test_mod == 0) as usize].push(new_val); } } + + fn handle_items2(&mut self, drains: &mut [Vec], mod_base: u64) { + self.inspected += self.items.len(); + + for item in self.items.drain(..) { + let mut new_val = self.operation.transform(item); + // Modular arithmetic is a good way to get less worried + new_val %= mod_base; + + drains[(new_val % self.test_mod == 0) as usize].push(new_val); + } + } } fn parse_operation(input: &[u8]) -> IResult<&[u8], Operation> { @@ -61,8 +73,8 @@ fn parse_operation(input: &[u8]) -> IResult<&[u8], Operation> { tag("new = old "), alt(( map_res( - separated_pair(take(1usize), tag(" "), nom::character::complete::u32), - |(op, val): (&[u8], u32)| match op[0] { + separated_pair(take(1usize), tag(" "), nom::character::complete::u64), + |(op, val): (&[u8], u64)| match op[0] { b'*' => Ok(Operation::Mul(val)), b'+' => Ok(Operation::Add(val)), _ => Err(anyhow::anyhow!("Invalid operation {op:?}")), @@ -74,7 +86,7 @@ fn parse_operation(input: &[u8]) -> IResult<&[u8], Operation> { } fn parse_monkey(input: &[u8]) -> IResult<&[u8], Monkey> { - use nom::character::complete::u32; + use nom::character::complete::u64; map( preceded( @@ -85,16 +97,16 @@ fn parse_monkey(input: &[u8]) -> IResult<&[u8], Monkey> { // Parse the starting items delimited( tag(" Starting items: "), - separated_list1(tag(", "), u32), + separated_list1(tag(", "), u64), newline, ), // Parse operation delimited(tag(" Operation: "), parse_operation, newline), // Parse the test - delimited(tag(" Test: divisible by "), u32, newline), + delimited(tag(" Test: divisible by "), u64, newline), // Parse both cases - delimited(tag(" If true: throw to monkey "), u32, newline), - delimited(tag(" If false: throw to monkey "), u32, newline), + delimited(tag(" If true: throw to monkey "), u64, newline), + delimited(tag(" If false: throw to monkey "), u64, newline), )), ), |(items, operation, test_mod, if_true, if_false)| Monkey { @@ -115,9 +127,9 @@ pub fn part1(input: &[u8]) -> Result { for i in 0..monkeys.len() { monkeys[i].handle_items(&mut drains); - for j in 0..2 { + for (j, drain) in drains.iter_mut().enumerate() { let target = monkeys[i].targets[j]; - monkeys[target].items.append(&mut drains[j]); + monkeys[target].items.append(drain); } } } @@ -129,8 +141,28 @@ pub fn part1(input: &[u8]) -> Result { Ok(result.to_string()) } -pub fn part2(_input: &[u8]) -> Result { - anyhow::bail!("not implemented") +pub fn part2(input: &[u8]) -> Result { + let mut monkeys = parse_input(input, separated_list0(newline, parse_monkey))?; + let mut drains = [Vec::new(), Vec::new()]; + + let mod_base: u64 = monkeys.iter().map(|m| m.test_mod).product(); + + for _ in 0..10000 { + for i in 0..monkeys.len() { + monkeys[i].handle_items2(&mut drains, mod_base); + + for (j, drain) in drains.iter_mut().enumerate() { + let target = monkeys[i].targets[j]; + monkeys[target].items.append(drain); + } + } + } + + monkeys.sort_by(|a, b| b.inspected.cmp(&a.inspected)); + + let result: usize = monkeys[0].inspected * monkeys[1].inspected; + + Ok(result.to_string()) } #[cfg(test)] @@ -143,4 +175,9 @@ mod tests { fn sample_part1() { assert_eq!(part1(SAMPLE).unwrap(), "10605"); } + + #[test] + fn sample_part2() { + assert_eq!(part2(SAMPLE).unwrap(), "2713310158"); + } } diff --git a/2022/src/samples/11.txt b/2022/src/samples/11.txt new file mode 100644 index 0000000..30e09e5 --- /dev/null +++ b/2022/src/samples/11.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