From afd943fcd7d9d500485fb18316bafe6b55a83c37 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Sun, 11 Dec 2022 17:33:10 +0100 Subject: [PATCH] 2022 - Day 11 --- 2022/input/11/input | 55 +++++++++++++ 2022/input/11/test-1 | 27 +++++++ 2022/src/bin/day11.rs | 176 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 2022/input/11/input create mode 100644 2022/input/11/test-1 create mode 100644 2022/src/bin/day11.rs diff --git a/2022/input/11/input b/2022/input/11/input new file mode 100644 index 0000000..0f98d52 --- /dev/null +++ b/2022/input/11/input @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 52, 60, 85, 69, 75, 75 + Operation: new = old * 17 + Test: divisible by 13 + If true: throw to monkey 6 + If false: throw to monkey 7 + +Monkey 1: + Starting items: 96, 82, 61, 99, 82, 84, 85 + Operation: new = old + 8 + Test: divisible by 7 + If true: throw to monkey 0 + If false: throw to monkey 7 + +Monkey 2: + Starting items: 95, 79 + Operation: new = old + 6 + Test: divisible by 19 + If true: throw to monkey 5 + If false: throw to monkey 3 + +Monkey 3: + Starting items: 88, 50, 82, 65, 77 + Operation: new = old * 19 + Test: divisible by 2 + If true: throw to monkey 4 + If false: throw to monkey 1 + +Monkey 4: + Starting items: 66, 90, 59, 90, 87, 63, 53, 88 + Operation: new = old + 7 + Test: divisible by 5 + If true: throw to monkey 1 + If false: throw to monkey 0 + +Monkey 5: + Starting items: 92, 75, 62 + Operation: new = old * old + Test: divisible by 3 + If true: throw to monkey 3 + If false: throw to monkey 4 + +Monkey 6: + Starting items: 94, 86, 76, 67 + Operation: new = old + 1 + Test: divisible by 11 + If true: throw to monkey 5 + If false: throw to monkey 2 + +Monkey 7: + Starting items: 57 + Operation: new = old + 2 + Test: divisible by 17 + If true: throw to monkey 6 + If false: throw to monkey 2 diff --git a/2022/input/11/test-1 b/2022/input/11/test-1 new file mode 100644 index 0000000..30e09e5 --- /dev/null +++ b/2022/input/11/test-1 @@ -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/2022/src/bin/day11.rs b/2022/src/bin/day11.rs new file mode 100644 index 0000000..fd8bfc1 --- /dev/null +++ b/2022/src/bin/day11.rs @@ -0,0 +1,176 @@ +#![feature(test)] +use std::{str::FromStr, cmp::{min, max}}; + +use anyhow::Result; +use aoc::Solver; + +// -- Runners -- +fn main() -> Result<()> { + Day::solve() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn part1_test1() -> Result<()> { + Day::test(Day::part1, "test-1", 10605) + } + #[test] + fn part1_solution() -> Result<()> { + Day::test(Day::part1, "input", 95472) + } + #[test] + fn part2_test1() -> Result<()> { + Day::test(Day::part2, "test-1", 2713310158) + } + #[test] + fn part2_solution() -> Result<()> { + Day::test(Day::part2, "input", 17926061332) + } + + // Benchmarks + extern crate test; + #[bench] + #[ignore] + fn part1_bench(b: &mut test::Bencher) { + Day::benchmark(Day::part1, b) + } + #[bench] + #[ignore] + fn part2_bench(b: &mut test::Bencher) { + Day::benchmark(Day::part2, b) + } +} + +fn gcd(a: i64, b: i64) -> i64 { + match ((a, b), (a & 1, b & 1)) { + ((x, y), _) if x == y => y, + ((0, x), _) | ((x, 0), _) => x, + ((x, y), (0, 1)) | ((y, x), (1, 0)) => gcd(x >> 1, y), + ((x, y), (0, 0)) => gcd(x >> 1, y >> 1) << 1, + ((x, y), (1, 1)) => { + let (x, y) = (min(x, y), max(x, y)); + gcd((y - x) >> 1, x) + } + _ => unreachable!(), + } +} + +fn lcm(a: i64, b: i64) -> i64 { + a * b / gcd(a, b) +} + +#[derive(Debug, Copy, Clone)] +enum Operation { + Add(i64), + AddOld, + Multiply(i64), + MultiplyOld, +} + +impl FromStr for Operation { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + let operation = s.split(" ").collect::>(); + + match operation.as_slice() { + ["old", "*", "old"] => Ok(Operation::MultiplyOld), + ["old", "*", value] => Ok(Operation::Multiply(value.parse()?)), + ["old", "+", "old"] => Ok(Operation::AddOld), + ["old", "+", value] => Ok(Operation::Add(value.parse()?)), + _ => Err(anyhow::anyhow!("Invalid input")), + } + } +} + +#[derive(Debug)] +struct Monkey { + items: Vec, + operation: Operation, + divisor: i64, + next: (usize, usize), + inspects: i64, +} + +impl FromStr for Monkey { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + let lines = s.lines().collect::>(); + let items = lines[1].split_once(": ").unwrap().1.split(", ").map(|num| num.parse().unwrap()).collect(); + + let operation: Operation = lines[2].split_once("= ").unwrap().1.parse()?; + + let divisor = lines[3].rsplit_once(" ").unwrap().1.parse()?; + + let next_true = lines[4].rsplit_once(" ").unwrap().1.parse()?; + let next_false = lines[5].rsplit_once(" ").unwrap().1.parse()?; + + Ok(Self {items, operation, divisor, next: (next_true, next_false), inspects: 0}) + } +} + +fn step(monkeys: &mut Vec, div: i64, reducer: i64) { + for idx in 0..monkeys.len() { + let items = std::mem::take(&mut monkeys[idx].items); + for item in items { + // Calculate the new item value + let mut i = match monkeys[idx].operation { + Operation::Add(v) => item + v, + Operation::AddOld => item + item, + Operation::Multiply(v) => item * v, + Operation::MultiplyOld => item * item, + } / div; + + i %= reducer; + + // Increase the inspect counter for this monkey + monkeys[idx].inspects += 1; + + let next; + if i % monkeys[idx].divisor == 0 { + next = monkeys[idx].next.0; + } else { + next = monkeys[idx].next.1; + } + monkeys[next].items.push(i); + } + } +} + +fn solution(input: &str, rounds: i32, div: i64) -> i64 { + let mut monkeys: Vec = input.split("\n\n").map(|line| line.parse().unwrap()).collect(); + + let reducer = monkeys.iter().fold(1, |acc, monkey| lcm(acc, monkey.divisor)); + + for _ in 0..rounds { + step(&mut monkeys, div, reducer); + } + + let mut inspects = monkeys.iter().map(|monkey| monkey.inspects).collect::>(); + inspects.sort(); + + inspects.into_iter().rev().take(2).reduce(|acc, inspects| acc * inspects).unwrap() +} + +// -- Solution -- +pub struct Day; +impl aoc::Solver for Day { + type Output1 = i64; + type Output2 = i64; + + fn day() -> u8 { + 11 + } + + fn part1(input: &str) -> Self::Output1 { + solution(input, 20, 3) + } + + fn part2(input: &str) -> Self::Output2 { + solution(input, 10000, 1) + } +}