From 44a837741d31798e6638af9b572cf152b2e43703 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Thu, 15 Dec 2022 11:00:41 -0500 Subject: [PATCH] Add bigint lib to day 11, needs so much optimization --- day11/Cargo.lock | 39 +++++++++++++ day11/Cargo.toml | 1 + day11/src/main.rs | 145 ++++++++++++++++++++++++++++++---------------- 3 files changed, 136 insertions(+), 49 deletions(-) diff --git a/day11/Cargo.lock b/day11/Cargo.lock index 4ab9be8..c75c7b5 100644 --- a/day11/Cargo.lock +++ b/day11/Cargo.lock @@ -2,6 +2,45 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "day11" version = "0.1.0" +dependencies = [ + "num-bigint", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] diff --git a/day11/Cargo.toml b/day11/Cargo.toml index 8f5b9a5..32d0598 100644 --- a/day11/Cargo.toml +++ b/day11/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +num-bigint = "^0.4.3" diff --git a/day11/src/main.rs b/day11/src/main.rs index fea9b98..4a214e0 100644 --- a/day11/src/main.rs +++ b/day11/src/main.rs @@ -1,23 +1,33 @@ +use num_bigint::BigUint; use std::collections::VecDeque; use std::ops::*; +use std::str::FromStr; + +/// Just to cut down on boilerplate for operations +/// with primitive types +#[inline(always)] +fn big(n: usize) -> BigUint { + n.into() +} #[derive(Debug, PartialEq, Copy, Clone)] -enum WorryType { +pub enum WorryType { Normal, Extra, } #[derive(Debug)] -struct Operation { - operator: char, - operand: String, +pub struct Operation { + pub operator: char, + pub operand: String, } impl Operation { - fn run(&self, old: u128) -> u128 { + #[inline(always)] + pub fn run(&self, old: BigUint) -> BigUint { let other = match self.operand.as_str() { - "old" => old, - _ => self.operand.parse::().unwrap(), + "old" => old.clone(), + _ => BigUint::from_str(&self.operand).unwrap(), }; match self.operator { @@ -30,24 +40,24 @@ impl Operation { } #[derive(Debug)] -struct Monkey { - items: VecDeque, - operation: Operation, - test: usize, - pass_monkey: usize, - fail_monkey: usize, - inspection_count: u128, - inspection_worry: WorryType, +pub struct Monkey { + pub items: VecDeque, + pub operation: Operation, + pub test: usize, + pub pass_monkey: usize, + pub fail_monkey: usize, + pub inspection_count: BigUint, + pub inspection_worry: WorryType, } impl Monkey { - fn from_behavior(raw: &str, inspection_worry: WorryType) -> Self { + pub fn from_behavior(raw: &str, inspection_worry: WorryType) -> Self { let lines: Vec<&str> = raw.lines().collect(); let item_parts: Vec<&str> = lines[1].split(": ").collect(); - let items: VecDeque = item_parts[1] + let items: VecDeque = item_parts[1] .split(", ") - .map(|i| i.parse::().unwrap()) + .map(|i| i.parse::().unwrap()) .collect(); let op_parts: Vec<&str> = lines[2].split(" = ").collect(); @@ -75,41 +85,42 @@ impl Monkey { test, pass_monkey, fail_monkey, - inspection_count: 0, + inspection_count: big(0), inspection_worry, } } - fn run_test(&self, item: u128) -> usize { - if item % (self.test as u128) == 0 { + pub fn run_test(&self, item: BigUint) -> usize { + if item % big(self.test) == big(0) { self.pass_monkey } else { self.fail_monkey } } - pub fn inspect(&mut self, item: u128) -> (usize, u128) { - self.inspection_count += 1; + #[inline(always)] + pub fn inspect(&mut self, item: BigUint) -> (usize, BigUint) { + self.inspection_count += big(1); let worry = if self.inspection_worry == WorryType::Normal { - self.operation.run(item) / 3 + self.operation.run(item) / big(3) } else { self.operation.run(item) }; - let new_monkey = self.run_test(worry); + let new_monkey = self.run_test(worry.clone()); (new_monkey, worry) } - pub fn catch(&mut self, item: u128) { + pub fn catch(&mut self, item: BigUint) { self.items.push_back(item); } } #[derive(Debug)] -struct MonkeyGame { - monkeys: Vec, +pub struct MonkeyGame { + pub monkeys: Vec, } impl MonkeyGame { @@ -123,11 +134,11 @@ impl MonkeyGame { } } - fn throw(&mut self, item: u128, to: usize) { + pub fn throw(&mut self, item: BigUint, to: usize) { self.monkeys[to].catch(item); } - fn do_round(&mut self) { + pub fn do_round(&mut self) { for m in 0..self.monkeys.len() { while let Some(worry) = self.monkeys[m].items.pop_front() { let (monkey_idx, worry) = self.monkeys[m].inspect(worry); @@ -136,38 +147,56 @@ impl MonkeyGame { } } - pub fn do_rounds(&mut self, rounds: usize) { - for _ in 0..rounds { + pub fn do_rounds(&mut self, rounds: usize) -> &Self { + for r in 0..rounds { + if r % 100 == 0 { + println!("Running round {}", r); + } + self.do_round(); } + + self } - pub fn get_inspection_counts(&self) -> Vec { - let mut counts: Vec = self.monkeys.iter().map(|m| m.inspection_count).collect(); + pub fn get_inspection_counts(&self) -> Vec { + let mut counts: Vec = self + .monkeys + .iter() + .map(|m| m.inspection_count.clone()) + .collect(); counts.sort(); counts.into_iter().rev().collect() } + + pub fn get_monkey_business(&self) -> BigUint { + let inspections = self.get_inspection_counts(); + + inspections.get(0).unwrap() * inspections.get(1).unwrap() + } } fn main() { let file_str = include_str!("input.txt"); - let mut game = MonkeyGame::from_file_str(file_str, WorryType::Normal); - game.do_rounds(20); + let monkey_business1 = MonkeyGame::from_file_str(file_str, WorryType::Normal) + .do_rounds(20) + .get_monkey_business(); - let inspections = game.get_inspection_counts(); - let monkey_business = inspections[0] * inspections[1]; + println!("Part 1 monkey business: {}", monkey_business1); - println!("Part 1 monkey business: {}", monkey_business); + let monkey_business1 = MonkeyGame::from_file_str(file_str, WorryType::Extra) + .do_rounds(500) + .get_monkey_business(); - // let mut game = MonkeyGame::from_file_str(file_str, WorryType::Extra); - // game.do_rounds(10_000); + println!("monkey business 400 rounds: {}", monkey_business1); - // let inspections = game.get_inspection_counts(); - // let monkey_business = inspections[0] * inspections[1]; - - // println!("Part 2 monkey business: {}", monkey_business); + // let monkey_business2 = MonkeyGame::from_file_str(file_str, WorryType::Extra) + // .do_rounds(10_000) + // .get_monkey_business(); + // + // println!("Part 2 monkey business: {}", monkey_business2); } #[cfg(test)] @@ -183,10 +212,20 @@ mod tests { let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal); game.do_round(); - assert_eq!(game.monkeys[0].items, VecDeque::from([20, 23, 27, 26])); + assert_eq!( + game.monkeys[0].items, + VecDeque::from([big(20), big(23), big(27), big(26)]) + ); assert_eq!( game.monkeys[1].items, - VecDeque::from([2080, 25, 167, 207, 401, 1046]) + VecDeque::from([ + big(2080), + big(25), + big(167), + big(207), + big(401), + big(1046) + ]) ); assert_eq!(game.monkeys[2].items, VecDeque::new()); assert_eq!(game.monkeys[3].items, VecDeque::new()); @@ -197,7 +236,15 @@ mod tests { let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal); game.do_rounds(20); - assert_eq!(game.monkeys[0].inspection_count, 101); - assert_eq!(game.monkeys[3].inspection_count, 105); + assert_eq!(game.monkeys[0].inspection_count, big(101)); + assert_eq!(game.monkeys[3].inspection_count, big(105)); + } + + fn test_monkey_10000_rounds() { + let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra); + game.do_rounds(10_000); + + assert_eq!(game.monkeys[0].inspection_count, big(52166)); + assert_eq!(game.monkeys[3].inspection_count, big(52013)); } }