diff --git a/Cargo.toml b/Cargo.toml index 1b13c20..82faf59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "advent-rs" -version = "2015.23.1" +version = "2015.24.1" edition = "2021" authors = ["Arnaud 'red' Rouyer"] readme = "README.md" diff --git a/NOTES_2015.md b/NOTES_2015.md index ce4ba96..382e215 100644 --- a/NOTES_2015.md +++ b/NOTES_2015.md @@ -663,3 +663,28 @@ year_2015::day_23/year_2015::day_23_v2 Heh, I love this one, whether it's in Ruby or in Rust. + +## Day 24: It Hangs in the Balance + +
+đź“ŠTests and benchmarks + +``` +test year_2015::day_24::tests::works_with_samples_v1 ... ok +test year_2015::day_24::tests::works_with_samples_v2 ... ok +test year_2015::tests::day_24 ... ok + +year_2015::day_24/year_2015::day_24_v1 + time: [15.294 ms 15.326 ms 15.360 ms] +year_2015::day_24/year_2015::day_24_v2 + time: [3.5474 ms 3.5596 ms 3.5719 ms] +``` +
+ +
+Ruby version comments + +>While this looks like YABA (Yet Another Bruteforce Algorithm), Ruby's got a very useful [`#combination`](https://ruby-doc.org/3.2.2/Array.html#method-i-combination) method that will generate permutations around for you. And of course, knowing when to exit the loop at the best time is half the battle. +
+ +Would you believe it? The `combinations(n)` method also exists in Rust! diff --git a/README.md b/README.md index 4ac469c..20e0d7f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ As I said, [Consistency is hard](https://github.com/joshleaves/advent-rb), and I haven't taken the time to pick up a new language in quite a while. I'm also adding notes that may be useful if you're (like me) discovering Rust: -- [2015, up to day 23](NOTES_2015.md) +- [2015, up to day 24](NOTES_2015.md) # Regarding style rules I'm gonna use a mix of what `cargo fmt` does, with some stuff that feels more natural to me. diff --git a/benches/advent-bench.rs b/benches/advent-bench.rs index ba4ef98..53031d4 100644 --- a/benches/advent-bench.rs +++ b/benches/advent-bench.rs @@ -21,6 +21,7 @@ use advent_rs::year_2015::day_20; use advent_rs::year_2015::day_21; use advent_rs::year_2015::day_22; use advent_rs::year_2015::day_23; +use advent_rs::year_2015::day_24; use criterion::{black_box, criterion_group, criterion_main, Criterion}; pub fn year_2015_benchmark(c: &mut Criterion) { @@ -255,6 +256,16 @@ pub fn year_2015_benchmark(c: &mut Criterion) { b.iter(|| day_23::day_23_v2(black_box(input_year_2015_day_23))) }); g2015_day_23.finish(); + + let mut g2015_day_24 = c.benchmark_group("year_2015::day_24"); + let input_year_2015_day_24 = include_str!("../inputs/year_2015_day_24_input"); + g2015_day_24.bench_function("year_2015::day_24_v1", |b| { + b.iter(|| day_24::day_24_v1(black_box(input_year_2015_day_24))) + }); + g2015_day_24.bench_function("year_2015::day_24_v2", |b| { + b.iter(|| day_24::day_24_v2(black_box(input_year_2015_day_24))) + }); + g2015_day_24.finish(); } criterion_group!(benches, year_2015_benchmark); diff --git a/inputs/year_2015_day_24_input b/inputs/year_2015_day_24_input new file mode 100644 index 0000000..67ab0c3 --- /dev/null +++ b/inputs/year_2015_day_24_input @@ -0,0 +1,28 @@ +1 +3 +5 +11 +13 +17 +19 +23 +29 +31 +37 +41 +43 +47 +53 +59 +67 +71 +73 +79 +83 +89 +97 +101 +103 +107 +109 +113 \ No newline at end of file diff --git a/src/year_2015.rs b/src/year_2015.rs index 5c059e3..bade567 100644 --- a/src/year_2015.rs +++ b/src/year_2015.rs @@ -56,6 +56,7 @@ pub mod day_20; pub mod day_21; pub mod day_22; pub mod day_23; +pub mod day_24; /// Returns the solution for a specified exercise and input. /// @@ -108,6 +109,7 @@ pub fn solve(day: u8, part: u8, input: impl Into) -> Option { 21 => Some(format!("{}", day_21::day_21(part, input))), 22 => Some(format!("{}", day_22::day_22(part, input))), 23 => Some(format!("{}", day_23::day_23(part, input))), + 24 => Some(format!("{}", day_24::day_24(part, input))), _ => None, } } @@ -275,4 +277,11 @@ mod tests { assert_eq!(day_23::day_23_v1(input), 307); assert_eq!(day_23::day_23_v2(input), 160); } + + #[test] + fn day_24() { + let input = include_str!("../inputs/year_2015_day_24_input"); + assert_eq!(day_24::day_24_v1(input), 10_439_961_859); + assert_eq!(day_24::day_24_v2(input), 72_050_269); + } } diff --git a/src/year_2015/day_24.rs b/src/year_2015/day_24.rs new file mode 100644 index 0000000..bb91261 --- /dev/null +++ b/src/year_2015/day_24.rs @@ -0,0 +1,73 @@ +//! Advent of Code 2015: Day 24: It Hangs in the Balance + +use itertools::Itertools; + +fn solve(numbers: &Vec, magic: u64) -> u64 { + let mut combos: Vec> = vec![]; + for i in 1..=numbers.len() { + let mut results: Vec> = numbers.iter().combinations(i).collect_vec(); + results.retain(|arr| arr.iter().copied().sum::() == magic); + if results.is_empty() { + continue; + } + if results.len() > 0 { + combos = results; + break; + } + } + let combos_values: Vec = combos + .iter() + .map(|combo| combo.iter().fold(1, |acc, elt| acc * *elt)) + .collect_vec(); + + if let Some(min_value) = combos_values.iter().min() { + *min_value + } else { + 0 + } +} + +fn parse_input(input: &str) -> Vec { + let mut numbers: Vec = vec![]; + for line in input.lines() { + let Ok(number) = line.parse::() else { + panic!("Invalid input: {}", line) + }; + numbers.push(number); + } + + numbers +} + +pub fn day_24_v1(input: impl Into) -> u64 { + let numbers = parse_input(&input.into()); + let magic = numbers.iter().sum::() / 3; + + solve(&numbers, magic) +} + +pub fn day_24_v2(input: impl Into) -> u64 { + let numbers = parse_input(&input.into()); + let magic = numbers.iter().sum::() / 4; + + solve(&numbers, magic) +} + +solvable!(day_24, day_24_v1, day_24_v2, u64); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn works_with_samples_v1() { + let sample_one = "1\n2\n3\n4\n5\n7\n8\n9\n10\n11"; + assert_eq!(day_24_v1(sample_one), 99); + } + + #[test] + fn works_with_samples_v2() { + let sample_one = "1\n2\n3\n4\n5\n7\n8\n9\n10\n11"; + assert_eq!(day_24_v2(sample_one), 44); + } +}