|
@@ -1,4 +1,4 @@
|
1
|
|
-use std::collections::HashMap;
|
|
1
|
+use std::collections::{HashMap, HashSet};
|
2
|
2
|
use std::error::Error;
|
3
|
3
|
use std::fs::File;
|
4
|
4
|
use std::io::{prelude::*, BufReader};
|
|
@@ -77,18 +77,54 @@ fn get_orbit_count_checksum(orbit_map: &OrbitMap) -> u32 {
|
77
|
77
|
checksum
|
78
|
78
|
}
|
79
|
79
|
|
|
80
|
+fn get_orbital_transfers(
|
|
81
|
+ orbit_map: &OrbitMap,
|
|
82
|
+ source: NodeIndex,
|
|
83
|
+ destination: NodeIndex,
|
|
84
|
+ visited: &mut HashSet<NodeIndex>,
|
|
85
|
+) -> Option<usize> {
|
|
86
|
+ visited.insert(source);
|
|
87
|
+ for neighbor in orbit_map.graph.neighbors_undirected(source) {
|
|
88
|
+ if neighbor == destination {
|
|
89
|
+ return Some(visited.len());
|
|
90
|
+ } else if !visited.contains(&neighbor) {
|
|
91
|
+ if let Some(neighbor_transfers) =
|
|
92
|
+ get_orbital_transfers(orbit_map, neighbor, destination, &mut visited.clone())
|
|
93
|
+ {
|
|
94
|
+ return Some(neighbor_transfers);
|
|
95
|
+ }
|
|
96
|
+ }
|
|
97
|
+ }
|
|
98
|
+ None
|
|
99
|
+}
|
|
100
|
+
|
80
|
101
|
fn solve_part1() -> Result<u32> {
|
81
|
102
|
let orbit_map = read_orbit_map(INPUT)?;
|
82
|
103
|
Ok(get_orbit_count_checksum(&orbit_map))
|
83
|
104
|
}
|
84
|
105
|
|
85
|
|
-fn solve_part2() -> Result<i32> {
|
|
106
|
+fn solve_part2() -> Result<usize> {
|
86
|
107
|
let orbit_map = read_orbit_map(INPUT)?;
|
87
|
|
- let you = orbit_map.map.get("YOU").expect("YOU not found in orbit map");
|
88
|
|
- let san = orbit_map.map.get("SAN").expect("SAN not found in orbit map");
|
89
|
|
- // let mut bfs = Bfs::new(&orbit_map.graph, *you);
|
90
|
|
- // that BFS doesn't tell me the edges from node for each iteration. guess I'll roll my own
|
91
|
|
- Ok(0)
|
|
108
|
+ let you = orbit_map
|
|
109
|
+ .map
|
|
110
|
+ .get("YOU")
|
|
111
|
+ .expect("YOU not found in orbit map");
|
|
112
|
+ let you_mass = orbit_map
|
|
113
|
+ .graph
|
|
114
|
+ .neighbors_directed(*you, Direction::Outgoing)
|
|
115
|
+ .next()
|
|
116
|
+ .expect("YOU is not orbiting a mass");
|
|
117
|
+ let san = orbit_map
|
|
118
|
+ .map
|
|
119
|
+ .get("SAN")
|
|
120
|
+ .expect("SAN not found in orbit map");
|
|
121
|
+ let san_mass = orbit_map
|
|
122
|
+ .graph
|
|
123
|
+ .neighbors_directed(*san, Direction::Outgoing)
|
|
124
|
+ .next()
|
|
125
|
+ .expect("SAN is not orbiting a mass");
|
|
126
|
+ let transfers = get_orbital_transfers(&orbit_map, you_mass, san_mass, &mut HashSet::new());
|
|
127
|
+ Ok(transfers.expect("No path found between YOU and SAN"))
|
92
|
128
|
}
|
93
|
129
|
|
94
|
130
|
fn main() -> Result<()> {
|
|
@@ -103,6 +139,7 @@ mod tests {
|
103
|
139
|
use super::*;
|
104
|
140
|
|
105
|
141
|
const TEST_INPUT: &str = "input/test.txt";
|
|
142
|
+ const TEST_INPUT2: &str = "input/test2.txt";
|
106
|
143
|
|
107
|
144
|
#[test]
|
108
|
145
|
fn reads_orbit_map() {
|
|
@@ -138,4 +175,38 @@ mod tests {
|
138
|
175
|
let orbit_map = read_orbit_map(TEST_INPUT).unwrap();
|
139
|
176
|
assert_eq!(get_orbit_count_checksum(&orbit_map), 42)
|
140
|
177
|
}
|
|
178
|
+
|
|
179
|
+ #[test]
|
|
180
|
+ fn finds_orbital_transfers_between_objects() {
|
|
181
|
+ let orbit_map = read_orbit_map(TEST_INPUT2).unwrap();
|
|
182
|
+ assert_eq!(
|
|
183
|
+ get_orbital_transfers(
|
|
184
|
+ &orbit_map,
|
|
185
|
+ *orbit_map.map.get("K").unwrap(),
|
|
186
|
+ *orbit_map.map.get("I").unwrap(),
|
|
187
|
+ &mut HashSet::new()
|
|
188
|
+ ).unwrap(),
|
|
189
|
+ 4
|
|
190
|
+ );
|
|
191
|
+
|
|
192
|
+ assert_eq!(
|
|
193
|
+ get_orbital_transfers(
|
|
194
|
+ &orbit_map,
|
|
195
|
+ *orbit_map.map.get("K").unwrap(),
|
|
196
|
+ *orbit_map.map.get("J").unwrap(),
|
|
197
|
+ &mut HashSet::new()
|
|
198
|
+ ).unwrap(),
|
|
199
|
+ 1
|
|
200
|
+ );
|
|
201
|
+
|
|
202
|
+ assert_eq!(
|
|
203
|
+ get_orbital_transfers(
|
|
204
|
+ &orbit_map,
|
|
205
|
+ *orbit_map.map.get("YOU").unwrap(),
|
|
206
|
+ *orbit_map.map.get("L").unwrap(),
|
|
207
|
+ &mut HashSet::new()
|
|
208
|
+ ).unwrap(),
|
|
209
|
+ 2
|
|
210
|
+ );
|
|
211
|
+ }
|
141
|
212
|
}
|