aboutsummaryrefslogtreecommitdiff
path: root/2022/src/day11.rs
blob: aad0b488bb6d4dd5dd1d3ea9207d64580f013e17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
mod utils;
extern crate nom;
use nom::{
    branch::alt,
    bytes::complete::{tag, take_until},
    character::complete::{digit0, u32},
    multi::separated_list0,
    IResult,
};
use utils::{max_n, read_input};

fn main() {
    let input = read_input();

    let (_, monkeys_items) = separated_list0(tag("\n\n"), Monkey::parse)(&input).unwrap();
    let (monkeys, items): (Vec<_>, Vec<_>) = monkeys_items.into_iter().unzip();

    println!(
        "Part 1: {}",
        monkey_business::<3, 20>(&monkeys, items.clone(), usize::MAX),
    );
    println!(
        "Part 2: {}",
        monkey_business::<1, 10000>(&monkeys, items, monkeys.iter().map(|x| x.test).product())
    );
}

fn monkey_business<const REDUCER: usize, const ROUNDS: usize>(
    monkeys: &[Monkey],
    mut items: Vec<Vec<usize>>,
    additional_reducer: usize,
) -> usize {
    let mut inspections = vec![0; monkeys.len()];
    for _ in 0..ROUNDS {
        for monkey_idx in 0..monkeys.len() {
            let curr_monkey = &monkeys[monkey_idx];
            while let Some(worry) = items[monkey_idx].pop() {
                let new_worry = (curr_monkey.do_op(worry) / REDUCER) % additional_reducer;
                inspections[monkey_idx] += 1;
                let throw_to = curr_monkey.throw_to(new_worry);

                items[throw_to].push(new_worry);
            }
        }
    }

    max_n(&mut inspections, 2).iter().product::<usize>()
}

#[derive(Debug)]
struct Monkey {
    op: Operation,
    test: usize,
    next_monkey: (usize, usize),
}

impl Monkey {
    fn parse(i: &str) -> IResult<&str, (Monkey, Vec<usize>)> {
        let (i, _) = tag("Monkey ")(i)?;
        let (i, _) = digit0(i)?;
        let (i, _) = tag(":\n  Starting items: ")(i)?;
        let (i, items) = separated_list0(tag(", "), u32)(i)?;
        let (i, _) = tag("\n  Operation: new = ")(i)?;
        let (i, op) = Operation::parse(i)?;
        let (i, _) = take_until("\n")(i)?;
        let (i, _) = tag("\n  Test: divisible by ")(i)?;
        let (i, test) = u32(i)?;
        let (i, _) = tag("\n    If true: throw to monkey ")(i)?;
        let (i, monkey_t) = u32(i)?;
        let (i, _) = tag("\n    If false: throw to monkey ")(i)?;
        let (i, monkey_f) = u32(i)?;

        Ok((
            i,
            (
                Monkey {
                    op,
                    test: test as usize,
                    next_monkey: (monkey_t as usize, monkey_f as usize),
                },
                items.into_iter().map(|x| x as usize).collect(),
            ),
        ))
    }

    fn do_op(&self, x: usize) -> usize {
        match self.op {
            Operation::Square => x * x,
            Operation::Add(c) => x + c,
            Operation::Mult(c) => x * c,
        }
    }
    fn throw_to(&self, x: usize) -> usize {
        if (x % self.test) == 0 {
            self.next_monkey.0
        } else {
            self.next_monkey.1
        }
    }
}

#[derive(Debug)]
enum Operation {
    Square,
    Add(usize),
    Mult(usize),
}

impl Operation {
    fn parse(i: &str) -> IResult<&str, Operation> {
        let (i, _) = tag("old ")(i)?;
        let (i, op) = alt((tag("* "), tag("+ ")))(i)?;
        if let Ok((i, _)) = tag::<&str, &str, (&str, nom::error::ErrorKind)>("old")(i) {
            Ok((i, Operation::Square))
        } else {
            let (i, x) = u32(i)?;
            Ok((
                i,
                match op {
                    "* " => Operation::Mult(x as usize),
                    "+ " => Operation::Add(x as usize),
                    _ => unreachable!(),
                },
            ))
        }
    }
}