Solve 2021/12
parent
e5673d55d8
commit
145a1a1ba0
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day12"
|
||||||
|
version = "0.1.0"
|
@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "day12"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
@ -0,0 +1,146 @@
|
|||||||
|
https://adventofcode.com/2021/day/12
|
||||||
|
|
||||||
|
## \--- Day 12: Passage Pathing ---
|
||||||
|
|
||||||
|
With your submarine's subterranean subsystems subsisting suboptimally, the
|
||||||
|
only way you're getting out of this cave anytime soon is by finding a path
|
||||||
|
yourself. Not just _a_ path - the only way to know if you've found the _best_
|
||||||
|
path is to find _all_ of them.
|
||||||
|
|
||||||
|
Fortunately, the sensors are still mostly working, and so you build a rough
|
||||||
|
map of the remaining caves (your puzzle input). For example:
|
||||||
|
|
||||||
|
[code]
|
||||||
|
|
||||||
|
start-A
|
||||||
|
start-b
|
||||||
|
A-c
|
||||||
|
A-b
|
||||||
|
b-d
|
||||||
|
A-end
|
||||||
|
b-end
|
||||||
|
|
||||||
|
[/code]
|
||||||
|
|
||||||
|
This is a list of how all of the caves are connected. You start in the cave
|
||||||
|
named `start`, and your destination is the cave named `end`. An entry like
|
||||||
|
`b-d` means that cave `b` is connected to cave `d` \- that is, you can move
|
||||||
|
between them.
|
||||||
|
|
||||||
|
So, the above cave system looks roughly like this:
|
||||||
|
|
||||||
|
[code]
|
||||||
|
|
||||||
|
start
|
||||||
|
/ \
|
||||||
|
c--A-----b--d
|
||||||
|
\ /
|
||||||
|
end
|
||||||
|
|
||||||
|
[/code]
|
||||||
|
|
||||||
|
Your goal is to find the number of distinct _paths_ that start at `start`, end
|
||||||
|
at `end`, and don't visit small caves more than once. There are two types of
|
||||||
|
caves: _big_ caves (written in uppercase, like `A`) and _small_ caves (written
|
||||||
|
in lowercase, like `b`). It would be a waste of time to visit any small cave
|
||||||
|
more than once, but big caves are large enough that it might be worth visiting
|
||||||
|
them multiple times. So, all paths you find should _visit small caves at most
|
||||||
|
once_ , and can _visit big caves any number of times_.
|
||||||
|
|
||||||
|
Given these rules, there are `_10_` paths through this example cave system:
|
||||||
|
|
||||||
|
[code]
|
||||||
|
|
||||||
|
start,A,b,A,c,A,end
|
||||||
|
start,A,b,A,end
|
||||||
|
start,A,b,end
|
||||||
|
start,A,c,A,b,A,end
|
||||||
|
start,A,c,A,b,end
|
||||||
|
start,A,c,A,end
|
||||||
|
start,A,end
|
||||||
|
start,b,A,c,A,end
|
||||||
|
start,b,A,end
|
||||||
|
start,b,end
|
||||||
|
|
||||||
|
[/code]
|
||||||
|
|
||||||
|
(Each line in the above list corresponds to a single path; the caves visited
|
||||||
|
by that path are listed in the order they are visited and separated by
|
||||||
|
commas.)
|
||||||
|
|
||||||
|
Note that in this cave system, cave `d` is never visited by any path: to do
|
||||||
|
so, cave `b` would need to be visited twice (once on the way to cave `d` and a
|
||||||
|
second time when returning from cave `d`), and since cave `b` is small, this
|
||||||
|
is not allowed.
|
||||||
|
|
||||||
|
Here is a slightly larger example:
|
||||||
|
|
||||||
|
[code]
|
||||||
|
|
||||||
|
dc-end
|
||||||
|
HN-start
|
||||||
|
start-kj
|
||||||
|
dc-start
|
||||||
|
dc-HN
|
||||||
|
LN-dc
|
||||||
|
HN-end
|
||||||
|
kj-sa
|
||||||
|
kj-HN
|
||||||
|
kj-dc
|
||||||
|
|
||||||
|
[/code]
|
||||||
|
|
||||||
|
The `19` paths through it are as follows:
|
||||||
|
|
||||||
|
[code]
|
||||||
|
|
||||||
|
start,HN,dc,HN,end
|
||||||
|
start,HN,dc,HN,kj,HN,end
|
||||||
|
start,HN,dc,end
|
||||||
|
start,HN,dc,kj,HN,end
|
||||||
|
start,HN,end
|
||||||
|
start,HN,kj,HN,dc,HN,end
|
||||||
|
start,HN,kj,HN,dc,end
|
||||||
|
start,HN,kj,HN,end
|
||||||
|
start,HN,kj,dc,HN,end
|
||||||
|
start,HN,kj,dc,end
|
||||||
|
start,dc,HN,end
|
||||||
|
start,dc,HN,kj,HN,end
|
||||||
|
start,dc,end
|
||||||
|
start,dc,kj,HN,end
|
||||||
|
start,kj,HN,dc,HN,end
|
||||||
|
start,kj,HN,dc,end
|
||||||
|
start,kj,HN,end
|
||||||
|
start,kj,dc,HN,end
|
||||||
|
start,kj,dc,end
|
||||||
|
|
||||||
|
[/code]
|
||||||
|
|
||||||
|
Finally, this even larger example has `226` paths through it:
|
||||||
|
|
||||||
|
[code]
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
[/code]
|
||||||
|
|
||||||
|
_How many paths through this cave system are there that visit small caves at
|
||||||
|
most once?_
|
||||||
|
|
@ -0,0 +1,7 @@
|
|||||||
|
start-A
|
||||||
|
start-b
|
||||||
|
A-c
|
||||||
|
A-b
|
||||||
|
b-d
|
||||||
|
A-end
|
||||||
|
b-end
|
@ -0,0 +1,5 @@
|
|||||||
|
start
|
||||||
|
/ \
|
||||||
|
c--A-----b--d
|
||||||
|
\ /
|
||||||
|
end
|
@ -0,0 +1,10 @@
|
|||||||
|
start,A,b,A,c,A,end
|
||||||
|
start,A,b,A,end
|
||||||
|
start,A,b,end
|
||||||
|
start,A,c,A,b,A,end
|
||||||
|
start,A,c,A,b,end
|
||||||
|
start,A,c,A,end
|
||||||
|
start,A,end
|
||||||
|
start,b,A,c,A,end
|
||||||
|
start,b,A,end
|
||||||
|
start,b,end
|
@ -0,0 +1,10 @@
|
|||||||
|
dc-end
|
||||||
|
HN-start
|
||||||
|
start-kj
|
||||||
|
dc-start
|
||||||
|
dc-HN
|
||||||
|
LN-dc
|
||||||
|
HN-end
|
||||||
|
kj-sa
|
||||||
|
kj-HN
|
||||||
|
kj-dc
|
@ -0,0 +1,19 @@
|
|||||||
|
start,HN,dc,HN,end
|
||||||
|
start,HN,dc,HN,kj,HN,end
|
||||||
|
start,HN,dc,end
|
||||||
|
start,HN,dc,kj,HN,end
|
||||||
|
start,HN,end
|
||||||
|
start,HN,kj,HN,dc,HN,end
|
||||||
|
start,HN,kj,HN,dc,end
|
||||||
|
start,HN,kj,HN,end
|
||||||
|
start,HN,kj,dc,HN,end
|
||||||
|
start,HN,kj,dc,end
|
||||||
|
start,dc,HN,end
|
||||||
|
start,dc,HN,kj,HN,end
|
||||||
|
start,dc,end
|
||||||
|
start,dc,kj,HN,end
|
||||||
|
start,kj,HN,dc,HN,end
|
||||||
|
start,kj,HN,dc,end
|
||||||
|
start,kj,HN,end
|
||||||
|
start,kj,dc,HN,end
|
||||||
|
start,kj,dc,end
|
@ -0,0 +1,18 @@
|
|||||||
|
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
|
@ -0,0 +1,25 @@
|
|||||||
|
fw-ll
|
||||||
|
end-dy
|
||||||
|
tx-fw
|
||||||
|
tx-tr
|
||||||
|
dy-jb
|
||||||
|
ZD-dy
|
||||||
|
dy-BL
|
||||||
|
dy-tr
|
||||||
|
dy-KX
|
||||||
|
KX-start
|
||||||
|
KX-tx
|
||||||
|
fw-ZD
|
||||||
|
tr-end
|
||||||
|
fw-jb
|
||||||
|
fw-yi
|
||||||
|
ZD-nr
|
||||||
|
start-fw
|
||||||
|
tx-ll
|
||||||
|
ll-jb
|
||||||
|
yi-jb
|
||||||
|
yi-ll
|
||||||
|
yi-start
|
||||||
|
ZD-end
|
||||||
|
ZD-jb
|
||||||
|
tx-ZD
|
@ -0,0 +1,144 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::io::stdin;
|
||||||
|
use std::io::BufRead;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
let arg = std::env::args().nth(1).unwrap_or_else(String::new);
|
||||||
|
match arg.as_str() {
|
||||||
|
"part1" => part1(),
|
||||||
|
_ => part2(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1() {
|
||||||
|
println!("Part1");
|
||||||
|
|
||||||
|
let mut map: HashMap<String, Vec<String>> = HashMap::new();
|
||||||
|
|
||||||
|
for line in stdin().lock().lines() {
|
||||||
|
let line = line.unwrap();
|
||||||
|
println!("{}", line);
|
||||||
|
let mut parts = line.split('-');
|
||||||
|
let cave_a = parts.next().unwrap().to_string();
|
||||||
|
let cave_b = parts.next().unwrap().to_string();
|
||||||
|
|
||||||
|
let cave_a_connections = map.entry(cave_a.clone()).or_insert_with(Vec::new);
|
||||||
|
cave_a_connections.push(cave_b.clone());
|
||||||
|
|
||||||
|
let cave_b_connections = map.entry(cave_b.clone()).or_insert_with(Vec::new);
|
||||||
|
cave_b_connections.push(cave_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:?}", map);
|
||||||
|
|
||||||
|
let mut incomplete_paths = Vec::new();
|
||||||
|
let mut paths = Vec::new();
|
||||||
|
|
||||||
|
incomplete_paths.push(vec!["start".to_string()]);
|
||||||
|
|
||||||
|
while !incomplete_paths.is_empty() {
|
||||||
|
let path = incomplete_paths.pop().unwrap();
|
||||||
|
let last_cave = path.last().unwrap();
|
||||||
|
|
||||||
|
let options = map.get(last_cave).unwrap();
|
||||||
|
|
||||||
|
for option in options {
|
||||||
|
let first_char = option.chars().next().unwrap();
|
||||||
|
if first_char.is_lowercase() {
|
||||||
|
let has_been_visited = path.iter().any(|cave| cave == option);
|
||||||
|
if has_been_visited {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut new_path = path.clone();
|
||||||
|
new_path.push(option.clone());
|
||||||
|
|
||||||
|
if option == "end" {
|
||||||
|
paths.push(new_path);
|
||||||
|
} else {
|
||||||
|
incomplete_paths.push(new_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for path in paths.iter() {
|
||||||
|
println!("{:?}", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
let path_count = paths.len();
|
||||||
|
dbg!(path_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2() {
|
||||||
|
println!("Part2");
|
||||||
|
|
||||||
|
let mut map: HashMap<String, Vec<String>> = HashMap::new();
|
||||||
|
|
||||||
|
for line in stdin().lock().lines() {
|
||||||
|
let line = line.unwrap();
|
||||||
|
println!("{}", line);
|
||||||
|
let mut parts = line.split('-');
|
||||||
|
let cave_a = parts.next().unwrap().to_string();
|
||||||
|
let cave_b = parts.next().unwrap().to_string();
|
||||||
|
|
||||||
|
let cave_a_connections = map.entry(cave_a.clone()).or_insert_with(Vec::new);
|
||||||
|
cave_a_connections.push(cave_b.clone());
|
||||||
|
|
||||||
|
let cave_b_connections = map.entry(cave_b.clone()).or_insert_with(Vec::new);
|
||||||
|
cave_b_connections.push(cave_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:?}", map);
|
||||||
|
|
||||||
|
let mut incomplete_paths = Vec::new();
|
||||||
|
let mut paths = Vec::new();
|
||||||
|
|
||||||
|
incomplete_paths.push(vec!["start".to_string()]);
|
||||||
|
|
||||||
|
while !incomplete_paths.is_empty() {
|
||||||
|
let path = incomplete_paths.pop().unwrap();
|
||||||
|
let last_cave = path.last().unwrap();
|
||||||
|
|
||||||
|
let options = map.get(last_cave).unwrap();
|
||||||
|
|
||||||
|
for option in options {
|
||||||
|
let first_char = option.chars().next().unwrap();
|
||||||
|
|
||||||
|
if option == "start" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if first_char.is_lowercase() {
|
||||||
|
let has_been_visited = path.iter().any(|cave| cave == option);
|
||||||
|
let mut visited_small_caves = path
|
||||||
|
.iter()
|
||||||
|
.filter(|cave| cave.chars().next().unwrap().is_lowercase())
|
||||||
|
.collect::<Vec<&String>>();
|
||||||
|
let count_small_caves = visited_small_caves.len();
|
||||||
|
visited_small_caves.sort();
|
||||||
|
visited_small_caves.dedup();
|
||||||
|
let count_unique_small_caves = visited_small_caves.len();
|
||||||
|
let is_any_small_cave_visited_twice = count_small_caves != count_unique_small_caves;
|
||||||
|
if is_any_small_cave_visited_twice && has_been_visited {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut new_path = path.clone();
|
||||||
|
new_path.push(option.clone());
|
||||||
|
|
||||||
|
if option == "end" {
|
||||||
|
paths.push(new_path);
|
||||||
|
} else {
|
||||||
|
incomplete_paths.push(new_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for path in paths.iter() {
|
||||||
|
println!("{:?}", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
let path_count = paths.len();
|
||||||
|
dbg!(path_count);
|
||||||
|
}
|
Loading…
Reference in New Issue