Rust Day 11
This commit is contained in:
parent
57216e6c0b
commit
e7a06642aa
7 changed files with 337 additions and 2 deletions
2
rust/Cargo.lock
generated
2
rust/Cargo.lock
generated
|
@ -4,4 +4,4 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "advent-of-code"
|
||||
version = "22.8.2"
|
||||
version = "22.11.2"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "advent-of-code"
|
||||
version = "22.8.2"
|
||||
version = "22.11.2"
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
|
||||
|
@ -63,6 +63,10 @@ path = "src/day09/main.rs"
|
|||
name = "day10"
|
||||
path = "src/day10/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "day11"
|
||||
path = "src/day11/main.rs"
|
||||
|
||||
[dependencies]
|
||||
# Required for one of the day06 solutions (commented out)
|
||||
# phf = { version = "0.11.1", features = ["macros"] }
|
55
rust/src/day11/input.txt
Normal file
55
rust/src/day11/input.txt
Normal file
|
@ -0,0 +1,55 @@
|
|||
Monkey 0:
|
||||
Starting items: 52, 78, 79, 63, 51, 94
|
||||
Operation: new = old * 13
|
||||
Test: divisible by 5
|
||||
If true: throw to monkey 1
|
||||
If false: throw to monkey 6
|
||||
|
||||
Monkey 1:
|
||||
Starting items: 77, 94, 70, 83, 53
|
||||
Operation: new = old + 3
|
||||
Test: divisible by 7
|
||||
If true: throw to monkey 5
|
||||
If false: throw to monkey 3
|
||||
|
||||
Monkey 2:
|
||||
Starting items: 98, 50, 76
|
||||
Operation: new = old * old
|
||||
Test: divisible by 13
|
||||
If true: throw to monkey 0
|
||||
If false: throw to monkey 6
|
||||
|
||||
Monkey 3:
|
||||
Starting items: 92, 91, 61, 75, 99, 63, 84, 69
|
||||
Operation: new = old + 5
|
||||
Test: divisible by 11
|
||||
If true: throw to monkey 5
|
||||
If false: throw to monkey 7
|
||||
|
||||
Monkey 4:
|
||||
Starting items: 51, 53, 83, 52
|
||||
Operation: new = old + 7
|
||||
Test: divisible by 3
|
||||
If true: throw to monkey 2
|
||||
If false: throw to monkey 0
|
||||
|
||||
Monkey 5:
|
||||
Starting items: 76, 76
|
||||
Operation: new = old + 4
|
||||
Test: divisible by 2
|
||||
If true: throw to monkey 4
|
||||
If false: throw to monkey 7
|
||||
|
||||
Monkey 6:
|
||||
Starting items: 75, 59, 93, 69, 76, 96, 65
|
||||
Operation: new = old * 19
|
||||
Test: divisible by 17
|
||||
If true: throw to monkey 1
|
||||
If false: throw to monkey 3
|
||||
|
||||
Monkey 7:
|
||||
Starting items: 89
|
||||
Operation: new = old + 2
|
||||
Test: divisible by 19
|
||||
If true: throw to monkey 2
|
||||
If false: throw to monkey 4
|
144
rust/src/day11/main.rs
Normal file
144
rust/src/day11/main.rs
Normal file
|
@ -0,0 +1,144 @@
|
|||
const INPUT: &str = include_str!("input.txt");
|
||||
|
||||
mod part_1;
|
||||
use part_1::part_1;
|
||||
mod part_2;
|
||||
use part_2::part_2;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub(crate) enum Op {
|
||||
Add(u64),
|
||||
Mul(u64),
|
||||
Square,
|
||||
}
|
||||
impl Op {
|
||||
fn perform(&self, worry: u64) -> u64 {
|
||||
match self {
|
||||
Op::Add(a) => a + worry,
|
||||
Op::Mul(a) => a * worry,
|
||||
Op::Square => worry.pow(2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub(crate) struct Test {
|
||||
pub divisible_by: u64,
|
||||
pub if_true: usize,
|
||||
pub if_false: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub(crate) struct Monkey {
|
||||
pub id: usize,
|
||||
pub items: Vec<u64>,
|
||||
pub operation: Op,
|
||||
pub test: Test,
|
||||
}
|
||||
|
||||
pub(crate) fn parse_input(input: &'static str) -> Vec<Monkey> {
|
||||
let normalized_line_endings = input.replace('\r', "");
|
||||
let monkeys = normalized_line_endings.split("\n\n");
|
||||
|
||||
let mut result = Vec::new();
|
||||
for monkey in monkeys {
|
||||
let mut chars = monkey.chars();
|
||||
|
||||
for _ in 0.."Monkey ".len() {
|
||||
chars.next();
|
||||
}
|
||||
let id_string = chars
|
||||
.by_ref()
|
||||
.take_while(|char| !matches!(char, ':'))
|
||||
.collect::<String>();
|
||||
|
||||
for _ in 0.."\n Starting items: ".len() {
|
||||
chars.next();
|
||||
}
|
||||
let starting_items_string = chars
|
||||
.by_ref()
|
||||
.take_while(|char| !matches!(char, '\n'))
|
||||
.collect::<String>();
|
||||
|
||||
for _ in 0.." Operation: new = old ".len() {
|
||||
chars.next();
|
||||
}
|
||||
let operation_string = chars
|
||||
.by_ref()
|
||||
.take_while(|char| !matches!(char, '\n'))
|
||||
.collect::<String>();
|
||||
|
||||
for _ in 0.." Test: divisible by ".len() {
|
||||
chars.next();
|
||||
}
|
||||
let divisible_by_string = chars
|
||||
.by_ref()
|
||||
.take_while(|char| matches!(char, '-' | '0'..='9'))
|
||||
.collect::<String>();
|
||||
|
||||
for _ in 0.." If true: throw to monkey ".len() {
|
||||
chars.next();
|
||||
}
|
||||
let if_true_string = chars
|
||||
.by_ref()
|
||||
.take_while(|char| char.is_numeric())
|
||||
.collect::<String>();
|
||||
|
||||
for _ in 0.." If false: throw to monkey ".len() {
|
||||
chars.next();
|
||||
}
|
||||
let if_false_string = chars
|
||||
.by_ref()
|
||||
.take_while(|char| char.is_numeric())
|
||||
.collect::<String>();
|
||||
|
||||
let id = id_string.parse().unwrap();
|
||||
let starting_items = starting_items_string
|
||||
.split(", ")
|
||||
.map(|num_string| num_string.parse().unwrap())
|
||||
.collect();
|
||||
let operation = if operation_string.starts_with('+') {
|
||||
Op::Add(
|
||||
operation_string
|
||||
.chars()
|
||||
.skip(2)
|
||||
.collect::<String>()
|
||||
.parse()
|
||||
.unwrap(),
|
||||
)
|
||||
} else if operation_string.chars().nth(2) == Some('o') {
|
||||
Op::Square
|
||||
} else {
|
||||
Op::Mul(
|
||||
operation_string
|
||||
.chars()
|
||||
.skip(2)
|
||||
.collect::<String>()
|
||||
.parse()
|
||||
.unwrap(),
|
||||
)
|
||||
};
|
||||
let divisible_by = divisible_by_string.parse().unwrap();
|
||||
let if_true = if_true_string.parse().expect("Non-numeric if_true?");
|
||||
let if_false = if_false_string.parse().unwrap();
|
||||
let test = Test {
|
||||
divisible_by,
|
||||
if_true,
|
||||
if_false,
|
||||
};
|
||||
result.push(Monkey {
|
||||
id,
|
||||
items: starting_items,
|
||||
operation,
|
||||
test,
|
||||
})
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let input = parse_input(INPUT);
|
||||
part_1(&input);
|
||||
part_2(&input);
|
||||
}
|
48
rust/src/day11/part_1.rs
Normal file
48
rust/src/day11/part_1.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use crate::Monkey;
|
||||
|
||||
const ROUND_COUNT: usize = 20;
|
||||
|
||||
pub(crate) fn part_1(input: &[Monkey]) -> u64 {
|
||||
let mut monkey_state = input.to_owned();
|
||||
let mut times_inspected = vec![0; monkey_state.len()];
|
||||
for _ in 0..ROUND_COUNT {
|
||||
for monkey_idx in 0..monkey_state.len() {
|
||||
while let Some(worry) = monkey_state[monkey_idx].items.pop() {
|
||||
let worry = monkey_state[monkey_idx].operation.perform(worry) / 3;
|
||||
|
||||
let throw_to = if worry % monkey_state[monkey_idx].test.divisible_by == 0 {
|
||||
monkey_state[monkey_idx].test.if_true
|
||||
} else {
|
||||
monkey_state[monkey_idx].test.if_false
|
||||
};
|
||||
|
||||
monkey_state[throw_to].items.push(worry);
|
||||
|
||||
times_inspected[monkey_idx] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
times_inspected.sort_unstable();
|
||||
times_inspected.reverse();
|
||||
let result = times_inspected[0] * times_inspected[1];
|
||||
|
||||
println!("Part 1: {result}");
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
const SAMPLE_INPUT: &str = include_str!("sample_input.txt");
|
||||
|
||||
#[test]
|
||||
fn test_with_solution() {
|
||||
assert_eq!(super::part_1(&crate::parse_input(crate::INPUT)), 58786);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_sample_solution() {
|
||||
assert_eq!(super::part_1(&crate::parse_input(SAMPLE_INPUT)), 10605);
|
||||
}
|
||||
}
|
57
rust/src/day11/part_2.rs
Normal file
57
rust/src/day11/part_2.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use crate::Monkey;
|
||||
|
||||
const ROUND_COUNT: usize = 10_000;
|
||||
|
||||
pub(crate) fn part_2(input: &[Monkey]) -> u64 {
|
||||
let mut monkey_state = input.to_owned();
|
||||
let mut times_inspected = vec![0; monkey_state.len()];
|
||||
|
||||
let lcm = monkey_state
|
||||
.iter()
|
||||
.map(|monkey| monkey.test.divisible_by)
|
||||
.product::<u64>();
|
||||
|
||||
for _ in 0..ROUND_COUNT {
|
||||
for monkey_idx in 0..monkey_state.len() {
|
||||
while let Some(worry) = monkey_state[monkey_idx].items.pop() {
|
||||
let worry = monkey_state[monkey_idx].operation.perform(worry);
|
||||
|
||||
let throw_to = if worry % monkey_state[monkey_idx].test.divisible_by == 0 {
|
||||
monkey_state[monkey_idx].test.if_true
|
||||
} else {
|
||||
monkey_state[monkey_idx].test.if_false
|
||||
};
|
||||
|
||||
monkey_state[throw_to].items.push(worry % lcm);
|
||||
|
||||
times_inspected[monkey_idx] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
times_inspected.sort_unstable();
|
||||
times_inspected.reverse();
|
||||
let result = times_inspected[0] * times_inspected[1];
|
||||
|
||||
println!("Part 2: {result}");
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
const SAMPLE_INPUT: &str = include_str!("sample_input.txt");
|
||||
|
||||
#[test]
|
||||
fn test_with_solution() {
|
||||
assert_eq!(
|
||||
super::part_2(&crate::parse_input(crate::INPUT)),
|
||||
14952185856
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_sample_solution() {
|
||||
assert_eq!(super::part_2(&crate::parse_input(SAMPLE_INPUT)), 2713310158);
|
||||
}
|
||||
}
|
27
rust/src/day11/sample_input.txt
Normal file
27
rust/src/day11/sample_input.txt
Normal file
|
@ -0,0 +1,27 @@
|
|||
Monkey 0:
|
||||
Starting items: 79, 98
|
||||
Operation: new = old * 19
|
||||
Test: divisible by 23
|
||||
If true: throw to monkey 2
|
||||
If false: throw to monkey 3
|
||||
|
||||
Monkey 1:
|
||||
Starting items: 54, 65, 75, 74
|
||||
Operation: new = old + 6
|
||||
Test: divisible by 19
|
||||
If true: throw to monkey 2
|
||||
If false: throw to monkey 0
|
||||
|
||||
Monkey 2:
|
||||
Starting items: 79, 60, 97
|
||||
Operation: new = old * old
|
||||
Test: divisible by 13
|
||||
If true: throw to monkey 1
|
||||
If false: throw to monkey 3
|
||||
|
||||
Monkey 3:
|
||||
Starting items: 74
|
||||
Operation: new = old + 3
|
||||
Test: divisible by 17
|
||||
If true: throw to monkey 0
|
||||
If false: throw to monkey 1
|
Loading…
Reference in a new issue