Add solution for 2022 day 11 part 1

This commit is contained in:
Patrick Auernig 2022-12-13 18:07:45 +01:00
parent c173b62d37
commit 273a54b4ca
10 changed files with 333 additions and 2 deletions

7
2022/Cargo.lock generated
View File

@ -48,6 +48,13 @@ version = "0.1.0"
name = "aoc-2022-10" name = "aoc-2022-10"
version = "0.1.0" version = "0.1.0"
[[package]]
name = "aoc-2022-11"
version = "0.1.0"
dependencies = [
"itertools",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.8.0" version = "1.8.0"

View File

@ -10,6 +10,7 @@ members = [
"./day-08", "./day-08",
"./day-09", "./day-09",
"./day-10", "./day-10",
"./day-11",
] ]

View File

@ -14,7 +14,7 @@
| [08] | ✓ | ✓ | [Rust] | | [08] | ✓ | ✓ | [Rust] |
| [09] | ✓ | ✓ | [Rust] | | [09] | ✓ | ✓ | [Rust] |
| [10] | ✓ | ✓ | [Rust] | | [10] | ✓ | ✓ | [Rust] |
| [11] | | | | | [11] | ✓ | | [Rust] |
| [12] | | | | | [12] | | | |
| [13] | | | | | [13] | | | |
| [14] | | | | | [14] | | | |

13
2022/day-11/Cargo.toml Normal file
View 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
View File

@ -0,0 +1,5 @@
@part PART INPUT_FILE="inputs/puzzle.txt":
cargo --quiet run --bin part_{{PART}} -- {{INPUT_FILE}}
clean:
cargo clean

View 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

View 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

View 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 = &notes[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
View 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()
}

View File

@ -9,4 +9,4 @@
- [2019](2019/README.md) (0% completed) - [2019](2019/README.md) (0% completed)
- [2020](2020/README.md) (20% completed) - [2020](2020/README.md) (20% completed)
- [2021](2021/README.md) (68% completed) - [2021](2021/README.md) (68% completed)
- [2022](2022/README.md) (40% completed) - [2022](2022/README.md) (42% completed)