summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShivesh Mandalia <mail@shivesh.org>2023-01-01 19:36:55 +0000
committerShivesh Mandalia <mail@shivesh.org>2023-01-01 19:36:55 +0000
commit55193703cff35373f291e5243330f038d9fc62e7 (patch)
treead236d2cc877a99f117f0021968f0618000706a9
parent67a326403f50929586fc27bc845fc4a4290ec1ec (diff)
downloadadvent_of_code_2022-55193703cff35373f291e5243330f038d9fc62e7.tar.gz
advent_of_code_2022-55193703cff35373f291e5243330f038d9fc62e7.zip
complete day 11
-rw-r--r--Cargo.lock18
-rw-r--r--Cargo.toml4
-rw-r--r--day11a/Cargo.toml11
-rw-r--r--day11a/examples/input.txt55
-rw-r--r--day11a/examples/test.txt27
-rw-r--r--day11a/src/main.rs438
-rw-r--r--day11b/Cargo.toml11
-rw-r--r--day11b/examples/input.txt55
-rw-r--r--day11b/examples/test.txt27
-rw-r--r--day11b/src/main.rs284
10 files changed, 928 insertions, 2 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d52e5c0..c636331 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -232,6 +232,24 @@ dependencies = [
]
[[package]]
+name = "day11a"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "itertools",
+ "nom",
+]
+
+[[package]]
+name = "day11b"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "itertools",
+ "nom",
+]
+
+[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index e42621b..c0bc003 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,8 +21,8 @@ members = [
"day09b",
"day10a",
"day10b",
- # "day11a",
- # "day11b",
+ "day11a",
+ "day11b",
# "day12a",
# "day12b",
# "day13a",
diff --git a/day11a/Cargo.toml b/day11a/Cargo.toml
new file mode 100644
index 0000000..0247f4b
--- /dev/null
+++ b/day11a/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "day11a"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+clap = { version = "3.2.20", features = ["derive"] }
+nom = "7.1.1"
+itertools = "0.10.5"
diff --git a/day11a/examples/input.txt b/day11a/examples/input.txt
new file mode 100644
index 0000000..26026b5
--- /dev/null
+++ b/day11a/examples/input.txt
@@ -0,0 +1,55 @@
+Monkey 0:
+ Starting items: 59, 74, 65, 86
+ Operation: new = old * 19
+ Test: divisible by 7
+ If true: throw to monkey 6
+ If false: throw to monkey 2
+
+Monkey 1:
+ Starting items: 62, 84, 72, 91, 68, 78, 51
+ Operation: new = old + 1
+ Test: divisible by 2
+ If true: throw to monkey 2
+ If false: throw to monkey 0
+
+Monkey 2:
+ Starting items: 78, 84, 96
+ Operation: new = old + 8
+ Test: divisible by 19
+ If true: throw to monkey 6
+ If false: throw to monkey 5
+
+Monkey 3:
+ Starting items: 97, 86
+ Operation: new = old * old
+ Test: divisible by 3
+ If true: throw to monkey 1
+ If false: throw to monkey 0
+
+Monkey 4:
+ Starting items: 50
+ Operation: new = old + 6
+ Test: divisible by 13
+ If true: throw to monkey 3
+ If false: throw to monkey 1
+
+Monkey 5:
+ Starting items: 73, 65, 69, 65, 51
+ Operation: new = old * 17
+ Test: divisible by 11
+ If true: throw to monkey 4
+ If false: throw to monkey 7
+
+Monkey 6:
+ Starting items: 69, 82, 97, 93, 82, 84, 58, 63
+ Operation: new = old + 5
+ Test: divisible by 5
+ If true: throw to monkey 5
+ If false: throw to monkey 7
+
+Monkey 7:
+ Starting items: 81, 78, 82, 76, 79, 80
+ Operation: new = old + 3
+ Test: divisible by 17
+ If true: throw to monkey 3
+ If false: throw to monkey 4
diff --git a/day11a/examples/test.txt b/day11a/examples/test.txt
new file mode 100644
index 0000000..30e09e5
--- /dev/null
+++ b/day11a/examples/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
diff --git a/day11a/src/main.rs b/day11a/src/main.rs
new file mode 100644
index 0000000..ad0d2cd
--- /dev/null
+++ b/day11a/src/main.rs
@@ -0,0 +1,438 @@
+/// --- Day 11: Monkey in the Middle ---
+///
+/// As you finally start making your way upriver, you realize your pack is much lighter than you
+/// remember. Just then, one of the items from your pack goes flying overhead. Monkeys are
+/// playing Keep Away with your missing things!
+///
+/// To get your stuff back, you need to be able to predict where the monkeys will throw your
+/// items. After some careful observation, you realize the monkeys operate based on how worried
+/// you are about each item.
+///
+/// You take some notes (your puzzle input) on the items each monkey currently has, how worried you
+/// are about those items, and how the monkey makes decisions based on your worry level. For
+/// example:
+///
+/// ```
+/// 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
+/// ```
+///
+/// Each monkey has several attributes:
+///
+/// Starting items lists your worry level for each item the monkey is currently holding in the
+/// order they will be inspected.
+/// Operation shows how your worry level changes as that monkey inspects an item. (An operation
+/// like new = old * 5 means that your worry level after the monkey inspected the item is five
+/// times whatever your worry level was before inspection.)
+/// Test shows how the monkey uses your worry level to decide where to throw an item next.
+/// If true shows what happens with an item if the Test was true.
+/// If false shows what happens with an item if the Test was false.
+///
+/// After each monkey inspects an item but before it tests your worry level, your relief that the
+/// monkey's inspection didn't damage the item causes your worry level to be divided by three and
+/// rounded down to the nearest integer.
+///
+/// The monkeys take turns inspecting and throwing items. On a single monkey's turn, it inspects
+/// and throws all of the items it is holding one at a time and in the order listed. Monkey 0 goes
+/// first, then monkey 1, and so on until each monkey has had one turn. The process of each monkey
+/// taking a single turn is called a round.
+///
+/// When a monkey throws an item to another monkey, the item goes on the end of the recipient
+/// monkey's list. A monkey that starts a round with no items could end up inspecting and throwing
+/// many items by the time its turn comes around. If a monkey is holding no items at the start of
+/// its turn, its turn ends.
+///
+/// In the above example, the first round proceeds as follows:
+///
+/// ```
+/// Monkey 0:
+/// Monkey inspects an item with a worry level of 79.
+/// Worry level is multiplied by 19 to 1501.
+/// Monkey gets bored with item. Worry level is divided by 3 to 500.
+/// Current worry level is not divisible by 23.
+/// Item with worry level 500 is thrown to monkey 3.
+/// Monkey inspects an item with a worry level of 98.
+/// Worry level is multiplied by 19 to 1862.
+/// Monkey gets bored with item. Worry level is divided by 3 to 620.
+/// Current worry level is not divisible by 23.
+/// Item with worry level 620 is thrown to monkey 3.
+/// Monkey 1:
+/// Monkey inspects an item with a worry level of 54.
+/// Worry level increases by 6 to 60.
+/// Monkey gets bored with item. Worry level is divided by 3 to 20.
+/// Current worry level is not divisible by 19.
+/// Item with worry level 20 is thrown to monkey 0.
+/// Monkey inspects an item with a worry level of 65.
+/// Worry level increases by 6 to 71.
+/// Monkey gets bored with item. Worry level is divided by 3 to 23.
+/// Current worry level is not divisible by 19.
+/// Item with worry level 23 is thrown to monkey 0.
+/// Monkey inspects an item with a worry level of 75.
+/// Worry level increases by 6 to 81.
+/// Monkey gets bored with item. Worry level is divided by 3 to 27.
+/// Current worry level is not divisible by 19.
+/// Item with worry level 27 is thrown to monkey 0.
+/// Monkey inspects an item with a worry level of 74.
+/// Worry level increases by 6 to 80.
+/// Monkey gets bored with item. Worry level is divided by 3 to 26.
+/// Current worry level is not divisible by 19.
+/// Item with worry level 26 is thrown to monkey 0.
+/// Monkey 2:
+/// Monkey inspects an item with a worry level of 79.
+/// Worry level is multiplied by itself to 6241.
+/// Monkey gets bored with item. Worry level is divided by 3 to 2080.
+/// Current worry level is divisible by 13.
+/// Item with worry level 2080 is thrown to monkey 1.
+/// Monkey inspects an item with a worry level of 60.
+/// Worry level is multiplied by itself to 3600.
+/// Monkey gets bored with item. Worry level is divided by 3 to 1200.
+/// Current worry level is not divisible by 13.
+/// Item with worry level 1200 is thrown to monkey 3.
+/// Monkey inspects an item with a worry level of 97.
+/// Worry level is multiplied by itself to 9409.
+/// Monkey gets bored with item. Worry level is divided by 3 to 3136.
+/// Current worry level is not divisible by 13.
+/// Item with worry level 3136 is thrown to monkey 3.
+/// Monkey 3:
+/// Monkey inspects an item with a worry level of 74.
+/// Worry level increases by 3 to 77.
+/// Monkey gets bored with item. Worry level is divided by 3 to 25.
+/// Current worry level is not divisible by 17.
+/// Item with worry level 25 is thrown to monkey 1.
+/// Monkey inspects an item with a worry level of 500.
+/// Worry level increases by 3 to 503.
+/// Monkey gets bored with item. Worry level is divided by 3 to 167.
+/// Current worry level is not divisible by 17.
+/// Item with worry level 167 is thrown to monkey 1.
+/// Monkey inspects an item with a worry level of 620.
+/// Worry level increases by 3 to 623.
+/// Monkey gets bored with item. Worry level is divided by 3 to 207.
+/// Current worry level is not divisible by 17.
+/// Item with worry level 207 is thrown to monkey 1.
+/// Monkey inspects an item with a worry level of 1200.
+/// Worry level increases by 3 to 1203.
+/// Monkey gets bored with item. Worry level is divided by 3 to 401.
+/// Current worry level is not divisible by 17.
+/// Item with worry level 401 is thrown to monkey 1.
+/// Monkey inspects an item with a worry level of 3136.
+/// Worry level increases by 3 to 3139.
+/// Monkey gets bored with item. Worry level is divided by 3 to 1046.
+/// Current worry level is not divisible by 17.
+/// Item with worry level 1046 is thrown to monkey 1.
+/// ```
+///
+/// After round 1, the monkeys are holding items with these worry levels:
+///
+/// ```
+/// Monkey 0: 20, 23, 27, 26
+/// Monkey 1: 2080, 25, 167, 207, 401, 1046
+/// Monkey 2:
+/// Monkey 3:
+/// ```
+///
+/// Monkeys 2 and 3 aren't holding any items at the end of the round; they both inspected items
+/// during the round and threw them all before the round ended.
+///
+/// This process continues for a few more rounds:
+///
+/// ```
+/// After round 2, the monkeys are holding items with these worry levels:
+/// Monkey 0: 695, 10, 71, 135, 350
+/// Monkey 1: 43, 49, 58, 55, 362
+/// Monkey 2:
+/// Monkey 3:
+///
+/// After round 3, the monkeys are holding items with these worry levels:
+/// Monkey 0: 16, 18, 21, 20, 122
+/// Monkey 1: 1468, 22, 150, 286, 739
+/// Monkey 2:
+/// Monkey 3:
+///
+/// After round 4, the monkeys are holding items with these worry levels:
+/// Monkey 0: 491, 9, 52, 97, 248, 34
+/// Monkey 1: 39, 45, 43, 258
+/// Monkey 2:
+/// Monkey 3:
+///
+/// After round 5, the monkeys are holding items with these worry levels:
+/// Monkey 0: 15, 17, 16, 88, 1037
+/// Monkey 1: 20, 110, 205, 524, 72
+/// Monkey 2:
+/// Monkey 3:
+///
+/// After round 6, the monkeys are holding items with these worry levels:
+/// Monkey 0: 8, 70, 176, 26, 34
+/// Monkey 1: 481, 32, 36, 186, 2190
+/// Monkey 2:
+/// Monkey 3:
+///
+/// After round 7, the monkeys are holding items with these worry levels:
+/// Monkey 0: 162, 12, 14, 64, 732, 17
+/// Monkey 1: 148, 372, 55, 72
+/// Monkey 2:
+/// Monkey 3:
+///
+/// After round 8, the monkeys are holding items with these worry levels:
+/// Monkey 0: 51, 126, 20, 26, 136
+/// Monkey 1: 343, 26, 30, 1546, 36
+/// Monkey 2:
+/// Monkey 3:
+///
+/// After round 9, the monkeys are holding items with these worry levels:
+/// Monkey 0: 116, 10, 12, 517, 14
+/// Monkey 1: 108, 267, 43, 55, 288
+/// Monkey 2:
+/// Monkey 3:
+///
+/// After round 10, the monkeys are holding items with these worry levels:
+/// Monkey 0: 91, 16, 20, 98
+/// Monkey 1: 481, 245, 22, 26, 1092, 30
+/// Monkey 2:
+/// Monkey 3:
+///
+/// ...
+///
+/// After round 15, the monkeys are holding items with these worry levels:
+/// Monkey 0: 83, 44, 8, 184, 9, 20, 26, 102
+/// Monkey 1: 110, 36
+/// Monkey 2:
+/// Monkey 3:
+///
+/// ...
+///
+/// After round 20, the monkeys are holding items with these worry levels:
+/// Monkey 0: 10, 12, 14, 26, 34
+/// Monkey 1: 245, 93, 53, 199, 115
+/// Monkey 2:
+/// Monkey 3:
+/// ```
+///
+/// Chasing all of the monkeys at once is impossible; you're going to have to focus on the two most
+/// active monkeys if you want any hope of getting your stuff back. Count the total number of times
+/// each monkey inspects items over 20 rounds:
+///
+/// ```
+/// Monkey 0 inspected items 101 times.
+/// Monkey 1 inspected items 95 times.
+/// Monkey 2 inspected items 7 times.
+/// Monkey 3 inspected items 105 times.
+/// ```
+///
+/// In this example, the two most active monkeys inspected items 101 and 105 times. The level of
+/// monkey business in this situation can be found by multiplying these together: 10605.
+///
+/// Figure out which monkeys to chase by counting how many items they inspect over 20 rounds. What
+/// is the level of monkey business after 20 rounds of stuff-slinging simian shenanigans?
+use clap::Parser;
+use itertools::Itertools;
+use nom::branch::alt;
+use nom::bytes::complete::tag;
+use nom::character::complete::{i32, newline, u8};
+use nom::combinator::{map, opt};
+use nom::error::{ContextError, ErrorKind as NomErrorKind, ParseError};
+use nom::multi::{many0, many1};
+use nom::sequence::{delimited, preceded, terminated, tuple};
+use nom::IResult;
+
+use std::collections::VecDeque;
+use std::fs::File;
+use std::io::prelude::*;
+use std::io::BufReader;
+use std::path::PathBuf;
+
+const FILEPATH: &'static str = "examples/input.txt";
+const ROUNDS: u8 = 20;
+
+pub type Input<'a> = &'a str;
+pub type Result<'a, T> = IResult<Input<'a>, T, Error<Input<'a>>>;
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum ErrorKind {
+ Nom(NomErrorKind),
+ Context(&'static str),
+ Custom(String),
+}
+
+#[derive(Parser, Debug)]
+#[clap(author, version, about, long_about = None)]
+struct Cli {
+ #[clap(short, long, default_value = FILEPATH)]
+ file: PathBuf,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct Error<I> {
+ pub errors: Vec<(I, ErrorKind)>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+enum Operation {
+ Add(i32),
+ Multiply(i32),
+ Square,
+}
+
+#[derive(Copy, Clone, Debug)]
+struct Test {
+ divisor: i32,
+ true_throw: u8,
+ false_throw: u8,
+}
+
+#[derive(Clone, Debug)]
+struct Monkey {
+ id: u8,
+ items: VecDeque<i32>,
+ operation: Operation,
+ test: Test,
+ ins_count: u64,
+}
+
+impl<I> ParseError<I> for Error<I> {
+ fn from_error_kind(input: I, kind: NomErrorKind) -> Self {
+ let errors = vec![(input, ErrorKind::Nom(kind))];
+ Self { errors }
+ }
+
+ fn append(input: I, kind: NomErrorKind, mut other: Self) -> Self {
+ other.errors.push((input, ErrorKind::Nom(kind)));
+ other
+ }
+}
+
+impl<I> ContextError<I> for Error<I> {
+ fn add_context(input: I, ctx: &'static str, mut other: Self) -> Self {
+ other.errors.push((input, ErrorKind::Context(ctx)));
+ other
+ }
+}
+
+fn parse_id(input: &str) -> Result<u8> {
+ delimited(tag("Monkey "), u8, tuple((tag(":"), newline)))(input)
+}
+
+fn parse_starting(input: &str) -> Result<Vec<i32>> {
+ delimited(
+ tag(" Starting items: "),
+ many0(terminated(i32, opt(tag(", ")))),
+ newline,
+ )(input)
+}
+
+fn parse_operation(input: &str) -> Result<Operation> {
+ delimited(
+ tag(" Operation: new = old "),
+ alt((
+ map(preceded(tag("* "), i32), |x: i32| Operation::Multiply(x)),
+ map(preceded(tag("+ "), i32), |x: i32| Operation::Add(x)),
+ map(preceded(tag("* "), tag("old")), |_| Operation::Square),
+ )),
+ newline,
+ )(input)
+}
+
+fn parse_test(input: &str) -> Result<Test> {
+ let (input, divisor) = delimited(tag(" Test: divisible by "), i32, newline)(input)?;
+ let (input, true_throw) = delimited(tag(" If true: throw to monkey "), u8, newline)(input)?;
+ let (input, false_throw) =
+ delimited(tag(" If false: throw to monkey "), u8, opt(newline))(input)?;
+ Ok((
+ input,
+ Test {
+ divisor,
+ true_throw,
+ false_throw,
+ },
+ ))
+}
+
+fn parse_monkey(input: &str) -> Result<Monkey> {
+ map(
+ tuple((parse_id, parse_starting, parse_operation, parse_test)),
+ |(id, items, operation, test)| Monkey {
+ id,
+ items: items.into(),
+ operation,
+ test,
+ ins_count: 0,
+ },
+ )(input)
+}
+
+fn parse(input: &str) -> Result<Vec<Monkey>> {
+ many1(terminated(parse_monkey, opt(newline)))(input)
+}
+
+fn main() {
+ let args = Cli::parse();
+
+ let file = File::open(&args.file).unwrap();
+ let mut reader = BufReader::new(file);
+
+ let mut buf = String::new();
+ let _ = reader.read_to_string(&mut buf).unwrap();
+ let (input, mut monkeys) = parse(&buf).unwrap();
+ assert_eq!(input.len(), 0);
+
+ for _ in 0..ROUNDS {
+ for idx in 0..monkeys.len() {
+ assert_eq!(idx, monkeys[idx].id as usize);
+ loop {
+ if monkeys[idx].items.is_empty() {
+ break;
+ }
+
+ let monkey = &mut monkeys[idx];
+ monkey.ins_count += 1;
+
+ let item = monkey.items.pop_front().unwrap();
+ let op_item = match monkey.operation {
+ Operation::Add(val) => item + val,
+ Operation::Multiply(val) => item * val,
+ Operation::Square => item * item,
+ };
+ let bo_item = op_item / 3;
+
+ let test = monkeys[idx].test.clone();
+ match bo_item % test.divisor {
+ 0 => monkeys[test.true_throw as usize].items.push_back(bo_item),
+ _ => monkeys[test.false_throw as usize].items.push_back(bo_item),
+ }
+ }
+ }
+ }
+
+ let res: u64 = monkeys
+ .into_iter()
+ .map(|m: Monkey| m.ins_count)
+ .sorted()
+ .rev()
+ .take(2)
+ .product();
+ println!("{res:#?}");
+}
diff --git a/day11b/Cargo.toml b/day11b/Cargo.toml
new file mode 100644
index 0000000..cb76776
--- /dev/null
+++ b/day11b/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "day11b"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+clap = { version = "3.2.20", features = ["derive"] }
+nom = "7.1.1"
+itertools = "0.10.5"
diff --git a/day11b/examples/input.txt b/day11b/examples/input.txt
new file mode 100644
index 0000000..26026b5
--- /dev/null
+++ b/day11b/examples/input.txt
@@ -0,0 +1,55 @@
+Monkey 0:
+ Starting items: 59, 74, 65, 86
+ Operation: new = old * 19
+ Test: divisible by 7
+ If true: throw to monkey 6
+ If false: throw to monkey 2
+
+Monkey 1:
+ Starting items: 62, 84, 72, 91, 68, 78, 51
+ Operation: new = old + 1
+ Test: divisible by 2
+ If true: throw to monkey 2
+ If false: throw to monkey 0
+
+Monkey 2:
+ Starting items: 78, 84, 96
+ Operation: new = old + 8
+ Test: divisible by 19
+ If true: throw to monkey 6
+ If false: throw to monkey 5
+
+Monkey 3:
+ Starting items: 97, 86
+ Operation: new = old * old
+ Test: divisible by 3
+ If true: throw to monkey 1
+ If false: throw to monkey 0
+
+Monkey 4:
+ Starting items: 50
+ Operation: new = old + 6
+ Test: divisible by 13
+ If true: throw to monkey 3
+ If false: throw to monkey 1
+
+Monkey 5:
+ Starting items: 73, 65, 69, 65, 51
+ Operation: new = old * 17
+ Test: divisible by 11
+ If true: throw to monkey 4
+ If false: throw to monkey 7
+
+Monkey 6:
+ Starting items: 69, 82, 97, 93, 82, 84, 58, 63
+ Operation: new = old + 5
+ Test: divisible by 5
+ If true: throw to monkey 5
+ If false: throw to monkey 7
+
+Monkey 7:
+ Starting items: 81, 78, 82, 76, 79, 80
+ Operation: new = old + 3
+ Test: divisible by 17
+ If true: throw to monkey 3
+ If false: throw to monkey 4
diff --git a/day11b/examples/test.txt b/day11b/examples/test.txt
new file mode 100644
index 0000000..30e09e5
--- /dev/null
+++ b/day11b/examples/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
diff --git a/day11b/src/main.rs b/day11b/src/main.rs
new file mode 100644
index 0000000..ddeaa3d
--- /dev/null
+++ b/day11b/src/main.rs
@@ -0,0 +1,284 @@
+/// --- Part Two ---
+///
+/// You're worried you might not ever get your items back. So worried, in fact, that your relief
+/// that a monkey's inspection didn't damage an item no longer causes your worry level to be
+/// divided by three.
+///
+/// Unfortunately, that relief was all that was keeping your worry levels from reaching ridiculous
+/// levels. You'll need to find another way to keep your worry levels manageable.
+///
+/// At this rate, you might be putting up with these monkeys for a very long time - possibly 10000
+/// rounds!
+///
+/// With these new rules, you can still figure out the monkey business after 10000 rounds. Using
+/// the same example above:
+///
+/// ```
+/// == After round 1 ==
+/// Monkey 0 inspected items 2 times.
+/// Monkey 1 inspected items 4 times.
+/// Monkey 2 inspected items 3 times.
+/// Monkey 3 inspected items 6 times.
+///
+/// == After round 20 ==
+/// Monkey 0 inspected items 99 times.
+/// Monkey 1 inspected items 97 times.
+/// Monkey 2 inspected items 8 times.
+/// Monkey 3 inspected items 103 times.
+///
+/// == After round 1000 ==
+/// Monkey 0 inspected items 5204 times.
+/// Monkey 1 inspected items 4792 times.
+/// Monkey 2 inspected items 199 times.
+/// Monkey 3 inspected items 5192 times.
+///
+/// == After round 2000 ==
+/// Monkey 0 inspected items 10419 times.
+/// Monkey 1 inspected items 9577 times.
+/// Monkey 2 inspected items 392 times.
+/// Monkey 3 inspected items 10391 times.
+///
+/// == After round 3000 ==
+/// Monkey 0 inspected items 15638 times.
+/// Monkey 1 inspected items 14358 times.
+/// Monkey 2 inspected items 587 times.
+/// Monkey 3 inspected items 15593 times.
+///
+/// == After round 4000 ==
+/// Monkey 0 inspected items 20858 times.
+/// Monkey 1 inspected items 19138 times.
+/// Monkey 2 inspected items 780 times.
+/// Monkey 3 inspected items 20797 times.
+///
+/// == After round 5000 ==
+/// Monkey 0 inspected items 26075 times.
+/// Monkey 1 inspected items 23921 times.
+/// Monkey 2 inspected items 974 times.
+/// Monkey 3 inspected items 26000 times.
+///
+/// == After round 6000 ==
+/// Monkey 0 inspected items 31294 times.
+/// Monkey 1 inspected items 28702 times.
+/// Monkey 2 inspected items 1165 times.
+/// Monkey 3 inspected items 31204 times.
+///
+/// == After round 7000 ==
+/// Monkey 0 inspected items 36508 times.
+/// Monkey 1 inspected items 33488 times.
+/// Monkey 2 inspected items 1360 times.
+/// Monkey 3 inspected items 36400 times.
+///
+/// == After round 8000 ==
+/// Monkey 0 inspected items 41728 times.
+/// Monkey 1 inspected items 38268 times.
+/// Monkey 2 inspected items 1553 times.
+/// Monkey 3 inspected items 41606 times.
+///
+/// == After round 9000 ==
+/// Monkey 0 inspected items 46945 times.
+/// Monkey 1 inspected items 43051 times.
+/// Monkey 2 inspected items 1746 times.
+/// Monkey 3 inspected items 46807 times.
+///
+/// == After round 10000 ==
+/// Monkey 0 inspected items 52166 times.
+/// Monkey 1 inspected items 47830 times.
+/// Monkey 2 inspected items 1938 times.
+/// Monkey 3 inspected items 52013 times.
+/// ```
+///
+/// After 10000 rounds, the two most active monkeys inspected items 52166 and 52013 times.
+/// Multiplying these together, the level of monkey business in this situation is now 2713310158.
+///
+/// Worry levels are no longer divided by three after each item is inspected; you'll need to find
+/// another way to keep your worry levels manageable. Starting again from the initial state in
+/// your puzzle input, what is the level of monkey business after 10000 rounds?
+use clap::Parser;
+use itertools::Itertools;
+use nom::branch::alt;
+use nom::bytes::complete::tag;
+use nom::character::complete::{i64, newline, u8};
+use nom::combinator::{map, opt};
+use nom::error::{ContextError, ErrorKind as NomErrorKind, ParseError};
+use nom::multi::{many0, many1};
+use nom::sequence::{delimited, preceded, terminated, tuple};
+use nom::IResult;
+
+use std::collections::VecDeque;
+use std::fs::File;
+use std::io::prelude::*;
+use std::io::BufReader;
+use std::path::PathBuf;
+
+const FILEPATH: &'static str = "examples/input.txt";
+const ROUNDS: u32 = 10000;
+
+pub type Input<'a> = &'a str;
+pub type Result<'a, T> = IResult<Input<'a>, T, Error<Input<'a>>>;
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum ErrorKind {
+ Nom(NomErrorKind),
+ Context(&'static str),
+ Custom(String),
+}
+
+#[derive(Parser, Debug)]
+#[clap(author, version, about, long_about = None)]
+struct Cli {
+ #[clap(short, long, default_value = FILEPATH)]
+ file: PathBuf,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct Error<I> {
+ pub errors: Vec<(I, ErrorKind)>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+enum Operation {
+ Add(i64),
+ Multiply(i64),
+ Square,
+}
+
+#[derive(Copy, Clone, Debug)]
+struct Test {
+ divisor: i64,
+ true_throw: u8,
+ false_throw: u8,
+}
+
+#[derive(Clone, Debug)]
+struct Monkey {
+ id: u8,
+ items: VecDeque<i64>,
+ operation: Operation,
+ test: Test,
+ ins_count: u64,
+}
+
+impl<I> ParseError<I> for Error<I> {
+ fn from_error_kind(input: I, kind: NomErrorKind) -> Self {
+ let errors = vec![(input, ErrorKind::Nom(kind))];
+ Self { errors }
+ }
+
+ fn append(input: I, kind: NomErrorKind, mut other: Self) -> Self {
+ other.errors.push((input, ErrorKind::Nom(kind)));
+ other
+ }
+}
+
+impl<I> ContextError<I> for Error<I> {
+ fn add_context(input: I, ctx: &'static str, mut other: Self) -> Self {
+ other.errors.push((input, ErrorKind::Context(ctx)));
+ other
+ }
+}
+
+fn parse_id(input: &str) -> Result<u8> {
+ delimited(tag("Monkey "), u8, tuple((tag(":"), newline)))(input)
+}
+
+fn parse_starting(input: &str) -> Result<Vec<i64>> {
+ delimited(
+ tag(" Starting items: "),
+ many0(terminated(i64, opt(tag(", ")))),
+ newline,
+ )(input)
+}
+
+fn parse_operation(input: &str) -> Result<Operation> {
+ delimited(
+ tag(" Operation: new = old "),
+ alt((
+ map(preceded(tag("* "), i64), |x: i64| Operation::Multiply(x)),
+ map(preceded(tag("+ "), i64), |x: i64| Operation::Add(x)),
+ map(preceded(tag("* "), tag("old")), |_| Operation::Square),
+ )),
+ newline,
+ )(input)
+}
+
+fn parse_test(input: &str) -> Result<Test> {
+ let (input, divisor) = delimited(tag(" Test: divisible by "), i64, newline)(input)?;
+ let (input, true_throw) = delimited(tag(" If true: throw to monkey "), u8, newline)(input)?;
+ let (input, false_throw) =
+ delimited(tag(" If false: throw to monkey "), u8, opt(newline))(input)?;
+ Ok((
+ input,
+ Test {
+ divisor,
+ true_throw,
+ false_throw,
+ },
+ ))
+}
+
+fn parse_monkey(input: &str) -> Result<Monkey> {
+ map(
+ tuple((parse_id, parse_starting, parse_operation, parse_test)),
+ |(id, items, operation, test)| Monkey {
+ id,
+ items: items.into(),
+ operation,
+ test,
+ ins_count: 0,
+ },
+ )(input)
+}
+
+fn parse(input: &str) -> Result<Vec<Monkey>> {
+ many1(terminated(parse_monkey, opt(newline)))(input)
+}
+
+fn main() {
+ let args = Cli::parse();
+
+ let file = File::open(&args.file).unwrap();
+ let mut reader = BufReader::new(file);
+
+ let mut buf = String::new();
+ let _ = reader.read_to_string(&mut buf).unwrap();
+ let (input, mut monkeys) = parse(&buf).unwrap();
+ assert_eq!(input.len(), 0);
+
+ let common_factor: i64 = monkeys.iter().map(|m: &Monkey| m.test.divisor).product();
+
+ for _ in 0..ROUNDS {
+ for idx in 0..monkeys.len() {
+ assert_eq!(idx, monkeys[idx].id as usize);
+ loop {
+ if monkeys[idx].items.is_empty() {
+ break;
+ }
+
+ let monkey = &mut monkeys[idx];
+ monkey.ins_count += 1;
+
+ let item = monkey.items.pop_front().unwrap();
+ let bo_item = match monkey.operation {
+ Operation::Add(val) => item + val,
+ Operation::Multiply(val) => item * val,
+ Operation::Square => item * item,
+ } % common_factor;
+
+ let test = monkeys[idx].test.clone();
+ match bo_item % test.divisor {
+ 0 => monkeys[test.true_throw as usize].items.push_back(bo_item),
+ _ => monkeys[test.false_throw as usize].items.push_back(bo_item),
+ }
+ }
+ }
+ }
+
+ let res: u64 = monkeys
+ .into_iter()
+ .map(|m: Monkey| m.ins_count)
+ .sorted()
+ .rev()
+ .take(2)
+ .product();
+ println!("{res:#?}");
+}