diff --git a/y2015/resources/17_input.txt b/y2015/resources/17_input.txt new file mode 100644 index 0000000..f796965 --- /dev/null +++ b/y2015/resources/17_input.txt @@ -0,0 +1,20 @@ +11 +30 +47 +31 +32 +36 +3 +1 +5 +3 +32 +36 +15 +11 +46 +26 +28 +1 +19 +3 diff --git a/y2015/src/bin/d17.rs b/y2015/src/bin/d17.rs new file mode 100644 index 0000000..d6bf4ec --- /dev/null +++ b/y2015/src/bin/d17.rs @@ -0,0 +1,20 @@ +use std::fs; + +use y2015::days::d17; + +fn main() { + part1(); + part2(); +} + +fn part1() { + let root = env!("CARGO_MANIFEST_DIR"); + let content = fs::read_to_string(format!("{root}/resources/17_input.txt")).unwrap(); + println!("{}", d17::process_part1(&content, 150)); +} + +fn part2() { + let root = env!("CARGO_MANIFEST_DIR"); + let content = fs::read_to_string(format!("{root}/resources/17_input.txt")).unwrap(); + println!("{}", d17::process_part2(&content, 150)); +} diff --git a/y2015/src/days/d15.rs b/y2015/src/days/d15.rs index 9e27d04..565568b 100644 --- a/y2015/src/days/d15.rs +++ b/y2015/src/days/d15.rs @@ -173,10 +173,6 @@ pub fn process_part1(input: &str) -> i64 { biggest_score } -pub fn process_part2(input: &str) -> u32 { - 0 -} - #[cfg(test)] mod tests { use super::*; diff --git a/y2015/src/days/d16.rs b/y2015/src/days/d16.rs index dbaea1e..edd6690 100644 --- a/y2015/src/days/d16.rs +++ b/y2015/src/days/d16.rs @@ -59,16 +59,3 @@ pub fn process_part2(input: &str) -> String { } "".to_string() } - -#[cfg(test)] -mod tests { - use super::*; - - const INPUT: &str = "{{EXAMPLE}}"; - - #[test] - fn part2() { - let result = process_part2(INPUT); - assert_eq!(result, 0); - } -} diff --git a/y2015/src/days/d17.rs b/y2015/src/days/d17.rs new file mode 100644 index 0000000..fa608b9 --- /dev/null +++ b/y2015/src/days/d17.rs @@ -0,0 +1,113 @@ +use std::{error::Error, fmt::Debug}; + +pub fn process_part1(input: &str, litres: u32) -> u32 { + let containers = input + .lines() + .map(|container| container.parse::().unwrap()) + .collect::>(); + let mut correct_combinations = Vec::new(); + for k in 1..=containers.len() { + let num_combinations = binomial(containers.len(), k); + for i in 1..=num_combinations { + let res = combination(containers.clone(), k, i).unwrap(); + if res.iter().sum::() == litres { + correct_combinations.push(res); + } + } + } + correct_combinations.len() as u32 +} + +pub fn process_part2(input: &str, litres: u32) -> u32 { + let containers = input + .lines() + .map(|container| container.parse::().unwrap()) + .collect::>(); + let mut correct_combinations = Vec::new(); + for k in 1..=containers.len() { + let num_combinations = binomial(containers.len(), k); + for i in 1..=num_combinations { + let res = combination(containers.clone(), k, i).unwrap(); + if res.iter().sum::() == litres { + correct_combinations.push(res); + } + } + if !correct_combinations.is_empty() { + break; + } + } + correct_combinations.len() as u32 +} + +fn combination( + elements: Vec, + k: usize, + nth: usize, +) -> Result, Box> { + let num_elements = elements.len(); + let num_combinations = binomial(num_elements, k); + if nth > num_combinations || k > num_elements || nth == 0 || k == 0 { + return Err(Box::from("Out of bounds")); + } + let mut i = 0; + let mut remaining_k = k; + let mut comb = Vec::new(); + let mut remainder = nth - 1; + while remaining_k > 0 { + // Count the number of combinations that start with elements[i] + // example with n = 5, k = 2 + // nth <= 4 select first + // nth <= 7 select second + // nth <= 9 select third + // nth == 10 select fourth + let count = binomial(num_elements - i - 1, remaining_k - 1); + if remainder < count { + // If the nth combination is within the count, pick this element + comb.push(elements[i].clone()); + remaining_k -= 1; + } else { + remainder -= count; + } + i += 1; + } + Ok(comb) +} + +fn factorial(num: usize) -> usize { + let mut fact = 1; + for n in 1..=num { + fact *= n; + } + fact +} + +fn binomial(n: usize, k: usize) -> usize { + if k > n { + 0 + } else { + factorial(n) / (factorial(k) * factorial(n - k)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const INPUT: &str = "20 +15 +10 +5 +5"; + + #[test] + fn part1() { + let result = process_part1(INPUT, 25); + assert_eq!(result, 4); + } + + #[test] + fn part2() { + let result = process_part2(INPUT, 25); + assert_eq!(result, 3); + } +} diff --git a/y2015/src/days/mod.rs b/y2015/src/days/mod.rs index 6bd83e0..7e6bd80 100644 --- a/y2015/src/days/mod.rs +++ b/y2015/src/days/mod.rs @@ -15,3 +15,5 @@ pub mod d8; pub mod d9; pub mod d16; + +pub mod d17;