advent-of-code/2022/src/day_11.rs
2022-12-11 14:29:47 -05:00

193 lines
5.7 KiB
Rust

#[derive(Debug, Clone, Copy)]
enum Param {
Old,
Value(u64),
}
#[derive(Debug, Clone, Copy)]
enum Op {
Add,
Mulitply,
}
#[derive(Debug, Clone, Copy)]
struct Operation {
left: Param,
op: Op,
right: Param,
}
#[derive(Debug, Clone)]
struct Monkey {
id: usize,
items: Vec<u64>,
operation: Operation,
test: u64,
test_failed_go_to: usize,
test_passed_go_to: usize,
}
type Data = Vec<Monkey>;
type Output = u64;
fn parse(input: &str) -> Data {
input
.split("\n\n")
.map(|lines| {
let mut line_iter = lines.lines();
let id = {
let title_line = line_iter.next().unwrap();
let (_prefix, id_block) = title_line.split_once(' ').unwrap();
let (id, _rest) = id_block.split_once(':').unwrap();
id.parse().unwrap()
};
let items = {
let items_line = line_iter.next().unwrap();
let (_prefix, items) = items_line.split_once(": ").unwrap();
items.split(", ").map(|num| num.parse().unwrap()).collect()
};
let operation = {
let operation_line = line_iter.next().unwrap();
let (_prefix, rest) = operation_line.split_once("= ").unwrap();
let (left_str, rest) = rest.split_once(' ').unwrap();
let left = match left_str {
"old" => Param::Old,
s => Param::Value(s.parse().unwrap()),
};
let (op_str, right_str) = rest.split_once(' ').unwrap();
let op_char = op_str.chars().next().unwrap();
let op = match op_char {
'+' => Op::Add,
'*' => Op::Mulitply,
_ => panic!("expected + or *; got {}", op_str),
};
let right = match right_str {
"old" => Param::Old,
s => Param::Value(s.parse().unwrap()),
};
Operation { left, op, right }
};
let test = {
let test_line = line_iter.next().unwrap();
let (_prefix, num) = test_line.split_once("by ").unwrap();
num.parse().unwrap()
};
let test_passed_go_to = {
let passed_line = line_iter.next().unwrap();
let (_prefix, num) = passed_line.split_once("monkey ").unwrap();
num.parse().unwrap()
};
let test_failed_go_to = {
let failed_line = line_iter.next().unwrap();
let (_prefix, num) = failed_line.split_once("monkey ").unwrap();
num.parse().unwrap()
};
Monkey {
id,
items,
operation,
test,
test_failed_go_to,
test_passed_go_to,
}
})
.collect()
}
fn part_one(mut data: Data) -> Output {
let mut counts = vec![0; data.len()];
for _ in 1..=20 {
for i in 0..data.len() {
for j in 0..data[i].items.len() {
let left = match data[i].operation.left {
Param::Value(v) => v,
Param::Old => data[i].items[j],
};
let right = match data[i].operation.right {
Param::Value(v) => v,
Param::Old => data[i].items[j],
};
let new_value = match data[i].operation.op {
Op::Add => left + right,
Op::Mulitply => left * right,
} / 3;
if new_value % data[i].test == 0 {
let idx = data[i].test_passed_go_to;
data[idx].items.push(new_value);
} else {
let idx = data[i].test_failed_go_to;
data[idx].items.push(new_value);
}
}
counts[i] += data[i].items.len();
data[i].items.clear();
}
}
counts.sort();
counts.reverse();
counts[0] as u64 * counts[1] as u64
}
fn part_two(mut data: Data) -> Output {
let mut counts = vec![0; data.len()];
let test_gcd = data.iter().fold(1, |acc, curr| acc * curr.test);
for round in 1..=10000 {
for i in 0..data.len() {
for j in 0..data[i].items.len() {
let left = match data[i].operation.left {
Param::Value(v) => v,
Param::Old => data[i].items[j],
};
let right = match data[i].operation.right {
Param::Value(v) => v,
Param::Old => data[i].items[j],
};
let new_value = match data[i].operation.op {
Op::Add => left + right,
Op::Mulitply => left * right,
};
if new_value % data[i].test == 0 {
let idx = data[i].test_passed_go_to;
data[idx].items.push(new_value % test_gcd);
} else {
let idx = data[i].test_failed_go_to;
data[idx].items.push(new_value % test_gcd);
}
}
counts[i] += data[i].items.len();
data[i].items.clear();
}
match round {
1 | 20 | 1000 => {
dbg!(&counts, round);
}
_ => {}
}
}
counts.sort();
counts.reverse();
counts[0] as u64 * counts[1] as u64
}
advent_of_code_macro::generate_tests!(
day 11,
parse,
part_one,
part_two,
sample tests [10_605, 2_713_310_158],
star tests [90_294, 18_170_818_354]
);