Add bigint lib to day 11, needs so much optimization

This commit is contained in:
Timothy Warren 2022-12-15 11:00:41 -05:00
parent b4e2bb1e26
commit 44a837741d
3 changed files with 136 additions and 49 deletions

39
day11/Cargo.lock generated
View File

@ -2,6 +2,45 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "day11" name = "day11"
version = "0.1.0" 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",
]

View File

@ -6,3 +6,4 @@ 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] [dependencies]
num-bigint = "^0.4.3"

View File

@ -1,23 +1,33 @@
use num_bigint::BigUint;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::ops::*; 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)] #[derive(Debug, PartialEq, Copy, Clone)]
enum WorryType { pub enum WorryType {
Normal, Normal,
Extra, Extra,
} }
#[derive(Debug)] #[derive(Debug)]
struct Operation { pub struct Operation {
operator: char, pub operator: char,
operand: String, pub operand: String,
} }
impl Operation { impl Operation {
fn run(&self, old: u128) -> u128 { #[inline(always)]
pub fn run(&self, old: BigUint) -> BigUint {
let other = match self.operand.as_str() { let other = match self.operand.as_str() {
"old" => old, "old" => old.clone(),
_ => self.operand.parse::<u128>().unwrap(), _ => BigUint::from_str(&self.operand).unwrap(),
}; };
match self.operator { match self.operator {
@ -30,24 +40,24 @@ impl Operation {
} }
#[derive(Debug)] #[derive(Debug)]
struct Monkey { pub struct Monkey {
items: VecDeque<u128>, pub items: VecDeque<BigUint>,
operation: Operation, pub operation: Operation,
test: usize, pub test: usize,
pass_monkey: usize, pub pass_monkey: usize,
fail_monkey: usize, pub fail_monkey: usize,
inspection_count: u128, pub inspection_count: BigUint,
inspection_worry: WorryType, pub inspection_worry: WorryType,
} }
impl Monkey { 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 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<u128> = item_parts[1] let items: VecDeque<BigUint> = item_parts[1]
.split(", ") .split(", ")
.map(|i| i.parse::<u128>().unwrap()) .map(|i| i.parse::<BigUint>().unwrap())
.collect(); .collect();
let op_parts: Vec<&str> = lines[2].split(" = ").collect(); let op_parts: Vec<&str> = lines[2].split(" = ").collect();
@ -75,41 +85,42 @@ impl Monkey {
test, test,
pass_monkey, pass_monkey,
fail_monkey, fail_monkey,
inspection_count: 0, inspection_count: big(0),
inspection_worry, inspection_worry,
} }
} }
fn run_test(&self, item: u128) -> usize { pub fn run_test(&self, item: BigUint) -> usize {
if item % (self.test as u128) == 0 { if item % big(self.test) == big(0) {
self.pass_monkey self.pass_monkey
} else { } else {
self.fail_monkey self.fail_monkey
} }
} }
pub fn inspect(&mut self, item: u128) -> (usize, u128) { #[inline(always)]
self.inspection_count += 1; pub fn inspect(&mut self, item: BigUint) -> (usize, BigUint) {
self.inspection_count += big(1);
let worry = if self.inspection_worry == WorryType::Normal { let worry = if self.inspection_worry == WorryType::Normal {
self.operation.run(item) / 3 self.operation.run(item) / big(3)
} else { } else {
self.operation.run(item) self.operation.run(item)
}; };
let new_monkey = self.run_test(worry); let new_monkey = self.run_test(worry.clone());
(new_monkey, worry) (new_monkey, worry)
} }
pub fn catch(&mut self, item: u128) { pub fn catch(&mut self, item: BigUint) {
self.items.push_back(item); self.items.push_back(item);
} }
} }
#[derive(Debug)] #[derive(Debug)]
struct MonkeyGame { pub struct MonkeyGame {
monkeys: Vec<Monkey>, pub monkeys: Vec<Monkey>,
} }
impl MonkeyGame { 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); self.monkeys[to].catch(item);
} }
fn do_round(&mut self) { pub fn do_round(&mut self) {
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);
@ -136,38 +147,56 @@ impl MonkeyGame {
} }
} }
pub fn do_rounds(&mut self, rounds: usize) { pub fn do_rounds(&mut self, rounds: usize) -> &Self {
for _ in 0..rounds { for r in 0..rounds {
if r % 100 == 0 {
println!("Running round {}", r);
}
self.do_round(); self.do_round();
} }
self
} }
pub fn get_inspection_counts(&self) -> Vec<u128> { pub fn get_inspection_counts(&self) -> Vec<BigUint> {
let mut counts: Vec<u128> = self.monkeys.iter().map(|m| m.inspection_count).collect(); let mut counts: Vec<BigUint> = self
.monkeys
.iter()
.map(|m| m.inspection_count.clone())
.collect();
counts.sort(); counts.sort();
counts.into_iter().rev().collect() 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() { fn main() {
let file_str = include_str!("input.txt"); let file_str = include_str!("input.txt");
let mut game = MonkeyGame::from_file_str(file_str, WorryType::Normal); let monkey_business1 = MonkeyGame::from_file_str(file_str, WorryType::Normal)
game.do_rounds(20); .do_rounds(20)
.get_monkey_business();
let inspections = game.get_inspection_counts(); println!("Part 1 monkey business: {}", monkey_business1);
let monkey_business = inspections[0] * inspections[1];
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); println!("monkey business 400 rounds: {}", monkey_business1);
// game.do_rounds(10_000);
// let inspections = game.get_inspection_counts(); // let monkey_business2 = MonkeyGame::from_file_str(file_str, WorryType::Extra)
// let monkey_business = inspections[0] * inspections[1]; // .do_rounds(10_000)
// .get_monkey_business();
// println!("Part 2 monkey business: {}", monkey_business); //
// println!("Part 2 monkey business: {}", monkey_business2);
} }
#[cfg(test)] #[cfg(test)]
@ -183,10 +212,20 @@ 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_round(); 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!( assert_eq!(
game.monkeys[1].items, 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[2].items, VecDeque::new());
assert_eq!(game.monkeys[3].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); 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, 101); assert_eq!(game.monkeys[0].inspection_count, big(101));
assert_eq!(game.monkeys[3].inspection_count, 105); 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));
} }
} }