Skip to content

Commit 3f6399d

Browse files
committedDec 12, 2021
Add day 12 (this is bad)
1 parent afbc616 commit 3f6399d

File tree

4 files changed

+178
-0
lines changed

4 files changed

+178
-0
lines changed
 

‎day12/Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎day12/Cargo.toml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "day12"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]

‎day12/input

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
we-NX
2+
ys-px
3+
ys-we
4+
px-end
5+
yq-NX
6+
px-NX
7+
yq-px
8+
qk-yq
9+
pr-NX
10+
wq-EY
11+
pr-oe
12+
wq-pr
13+
ys-end
14+
start-we
15+
ys-start
16+
oe-DW
17+
EY-oe
18+
end-oe
19+
pr-yq
20+
pr-we
21+
wq-start
22+
oe-NX
23+
yq-EY
24+
ys-wq
25+
ys-pr

‎day12/src/main.rs

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
use std::collections::HashMap;
2+
3+
type Path = Vec<String>;
4+
5+
#[derive(Debug, Clone)]
6+
struct Node {
7+
label: String,
8+
neighbors: Vec<String>,
9+
visited: i32,
10+
}
11+
12+
impl Node {
13+
fn new(label: &str) -> Node {
14+
if label.len() == 0 {
15+
panic!("Node label cannot be empty");
16+
}
17+
18+
Node {
19+
label: label.to_owned(),
20+
neighbors: vec![],
21+
visited: 0,
22+
}
23+
}
24+
25+
fn is_large(&self) -> bool {
26+
self.label.chars().next().unwrap().is_uppercase()
27+
}
28+
}
29+
30+
#[derive(Debug, Clone)]
31+
struct Caves {
32+
map: HashMap<String, Node>,
33+
already_visited_twice_small_cave: bool,
34+
}
35+
36+
impl Caves {
37+
fn load(input: &str) -> Self {
38+
let mut map = HashMap::new();
39+
for line in input.lines() {
40+
let labels: Vec<String> = line.split("-").map(|s| s.into()).collect();
41+
let from_label = labels[0].clone();
42+
let to_label = labels[1].clone();
43+
let from_node = map
44+
.entry(from_label.clone())
45+
.or_insert(Node::new(&from_label));
46+
from_node.neighbors.push(to_label.clone());
47+
48+
let to_node = map.entry(to_label.clone()).or_insert(Node::new(&to_label));
49+
to_node.neighbors.push(from_label.clone());
50+
}
51+
52+
Caves {
53+
map,
54+
already_visited_twice_small_cave: false,
55+
}
56+
}
57+
58+
fn find_paths(mut self, node: &str, path: Path, limit: i32) -> Option<Vec<Path>> {
59+
let mut path = path;
60+
path.push(node.into());
61+
if self.map[node.into()].label == String::from("end") {
62+
return Some(vec![path]);
63+
}
64+
let visit_node = self.map.get_mut(node.into()).unwrap();
65+
visit_node.visited += 1;
66+
if visit_node.visited >= limit && !visit_node.is_large() {
67+
self.already_visited_twice_small_cave = true;
68+
}
69+
70+
let child_paths: Vec<Path> = self.map[node]
71+
.neighbors
72+
.iter()
73+
.filter(|node| {
74+
let node = self.map.get(node.clone()).unwrap();
75+
node.label != "start"
76+
&& (node.is_large()
77+
|| (node.visited == 0)
78+
|| (node.visited < limit && !self.already_visited_twice_small_cave))
79+
})
80+
.filter_map(|neigh| self.clone().find_paths(&neigh, path.clone(), limit))
81+
.flatten()
82+
.collect();
83+
84+
if child_paths.len() == 0 {
85+
return None;
86+
}
87+
Some(child_paths)
88+
}
89+
}
90+
91+
fn part_1(caves: &Caves) -> usize {
92+
let paths = caves.clone().find_paths("start", vec![], 1).unwrap();
93+
paths.len()
94+
}
95+
96+
fn part_2(caves: &Caves) -> usize {
97+
let paths = caves.clone().find_paths("start", vec![], 2).unwrap();
98+
paths.len()
99+
}
100+
101+
fn main() {
102+
let caves = Caves::load(std::fs::read_to_string("input").unwrap().as_str());
103+
println!("Part 1: {}", part_1(&caves));
104+
println!("Part 2: {}", part_2(&caves));
105+
}
106+
107+
#[cfg(test)]
108+
mod tests {
109+
use super::*;
110+
111+
#[test]
112+
fn test_cave_loading() {
113+
let input =
114+
"dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc";
115+
let caves = Caves::load(input);
116+
assert_eq!(caves.map.len(), 7);
117+
assert_eq!(caves.map["start".into()].neighbors.len(), 3);
118+
}
119+
120+
#[test]
121+
fn test_part_1() {
122+
let input =
123+
"dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc";
124+
let caves = Caves::load(input);
125+
let paths = part_1(&caves);
126+
assert_eq!(paths, 19);
127+
}
128+
129+
#[test]
130+
fn test_part_2() {
131+
let input =
132+
"dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc";
133+
let caves = Caves::load(input);
134+
let paths = part_2(&caves);
135+
136+
assert_eq!(paths, 103);
137+
}
138+
}

0 commit comments

Comments
 (0)
Please sign in to comment.