1use crate::util::parse::*;
45use crate::util::thread::*;
46use std::sync::Mutex;
47
48pub struct Monkey {
49 items: Vec<u64>,
50 operation: Operation,
51 test: u64,
52 yes: usize,
53 no: usize,
54}
55
56pub enum Operation {
57 Square,
58 Multiply(u64),
59 Add(u64),
60}
61
62type Pair = (usize, u64);
63type Business = [u64; 8];
64
65struct Shared<'a> {
66 monkeys: &'a [Monkey],
67 mutex: Mutex<Exclusive>,
68}
69
70struct Exclusive {
71 pairs: Vec<Pair>,
72 business: Business,
73}
74
75pub fn parse(input: &str) -> Vec<Monkey> {
78 fn helper(chunk: &[&str]) -> Monkey {
80 let items = chunk[1].iter_unsigned().collect();
81 let tokens: Vec<_> = chunk[2].split(' ').rev().take(2).collect();
82 let operation = match tokens[..] {
83 ["old", _] => Operation::Square,
84 [y, "*"] => Operation::Multiply(y.unsigned()),
85 [y, "+"] => Operation::Add(y.unsigned()),
86 _ => unreachable!(),
87 };
88 let test = chunk[3].unsigned();
89 let yes = chunk[4].unsigned();
90 let no = chunk[5].unsigned();
91 Monkey { items, operation, test, yes, no }
92 }
93 input.lines().collect::<Vec<&str>>().chunks(7).map(helper).collect()
94}
95
96pub fn part1(input: &[Monkey]) -> u64 {
97 solve(input, sequential)
98}
99
100pub fn part2(input: &[Monkey]) -> u64 {
101 solve(input, parallel)
102}
103
104fn solve(monkeys: &[Monkey], play: impl Fn(&[Monkey], Vec<Pair>) -> Business) -> u64 {
106 let mut pairs = Vec::new();
107
108 for (from, monkey) in monkeys.iter().enumerate() {
109 for &item in &monkey.items {
110 pairs.push((from, item));
111 }
112 }
113
114 let mut business = play(monkeys, pairs);
115 business.sort_unstable();
116 business.iter().rev().take(2).product()
117}
118
119fn sequential(monkeys: &[Monkey], pairs: Vec<Pair>) -> Business {
121 let mut business = [0; 8];
122
123 for pair in pairs {
124 let extra = play(monkeys, 20, |x| x / 3, pair);
125 business.iter_mut().enumerate().for_each(|(i, b)| *b += extra[i]);
126 }
127
128 business
129}
130
131fn parallel(monkeys: &[Monkey], pairs: Vec<Pair>) -> Business {
133 let shared = Shared { monkeys, mutex: Mutex::new(Exclusive { pairs, business: [0; 8] }) };
134
135 spawn(|| worker(&shared));
137
138 shared.mutex.into_inner().unwrap().business
139}
140
141fn worker(shared: &Shared<'_>) {
143 let product: u64 = shared.monkeys.iter().map(|m| m.test).product();
144
145 loop {
146 let Some(pair) = shared.mutex.lock().unwrap().pairs.pop() else {
149 break;
150 };
151
152 let extra = play(shared.monkeys, 10000, |x| x % product, pair);
153
154 let mut exclusive = shared.mutex.lock().unwrap();
155 exclusive.business.iter_mut().enumerate().for_each(|(i, b)| *b += extra[i]);
156 }
157}
158
159fn play(monkeys: &[Monkey], max_rounds: u32, adjust: impl Fn(u64) -> u64, pair: Pair) -> Business {
164 let (mut from, mut item) = pair;
165 let mut rounds = 0;
166 let mut business = [0; 8];
167
168 while rounds < max_rounds {
169 let worry = match monkeys[from].operation {
170 Operation::Square => item * item,
171 Operation::Multiply(y) => item * y,
172 Operation::Add(y) => item + y,
173 };
174 item = adjust(worry);
175
176 let to = if item % monkeys[from].test == 0 { monkeys[from].yes } else { monkeys[from].no };
177
178 rounds += (to < from) as u32;
181 business[from] += 1;
182 from = to;
183 }
184
185 business
186}