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);
+ }
+}