From 345b28787ad328fd24341dd4aa95869307723154 Mon Sep 17 00:00:00 2001 From: mirsella Date: Sat, 7 Dec 2024 06:50:32 +0100 Subject: [PATCH] add day7 --- 2024/day7/.gitignore | 19 ++++++++++ 2024/day7/Cargo.toml | 14 +++++++ 2024/day7/src/main.rs | 86 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 2024/day7/.gitignore create mode 100644 2024/day7/Cargo.toml create mode 100644 2024/day7/src/main.rs diff --git a/2024/day7/.gitignore b/2024/day7/.gitignore new file mode 100644 index 0000000..e983cca --- /dev/null +++ b/2024/day7/.gitignore @@ -0,0 +1,19 @@ +input.txt +flamegraph.svg +perf.data* +### Rust +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + diff --git a/2024/day7/Cargo.toml b/2024/day7/Cargo.toml new file mode 100644 index 0000000..c9b7036 --- /dev/null +++ b/2024/day7/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "da7" +authors = ["mirsella "] +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +regex = { workspace = true } +itertools = { workspace = true } +pathfinding = { workspace = true } +rayon = { workspace = true } +indexmap = { workspace = true } diff --git a/2024/day7/src/main.rs b/2024/day7/src/main.rs new file mode 100644 index 0000000..f1507e7 --- /dev/null +++ b/2024/day7/src/main.rs @@ -0,0 +1,86 @@ +use itertools::Itertools; + +fn part1(input: &str) -> usize { + let lines = input.lines().map(|l| { + let mut s = l + .split_whitespace() + .map(|s| s.trim_end_matches(':').parse::().unwrap()); + (s.next().unwrap(), s.collect_vec()) + }); + fn try_operator(total: usize, values: &[usize], acc: usize) -> bool { + if (acc + values[0] == total || acc * values[0] == total) && values.len() == 1 { + return true; + } + if values.len() > 1 { + if try_operator(total, &values[1..], acc + values[0]) { + return true; + } + if try_operator(total, &values[1..], acc * values[0]) { + return true; + } + } + false + } + lines + .filter_map(|(total, values)| try_operator(total, &values[1..], values[0]).then_some(total)) + .sum() +} + +fn part2(input: &str) -> usize { + let lines = input.lines().map(|l| { + let mut s = l + .split_whitespace() + .map(|s| s.trim_end_matches(':').parse::().unwrap()); + (s.next().unwrap(), s.collect_vec()) + }); + fn try_operator(total: usize, values: &[usize], acc: usize) -> bool { + let add = values[0] + acc; + let mul = values[0] * acc; + let concat = format!("{}{}", acc, values[0]).parse::().unwrap(); + if (add == total || mul == total || concat == total) && values.len() == 1 { + return true; + } + if values.len() > 1 { + if try_operator(total, &values[1..], add) { + return true; + } + if try_operator(total, &values[1..], mul) { + return true; + } + if try_operator(total, &values[1..], concat) { + return true; + } + } + false + } + lines + .filter_map(|(total, values)| try_operator(total, &values[1..], values[0]).then_some(total)) + .sum() +} + +fn main() { + let input = include_str!("../input.txt"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); +} + +#[cfg(test)] +mod tests { + const INPUT: &str = "190: 10 19 +3267: 81 40 27 +83: 17 5 +156: 15 6 +7290: 6 8 6 15 +161011: 16 10 13 +192: 17 8 14 +21037: 9 7 18 13 +292: 11 6 16 20"; + #[test] + fn part1() { + assert_eq!(super::part1(INPUT), 3749); + } + #[test] + fn part2() { + assert_eq!(super::part2(INPUT), 11387); + } +}