Files
contests/advent_of_code/2022/11/src/main.rs

200 lines
4.5 KiB
Rust

use std::collections::VecDeque;
use nom::{
character::complete::{self, multispace1, one_of, multispace0},
multi::{separated_list1, many1},
bytes::complete::tag,
sequence::{delimited, preceded},
branch::alt,
*,
};
#[derive(Debug)]
enum Value {
Old,
Val(u64),
} use Value::*;
#[derive(Debug)]
enum Operation {
Mult(Value),
Add(Value),
} use Operation::*;
#[derive(Debug)]
pub struct Test {
divisible_by: u64,
on_false: usize,
on_true: usize,
}
#[derive(Debug)]
pub struct Monkey {
items: VecDeque<u64>,
operation: Operation,
test: Test,
number_of_inspections: u64,
}
impl Monkey {
pub fn handle_items(&mut self, magic_number: u64) -> Vec<(u64, usize)> {
let mut result = Vec::new();
while !self.items.is_empty() {
self.number_of_inspections += 1;
let mut item = self.items.pop_front().unwrap();
item = match self.operation {
Mult(Old) => {item * item},
Mult(Val(num)) => {item * num},
Add(Old) => {item * 2},
Add(Val(num)) => {item + num},
};
// item /= 3;
item = item % magic_number;
let throw_to_monkey = match item % self.test.divisible_by == 0 {
true => self.test.on_true,
false => self.test.on_false,
};
result.push((item, throw_to_monkey));
}
result
}
}
fn parse_operation(input: &str) -> IResult<&str, Operation> {
let (input, op) = preceded(
tag("Operation: new = old "),
one_of("+*"),
)(input)?;
let (input, num) : (&str, Value) = preceded(
multispace1,
alt((
complete::u64.map(|num| Value::Val(num)),
tag("old").map(|_| Value::Old),
)),
)(input)?;
let func = match op {
'*' => Operation::Mult(num),
'+' => Operation::Add(num),
_ => unreachable!(),
};
Ok((input, func))
}
fn parse_test(input: &str) -> IResult<&str, Test> {
let (input, divisible_by) = preceded(
tag("Test: divisible by "),
complete::u64,
)(input)?;
let (input, _) = multispace1(input)?;
let (input, on_true) = preceded(
tag("If true: throw to monkey "),
complete::u32,
)(input)?;
let (input, _) = multispace1(input)?;
let (input, on_false) = preceded(
tag("If false: throw to monkey "),
complete::u32,
)(input)?;
// Generate Test
let t = Test {
divisible_by,
on_false: on_false as usize,
on_true: on_true as usize,
};
Ok((input, t))
}
fn parse_input(input: &str) -> IResult<&str, Monkey> {
// Parse: Monkey _id:
let (input, _id) = delimited(
tag("Monkey "),
complete::u32,
tag(":"),
)(input)?;
let (input, _) = multispace1(input)?;
// Parse: Starting items: num1, num2
let (input, levels) = preceded(
tag("Starting items: "),
separated_list1(tag(", "), complete::u64),
)(input)?;
let (input, _) = multispace1(input)?;
//Parse: Operation: new = old {+ num|old}, {* num|old}
let (input, operation) = parse_operation(input)?;
let (input, _) = multispace1(input)?;
//Parse: Test: divisible by num
// If true: throw to monkey #
// If false: throw to monkey #
let (input, test) = parse_test(input)?;
let (input, _) = multispace0(input)?;
// Generate a monkey here
let items = VecDeque::from_iter(levels);
let m = Monkey {
items,
operation,
test,
number_of_inspections: 0,
};
Ok((input, m))
}
fn part1and2() {
let input_text = include_str!("../input.txt");
let (_, mut monkeys) = many1(parse_input)(input_text).unwrap();
let magic_number = monkeys
.iter()
.map(|m| m.test.divisible_by)
.product();
for _i in 0..10000 {
for monkey_index in 0..monkeys.len() {
let monkey = monkeys.get_mut(monkey_index).unwrap();
let new_item_list = monkey.handle_items(magic_number);
for (item, thrown_to_monkey) in new_item_list {
monkeys[thrown_to_monkey].items.push_back(item);
}
}
}
let mut results = monkeys
.iter()
.map(|m| m.number_of_inspections)
.collect::<Vec<u64>>();
results.sort_by(|a, b| b.cmp(a));
println!("{} * {} = {}", results[0], results[1], results[0] * results[1]);
}
fn main() {
part1and2();
}