1
0
Fork 0
This commit is contained in:
Lars Martens 2021-12-12 12:09:53 +01:00
parent 291834774d
commit cf9b8f0321
2 changed files with 214 additions and 0 deletions

21
input/12.txt Normal file
View file

@ -0,0 +1,21 @@
mx-IQ
mx-HO
xq-start
start-HO
IE-qc
HO-end
oz-xq
HO-ni
ni-oz
ni-MU
sa-IE
IE-ni
end-sa
oz-sa
MU-start
MU-sa
oz-IE
HO-xq
MU-xq
IE-end
MU-mx

193
src/bin/12.rs Normal file
View file

@ -0,0 +1,193 @@
use std::collections::HashMap;
fn main() {
let puzzle = Network::from_str(include_str!("../../input/12.txt"));
println!("First solution: {}", puzzle.solve(Path::new(), false));
println!("Second solution: {}", puzzle.solve(Path::new(), true));
}
type Cave = &'static str;
struct Network {
connections: HashMap<Cave, Vec<Cave>>,
}
#[derive(Clone, Debug)]
struct Path {
caves: Vec<Cave>,
}
impl Network {
// Recursively count the number of paths.
fn solve(&self, current: Path, part2: bool) -> usize {
if current.end() == "end" {
return 1;
}
let mut n = 0;
for &next in &self.connections[current.end()] {
let can_visit = if part2 {
current.can_visit_plus(next)
} else {
current.can_visit(next)
};
if can_visit && next != "start" {
let mut next_path = current.clone();
next_path.visit(next);
n += self.solve(next_path, part2);
}
}
n
}
fn from_str(s: &'static str) -> Self {
let mut connections: HashMap<Cave, Vec<Cave>> = HashMap::new();
for (from, to) in s.lines().filter_map(|l| l.trim().split_once('-')) {
connections.entry(from).or_default().push(to);
connections.entry(to).or_default().push(from);
}
Self { connections }
}
}
impl Path {
fn new() -> Self {
Self {
caves: vec!["start"],
}
}
fn can_visit(&self, c: Cave) -> bool {
if c.to_lowercase() == c {
// Small caves may be visitied at most once
!self.caves.iter().any(|&cc| c == cc)
} else {
// Big caves can be visited any number of times
true
}
}
// Allows a single small cave to be visited twice.
fn can_visit_plus(&self, c: Cave) -> bool {
if c.to_lowercase() == c {
let already_visited = self.caves.iter().any(|&cc| c == cc);
if already_visited {
// We have already been to this small cave. Find out if we visited any single
// cave twice already.
let mut only_small_caves: Vec<Cave> = self
.caves
.clone()
.into_iter()
.filter(|&s| s.to_lowercase() == s)
.collect();
only_small_caves.sort_unstable();
let a = only_small_caves.len();
only_small_caves.dedup();
let b = only_small_caves.len();
a == b
} else {
true
}
} else {
true
}
}
fn visit(&mut self, c: Cave) {
self.caves.push(c);
}
fn end(&self) -> Cave {
self.caves.last().unwrap()
}
}
#[cfg(test)]
mod test {
use crate::{Network, Path};
#[test]
fn input10() {
assert_eq!(
Network::from_str(
r"start-A
start-b
A-c
A-b
b-d
A-end
b-end
"
)
.solve(Path::new(), false),
10
);
}
#[test]
fn input10plus() {
assert_eq!(
Network::from_str(
r"start-A
start-b
A-c
A-b
b-d
A-end
b-end
"
)
.solve(Path::new(), true),
36
);
}
#[test]
fn input19() {
assert_eq!(
Network::from_str(
r"dc-end
HN-start
start-kj
dc-start
dc-HN
LN-dc
HN-end
kj-sa
kj-HN
kj-dc
"
)
.solve(Path::new(), false),
19
);
}
#[test]
fn input226() {
assert_eq!(
Network::from_str(
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
"
)
.solve(Path::new(), false),
226
);
}
}