diff --git a/.aoc-cache/11.txt b/.aoc-cache/11.txt new file mode 100644 index 0000000..ac99361 --- /dev/null +++ b/.aoc-cache/11.txt @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 66, 71, 94 + Operation: new = old * 5 + Test: divisible by 3 + If true: throw to monkey 7 + If false: throw to monkey 4 + +Monkey 1: + Starting items: 70 + Operation: new = old + 6 + Test: divisible by 17 + If true: throw to monkey 3 + If false: throw to monkey 0 + +Monkey 2: + Starting items: 62, 68, 56, 65, 94, 78 + Operation: new = old + 5 + Test: divisible by 2 + If true: throw to monkey 3 + If false: throw to monkey 1 + +Monkey 3: + Starting items: 89, 94, 94, 67 + Operation: new = old + 2 + Test: divisible by 19 + If true: throw to monkey 7 + If false: throw to monkey 0 + +Monkey 4: + Starting items: 71, 61, 73, 65, 98, 98, 63 + Operation: new = old * 7 + Test: divisible by 11 + If true: throw to monkey 5 + If false: throw to monkey 6 + +Monkey 5: + Starting items: 55, 62, 68, 61, 60 + Operation: new = old + 7 + Test: divisible by 5 + If true: throw to monkey 2 + If false: throw to monkey 1 + +Monkey 6: + Starting items: 93, 91, 69, 64, 72, 89, 50, 71 + Operation: new = old + 1 + Test: divisible by 13 + If true: throw to monkey 5 + If false: throw to monkey 2 + +Monkey 7: + Starting items: 76, 50 + Operation: new = old * old + Test: divisible by 7 + If true: throw to monkey 4 + If false: throw to monkey 6 diff --git a/src/bin/day_11.rs b/src/bin/day_11.rs new file mode 100644 index 0000000..888a49c --- /dev/null +++ b/src/bin/day_11.rs @@ -0,0 +1,119 @@ +use std::collections::VecDeque; + +use aoc_2022::prelude::*; + +#[derive(Clone, Debug)] +enum Op { + Add(i128), + Mult(i128), + Sq, +} + +impl Op { + pub fn apply(&self, v: i128) -> i128 { + match self { + Op::Add(v2) => v + *v2, + Op::Mult(v2) => v * *v2, + Op::Sq => v * v, + } + } +} + +#[derive(Clone, Debug)] +struct Monkey { + starting_items: VecDeque, + op: Op, + test: i128, + tr: usize, + fal: usize, + inspected: usize, +} + +type Input = Vec; + +fn parse(s: &str) -> Result { + let mut monkeys = vec![]; + for monkey in s.split("\n\n") { + let lines = monkey.lines().collect::>(); + let starting_items = ints(lines[1]).into_iter().map(|v| v as i128).collect(); + let op = if lines[2].contains("old * old") { + Op::Sq + } else if lines[2].contains("+") { + Op::Add(ints(lines[2])[0] as i128) + } else { + Op::Mult(ints(lines[2])[0] as i128) + }; + let test = ints(lines[3])[0] as i128; + let tr = ints(lines[4])[0] as usize; + let fal = ints(lines[5])[0] as usize; + let monkey = Monkey { + starting_items, + op, + test, + tr, + fal, + inspected: 0, + }; + monkeys.push(monkey); + } + Ok(monkeys) +} + +#[aoc(day = 11, parse = parse, test_cases = ["day_11.txt"])] +fn day_11(input: Input) -> Result<()> { + // Part 1 + let mut monkeys = input.clone(); + for round in 0..20 { + for i in 0..monkeys.len() { + while let Some(item) = monkeys[i].starting_items.pop_front() { + monkeys[i].inspected += 1; + let (item, next) = { + let monkey = &monkeys[i]; + let item = monkey.op.apply(item); + let item = item / 3; + (item, if item % monkey.test == 0 { + monkey.tr + } else { + monkey.fal + }) + }; + monkeys[next].starting_items.push_back(item); + } + } + } + monkeys.sort_by_cached_key(|m| m.inspected); + monkeys.reverse(); + let monkey_business = monkeys[0].inspected * monkeys[1].inspected; + println!("Part one: {monkey_business}"); + + // Part 2 + let mut monkeys = input.clone(); + let mut md = 1; + for m in &input { + md *= m.test; + } + for round in 0..10_000 { + for i in 0..monkeys.len() { + while let Some(item) = monkeys[i].starting_items.pop_front() { + monkeys[i].inspected += 1; + let (item, next) = { + let monkey = &monkeys[i]; + let item = monkey.op.apply(item); + let item = item % md; + (item, if item % monkey.test == 0 { + monkey.tr + } else { + monkey.fal + }) + }; + monkeys[next].starting_items.push_back(item); + } + } + } + monkeys.sort_by_cached_key(|m| m.inspected); + monkeys.reverse(); + let monkey_business = monkeys[0].inspected * monkeys[1].inspected; + println!("Part two: {monkey_business}"); + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 84472aa..de4ef17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ use std::path::Path; use color_eyre::{eyre::eyre, Result}; +use regex::Regex; pub fn load_data Result>(day: u8, parse: F) -> Result { let s = fetch_input(day)?; @@ -35,6 +36,14 @@ pub fn fetch_input(day: u8) -> Result { } } +pub fn ints(s: &str) -> Vec { + let re = Regex::new("([1-9][0-9]*|0)").unwrap(); + + re.find_iter(s).map(|m| { + m.as_str().parse().unwrap() + }).collect() +} + /// A writer that does nothing. can be used to have conditional debugging. pub struct NullWriter; @@ -49,7 +58,7 @@ impl std::io::Write for NullWriter { } pub mod prelude { - pub use super::{data, load_data}; + pub use super::{data, ints, load_data}; pub use color_eyre::{eyre::{bail, eyre}, Result}; pub use aoc_proc::aoc; } diff --git a/test_cases/day_11.txt b/test_cases/day_11.txt new file mode 100644 index 0000000..30e09e5 --- /dev/null +++ b/test_cases/day_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