Compare commits

...

2 commits

Author SHA1 Message Date
77e443e6c8 2022 day11/rust: add solution 2022-12-11 09:39:15 +01:00
d20c6632fa 2022 day11: add data 2022-12-11 09:05:05 +01:00
6 changed files with 265 additions and 0 deletions

2
2022/data/day11.expected Normal file
View file

@ -0,0 +1,2 @@
66124
19309892877

55
2022/data/day11.input Normal file
View file

@ -0,0 +1,55 @@
Monkey 0:
Starting items: 75, 75, 98, 97, 79, 97, 64
Operation: new = old * 13
Test: divisible by 19
If true: throw to monkey 2
If false: throw to monkey 7
Monkey 1:
Starting items: 50, 99, 80, 84, 65, 95
Operation: new = old + 2
Test: divisible by 3
If true: throw to monkey 4
If false: throw to monkey 5
Monkey 2:
Starting items: 96, 74, 68, 96, 56, 71, 75, 53
Operation: new = old + 1
Test: divisible by 11
If true: throw to monkey 7
If false: throw to monkey 3
Monkey 3:
Starting items: 83, 96, 86, 58, 92
Operation: new = old + 8
Test: divisible by 17
If true: throw to monkey 6
If false: throw to monkey 1
Monkey 4:
Starting items: 99
Operation: new = old * old
Test: divisible by 5
If true: throw to monkey 0
If false: throw to monkey 5
Monkey 5:
Starting items: 60, 54, 83
Operation: new = old + 4
Test: divisible by 2
If true: throw to monkey 2
If false: throw to monkey 0
Monkey 6:
Starting items: 77, 67
Operation: new = old * 17
Test: divisible by 13
If true: throw to monkey 4
If false: throw to monkey 1
Monkey 7:
Starting items: 95, 65, 58, 76
Operation: new = old + 5
Test: divisible by 7
If true: throw to monkey 3
If false: throw to monkey 6

View file

@ -0,0 +1,9 @@
[package]
name = "rust_2022_11"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
aoc = { path = "../../../common/rust" }

191
2022/day11/rust/src/main.rs Normal file
View file

@ -0,0 +1,191 @@
#![warn(clippy::pedantic)]
use std::{
cmp::Reverse,
io::{stdin, Read},
ops::Rem,
str::FromStr,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Operand {
Const(usize),
Old,
}
impl Operand {
fn evaluate(self, old: usize) -> usize {
match self {
Self::Old => old,
Self::Const(c) => c,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Operation {
Add(Operand),
Multiply(Operand),
Divide(Operand),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Test {
Divisible(usize),
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct Item {
value: usize,
}
impl Item {
fn apply_operation(&mut self, op: Operation, modulo: Option<usize>) {
match op {
Operation::Add(x) => self.value += x.evaluate(self.value),
Operation::Multiply(x) => self.value *= x.evaluate(self.value),
Operation::Divide(x) => {
assert!(modulo.is_none(), "can't divide under modulo arithmetic");
self.value /= x.evaluate(self.value);
}
}
if let Some(modulo) = modulo {
self.value %= modulo;
}
}
fn apply_test(&self, test: Test) -> bool {
match test {
Test::Divisible(n) => self.value.rem(n) == 0,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct Monkey {
items: Vec<Item>,
operation: Operation,
test: Test,
target_pass: usize,
target_fail: usize,
inspections: usize,
}
impl Monkey {
fn throw_item(&mut self, divisor: Option<usize>, modulo: Option<usize>) -> (usize, Item) {
self.inspections += 1;
let mut item = self.items.remove(0);
item.apply_operation(self.operation, modulo);
if let Some(divisor) = divisor {
item.apply_operation(Operation::Divide(Operand::Const(divisor)), modulo);
}
let target = if item.apply_test(self.test) {
self.target_pass
} else {
self.target_fail
};
(target, item)
}
}
impl FromStr for Monkey {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut lines = s.lines();
lines.next().unwrap();
let items: Vec<_> = lines
.next()
.unwrap()
.split_once(':')
.unwrap()
.1
.trim()
.split(", ")
.map(|i| i.parse().unwrap())
.map(|value| Item { value })
.collect();
let op: Vec<_> = lines.next().unwrap().split_whitespace().collect();
let (operand, op) = op.split_last().unwrap();
let (operator, _) = op.split_last().unwrap();
let operand = match *operand {
"old" => Operand::Old,
i => Operand::Const(i.parse().unwrap()),
};
let operation = match *operator {
"+" => Operation::Add(operand),
"*" => Operation::Multiply(operand),
_ => panic!("invalid operator {operator}"),
};
let mut lastnum = || {
lines
.next()
.unwrap()
.split_whitespace()
.last()
.unwrap()
.parse()
.unwrap()
};
let test = Test::Divisible(lastnum());
let target_pass = lastnum();
let target_fail = lastnum();
Ok(Monkey {
items,
operation,
test,
target_pass,
target_fail,
inspections: 0,
})
}
}
fn play(monkeys: &mut [Monkey], rounds: usize, divisor: Option<usize>) -> usize {
let modulo = match divisor {
Some(_) => None,
None => Some(
monkeys
.iter()
.map(|m| {
let Test::Divisible(i) = m.test;
i
})
.product(),
),
};
for _round in 0..rounds {
for i in 0..monkeys.len() {
for _j in 0..monkeys[i].items.len() {
let (target, item) = monkeys[i].throw_item(divisor, modulo);
monkeys[target].items.push(item);
}
}
}
let mut levels: Vec<_> = monkeys.iter().map(|m| m.inspections).collect();
levels.sort_unstable_by_key(|i| Reverse(*i));
levels[0] * levels[1]
}
fn main() {
let mut data = String::new();
stdin().read_to_string(&mut data).unwrap();
let mut monkeys: Vec<Monkey> = data
.split("\n\n")
.map(|monkey| monkey.parse().unwrap())
.collect();
println!("{:?}", play(&mut monkeys.clone(), 20, Some(3)));
println!("{:?}", play(&mut monkeys, 10_000, None));
}

7
Cargo.lock generated
View file

@ -538,6 +538,13 @@ dependencies = [
"aoc",
]
[[package]]
name = "rust_2022_11"
version = "0.1.0"
dependencies = [
"aoc",
]
[[package]]
name = "ryu"
version = "1.0.11"

View file

@ -20,4 +20,5 @@ members = [
"2022/day8/rust",
"2022/day9/rust",
"2022/day10/rust",
"2022/day11/rust",
]