diff --git a/day11/Cargo.lock b/day11/Cargo.lock index c75c7b5..36ef88f 100644 --- a/day11/Cargo.lock +++ b/day11/Cargo.lock @@ -3,44 +3,287 @@ version = 3 [[package]] -name = "autocfg" -version = "1.1.0" +name = "base64" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +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]] name = "day11" version = "0.1.0" dependencies = [ - "num-bigint", + "malachite", ] [[package]] -name = "num-bigint" -version = "0.4.3" +name = "digest" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "generic-array", ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "either" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "embed-doc-image" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af36f591236d9d822425cb6896595658fa558fcebf5ee8accac1d4b92c47166e" dependencies = [ - "autocfg", - "num-traits", + "base64", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "num-traits" -version = "0.2.15" +name = "generic-array" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ - "autocfg", + "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" diff --git a/day11/Cargo.toml b/day11/Cargo.toml index 32d0598..4089b32 100644 --- a/day11/Cargo.toml +++ b/day11/Cargo.toml @@ -6,4 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -num-bigint = "^0.4.3" +malachite = "0.3.0" + +[profile.dev] +debug = 1 \ No newline at end of file diff --git a/day11/src/main.rs b/day11/src/main.rs index 4a214e0..67b72bd 100644 --- a/day11/src/main.rs +++ b/day11/src/main.rs @@ -1,12 +1,13 @@ -use num_bigint::BigUint; +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::ops::*; use std::str::FromStr; /// Just to cut down on boilerplate for operations /// with primitive types -#[inline(always)] -fn big(n: usize) -> BigUint { +fn big(n: usize) -> Integer { n.into() } @@ -16,24 +17,46 @@ pub enum WorryType { Extra, } +#[derive(Debug, PartialEq, Clone)] +enum Operand { + Old, + Literal(Integer) +} + #[derive(Debug)] -pub struct Operation { - pub operator: char, - pub operand: String, +struct Operation { + operator: char, + operand: Operand, } impl Operation { + fn new(operator: char, operand: &str) -> Self { + let operand = match operand { + "old" => Operand::Old, + _ => Operand::Literal(Integer::from_str(operand).unwrap()), + }; + + Operation { + operator, + operand, + } + } + #[inline(always)] - pub fn run(&self, old: BigUint) -> BigUint { - let other = match self.operand.as_str() { - "old" => old.clone(), - _ => BigUint::from_str(&self.operand).unwrap(), + fn run(&self, old: Integer) -> Integer { + let operand = self.operand.clone(); + if operand == Operand::Old && self.operator == '*' { + return old.square(); + } + + let other = match operand { + Operand::Old => old.clone(), + Operand::Literal(other) => other, }; match self.operator { - '+' => old.add(other), - '-' => old.sub(other), - '*' => old.mul(other), + '+' => old + other, + '*' => old * other, _ => panic!("Invalid operator"), } } @@ -41,13 +64,13 @@ impl Operation { #[derive(Debug)] 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, + items: VecDeque, + operation: Operation, + test: Integer, + pass_monkey: usize, + fail_monkey: usize, + inspection_count: Integer, + inspection_worry: WorryType, } impl Monkey { @@ -55,9 +78,9 @@ impl Monkey { 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(); @@ -78,20 +101,21 @@ impl Monkey { Monkey { items, - operation: Operation { - operator: operator.chars().next().unwrap(), - operand: operand.to_string(), - }, - test, + operation: Operation::new( + operator.chars().next().unwrap(), + operand + ), + test: big(test), pass_monkey, fail_monkey, - inspection_count: big(0), + inspection_count: Integer::ZERO, inspection_worry, } } - pub fn run_test(&self, item: BigUint) -> usize { - if item % big(self.test) == big(0) { + #[inline(always)] + fn run_test(&self, item: &Integer) -> usize { + if item.divisible_by(&self.test) { self.pass_monkey } else { self.fail_monkey @@ -99,7 +123,7 @@ impl Monkey { } #[inline(always)] - pub fn inspect(&mut self, item: BigUint) -> (usize, BigUint) { + pub fn inspect(&mut self, item: Integer) -> (usize, Integer) { self.inspection_count += big(1); let worry = if self.inspection_worry == WorryType::Normal { @@ -108,19 +132,20 @@ impl Monkey { self.operation.run(item) }; - let new_monkey = self.run_test(worry.clone()); + let new_monkey = self.run_test(&worry); (new_monkey, worry) } - pub fn catch(&mut self, item: BigUint) { + #[inline(always)] + pub fn catch(&mut self, item: Integer) { self.items.push_back(item); } } #[derive(Debug)] pub struct MonkeyGame { - pub monkeys: Vec, + monkeys: Vec, } impl MonkeyGame { @@ -134,33 +159,30 @@ impl MonkeyGame { } } - pub fn throw(&mut self, item: BigUint, to: usize) { + fn throw(&mut self, item: Integer, to: usize) { self.monkeys[to].catch(item); } - 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); - self.throw(worry, monkey_idx); - } - } - } - + #[inline(always)] 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(); + 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); + self.throw(worry, monkey_idx); + } + } } self } - pub fn get_inspection_counts(&self) -> Vec { - let mut counts: Vec = self + pub fn get_inspection_counts(&self) -> Vec { + let mut counts: Vec = self .monkeys .iter() .map(|m| m.inspection_count.clone()) @@ -171,7 +193,7 @@ impl MonkeyGame { counts.into_iter().rev().collect() } - pub fn get_monkey_business(&self) -> BigUint { + pub fn get_monkey_business(&self) -> Integer { let inspections = self.get_inspection_counts(); inspections.get(0).unwrap() * inspections.get(1).unwrap() @@ -183,20 +205,12 @@ fn main() { let monkey_business1 = MonkeyGame::from_file_str(file_str, WorryType::Normal) .do_rounds(20) .get_monkey_business(); - println!("Part 1 monkey business: {}", monkey_business1); - let monkey_business1 = MonkeyGame::from_file_str(file_str, WorryType::Extra) - .do_rounds(500) + let monkey_business2 = MonkeyGame::from_file_str(file_str, WorryType::Extra) + .do_rounds(10_000) .get_monkey_business(); - - println!("monkey business 400 rounds: {}", monkey_business1); - - // 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); + println!("Part 2 monkey business: {}", monkey_business2); } #[cfg(test)] @@ -208,9 +222,9 @@ mod tests { } #[test] - fn test_monkey_round() { + fn monkey_round() { let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal); - game.do_round(); + game.do_rounds(1); assert_eq!( game.monkeys[0].items, @@ -232,15 +246,44 @@ mod tests { } #[test] - fn test_monkey_20_rounds() { + fn monkey_20_rounds() { let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal); game.do_rounds(20); assert_eq!(game.monkeys[0].inspection_count, big(101)); assert_eq!(game.monkeys[3].inspection_count, big(105)); + assert_eq!(game.get_monkey_business(), big(10605)); } - fn test_monkey_10000_rounds() { + 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] + fn monkey_20_rounds_extra_worry() { + let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra); + game.do_rounds(20); + + assert_eq!(game.monkeys[0].inspection_count, big(99)); + assert_eq!(game.monkeys[3].inspection_count, big(103)); + assert_eq!(game.get_monkey_business(), big(10197)); + } + + + fn monkey_1000_rounds_extra_worry() { + let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra); + game.do_rounds(1000); + + assert_eq!(game.monkeys[0].inspection_count, big(5204)); + assert_eq!(game.monkeys[3].inspection_count, big(5192)); + } + + + fn monkey_10_000_rounds_extra_worry() { let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra); game.do_rounds(10_000);