From 1a1dda4306a5e113010f7370150c60a742ebfaf4 Mon Sep 17 00:00:00 2001 From: Wesley Moore Date: Sun, 11 Dec 2022 22:05:35 +1000 Subject: [PATCH] Day 11 part 1 --- 2022/Cargo.lock | 18 +++++ 2022/Cargo.toml | 1 + 2022/input/day_11.txt | 55 ++++++++++++++ 2022/src/bin/day11.rs | 173 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 2022/input/day_11.txt create mode 100644 2022/src/bin/day11.rs diff --git a/2022/Cargo.lock b/2022/Cargo.lock index 325f0b8..b01508b 100644 --- a/2022/Cargo.lock +++ b/2022/Cargo.lock @@ -5,3 +5,21 @@ version = 3 [[package]] name = "advent-of-code" version = "0.1.0" +dependencies = [ + "regex", +] + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" diff --git a/2022/Cargo.toml b/2022/Cargo.toml index cb161c1..02d373c 100644 --- a/2022/Cargo.toml +++ b/2022/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +regex = { version = "1.7.0", default-features = false, features = ["std", "unicode-perl"] } diff --git a/2022/input/day_11.txt b/2022/input/day_11.txt new file mode 100644 index 0000000..809f96c --- /dev/null +++ b/2022/input/day_11.txt @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 57, 58 + Operation: new = old * 19 + Test: divisible by 7 + If true: throw to monkey 2 + If false: throw to monkey 3 + +Monkey 1: + Starting items: 66, 52, 59, 79, 94, 73 + Operation: new = old + 1 + Test: divisible by 19 + If true: throw to monkey 4 + If false: throw to monkey 6 + +Monkey 2: + Starting items: 80 + Operation: new = old + 6 + Test: divisible by 5 + If true: throw to monkey 7 + If false: throw to monkey 5 + +Monkey 3: + Starting items: 82, 81, 68, 66, 71, 83, 75, 97 + Operation: new = old + 5 + Test: divisible by 11 + If true: throw to monkey 5 + If false: throw to monkey 2 + +Monkey 4: + Starting items: 55, 52, 67, 70, 69, 94, 90 + Operation: new = old * old + Test: divisible by 17 + If true: throw to monkey 0 + If false: throw to monkey 3 + +Monkey 5: + Starting items: 69, 85, 89, 91 + Operation: new = old + 7 + Test: divisible by 13 + If true: throw to monkey 1 + If false: throw to monkey 7 + +Monkey 6: + Starting items: 75, 53, 73, 52, 75 + Operation: new = old * 7 + Test: divisible by 2 + If true: throw to monkey 0 + If false: throw to monkey 4 + +Monkey 7: + Starting items: 94, 60, 79 + Operation: new = old + 2 + Test: divisible by 3 + If true: throw to monkey 1 + If false: throw to monkey 6 diff --git a/2022/src/bin/day11.rs b/2022/src/bin/day11.rs new file mode 100644 index 0000000..3bc8db4 --- /dev/null +++ b/2022/src/bin/day11.rs @@ -0,0 +1,173 @@ +use regex::Regex; +use std::error::Error; + +#[derive(Debug)] +struct Monkey { + items: Vec, + op: Operation, + test: Test, + items_inspected: usize, +} + +#[derive(Debug)] +struct Operation { + operator: char, + operand1: Operand, + operand2: Operand, +} + +#[derive(Debug)] +struct Test { + divisible_by: isize, + if_true: usize, + if_false: usize, +} + +#[derive(Debug)] +enum Operand { + Old, + Const(isize), +} + +struct TurnResult { + if_true: (usize, Vec), + if_false: (usize, Vec), +} + +fn main() -> Result<(), Box> { + let input = std::fs::read_to_string("input/day_11.txt")?; + let re = Regex::new( + r"^Monkey \d: + Starting items: (?P.+) + Operation: new = (?P\w+) (?P.) (?P\w+) + Test: divisible by (?P
\d+) + If true: throw to monkey (?P\d+) + If false: throw to monkey (?P\d+)$", + )?; + + part1(&input, &re)?; + part2(&input)?; + + Ok(()) +} + +fn part1(input: &str, re: &Regex) -> Result<(), Box> { + let mut monkeys = input + .split("\n\n") + .map(|s| parse_monkey(s, re)) + .collect::, _>>()?; + for _round in 0..20 { + for i in 0..monkeys.len() { + take_turn(i, &mut monkeys) + } + } + + monkeys.sort_by(|a, b| a.items_inspected.cmp(&b.items_inspected)); + let monkey_business = + monkeys[monkeys.len() - 2].items_inspected * monkeys[monkeys.len() - 1].items_inspected; + + println!("Monkey business: {}", monkey_business); + + Ok(()) +} + +fn part2(input: &str) -> Result<(), Box> { + Ok(()) +} + +fn parse_monkey(input: &str, re: &Regex) -> Result> { + let caps = re + .captures(input.trim()) + .ok_or_else(|| format!("text did not match regex: {}", input))?; + let items = caps + .name("items") + .unwrap() + .as_str() + .split(", ") + .map(|item| item.parse()) + .collect::, _>>()?; + let opa = parse_operand(caps.name("opa").unwrap().as_str())?; + let opb = parse_operand(caps.name("opb").unwrap().as_str())?; + let op = caps.name("op").unwrap().as_str().chars().next().unwrap(); + let div = caps.name("div").unwrap().as_str().parse()?; + let if_true = caps.name("if_true").unwrap().as_str().parse()?; + let if_false = caps.name("if_false").unwrap().as_str().parse()?; + + Ok(Monkey { + items, + op: Operation { + operator: op, + operand1: opa, + operand2: opb, + }, + test: Test { + divisible_by: div, + if_true, + if_false, + }, + items_inspected: 0, + }) +} + +fn parse_operand(input: &str) -> Result> { + match input { + "old" => Ok(Operand::Old), + otherwise => { + let val = otherwise.parse()?; + Ok(Operand::Const(val)) + } + } +} + +fn take_turn(i: usize, monkeys: &mut [Monkey]) { + let mut res = monkeys[i].take_turn(); + monkeys[res.if_true.0].items.append(&mut res.if_true.1); + monkeys[res.if_false.0].items.append(&mut res.if_false.1); +} + +impl Monkey { + fn take_turn(&mut self) -> TurnResult { + let mut if_true = Vec::new(); + let mut if_false = Vec::new(); + + for item in self.items.iter().copied() { + let new = self.op.eval(item) / 3; + if self.test.test(new) { + if_true.push(new); + } else { + if_false.push(new); + } + } + self.items_inspected += self.items.len(); + self.items.clear(); + TurnResult { + if_true: (self.test.if_true, if_true), + if_false: (self.test.if_false, if_false), + } + } +} + +impl Operation { + fn eval(&self, old: isize) -> isize { + match self.operator { + '+' => self.operand1.val(old) + self.operand2.val(old), + '*' => self.operand1.val(old) * self.operand2.val(old), + _ => unreachable!("unknown op"), + } + } +} + +impl Operand { + fn val(&self, old: isize) -> isize { + match self { + Operand::Old => old, + Operand::Const(v) => *v, + } + } +} + +impl Test { + fn test(&self, item: isize) -> bool { + item % self.divisible_by == 0 + } +}