From c5989cc613762debe698ce5a5f6f37a4c0d8387f Mon Sep 17 00:00:00 2001 From: Timothy Quilling Date: Sun, 8 Dec 2024 12:18:53 -0500 Subject: [PATCH] add 2024 day7 in rust; wildcard gitignore puzzle notes --- .gitignore | 3 +- Cargo.toml | 4 ++ src/2024/day7/rust/mod.rs | 103 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 src/2024/day7/rust/mod.rs diff --git a/.gitignore b/.gitignore index dd00645..feee64f 100644 --- a/.gitignore +++ b/.gitignore @@ -46,8 +46,7 @@ coverage input.txt input_example.txt input_example_b.txt -prompt_a.md -prompt_b.md +puzzle_*.md ## Python # Byte-compiled / optimized / DLL files diff --git a/Cargo.toml b/Cargo.toml index d29df06..d8cac80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,10 @@ path = "src/2024/day5/rust/mod.rs" name = "2024_day6" path = "src/2024/day6/rust/mod.rs" +[[bin]] +name = "2024_day7" +path = "src/2024/day7/rust/mod.rs" + [lints.rust] unsafe_code = "forbid" diff --git a/src/2024/day7/rust/mod.rs b/src/2024/day7/rust/mod.rs new file mode 100644 index 0000000..f4eb1e0 --- /dev/null +++ b/src/2024/day7/rust/mod.rs @@ -0,0 +1,103 @@ +struct TestCase { + test_val: i64, + nums: Vec, +} + +pub fn part_a(input: &str) -> i64 { + parse_input(input).iter() + .filter_map(|test_case| if can_create(&test_case.test_val, &test_case.nums, false) { Some(test_case.test_val) } else { None }) + .sum() +} + +pub fn part_b(input: &str) -> i64 { + parse_input(input).iter() + .filter_map(|test_case| if can_create(&test_case.test_val, &test_case.nums, true) { Some(test_case.test_val) } else { None }) + .sum() +} + +fn parse_input(input: &str) -> Vec { + input.lines() + .filter_map(|line| { + let parts: Vec<_> = line.split(": ").collect(); + parts[0].parse::().map_or(None, |test_val| { + let nums = parts[1].split_whitespace() + .filter_map(|s| s.parse::().ok()) + .collect(); + Some(TestCase { test_val, nums }) + }) + }) + .collect() +} + +fn can_create(test_val: &i64, nums: &[i64], is_part_b: bool) -> bool { + fn evaluate(expr: &[i64], acc: i64, is_part_b: bool, test_val: i64) -> Vec { + if expr.is_empty() { + return vec![acc]; + } + let first = expr[0]; + let rest = &expr[1..]; + let mut results = Vec::new(); + + if acc + first - 1 > test_val { + return results; + } + + results.extend(evaluate(rest, acc + first, is_part_b, test_val)); + results.extend(evaluate(rest, acc * first, is_part_b, test_val)); + + if is_part_b { + match format!("{}{}", acc, first).parse::() { + Ok(concat_result) if concat_result <= test_val => { + results.extend(evaluate(rest, concat_result, is_part_b, test_val)); + } + _ => {} + } + } + + results + } + + if nums.is_empty() { + return *test_val == 0; + } + + let first_num = nums[0]; + let options = evaluate(&nums[1..], first_num, is_part_b, *test_val); + options.contains(test_val) +} + +pub fn main() { + let input = include_str!("../input.txt"); + let example_input = include_str!("../input_example.txt"); + // let example_input_b = include_str!("../input_example_b.txt"); + let day: u8 = 7; + println!("Day {} Example Part A: {}", day, part_a(example_input)); + println!("Day {} Part A: {}", day, part_a(input)); + println!("Day {} Example Part B: {}", day, part_b(example_input)); + println!("Day {} Part B: {}", day, part_b(input)); +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_part_a_example() { + let example_input = include_str!("../input_example.txt"); + assert_eq!(part_a(example_input), 3749); + } + #[test] + fn test_part_a() { + let input = include_str!("../input.txt"); + assert_eq!(part_a(input), 3312271365652); + } + #[test] + fn test_part_b_example() { + let example_input_b = include_str!("../input_example.txt"); + assert_eq!(part_b(example_input_b), 11387); + } + #[test] + fn test_part_b() { + let input = include_str!("../input.txt"); + assert_eq!(part_b(input), 509463489296712); + } +} -- 2.51.2