From 292638ea1da3f20974da54abe0d06ca48a025cae Mon Sep 17 00:00:00 2001 From: Keenan Tims Date: Thu, 11 Dec 2025 00:23:22 -0800 Subject: [PATCH] day11: part2 --- .aoc_tiles/tiles/2025/11.png | Bin 4874 -> 5813 bytes README.md | 2 +- src/day11.rs | 106 ++++++++++++++++++++++++++--------- 3 files changed, 80 insertions(+), 28 deletions(-) diff --git a/.aoc_tiles/tiles/2025/11.png b/.aoc_tiles/tiles/2025/11.png index a3e9c6376d7212ae9e51b552e31daeebcfebcaef..cd962b6c2cc1def3beae1767de5996214dc4fd9b 100644 GIT binary patch literal 5813 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 diff --git a/README.md b/README.md index 3d75012..923f7eb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- 2025 - 19 ⭐ - Rust + 2025 - 20 ⭐ - Rust

diff --git a/src/day11.rs b/src/day11.rs index 308ea7a..2bf1e7d 100644 --- a/src/day11.rs +++ b/src/day11.rs @@ -1,27 +1,19 @@ use aoc_runner_derive::{aoc, aoc_generator}; -use cached::proc_macro::cached; -use indicatif::{ProgressBar, ProgressFinish, ProgressStyle}; -use itertools::Itertools; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; type Edges = HashMap>; #[aoc_generator(day11)] -fn parse(input: &str) -> (Edges, Edges) { +fn parse(input: &str) -> Edges { let mut edges: Edges = HashMap::new(); - let mut rev_edges: Edges = HashMap::new(); for l in input.lines() { let (k, rest) = l.split_once(": ").unwrap(); for v in rest.split_ascii_whitespace() { edges.entry(k.to_string()).or_default().push(v.to_string()); - rev_edges - .entry(v.to_string()) - .or_default() - .push(k.to_string()); } } - (edges, rev_edges) + edges } fn find_path(cur: &str, goal: &str, edges: &Edges) -> u64 { @@ -35,26 +27,72 @@ fn find_path(cur: &str, goal: &str, edges: &Edges) -> u64 { } } +fn mark_paths<'a>( + cur: &'a str, + edges: &'a Edges, + mut reachable: HashSet<&'a str>, +) -> HashSet<&'a str> { + reachable.insert(cur); + if let Some(nexts) = edges.get(cur) { + for n in nexts { + if !reachable.contains(&n.as_str()) { + // reachable.insert(n); + reachable = mark_paths(n, edges, reachable); + } + } + } + reachable +} + #[aoc(day11, part1)] -fn part1((fwd, rev): &(Edges, Edges)) -> u64 { - let mut count = 0u64; - let mut to_check = Vec::from_iter(rev["out"].iter()); - - let mut pb = ProgressBar::no_length() - .with_style( - ProgressStyle::with_template( - "[{elapsed_precise}/{eta_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {per_sec}", - ) - .unwrap(), - ) - .with_finish(indicatif::ProgressFinish::AndLeave); - +fn part1(fwd: &Edges) -> u64 { find_path("you", "out", fwd) } #[aoc(day11, part2)] -fn part2(input: &(Edges, Edges)) -> u64 { - 0 +fn part2(edges: &Edges) -> u64 { + let mut rev = Edges::from_iter(edges.keys().map(|k| (k.to_owned(), vec![]))); + for (from, tos) in edges { + for to in tos { + rev.entry(to.to_owned()).or_default().push(from.to_owned()); + } + } + let mut reachable_dac = mark_paths("dac", edges, HashSet::new()); + reachable_dac = mark_paths("dac", &rev, reachable_dac); + let mut reachable_fft = mark_paths("fft", edges, HashSet::new()); + reachable_fft = mark_paths("fft", &rev, reachable_fft); + + let reachable: HashSet<&str> = reachable_dac + .intersection(&reachable_fft) + .copied() + .collect(); + + let unreachable: HashSet<&str> = HashSet::from_iter(edges.keys().map(|k| k.as_str())) + .difference(&reachable) + .copied() + .collect(); + + let mut reachable_edges = edges.clone(); + + for k in &unreachable { + reachable_edges.remove(*k); + } + for (_k, v) in reachable_edges.iter_mut() { + for ur in &unreachable { + if let Some(idx) = v.iter().position(|s| s == ur) { + v.remove(idx); + } + } + } + + // This is a bit of a cheat from viewing the graph and realizing all paths are ordered this way. + // However, knowing that fact that we can partition in this way, we could use a shortest-path algo + // to determine which order fft and dac are in. + // + // The assumption holds on my data and the example, so I think it's probably true of all inputs. + find_path("svr", "fft", &reachable_edges) + * find_path("fft", "dac", &reachable_edges) + * find_path("dac", "out", &reachable_edges) } #[cfg(test)] @@ -74,6 +112,20 @@ ggg: out hhh: ccc fff iii iii: out"; + const EXAMPLE2: &str = "svr: aaa bbb +aaa: fft +fft: ccc +bbb: tty +tty: ccc +ccc: ddd eee +ddd: hub +hub: fff +eee: dac +dac: fff +fff: ggg hhh +ggg: out +hhh: out"; + #[rstest] #[case(EXAMPLE, 5)] fn part1_example(#[case] input: &str, #[case] expected: u64) { @@ -81,7 +133,7 @@ iii: out"; } #[rstest] - #[case(EXAMPLE, 0)] + #[case(EXAMPLE2, 2)] fn part2_example(#[case] input: &str, #[case] expected: u64) { assert_eq!(part2(&parse(input)), expected); }