diff --git a/src/day11/1.rs b/src/day11/1.rs new file mode 100644 index 0000000..4203218 --- /dev/null +++ b/src/day11/1.rs @@ -0,0 +1,133 @@ +#![feature(test)] + +use std::{cmp::Reverse, rc::Rc}; +extern crate test; + +const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")]; + +#[derive(Clone)] +struct Monkey { + items: Vec, + operation: Rc usize>>, + div_by_test: usize, + if_true: usize, + if_false: usize, +} + +fn parse(input: &'static str) -> Vec { + input + .split("\n\n") + .filter(|c| !c.is_empty()) + .map(|set| { + let mut lines = set.lines().skip(1); + + let sitems: Vec = lines + .next() + .unwrap() + .split(',') + .map(|c| { + c.chars() + .filter(|c| c.is_numeric()) + .fold(0, |a, x| (a * 10) + (x as u8 - b'0') as usize) + }) + .collect(); + + let op = lines.next().unwrap(); + let nop = op + .bytes() + .filter(|c| (b'0'..=b'9').contains(c)) + .fold(0, |a, x| (a * 10) + (x - b'0') as usize); + + let op = move |old: usize| -> usize { + if op.contains("old * old") { + old * old + } else if op.contains("old +") { + old + nop + } else if op.contains("old *") { + old * nop + } else { + unreachable!() + } + }; + + let test = lines + .next() + .unwrap() + .bytes() + .filter(|c| (b'0'..=b'9').contains(c)) + .fold(0, |a, x| (a * 10) + (x - b'0') as usize); + + let true_result = lines + .next() + .unwrap() + .bytes() + .filter(|c| (b'0'..=b'9').contains(c)) + .fold(0, |a, x| (a * 10) + (x - b'0') as usize); + + let false_result = lines + .next() + .unwrap() + .bytes() + .filter(|c| (b'0'..=b'9').contains(c)) + .fold(0, |a, x| (a * 10) + (x - b'0') as usize); + + Monkey { + items: sitems, + operation: Rc::new(Box::new(op)), + div_by_test: test, + if_true: true_result, + if_false: false_result, + } + // + }) + .collect() +} + +fn main() { + for input in INPUTS.iter() { + let output = parse(input); + let score = solution(output); + println!("{}", score); + } +} + +fn solution(mut input: Vec) -> usize { + let mlen = input.len(); + let mut activity = vec![0; mlen]; + + for _ in 0..20 { + for i in 0..mlen { + let monkey = &input[i].clone(); + let ilen = monkey.items.len(); + + for j in 0..ilen { + let item = monkey.items[j]; + + let newwlevel = (monkey.operation)(item); + let calmed_down_level = newwlevel / 3; + + if calmed_down_level % monkey.div_by_test == 0 { + input[monkey.if_true].items.push(calmed_down_level); + } else { + input[monkey.if_false].items.push(calmed_down_level); + } + + activity[i] += 1; + } + input[i].items.clear(); + } + } + + activity.select_nth_unstable_by_key(1, |c| Reverse(*c)); + + activity[0] * activity[1] +} + +#[bench] +fn solution_bench(b: &mut test::Bencher) { + b.iter(|| { + let input = parse(INPUTS[1]); + let result = solution(input); + test::black_box(result); + }) +} diff --git a/src/day11/2.rs b/src/day11/2.rs new file mode 100644 index 0000000..411cb2c --- /dev/null +++ b/src/day11/2.rs @@ -0,0 +1,146 @@ +#![feature(test)] + +use std::cmp::Reverse; +extern crate test; + +const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")]; + +#[derive(Clone)] +struct Monkey { + items: Vec, + operation: Operation, + div_by_test: usize, + if_true: usize, + if_false: usize, +} + +#[derive(Clone, Debug, Copy)] +enum Operation { + MulOld, + MulNop(usize), + AddNop(usize), +} + +impl Operation { + fn apply(&self, v: usize) -> usize { + match self { + Operation::MulOld => v * v, + Operation::MulNop(i) => v * i, + Operation::AddNop(i) => v + i, + } + } +} + +fn parse(input: &'static str) -> (Vec, usize) { + let mut lcm = 1; + let output = input + .split("\n\n") + .filter(|c| !c.is_empty()) + .map(|set| { + let mut lines = set.lines().skip(1); + + let sitems: Vec = lines.next().unwrap()[18..] + .split(',') + .map(|c| { + c.bytes() + .filter(|&c| c != b' ') + .fold(0, |a, x| (a * 10) + (x - b'0') as usize) + }) + .collect(); + + let op = match lines.next().unwrap()[23..].split_at(1) { + ("*", " old") => Operation::MulOld, + ("+", v) => Operation::AddNop( + v[1..] + .bytes() + .fold(0, |a, x| (a * 10) + (x - b'0') as usize), + ), + ("*", v) => Operation::MulNop( + v[1..] + .bytes() + .fold(0, |a, x| (a * 10) + (x - b'0') as usize), + ), + (_, _) => unreachable!(), + }; + + let test = lines.next().unwrap()[21..] + .bytes() + .fold(0, |a, x| (a * 10) + (x - b'0') as usize); + + let true_result = lines.next().unwrap()[29..] + .bytes() + .fold(0, |a, x| (a * 10) + (x - b'0') as usize); + + let false_result = lines.next().unwrap()[30..] + .bytes() + .fold(0, |a, x| (a * 10) + (x - b'0') as usize); + + lcm = lcm * test / gcd(lcm, test); + + Monkey { + items: sitems, + operation: op, + div_by_test: test, + if_true: true_result, + if_false: false_result, + } + }) + .collect(); + + (output, lcm) +} + +fn main() { + for input in INPUTS.iter() { + let output = parse(input); + let score = solution(output.0, output.1); + println!("{}", score); + } +} + +fn solution(mut input: Vec, lcm: usize) -> usize { + let mlen = input.len(); + let mut activity = [0; 8]; + + for _ in 0..10000 { + for i in 0..mlen { + activity[i] += input[i].items.len(); + let if_true = input[i].if_true; + let if_false = input[i].if_false; + let operation = input[i].operation; + let div_by_test = input[i].div_by_test; + + while let Some(item) = input[i].items.pop() { + let newwlevel = operation.apply(item); + let newwlevel = newwlevel % lcm; + + if newwlevel % div_by_test == 0 { + input[if_true].items.push(newwlevel); + } else { + input[if_false].items.push(newwlevel); + } + } + } + } + + activity.select_nth_unstable_by_key(1, |c| Reverse(*c)); + + activity[0] * activity[1] +} + +#[bench] +fn solution_bench(b: &mut test::Bencher) { + b.iter(|| { + let input = parse(INPUTS[1]); + let result = solution(input.0, input.1); + test::black_box(result); + }) +} + +#[inline] +const fn gcd(a: usize, b: usize) -> usize { + if b == 0 { + return a; + } + gcd(b, a % b) +} diff --git a/src/day11/input.txt b/src/day11/input.txt new file mode 100644 index 0000000..a458ed3 --- /dev/null +++ b/src/day11/input.txt @@ -0,0 +1,56 @@ +Monkey 0: + Starting items: 83, 97, 95, 67 + Operation: new = old * 19 + Test: divisible by 17 + If true: throw to monkey 2 + If false: throw to monkey 7 + +Monkey 1: + Starting items: 71, 70, 79, 88, 56, 70 + Operation: new = old + 2 + Test: divisible by 19 + If true: throw to monkey 7 + If false: throw to monkey 0 + +Monkey 2: + Starting items: 98, 51, 51, 63, 80, 85, 84, 95 + Operation: new = old + 7 + Test: divisible by 7 + If true: throw to monkey 4 + If false: throw to monkey 3 + +Monkey 3: + Starting items: 77, 90, 82, 80, 79 + Operation: new = old + 1 + Test: divisible by 11 + If true: throw to monkey 6 + If false: throw to monkey 4 + +Monkey 4: + Starting items: 68 + Operation: new = old * 5 + Test: divisible by 13 + If true: throw to monkey 6 + If false: throw to monkey 5 + +Monkey 5: + Starting items: 60, 94 + Operation: new = old + 5 + Test: divisible by 3 + If true: throw to monkey 1 + If false: throw to monkey 0 + +Monkey 6: + Starting items: 81, 51, 85 + Operation: new = old * old + Test: divisible by 5 + If true: throw to monkey 5 + If false: throw to monkey 1 + +Monkey 7: + Starting items: 98, 81, 63, 65, 84, 71, 84 + Operation: new = old + 3 + Test: divisible by 2 + If true: throw to monkey 2 + If false: throw to monkey 3 + diff --git a/src/day11/sample.txt b/src/day11/sample.txt new file mode 100644 index 0000000..30e09e5 --- /dev/null +++ b/src/day11/sample.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