Day 12
This commit is contained in:
parent
291834774d
commit
cf9b8f0321
2 changed files with 214 additions and 0 deletions
21
input/12.txt
Normal file
21
input/12.txt
Normal 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
193
src/bin/12.rs
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue