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