This commit is contained in:
2022-12-11 22:34:12 +01:00
parent 242b284a59
commit 7993a0896b
7 changed files with 360 additions and 0 deletions

83
Cargo.lock generated
View File

@@ -8,8 +8,15 @@ version = "0.1.0"
dependencies = [
"itertools",
"nom",
"num",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "either"
version = "1.8.0"
@@ -46,3 +53,79 @@ dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]

View File

@@ -8,3 +8,4 @@ edition = "2021"
[dependencies]
itertools = "0.10.5"
nom = "7.1.1"
num = "0.4.0"

55
inputs/day11.txt Normal file
View File

@@ -0,0 +1,55 @@
Monkey 0:
Starting items: 56, 52, 58, 96, 70, 75, 72
Operation: new = old * 17
Test: divisible by 11
If true: throw to monkey 2
If false: throw to monkey 3
Monkey 1:
Starting items: 75, 58, 86, 80, 55, 81
Operation: new = old + 7
Test: divisible by 3
If true: throw to monkey 6
If false: throw to monkey 5
Monkey 2:
Starting items: 73, 68, 73, 90
Operation: new = old * old
Test: divisible by 5
If true: throw to monkey 1
If false: throw to monkey 7
Monkey 3:
Starting items: 72, 89, 55, 51, 59
Operation: new = old + 1
Test: divisible by 7
If true: throw to monkey 2
If false: throw to monkey 7
Monkey 4:
Starting items: 76, 76, 91
Operation: new = old * 3
Test: divisible by 19
If true: throw to monkey 0
If false: throw to monkey 3
Monkey 5:
Starting items: 88
Operation: new = old + 4
Test: divisible by 2
If true: throw to monkey 6
If false: throw to monkey 4
Monkey 6:
Starting items: 64, 63, 56, 50, 77, 55, 55, 86
Operation: new = old + 8
Test: divisible by 13
If true: throw to monkey 4
If false: throw to monkey 0
Monkey 7:
Starting items: 79, 58
Operation: new = old + 6
Test: divisible by 17
If true: throw to monkey 1
If false: throw to monkey 5

8
src/bin/day11_1.rs Normal file
View File

@@ -0,0 +1,8 @@
use std::fs;
use aoc2022::day11::process_part_1;
fn main() {
let file = fs::read_to_string("./inputs/day11.txt").unwrap();
println!("{}", process_part_1(&file));
}

8
src/bin/day11_2.rs Normal file
View File

@@ -0,0 +1,8 @@
use std::fs;
use aoc2022::day11::process_part_2;
fn main() {
let file = fs::read_to_string("./inputs/day11.txt").unwrap();
println!("{}", process_part_2(&file));
}

204
src/day11.rs Normal file
View File

@@ -0,0 +1,204 @@
use std::collections::VecDeque;
use itertools::Itertools;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete;
use nom::character::complete::{newline, space1};
use nom::multi::separated_list1;
use nom::sequence::{delimited, preceded};
use nom::{IResult, Parser};
pub fn process_part_1(input: &str) -> usize {
let mut monkeys = parse(input).unwrap().1;
// Sadly we are doing concurrent array indexing in rust with borrows
for _round in 0..20 {
for monkey_id in 0..monkeys.len() {
while !monkeys[monkey_id].items.is_empty() {
// I'm relying on rust's magic 'figure out when we can drop this to make it work'
// here. This var can be dropped *just* before the last line of the block to make it
// so we aren't borrowing mutably twice.
let monkey = &mut monkeys[monkey_id];
monkey.num_inspected += 1;
let item = monkey.items.pop_front().unwrap();
let item = monkey.operation.execute(item) / 3;
let next_monkey_id = if item % monkey.test_mod == 0 {
monkey.target_true
} else {
monkey.target_false
};
monkeys[next_monkey_id].items.push_back(item);
}
}
}
monkeys
.iter()
.map(|monkey| monkey.num_inspected)
.sorted()
.rev()
.take(2)
.product()
}
pub fn process_part_2(input: &str) -> usize {
let mut monkeys = parse(input).unwrap().1;
// Since we only care for divisibility in tests, we can just modulo every item with
// the LCM of all tests. This allows all tests to check for eligibility without actually
// letting the number grow huge.
let lcm = monkeys
.iter()
.map(|x| x.test_mod)
.reduce(num::integer::lcm)
.unwrap();
for _round in 0..10000 {
for monkey_id in 0..monkeys.len() {
while !monkeys[monkey_id].items.is_empty() {
let monkey = &mut monkeys[monkey_id];
monkey.num_inspected += 1;
let item = monkey.items.pop_front().unwrap();
let item = monkey.operation.execute(item) % lcm;
let next_monkey_id = if item % monkey.test_mod == 0 {
monkey.target_true
} else {
monkey.target_false
};
monkeys[next_monkey_id].items.push_back(item);
}
}
}
monkeys
.iter()
.map(|monkey| monkey.num_inspected)
.sorted()
.rev()
.take(2)
.product()
}
#[derive(Debug)]
enum Operation {
Add(u64),
Multiply(u64),
MultiplySelf,
}
impl Operation {
fn execute(&self, item: u64) -> u64 {
match self {
Operation::Add(x) => item + x,
Operation::Multiply(x) => item * x,
Operation::MultiplySelf => item * item,
}
}
}
#[derive(Debug)]
struct Monkey {
items: VecDeque<u64>,
operation: Operation,
test_mod: u64,
target_true: usize,
target_false: usize,
num_inspected: usize,
}
fn parse(input: &str) -> IResult<&str, Vec<Monkey>> {
separated_list1(newline, parse_monkey)(input)
}
fn parse_monkey(input: &str) -> IResult<&str, Monkey> {
let (input, _id) = delimited(tag("Monkey "), complete::u64, tag(":\n"))(input)?;
let (input, items) = preceded(
space1,
delimited(
tag("Starting items: "),
separated_list1(tag(", "), complete::u64),
newline,
),
)(input)?;
let (input, operation) = delimited(space1, parse_operation, newline)(input)?;
let (input, test_mod) = preceded(
space1,
delimited(tag("Test: divisible by "), complete::u64, newline),
)(input)?;
let (input, target_true) = preceded(
space1,
delimited(tag("If true: throw to monkey "), complete::u64, newline),
)(input)?;
let (input, target_false) = preceded(
space1,
delimited(tag("If false: throw to monkey "), complete::u64, newline),
)(input)?;
Ok((
input,
Monkey {
items: VecDeque::from(items),
operation,
test_mod,
target_true: target_true as usize,
target_false: target_false as usize,
num_inspected: 0,
},
))
}
fn parse_operation(input: &str) -> IResult<&str, Operation> {
let (input, _) = tag("Operation: new = old ")(input)?;
alt((
tag("* old").map(|_| Operation::MultiplySelf),
preceded(tag("+ "), complete::u64).map(Operation::Add),
preceded(tag("* "), complete::u64).map(Operation::Multiply),
))(input)
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = "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
";
#[test]
fn day1() {
assert_eq!(process_part_1(INPUT), 10605);
}
#[test]
fn day2() {
assert_eq!(process_part_2(INPUT), 2713310158);
}
}

View File

@@ -11,3 +11,4 @@ pub mod day07;
pub mod day08;
pub mod day09;
pub mod day10;
pub mod day11;