Add solution for 2022 day 11 part 1
This commit is contained in:
parent
c173b62d37
commit
273a54b4ca
7
2022/Cargo.lock
generated
7
2022/Cargo.lock
generated
@ -48,6 +48,13 @@ version = "0.1.0"
|
||||
name = "aoc-2022-10"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "aoc-2022-11"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.0"
|
||||
|
@ -10,6 +10,7 @@ members = [
|
||||
"./day-08",
|
||||
"./day-09",
|
||||
"./day-10",
|
||||
"./day-11",
|
||||
]
|
||||
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
| [08] | ✓ | ✓ | [Rust] |
|
||||
| [09] | ✓ | ✓ | [Rust] |
|
||||
| [10] | ✓ | ✓ | [Rust] |
|
||||
| [11] | | | |
|
||||
| [11] | ✓ | | [Rust] |
|
||||
| [12] | | | |
|
||||
| [13] | | | |
|
||||
| [14] | | | |
|
||||
|
13
2022/day-11/Cargo.toml
Normal file
13
2022/day-11/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "aoc-2022-11"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
doctest = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.10.5"
|
5
2022/day-11/Justfile
Normal file
5
2022/day-11/Justfile
Normal file
@ -0,0 +1,5 @@
|
||||
@part PART INPUT_FILE="inputs/puzzle.txt":
|
||||
cargo --quiet run --bin part_{{PART}} -- {{INPUT_FILE}}
|
||||
|
||||
clean:
|
||||
cargo clean
|
55
2022/day-11/inputs/puzzle.txt
Normal file
55
2022/day-11/inputs/puzzle.txt
Normal file
@ -0,0 +1,55 @@
|
||||
Monkey 0:
|
||||
Starting items: 99, 63, 76, 93, 54, 73
|
||||
Operation: new = old * 11
|
||||
Test: divisible by 2
|
||||
If true: throw to monkey 7
|
||||
If false: throw to monkey 1
|
||||
|
||||
Monkey 1:
|
||||
Starting items: 91, 60, 97, 54
|
||||
Operation: new = old + 1
|
||||
Test: divisible by 17
|
||||
If true: throw to monkey 3
|
||||
If false: throw to monkey 2
|
||||
|
||||
Monkey 2:
|
||||
Starting items: 65
|
||||
Operation: new = old + 7
|
||||
Test: divisible by 7
|
||||
If true: throw to monkey 6
|
||||
If false: throw to monkey 5
|
||||
|
||||
Monkey 3:
|
||||
Starting items: 84, 55
|
||||
Operation: new = old + 3
|
||||
Test: divisible by 11
|
||||
If true: throw to monkey 2
|
||||
If false: throw to monkey 6
|
||||
|
||||
Monkey 4:
|
||||
Starting items: 86, 63, 79, 54, 83
|
||||
Operation: new = old * old
|
||||
Test: divisible by 19
|
||||
If true: throw to monkey 7
|
||||
If false: throw to monkey 0
|
||||
|
||||
Monkey 5:
|
||||
Starting items: 96, 67, 56, 95, 64, 69, 96
|
||||
Operation: new = old + 4
|
||||
Test: divisible by 5
|
||||
If true: throw to monkey 4
|
||||
If false: throw to monkey 0
|
||||
|
||||
Monkey 6:
|
||||
Starting items: 66, 94, 70, 93, 72, 67, 88, 51
|
||||
Operation: new = old * 5
|
||||
Test: divisible by 13
|
||||
If true: throw to monkey 4
|
||||
If false: throw to monkey 5
|
||||
|
||||
Monkey 7:
|
||||
Starting items: 59, 59, 74
|
||||
Operation: new = old + 8
|
||||
Test: divisible by 3
|
||||
If true: throw to monkey 1
|
||||
If false: throw to monkey 3
|
27
2022/day-11/inputs/test.txt
Normal file
27
2022/day-11/inputs/test.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
|
87
2022/day-11/src/bin/part_one.rs
Normal file
87
2022/day-11/src/bin/part_one.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
env, io,
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use aoc_2022_11::parse_input;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let infile_path = env::args().nth(1).expect("input file");
|
||||
|
||||
let result = solve(&infile_path)?;
|
||||
|
||||
println!("{result}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn solve(path: &str) -> io::Result<u64> {
|
||||
let notes = parse_input(path)?;
|
||||
|
||||
let mut activity_counter = HashMap::<usize, u64>::new();
|
||||
let mut state = notes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| (i, v.items.clone()))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
|
||||
for _ in 0..20 {
|
||||
for monkey_id in 0..state.len() {
|
||||
let items = {
|
||||
let state = state.get_mut(&monkey_id).unwrap();
|
||||
state.drain(..).collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
for item in items {
|
||||
activity_counter
|
||||
.entry(monkey_id)
|
||||
.and_modify(|v| *v += 1)
|
||||
.or_insert(1);
|
||||
|
||||
let note = ¬es[monkey_id];
|
||||
|
||||
let new_value = note.operation.apply(item) / 3;
|
||||
|
||||
let next_monkey = if new_value % note.test_mod == 0 {
|
||||
note.next_monkey_when_true
|
||||
} else {
|
||||
note.next_monkey_when_false
|
||||
};
|
||||
|
||||
state
|
||||
.entry(next_monkey)
|
||||
.and_modify(|f| f.push(new_value))
|
||||
.or_insert_with(|| vec![new_value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let most_active_product = activity_counter
|
||||
.values()
|
||||
.sorted_by(|a, b| b.cmp(a))
|
||||
.take(2)
|
||||
.copied()
|
||||
.reduce(|acc, val| acc * val)
|
||||
.unwrap();
|
||||
|
||||
Ok(most_active_product)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sample() {
|
||||
let result = solve("inputs/test.txt").unwrap();
|
||||
assert_eq!(10_605, result)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn puzzle() {
|
||||
let result = solve("inputs/puzzle.txt").unwrap();
|
||||
assert_eq!(316_888, result);
|
||||
}
|
||||
}
|
136
2022/day-11/src/lib.rs
Normal file
136
2022/day-11/src/lib.rs
Normal file
@ -0,0 +1,136 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, Read},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
pub type WorryLevel = u64;
|
||||
pub type MonkeyId = usize;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Param {
|
||||
Old,
|
||||
Val(WorryLevel),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Operation {
|
||||
Mul(Param, Param),
|
||||
Add(Param, Param),
|
||||
Noop,
|
||||
}
|
||||
|
||||
impl Operation {
|
||||
pub fn apply(&self, old: WorryLevel) -> WorryLevel {
|
||||
match self {
|
||||
Self::Mul(Param::Old, Param::Val(val)) => old * val,
|
||||
Self::Mul(Param::Old, Param::Old) => old * old,
|
||||
Self::Add(Param::Old, Param::Val(val)) => old + val,
|
||||
Self::Add(Param::Old, Param::Old) => old + old,
|
||||
_ => panic!("unsupported operation"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Note {
|
||||
pub items: Vec<WorryLevel>,
|
||||
pub operation: Operation,
|
||||
pub test_mod: WorryLevel,
|
||||
pub next_monkey_when_true: MonkeyId,
|
||||
pub next_monkey_when_false: MonkeyId,
|
||||
}
|
||||
|
||||
pub fn parse_input<P>(path: P) -> io::Result<Vec<Note>>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut file = File::open(path)?;
|
||||
let mut input = String::new();
|
||||
file.read_to_string(&mut input)?;
|
||||
|
||||
let notes = input.split("\n\n").map(|part| parse_note(part)).collect();
|
||||
|
||||
Ok(notes)
|
||||
}
|
||||
|
||||
fn parse_note(input: &str) -> Note {
|
||||
let mut items = vec![];
|
||||
let mut operation = Operation::Noop;
|
||||
let mut test_mod = 0;
|
||||
let mut next_monkey_when_true = 0;
|
||||
let mut next_monkey_when_false = 0;
|
||||
|
||||
for line in input.lines() {
|
||||
let line = line.trim_start();
|
||||
let (val, rem) = line.split_once(':').unwrap();
|
||||
|
||||
match val {
|
||||
"Starting items" => {
|
||||
items = parse_starting_items(rem);
|
||||
}
|
||||
"Operation" => {
|
||||
operation = parse_operation(rem);
|
||||
}
|
||||
"Test" => {
|
||||
test_mod = parse_test(rem);
|
||||
}
|
||||
"If true" => {
|
||||
next_monkey_when_true = parse_next_monkey(rem);
|
||||
}
|
||||
"If false" => {
|
||||
next_monkey_when_false = parse_next_monkey(rem);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Note {
|
||||
items,
|
||||
operation,
|
||||
test_mod,
|
||||
next_monkey_when_true,
|
||||
next_monkey_when_false,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_starting_items(input: &str) -> Vec<WorryLevel> {
|
||||
input
|
||||
.split(',')
|
||||
.map(|val| val.trim_start().parse().unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn parse_operation(input: &str) -> Operation {
|
||||
let input = input.strip_prefix(" new = old ").unwrap();
|
||||
let op_and_val = input.split_whitespace().collect::<Vec<&str>>();
|
||||
match *op_and_val {
|
||||
["*", "old"] => Operation::Mul(Param::Old, Param::Old),
|
||||
["*", val] => {
|
||||
let val = val.parse().unwrap();
|
||||
Operation::Mul(Param::Old, Param::Val(val))
|
||||
}
|
||||
["+", "old"] => Operation::Add(Param::Old, Param::Old),
|
||||
["+", val] => {
|
||||
let val = val.parse().unwrap();
|
||||
Operation::Add(Param::Old, Param::Val(val))
|
||||
}
|
||||
_ => panic!("Unsupported operation"),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_test(input: &str) -> WorryLevel {
|
||||
input
|
||||
.strip_prefix(" divisible by ")
|
||||
.unwrap()
|
||||
.parse()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn parse_next_monkey(input: &str) -> MonkeyId {
|
||||
input
|
||||
.strip_prefix(" throw to monkey ")
|
||||
.unwrap()
|
||||
.parse()
|
||||
.unwrap()
|
||||
}
|
Loading…
Reference in New Issue
Block a user