From a2ccf9b271bb7ecfdd5bc5175e5c631a99737cb6 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Thu, 11 Dec 2025 20:55:46 +0200 Subject: [PATCH] Finish day-11 part-1 --- 2025/Cargo.lock | 15 ++++ 2025/Cargo.toml | 1 + 2025/day-11/Cargo.toml | 27 +++++++ 2025/day-11/benches/benchmarks.rs | 15 ++++ 2025/day-11/src/bin/part1.rs | 12 ++++ 2025/day-11/src/bin/part2.rs | 12 ++++ 2025/day-11/src/lib.rs | 2 + 2025/day-11/src/part1.rs | 113 ++++++++++++++++++++++++++++++ 2025/day-11/src/part2.rs | 23 ++++++ 9 files changed, 220 insertions(+) create mode 100644 2025/day-11/Cargo.toml create mode 100644 2025/day-11/benches/benchmarks.rs create mode 100644 2025/day-11/src/bin/part1.rs create mode 100644 2025/day-11/src/bin/part2.rs create mode 100644 2025/day-11/src/lib.rs create mode 100644 2025/day-11/src/part1.rs create mode 100644 2025/day-11/src/part2.rs diff --git a/2025/Cargo.lock b/2025/Cargo.lock index 14475ce..0656a9d 100644 --- a/2025/Cargo.lock +++ b/2025/Cargo.lock @@ -252,6 +252,21 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "day-11" +version = "0.1.0" +dependencies = [ + "divan", + "itertools", + "miette", + "nom", + "rstest", + "test-log", + "thiserror", + "tracing", + "tracing-subscriber", +] + [[package]] name = "divan" version = "0.1.21" diff --git a/2025/Cargo.toml b/2025/Cargo.toml index 0ff119a..222d0c5 100644 --- a/2025/Cargo.toml +++ b/2025/Cargo.toml @@ -11,6 +11,7 @@ members = [ "day-08", "day-09", "day-10", + "day-11", ] default-members = ["day-*"] resolver = "2" diff --git a/2025/day-11/Cargo.toml b/2025/day-11/Cargo.toml new file mode 100644 index 0000000..841d565 --- /dev/null +++ b/2025/day-11/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "day-11" +version = "0.1.0" +edition = "2024" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +itertools.workspace = true +nom.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +miette.workspace = true +thiserror.workspace = true + +[dev-dependencies] +divan.workspace = true +rstest.workspace = true +test-log.workspace = true + +[[bench]] +name = "day-11-bench" +path = "benches/benchmarks.rs" +harness = false + +[lints] +workspace = true diff --git a/2025/day-11/benches/benchmarks.rs b/2025/day-11/benches/benchmarks.rs new file mode 100644 index 0000000..85f08b2 --- /dev/null +++ b/2025/day-11/benches/benchmarks.rs @@ -0,0 +1,15 @@ +use day_11::{part1, part2}; + +fn main() { + divan::main(); +} + +#[divan::bench] +fn part1() { + part1::process(divan::black_box(include_str!("../input1.txt"))).unwrap(); +} + +#[divan::bench] +fn part2() { + part2::process(divan::black_box(include_str!("../input2.txt"))).unwrap(); +} diff --git a/2025/day-11/src/bin/part1.rs b/2025/day-11/src/bin/part1.rs new file mode 100644 index 0000000..00100fd --- /dev/null +++ b/2025/day-11/src/bin/part1.rs @@ -0,0 +1,12 @@ +use day_11::part1::process; +use miette::{Context, Result}; + +#[tracing::instrument] +fn main() -> Result<()> { + tracing_subscriber::fmt::init(); + + let file = include_str!("../../input1.txt"); + let result = process(file).context("process part 1")?; + println!("{result}"); + Ok(()) +} diff --git a/2025/day-11/src/bin/part2.rs b/2025/day-11/src/bin/part2.rs new file mode 100644 index 0000000..ab4aa52 --- /dev/null +++ b/2025/day-11/src/bin/part2.rs @@ -0,0 +1,12 @@ +use day_11::part2::process; +use miette::{Context, Result}; + +#[tracing::instrument] +fn main() -> Result<()> { + tracing_subscriber::fmt::init(); + + let file = include_str!("../../input2.txt"); + let result = process(file).context("process part 2")?; + println!("{result}"); + Ok(()) +} diff --git a/2025/day-11/src/lib.rs b/2025/day-11/src/lib.rs new file mode 100644 index 0000000..faaf542 --- /dev/null +++ b/2025/day-11/src/lib.rs @@ -0,0 +1,2 @@ +pub mod part1; +pub mod part2; diff --git a/2025/day-11/src/part1.rs b/2025/day-11/src/part1.rs new file mode 100644 index 0000000..8420154 --- /dev/null +++ b/2025/day-11/src/part1.rs @@ -0,0 +1,113 @@ +use itertools::Itertools; +use miette::miette; +use std::str::FromStr; + +#[derive(Debug, Clone, PartialEq, Eq)] +struct Name([char; 3]); + +impl Name { + const YOU: Self = Self(['y', 'o', 'u']); + const OUT: Self = Self(['o', 'u', 't']); +} + +impl FromStr for Name { + type Err = String; + fn from_str(s: &str) -> Result { + let chars = s.trim().chars().collect_vec(); + if chars.len() != 3 { + return Err(format!( + "Name must be exactly 3 characters, got {}", + chars.len() + )); + } + Ok(Self([chars[0], chars[1], chars[2]])) + } +} + +#[derive(Debug, Clone)] +struct Device { + input: Name, + outputs: Vec, +} + +impl FromStr for Device { + type Err = String; + fn from_str(s: &str) -> Result { + let trimmed = s.trim(); + let (input_str, output_str) = trimmed.split_once(':').ok_or("Missing `:`")?; + + Ok(Self { + input: Name::from_str(input_str)?, + outputs: output_str + .split_whitespace() + .map(Name::from_str) + .collect::, _>>()?, + }) + } +} + +#[derive(Debug, Clone)] +struct Rack(Vec); + +impl FromStr for Rack { + type Err = String; + fn from_str(s: &str) -> Result { + let rack = s + .lines() + .map(Device::from_str) + .collect::, _>>()?; + Ok(Self(rack)) + } +} + +impl Rack { + fn solve(&self) -> usize { + dfs(&Name::YOU, &self.0) + } +} + +fn dfs(current: &Name, devices: &[Device]) -> usize { + if current == &Name::OUT { + return 1; + } + devices + .iter() + .find(|d| d.input == *current) + .map_or(0, |device| { + device + .outputs + .iter() + .map(|output| dfs(output, devices)) + .sum() + }) +} + +#[tracing::instrument] +#[allow(clippy::missing_panics_doc)] +#[allow(clippy::missing_errors_doc)] +pub fn process(input: &str) -> miette::Result { + let rack = Rack::from_str(input).map_err(|e| miette!("{e}"))?; + Ok(rack.solve()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_process() -> miette::Result<()> { + let input = "aaa: you hhh +you: bbb ccc +bbb: ddd eee +ccc: ddd eee fff +ddd: ggg +eee: out +fff: out +ggg: out +hhh: ccc fff iii +iii: out"; + let result = 5; + assert_eq!(process(input)?, result); + Ok(()) + } +} diff --git a/2025/day-11/src/part2.rs b/2025/day-11/src/part2.rs new file mode 100644 index 0000000..ad0941a --- /dev/null +++ b/2025/day-11/src/part2.rs @@ -0,0 +1,23 @@ +use miette::miette; + +#[tracing::instrument] +#[allow(clippy::missing_panics_doc)] +#[allow(clippy::missing_errors_doc)] +pub fn process(input: &str) -> miette::Result { + todo!("day xx - part 2"); + Ok(0) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_process() -> miette::Result<()> { + let input = ""; + todo!("haven't built test yet"); + let result = 0; + assert_eq!(process(input)?, result); + Ok(()) + } +}