diff --git a/day11/Cargo.lock b/day11/Cargo.lock new file mode 100644 index 0000000..4ab9be8 --- /dev/null +++ b/day11/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "day11" +version = "0.1.0" diff --git a/day11/Cargo.toml b/day11/Cargo.toml new file mode 100644 index 0000000..8f5b9a5 --- /dev/null +++ b/day11/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "day11" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/day11/input.txt b/day11/input.txt new file mode 100644 index 0000000..ef22f88 --- /dev/null +++ b/day11/input.txt @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 66, 79 + Operation: new = old * 11 + Test: divisible by 7 + If true: throw to monkey 6 + If false: throw to monkey 7 + +Monkey 1: + Starting items: 84, 94, 94, 81, 98, 75 + Operation: new = old * 17 + Test: divisible by 13 + If true: throw to monkey 5 + If false: throw to monkey 2 + +Monkey 2: + Starting items: 85, 79, 59, 64, 79, 95, 67 + Operation: new = old + 8 + Test: divisible by 5 + If true: throw to monkey 4 + If false: throw to monkey 5 + +Monkey 3: + Starting items: 70 + Operation: new = old + 3 + Test: divisible by 19 + If true: throw to monkey 6 + If false: throw to monkey 0 + +Monkey 4: + Starting items: 57, 69, 78, 78 + Operation: new = old + 4 + Test: divisible by 2 + If true: throw to monkey 0 + If false: throw to monkey 3 + +Monkey 5: + Starting items: 65, 92, 60, 74, 72 + Operation: new = old + 7 + Test: divisible by 11 + If true: throw to monkey 3 + If false: throw to monkey 4 + +Monkey 6: + Starting items: 77, 91, 91 + Operation: new = old * old + Test: divisible by 17 + If true: throw to monkey 1 + If false: throw to monkey 7 + +Monkey 7: + Starting items: 76, 58, 57, 55, 67, 77, 54, 99 + Operation: new = old + 6 + Test: divisible by 3 + If true: throw to monkey 2 + If false: throw to monkey 1 diff --git a/day11/src/main.rs b/day11/src/main.rs new file mode 100644 index 0000000..543560c --- /dev/null +++ b/day11/src/main.rs @@ -0,0 +1,158 @@ +use std::num::ParseIntError; +use std::env; +use std::fs::File; +use std::io::{self, BufRead, Lines}; +use std::collections::VecDeque; + +#[derive(Debug)] +enum Operator { Add, Mul } +#[derive(Debug)] +enum Operand { Old, Imm(u64) } + +#[derive(Debug)] +struct Operation { left: Operand, op: Operator, right: Operand } +impl Operation { + fn perform(&self, old: u64) -> u64 { + let left = match self.left { + Operand::Old => old, + Operand::Imm(x) => x, + }; + let right = match self.right { + Operand::Old => old, + Operand::Imm(x) => x, + }; + match self.op { + Operator::Add => left + right, + Operator::Mul => left * right, + } + } +} + +#[derive(Debug)] +struct Monkey { + id: u64, + items: VecDeque, + operation: Operation, + div_by_test: u64, + true_throw: u64, + false_throw: u64, +} + +#[derive(Debug)] +enum MonkeyError { + ParseError(), + ParseIntError(ParseIntError), + IoError(io::Error), +} +impl From for MonkeyError { + fn from(e: ParseIntError) -> Self { MonkeyError::ParseIntError(e) } +} +impl From for MonkeyError { + fn from(e: io::Error) -> Self { MonkeyError::IoError(e) } +} + +fn parse_monkey( + lines: &mut Lines +) -> Result, MonkeyError> { + let id = match lines.next() { + Some(line) => line? + .strip_prefix("Monkey ").ok_or(MonkeyError::ParseError())? + .strip_suffix(":").ok_or(MonkeyError::ParseError())? + .parse::()?, + None => return Ok(None), + }; + + let starting_items = lines.next().ok_or(MonkeyError::ParseError())?? + .strip_prefix(" Starting items: ").ok_or(MonkeyError::ParseError())? + .split(", ") + .map(|item| item.parse::()) + .collect::, _>>()?; + + let op_line = lines.next().ok_or(MonkeyError::ParseError())??; + let op_vec = op_line + .strip_prefix(" Operation: new = ").ok_or(MonkeyError::ParseError())? + .split(' ').collect::>(); + let (left, operator, right) = (op_vec[0], op_vec[1], op_vec[2]); + let operation = Operation { + left: match left { + "old" => Operand::Old, + _ => Operand::Imm(left.parse()?) + }, + op: match operator { + "+" => Ok(Operator::Add), + "*" => Ok(Operator::Mul), + _ => Err(MonkeyError::ParseError()) + }?, + right: match right { + "old" => Operand::Old, + _ => Operand::Imm(right.parse()?) + }, + }; + + let test_val = lines.next().ok_or(MonkeyError::ParseError())?? + .strip_prefix(" Test: divisible by ").ok_or(MonkeyError::ParseError())? + .parse::()?; + + let true_throw = lines.next().ok_or(MonkeyError::ParseError())?? + .strip_prefix(" If true: throw to monkey ") + .ok_or(MonkeyError::ParseError())? + .parse::()?; + let false_throw = lines.next().ok_or(MonkeyError::ParseError())?? + .strip_prefix(" If false: throw to monkey ") + .ok_or(MonkeyError::ParseError())? + .parse::()?; + + // Remove empty line if exists + match lines.next() { + None => Ok(()), + Some(Err(e)) => Err(e), + Some(Ok(s)) => Ok(match s.as_str() { + "" => Ok(()), + _ => Err(MonkeyError::ParseError()), + }?), + }?; + + Ok(Some(Monkey { + id: id, + items: starting_items, + operation: operation, + div_by_test: test_val, + true_throw: true_throw, + false_throw: false_throw, + }) +)} + +fn main() { + let file = File::open(&env::args().nth(1).unwrap()).unwrap(); + let mut lines = io::BufReader::new(file).lines(); + let mut monkeys: Vec = Vec::new(); + + loop { + match parse_monkey(&mut lines) { + Ok(None) => break, + Ok(Some(m)) => { assert!(m.id == monkeys.len() as u64); monkeys.push(m) }, + Err(e) => eprintln!("{:?}", e), + } + } + let mut monkey_item_counts = vec![0; monkeys.len()]; + + for _round in 1..=20 { + for i in 0..monkeys.len() { + monkey_item_counts[i] += monkeys[i].items.len(); + + for _item in 0..monkeys[i].items.len() { + let old_item = monkeys[i].items.pop_front().unwrap(); + let new_item = monkeys[i].operation.perform(old_item) / 3; + let new_i = if new_item % monkeys[i].div_by_test == 0 { + monkeys[i].true_throw + } else { + monkeys[i].false_throw + } as usize; + monkeys[new_i].items.push_back(new_item); + } + } + } + monkey_item_counts.sort_by(|x, y| y.cmp(x)); + println!("{:?}", monkey_item_counts[0]*monkey_item_counts[1]); +} + diff --git a/day11/test.txt b/day11/test.txt new file mode 100644 index 0000000..30e09e5 --- /dev/null +++ b/day11/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