Complete day 11 (albeit with help)

This commit is contained in:
Timothy Warren 2022-12-21 09:39:48 -05:00
parent 9d8c47a9a1
commit 79623dcd00
3 changed files with 58 additions and 367 deletions

282
day11/Cargo.lock generated
View File

@ -2,288 +2,6 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"block-padding",
"generic-array",
]
[[package]]
name = "block-padding"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cpufeatures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "day11" name = "day11"
version = "0.1.0" version = "0.1.0"
dependencies = [
"malachite",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "embed-doc-image"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af36f591236d9d822425cb6896595658fa558fcebf5ee8accac1d4b92c47166e"
dependencies = [
"base64",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "generic-array"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "itertools"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
[[package]]
name = "keccak"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768"
dependencies = [
"cpufeatures",
]
[[package]]
name = "libc"
version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "malachite"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80f6be3354f81a8566e001afe15cb774ce4c7f09ecc19f395f111943c3fba343"
dependencies = [
"malachite-base",
"malachite-nz",
"malachite-q",
]
[[package]]
name = "malachite-base"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30e363f2fe3ec28952bd742c49e81183d00140bf45894a26d3dc2d8dfc126fda"
dependencies = [
"itertools",
"rand",
"rand_chacha",
"ryu",
"sha3",
]
[[package]]
name = "malachite-nz"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6b0e6908a9ab7394526b00f2ec44816adfd47a72acbafdb0b3d0b16ec0ac6af"
dependencies = [
"embed-doc-image",
"itertools",
"malachite-base",
]
[[package]]
name = "malachite-q"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9850d5c4e7b95324d9e9c344f220e189af7cc78eb21c67ac47822757097bd9ce"
dependencies = [
"itertools",
"malachite-base",
"malachite-nz",
]
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "ryu"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "sha3"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809"
dependencies = [
"block-buffer",
"digest",
"keccak",
"opaque-debug",
]
[[package]]
name = "syn"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "unicode-ident"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"

View File

@ -4,9 +4,3 @@ version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
malachite = "0.3.0"
[profile.dev]
debug = 1

View File

@ -1,26 +1,16 @@
use malachite::integer::Integer;
use malachite::num::arithmetic::traits::DivisibleBy;
use malachite::num::arithmetic::traits::Square;
use malachite::num::basic::traits::Zero;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::str::FromStr; use std::str::FromStr;
/// Just to cut down on boilerplate for operations
/// with primitive types
fn big(n: usize) -> Integer {
n.into()
}
#[derive(Debug, PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
pub enum WorryType { pub enum WorryType {
Normal, Normal,
Extra, Extra,
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
enum Operand { enum Operand {
Old, Old,
Literal(Integer) Literal(usize),
} }
#[derive(Debug)] #[derive(Debug)]
@ -33,24 +23,21 @@ impl Operation {
fn new(operator: char, operand: &str) -> Self { fn new(operator: char, operand: &str) -> Self {
let operand = match operand { let operand = match operand {
"old" => Operand::Old, "old" => Operand::Old,
_ => Operand::Literal(Integer::from_str(operand).unwrap()), _ => Operand::Literal(usize::from_str(operand).unwrap()),
}; };
Operation { Operation { operator, operand }
operator,
operand,
}
} }
#[inline(always)] #[inline(always)]
fn run(&self, old: Integer) -> Integer { fn run(&self, old: usize) -> usize {
let operand = self.operand.clone(); let operand = self.operand;
if operand == Operand::Old && self.operator == '*' { if operand == Operand::Old && self.operator == '*' {
return old.square(); return old * old;
} }
let other = match operand { let other = match operand {
Operand::Old => old.clone(), Operand::Old => old,
Operand::Literal(other) => other, Operand::Literal(other) => other,
}; };
@ -64,12 +51,12 @@ impl Operation {
#[derive(Debug)] #[derive(Debug)]
pub struct Monkey { pub struct Monkey {
items: VecDeque<Integer>, items: VecDeque<usize>,
operation: Operation, operation: Operation,
test: Integer, test: usize,
pass_monkey: usize, pass_monkey: usize,
fail_monkey: usize, fail_monkey: usize,
inspection_count: Integer, inspection_count: usize,
inspection_worry: WorryType, inspection_worry: WorryType,
} }
@ -78,9 +65,9 @@ impl Monkey {
let lines: Vec<&str> = raw.lines().collect(); let lines: Vec<&str> = raw.lines().collect();
let item_parts: Vec<&str> = lines[1].split(": ").collect(); let item_parts: Vec<&str> = lines[1].split(": ").collect();
let items: VecDeque<Integer> = item_parts[1] let items: VecDeque<usize> = item_parts[1]
.split(", ") .split(", ")
.map(|i| i.parse::<Integer>().unwrap()) .map(|i| i.parse::<usize>().unwrap())
.collect(); .collect();
let op_parts: Vec<&str> = lines[2].split(" = ").collect(); let op_parts: Vec<&str> = lines[2].split(" = ").collect();
@ -101,21 +88,18 @@ impl Monkey {
Monkey { Monkey {
items, items,
operation: Operation::new( operation: Operation::new(operator.chars().next().unwrap(), operand),
operator.chars().next().unwrap(), test,
operand
),
test: big(test),
pass_monkey, pass_monkey,
fail_monkey, fail_monkey,
inspection_count: Integer::ZERO, inspection_count: 0,
inspection_worry, inspection_worry,
} }
} }
#[inline(always)] #[inline(always)]
fn run_test(&self, item: &Integer) -> usize { fn run_test(&self, item: &usize) -> usize {
if item.divisible_by(&self.test) { if item % self.test == 0 {
self.pass_monkey self.pass_monkey
} else { } else {
self.fail_monkey self.fail_monkey
@ -123,12 +107,17 @@ impl Monkey {
} }
#[inline(always)] #[inline(always)]
pub fn inspect(&mut self, item: Integer) -> (usize, Integer) { pub fn inspect(&mut self, mut item: usize, divisor_product: usize) -> (usize, usize) {
self.inspection_count += big(1); self.inspection_count += 1;
let worry = if self.inspection_worry == WorryType::Normal { let worry = if self.inspection_worry == WorryType::Normal {
self.operation.run(item) / big(3) self.operation.run(item) / 3
} else { } else {
// This is the whole key to keeping the number small enough to be practical.
// I don't really understand it, but I was sick of this not being finished,
// so I based the fix on
// https://fasterthanli.me/series/advent-of-code-2022/part-11
item %= divisor_product;
self.operation.run(item) self.operation.run(item)
}; };
@ -138,7 +127,7 @@ impl Monkey {
} }
#[inline(always)] #[inline(always)]
pub fn catch(&mut self, item: Integer) { pub fn catch(&mut self, item: usize) {
self.items.push_back(item); self.items.push_back(item);
} }
} }
@ -146,20 +135,27 @@ impl Monkey {
#[derive(Debug)] #[derive(Debug)]
pub struct MonkeyGame { pub struct MonkeyGame {
monkeys: Vec<Monkey>, monkeys: Vec<Monkey>,
divisor_product: usize,
} }
impl MonkeyGame { impl MonkeyGame {
pub fn from_file_str(file_str: &'static str, inspection_worry: WorryType) -> Self { pub fn from_file_str(file_str: &'static str, inspection_worry: WorryType) -> Self {
let behaviors = file_str.split("\n\n"); let behaviors = file_str.split("\n\n");
let monkeys: Vec<Monkey> = behaviors
.map(|m| Monkey::from_behavior(m, inspection_worry))
.collect();
// The magic divisor for getting the result with normal integer sizes
let divisor_product = monkeys.iter().map(|m| m.test).product::<usize>();
Self { Self {
monkeys: behaviors monkeys,
.map(|m| Monkey::from_behavior(m, inspection_worry)) divisor_product,
.collect(),
} }
} }
fn throw(&mut self, item: Integer, to: usize) { fn throw(&mut self, item: usize, to: usize) {
self.monkeys[to].catch(item); self.monkeys[to].catch(item);
} }
@ -172,7 +168,7 @@ impl MonkeyGame {
for m in 0..self.monkeys.len() { for m in 0..self.monkeys.len() {
while let Some(worry) = self.monkeys[m].items.pop_front() { while let Some(worry) = self.monkeys[m].items.pop_front() {
let (monkey_idx, worry) = self.monkeys[m].inspect(worry); let (monkey_idx, worry) = self.monkeys[m].inspect(worry, self.divisor_product);
self.throw(worry, monkey_idx); self.throw(worry, monkey_idx);
} }
} }
@ -181,8 +177,8 @@ impl MonkeyGame {
self self
} }
pub fn get_inspection_counts(&self) -> Vec<Integer> { pub fn get_inspection_counts(&self) -> Vec<usize> {
let mut counts: Vec<Integer> = self let mut counts: Vec<usize> = self
.monkeys .monkeys
.iter() .iter()
.map(|m| m.inspection_count.clone()) .map(|m| m.inspection_count.clone())
@ -193,7 +189,7 @@ impl MonkeyGame {
counts.into_iter().rev().collect() counts.into_iter().rev().collect()
} }
pub fn get_monkey_business(&self) -> Integer { pub fn get_monkey_business(&self) -> usize {
let inspections = self.get_inspection_counts(); let inspections = self.get_inspection_counts();
inspections.get(0).unwrap() * inspections.get(1).unwrap() inspections.get(0).unwrap() * inspections.get(1).unwrap()
@ -226,20 +222,10 @@ mod tests {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal); let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal);
game.do_rounds(1); game.do_rounds(1);
assert_eq!( assert_eq!(game.monkeys[0].items, VecDeque::from([20, 23, 27, 26]));
game.monkeys[0].items,
VecDeque::from([big(20), big(23), big(27), big(26)])
);
assert_eq!( assert_eq!(
game.monkeys[1].items, game.monkeys[1].items,
VecDeque::from([ VecDeque::from([2080, 25, 167, 207, 401, 1046])
big(2080),
big(25),
big(167),
big(207),
big(401),
big(1046)
])
); );
assert_eq!(game.monkeys[2].items, VecDeque::new()); assert_eq!(game.monkeys[2].items, VecDeque::new());
assert_eq!(game.monkeys[3].items, VecDeque::new()); assert_eq!(game.monkeys[3].items, VecDeque::new());
@ -250,17 +236,9 @@ mod tests {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal); let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal);
game.do_rounds(20); game.do_rounds(20);
assert_eq!(game.monkeys[0].inspection_count, big(101)); assert_eq!(game.monkeys[0].inspection_count, 101);
assert_eq!(game.monkeys[3].inspection_count, big(105)); assert_eq!(game.monkeys[3].inspection_count, 105);
assert_eq!(game.get_monkey_business(), big(10605)); assert_eq!(game.get_monkey_business(), 10605);
}
fn monkey_10_000_rounds() {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal);
game.do_rounds(10_000);
assert_eq!(game.monkeys[0].inspection_count, big(52166));
assert_eq!(game.monkeys[3].inspection_count, big(52013));
} }
#[test] #[test]
@ -268,26 +246,27 @@ mod tests {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra); let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra);
game.do_rounds(20); game.do_rounds(20);
assert_eq!(game.monkeys[0].inspection_count, big(99)); assert_eq!(game.monkeys[0].inspection_count, 99);
assert_eq!(game.monkeys[3].inspection_count, big(103)); assert_eq!(game.monkeys[3].inspection_count, 103);
assert_eq!(game.get_monkey_business(), big(10197)); assert_eq!(game.get_monkey_business(), 10197);
} }
#[test]
fn monkey_1000_rounds_extra_worry() { fn monkey_1000_rounds_extra_worry() {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra); let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra);
game.do_rounds(1000); game.do_rounds(1000);
assert_eq!(game.monkeys[0].inspection_count, big(5204)); assert_eq!(game.monkeys[0].inspection_count, 5204);
assert_eq!(game.monkeys[3].inspection_count, big(5192)); assert_eq!(game.monkeys[3].inspection_count, 5192);
} }
#[test]
fn monkey_10_000_rounds_extra_worry() { fn monkey_10_000_rounds_extra_worry() {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra); let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra);
game.do_rounds(10_000); game.do_rounds(10_000);
assert_eq!(game.monkeys[0].inspection_count, big(52166)); assert_eq!(game.monkeys[0].inspection_count, 52166);
assert_eq!(game.monkeys[3].inspection_count, big(52013)); assert_eq!(game.monkeys[3].inspection_count, 52013);
assert_eq!(game.get_monkey_business(), 2713310158);
} }
} }