From 273a54b4cacc71b8fe0568f036fa6e0d863f6558 Mon Sep 17 00:00:00 2001 From: Patrick Auernig Date: Tue, 13 Dec 2022 18:07:45 +0100 Subject: [PATCH] Add solution for 2022 day 11 part 1 --- 2022/Cargo.lock | 7 ++ 2022/Cargo.toml | 1 + 2022/README.md | 2 +- 2022/day-11/Cargo.toml | 13 +++ 2022/day-11/Justfile | 5 ++ 2022/day-11/inputs/puzzle.txt | 55 +++++++++++++ 2022/day-11/inputs/test.txt | 27 +++++++ 2022/day-11/src/bin/part_one.rs | 87 ++++++++++++++++++++ 2022/day-11/src/lib.rs | 136 ++++++++++++++++++++++++++++++++ README.md | 2 +- 10 files changed, 333 insertions(+), 2 deletions(-) create mode 100644 2022/day-11/Cargo.toml create mode 100644 2022/day-11/Justfile create mode 100644 2022/day-11/inputs/puzzle.txt create mode 100644 2022/day-11/inputs/test.txt create mode 100644 2022/day-11/src/bin/part_one.rs create mode 100644 2022/day-11/src/lib.rs diff --git a/2022/Cargo.lock b/2022/Cargo.lock index 4a47273..c13379a 100644 --- a/2022/Cargo.lock +++ b/2022/Cargo.lock @@ -48,6 +48,13 @@ version = "0.1.0" name = "aoc-2022-10" version = "0.1.0" +[[package]] +name = "aoc-2022-11" +version = "0.1.0" +dependencies = [ + "itertools", +] + [[package]] name = "either" version = "1.8.0" diff --git a/2022/Cargo.toml b/2022/Cargo.toml index 0b4585e..e8d12cf 100644 --- a/2022/Cargo.toml +++ b/2022/Cargo.toml @@ -10,6 +10,7 @@ members = [ "./day-08", "./day-09", "./day-10", + "./day-11", ] diff --git a/2022/README.md b/2022/README.md index 8d62af3..ce3757e 100644 --- a/2022/README.md +++ b/2022/README.md @@ -14,7 +14,7 @@ | [08] | ✓ | ✓ | [Rust] | | [09] | ✓ | ✓ | [Rust] | | [10] | ✓ | ✓ | [Rust] | -| [11] | | | | +| [11] | ✓ | | [Rust] | | [12] | | | | | [13] | | | | | [14] | | | | diff --git a/2022/day-11/Cargo.toml b/2022/day-11/Cargo.toml new file mode 100644 index 0000000..f598d1a --- /dev/null +++ b/2022/day-11/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "aoc-2022-11" +version = "0.1.0" +edition = "2021" + + +[lib] +test = false +doctest = false + + +[dependencies] +itertools = "0.10.5" diff --git a/2022/day-11/Justfile b/2022/day-11/Justfile new file mode 100644 index 0000000..7d08527 --- /dev/null +++ b/2022/day-11/Justfile @@ -0,0 +1,5 @@ +@part PART INPUT_FILE="inputs/puzzle.txt": + cargo --quiet run --bin part_{{PART}} -- {{INPUT_FILE}} + +clean: + cargo clean diff --git a/2022/day-11/inputs/puzzle.txt b/2022/day-11/inputs/puzzle.txt new file mode 100644 index 0000000..49a33e8 --- /dev/null +++ b/2022/day-11/inputs/puzzle.txt @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 99, 63, 76, 93, 54, 73 + Operation: new = old * 11 + Test: divisible by 2 + If true: throw to monkey 7 + If false: throw to monkey 1 + +Monkey 1: + Starting items: 91, 60, 97, 54 + Operation: new = old + 1 + Test: divisible by 17 + If true: throw to monkey 3 + If false: throw to monkey 2 + +Monkey 2: + Starting items: 65 + Operation: new = old + 7 + Test: divisible by 7 + If true: throw to monkey 6 + If false: throw to monkey 5 + +Monkey 3: + Starting items: 84, 55 + Operation: new = old + 3 + Test: divisible by 11 + If true: throw to monkey 2 + If false: throw to monkey 6 + +Monkey 4: + Starting items: 86, 63, 79, 54, 83 + Operation: new = old * old + Test: divisible by 19 + If true: throw to monkey 7 + If false: throw to monkey 0 + +Monkey 5: + Starting items: 96, 67, 56, 95, 64, 69, 96 + Operation: new = old + 4 + Test: divisible by 5 + If true: throw to monkey 4 + If false: throw to monkey 0 + +Monkey 6: + Starting items: 66, 94, 70, 93, 72, 67, 88, 51 + Operation: new = old * 5 + Test: divisible by 13 + If true: throw to monkey 4 + If false: throw to monkey 5 + +Monkey 7: + Starting items: 59, 59, 74 + Operation: new = old + 8 + Test: divisible by 3 + If true: throw to monkey 1 + If false: throw to monkey 3 \ No newline at end of file diff --git a/2022/day-11/inputs/test.txt b/2022/day-11/inputs/test.txt new file mode 100644 index 0000000..c04eddb --- /dev/null +++ b/2022/day-11/inputs/test.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 \ No newline at end of file diff --git a/2022/day-11/src/bin/part_one.rs b/2022/day-11/src/bin/part_one.rs new file mode 100644 index 0000000..0e5c7e9 --- /dev/null +++ b/2022/day-11/src/bin/part_one.rs @@ -0,0 +1,87 @@ +use std::{ + collections::{BTreeMap, HashMap}, + env, io, +}; + +use itertools::Itertools; + +use aoc_2022_11::parse_input; + +fn main() -> io::Result<()> { + let infile_path = env::args().nth(1).expect("input file"); + + let result = solve(&infile_path)?; + + println!("{result}"); + + Ok(()) +} + +fn solve(path: &str) -> io::Result { + let notes = parse_input(path)?; + + let mut activity_counter = HashMap::::new(); + let mut state = notes + .iter() + .enumerate() + .map(|(i, v)| (i, v.items.clone())) + .collect::>(); + + for _ in 0..20 { + for monkey_id in 0..state.len() { + let items = { + let state = state.get_mut(&monkey_id).unwrap(); + state.drain(..).collect::>() + }; + + for item in items { + activity_counter + .entry(monkey_id) + .and_modify(|v| *v += 1) + .or_insert(1); + + let note = ¬es[monkey_id]; + + let new_value = note.operation.apply(item) / 3; + + let next_monkey = if new_value % note.test_mod == 0 { + note.next_monkey_when_true + } else { + note.next_monkey_when_false + }; + + state + .entry(next_monkey) + .and_modify(|f| f.push(new_value)) + .or_insert_with(|| vec![new_value]); + } + } + } + + let most_active_product = activity_counter + .values() + .sorted_by(|a, b| b.cmp(a)) + .take(2) + .copied() + .reduce(|acc, val| acc * val) + .unwrap(); + + Ok(most_active_product) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn sample() { + let result = solve("inputs/test.txt").unwrap(); + assert_eq!(10_605, result) + } + + #[test] + fn puzzle() { + let result = solve("inputs/puzzle.txt").unwrap(); + assert_eq!(316_888, result); + } +} diff --git a/2022/day-11/src/lib.rs b/2022/day-11/src/lib.rs new file mode 100644 index 0000000..1f9ebf6 --- /dev/null +++ b/2022/day-11/src/lib.rs @@ -0,0 +1,136 @@ +use std::{ + fs::File, + io::{self, Read}, + path::Path, +}; + +pub type WorryLevel = u64; +pub type MonkeyId = usize; + +#[derive(Debug)] +pub enum Param { + Old, + Val(WorryLevel), +} + +#[derive(Debug)] +pub enum Operation { + Mul(Param, Param), + Add(Param, Param), + Noop, +} + +impl Operation { + pub fn apply(&self, old: WorryLevel) -> WorryLevel { + match self { + Self::Mul(Param::Old, Param::Val(val)) => old * val, + Self::Mul(Param::Old, Param::Old) => old * old, + Self::Add(Param::Old, Param::Val(val)) => old + val, + Self::Add(Param::Old, Param::Old) => old + old, + _ => panic!("unsupported operation"), + } + } +} + +#[derive(Debug)] +pub struct Note { + pub items: Vec, + pub operation: Operation, + pub test_mod: WorryLevel, + pub next_monkey_when_true: MonkeyId, + pub next_monkey_when_false: MonkeyId, +} + +pub fn parse_input

(path: P) -> io::Result> +where + P: AsRef, +{ + let mut file = File::open(path)?; + let mut input = String::new(); + file.read_to_string(&mut input)?; + + let notes = input.split("\n\n").map(|part| parse_note(part)).collect(); + + Ok(notes) +} + +fn parse_note(input: &str) -> Note { + let mut items = vec![]; + let mut operation = Operation::Noop; + let mut test_mod = 0; + let mut next_monkey_when_true = 0; + let mut next_monkey_when_false = 0; + + for line in input.lines() { + let line = line.trim_start(); + let (val, rem) = line.split_once(':').unwrap(); + + match val { + "Starting items" => { + items = parse_starting_items(rem); + } + "Operation" => { + operation = parse_operation(rem); + } + "Test" => { + test_mod = parse_test(rem); + } + "If true" => { + next_monkey_when_true = parse_next_monkey(rem); + } + "If false" => { + next_monkey_when_false = parse_next_monkey(rem); + } + _ => (), + } + } + + Note { + items, + operation, + test_mod, + next_monkey_when_true, + next_monkey_when_false, + } +} + +fn parse_starting_items(input: &str) -> Vec { + input + .split(',') + .map(|val| val.trim_start().parse().unwrap()) + .collect() +} + +fn parse_operation(input: &str) -> Operation { + let input = input.strip_prefix(" new = old ").unwrap(); + let op_and_val = input.split_whitespace().collect::>(); + match *op_and_val { + ["*", "old"] => Operation::Mul(Param::Old, Param::Old), + ["*", val] => { + let val = val.parse().unwrap(); + Operation::Mul(Param::Old, Param::Val(val)) + } + ["+", "old"] => Operation::Add(Param::Old, Param::Old), + ["+", val] => { + let val = val.parse().unwrap(); + Operation::Add(Param::Old, Param::Val(val)) + } + _ => panic!("Unsupported operation"), + } +} + +fn parse_test(input: &str) -> WorryLevel { + input + .strip_prefix(" divisible by ") + .unwrap() + .parse() + .unwrap() +} + +fn parse_next_monkey(input: &str) -> MonkeyId { + input + .strip_prefix(" throw to monkey ") + .unwrap() + .parse() + .unwrap() +} diff --git a/README.md b/README.md index bcbb952..04f0986 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,4 @@ - [2019](2019/README.md) (0% completed) - [2020](2020/README.md) (20% completed) - [2021](2021/README.md) (68% completed) -- [2022](2022/README.md) (40% completed) +- [2022](2022/README.md) (42% completed)