From 1bf6e922616eb234587d890d9bec9d6d972a7a41 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 12 Dec 2021 11:47:16 -0500 Subject: [PATCH] Day 12 --- input/day12.txt | 25 ++++++++ src/day11.rs | 2 +- src/day12.rs | 158 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 3 +- 4 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 input/day12.txt create mode 100644 src/day12.rs diff --git a/input/day12.txt b/input/day12.txt new file mode 100644 index 0000000..2b19f82 --- /dev/null +++ b/input/day12.txt @@ -0,0 +1,25 @@ +we-NX +ys-px +ys-we +px-end +yq-NX +px-NX +yq-px +qk-yq +pr-NX +wq-EY +pr-oe +wq-pr +ys-end +start-we +ys-start +oe-DW +EY-oe +end-oe +pr-yq +pr-we +wq-start +oe-NX +yq-EY +ys-wq +ys-pr diff --git a/src/day11.rs b/src/day11.rs index 905ab40..6c3bb11 100644 --- a/src/day11.rs +++ b/src/day11.rs @@ -36,7 +36,7 @@ pub fn day11() { println!("{:?}", grid); - for step in 0..100 { + for _step in 0..100 { let (new, flashed) = grid.step(); // println!("after step: {}, new grid: {:?}", step + 1, new); grid = new; diff --git a/src/day12.rs b/src/day12.rs new file mode 100644 index 0000000..7a79e66 --- /dev/null +++ b/src/day12.rs @@ -0,0 +1,158 @@ +use std::collections::{HashMap, HashSet, VecDeque}; +use std::fmt::Debug; +use std::fmt::Formatter; + +pub fn day12() { + // 10 paths, 36 + // let input = r#" + // start-A + // start-b + // A-c + // A-b + // b-d + // A-end + // b-end"#; + // 19 paths, 103 + // let input = r#" + // dc-end + // HN-start + // start-kj + // dc-start + // dc-HN + // LN-dc + // HN-end + // kj-sa + // kj-HN + // kj-dc + // "#; + // 226 paths, 3059 + // let input = r#" + // fs-end + // he-DX + // fs-he + // start-DX + // pj-DX + // end-zg + // zg-sl + // zg-pj + // pj-he + // RW-he + // fs-DX + // pj-RW + // zg-RW + // start-pj + // he-WI + // zg-he + // pj-fs + // start-RW + // "#; + let input = include_str!("../input/day12.txt"); + + let graph = parse_graph(&input); + println!("{:?}", graph); + + println!("{:?}", count_paths(&graph, false)); + println!("{:?}", count_paths(&graph, true)); +} + +fn parse_graph(input: &'static str) -> Graph { + let mut nodes = HashSet::new(); + let mut connections: HashMap> = HashMap::new(); + for line in input.trim().lines() { + let (a, b) = line.trim().split_once("-").unwrap(); + let first: Node = a.into(); + let second: Node = b.into(); + nodes.insert(first.clone()); + nodes.insert(second.clone()); + connections + .entry(first.clone()) + .or_insert(vec![]) + .push(second.clone()); + connections.entry(second).or_insert(vec![]).push(first); + } + + Graph { nodes, connections } +} + +#[derive(PartialEq, Eq, Hash, Clone)] +enum Node { + Start, + End, + Small(&'static str), + Big(&'static str), +} + +impl Node { + fn big(&self) -> bool { + match self { + Self::Big(_) => true, + _ => false, + } + } +} + +impl Debug for Node { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Start => write!(f, "start"), + Self::End => write!(f, "end"), + Self::Small(s) | Self::Big(s) => write!(f, "{}", s), + } + } +} + +impl From<&'static str> for Node { + fn from(s: &'static str) -> Self { + if s == "start" { + Self::Start + } else if s == "end" { + Self::End + } else if s.chars().all(|c| c.is_uppercase()) { + Self::Big(s) + } else { + Self::Small(s) + } + } +} + +#[derive(Debug)] +struct Graph { + nodes: HashSet, + connections: HashMap>, +} + +fn count_paths(g: &Graph, allow_visiting_small_twice: bool) -> usize { + let mut queue: VecDeque<(Vec<&Node>, bool)> = VecDeque::new(); + queue.push_front((vec![&Node::Start], false)); + let mut count = 0; + + while let Some((path, mut seen_any_small_twice)) = queue.pop_front() { + let last = path.last().unwrap().clone(); + + if last == &Node::End { + // println!("{:?}", path); + count += 1; + continue; + } + + // current is small and seen current before + if !last.big() && path.iter().rev().skip(1).any(|&n| n == last) { + // if visting small twice is always prohibited (part 1), or we're revisting the start, + // or visiting a _single_ small twice is allowed but we've already done it + if !allow_visiting_small_twice || last == &Node::Start || seen_any_small_twice { + continue; + } + // note that we've now seen a single small cave twice, so any paths descended from this + // one can't do so themselves + seen_any_small_twice = true; + } + + for connected in &g.connections[last] { + let mut new_path = path.clone(); + new_path.push(connected); + queue.push_back((new_path, seen_any_small_twice)); + } + } + + count +} diff --git a/src/main.rs b/src/main.rs index 05bb30f..9d2af2d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,8 @@ mod day08; mod day09; mod day10; mod day11; +mod day12; fn main() { - day11::day11(); + day12::day12(); }