2021: day12: part 2

This commit is contained in:
Antoine Martin 2021-12-13 14:37:32 +01:00
parent c439b3a265
commit 28b84ae865

View file

@ -9,6 +9,7 @@ pub fn run() -> Result<String> {
let mut res = String::with_capacity(128); let mut res = String::with_capacity(128);
writeln!(res, "part 1: {}", part1(INPUT)?)?; writeln!(res, "part 1: {}", part1(INPUT)?)?;
writeln!(res, "part 2: {}", part2(INPUT)?)?;
Ok(res) Ok(res)
} }
@ -19,6 +20,12 @@ fn part1(input: &str) -> Result<usize> {
cave_map.count_paths() cave_map.count_paths()
} }
fn part2(input: &str) -> Result<usize> {
let cave_map: CaveMap = input.try_into()?;
cave_map.count_paths_twice()
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct Cave<'a> { struct Cave<'a> {
name: &'a str, name: &'a str,
@ -94,6 +101,46 @@ impl<'a> CaveMap<'a> {
paths paths
} }
fn count_paths_twice(&self) -> Result<usize> {
let start = *self
.connections
.keys()
.find(|cave| cave.is_start())
.context("couldn't find starting cave")?;
Ok(self.count_paths_twice_rec(start, HashSet::new(), false))
}
fn count_paths_twice_rec(
&self,
from: Cave<'a>,
mut small_seen: HashSet<Cave<'a>>,
visited_twice: bool,
) -> usize {
if from.is_end() {
return 1;
}
if from.is_small() {
small_seen.insert(from);
}
let mut paths = 0;
for dst in &self.connections[&from] {
let will_visit_twice = small_seen.contains(dst) && dst.is_small();
if will_visit_twice && (visited_twice || dst.is_start()) {
continue;
}
paths += self.count_paths_twice_rec(
*dst,
small_seen.clone(),
visited_twice || will_visit_twice,
);
}
paths
}
} }
impl<'a> TryFrom<&'a str> for CaveMap<'a> { impl<'a> TryFrom<&'a str> for CaveMap<'a> {
@ -137,4 +184,16 @@ mod tests {
fn part1_real() { fn part1_real() {
assert_eq!(part1(INPUT).unwrap(), 5252); assert_eq!(part1(INPUT).unwrap(), 5252);
} }
#[test]
fn part2_provided() {
assert_eq!(part2(PROVIDED1).unwrap(), 36);
assert_eq!(part2(PROVIDED2).unwrap(), 103);
assert_eq!(part2(PROVIDED3).unwrap(), 3509);
}
#[test]
fn part2_real() {
assert_eq!(part2(INPUT).unwrap(), 147784);
}
} }