diff --git a/2019/src/bin/day6.rs b/2019/src/bin/day6.rs index 1e50d25..33ea5db 100644 --- a/2019/src/bin/day6.rs +++ b/2019/src/bin/day6.rs @@ -14,6 +14,7 @@ fn main() -> io::Result<()> { let orbits = parse_input(&input); println!("Part 1: {}", number_of_orbits(&orbits)); + println!("Part 2: {}", orbital_transfers(&orbits, "YOU", "SAN")); Ok(()) } @@ -36,6 +37,32 @@ fn number_of_orbits(input: &[Orbit<'_>]) -> usize { .sum() } +fn orbital_transfers(input: &[Orbit<'_>], from: &str, to: &str) -> usize { + let nodes = build_tree(input); + + // Find the to and from nodes + let from = nodes + .iter() + .find(|node| node.name == from) + .expect("unable to find from node"); + let to = nodes + .iter() + .find(|node| node.name == to) + .expect("unable to find to node"); + + // Find the longest shared path they have on the way to COM and then the two remaining parts + // give the path between them. + let from_nodes_to_com = nodes_to_com(&nodes, from, Vec::new()); + let to_nodes_to_com = nodes_to_com(&nodes, to, Vec::new()); + let mut i = 0; + while from_nodes_to_com[i].name == to_nodes_to_com[i].name { + i += 1; + } + + // - 2 since we don't count the path from 'from' to the object it's orbiting. Same for 'to'. + from_nodes_to_com[i..].len() + to_nodes_to_com[i..].len() - 2 +} + fn build_tree<'a>(input: &'a [Orbit<'a>]) -> Vec> { // Build the tree from the input let mut nodes: Vec> = Vec::with_capacity(input.len()); @@ -85,11 +112,25 @@ fn count_orbits(nodes: &[Node], node_index: usize, count: usize) -> usize { } } +fn nodes_to_com<'a>( + nodes: &'a [Node], + current_node: &'a Node, + mut path: Vec<&'a Node<'a>>, +) -> Vec<&'a Node<'a>> { + path.push(current_node); + if let Some(parent_index) = current_node.parent { + nodes_to_com(nodes, &nodes[parent_index], path) + } else { + path.reverse(); + path + } +} + #[cfg(test)] mod tests { use super::*; - const TEST_INPUT: &str = "B)C + const TEST_INPUT1: &str = "B)C COM)B C)D D)E @@ -100,11 +141,32 @@ D)I E)J J)K K)L +"; + + const TEST_INPUT2: &str = "COM)B +B)C +C)D +D)E +E)F +B)G +G)H +D)I +E)J +J)K +K)L +K)YOU +I)SAN "; #[test] fn test_number_of_orbits() { - let orbits = parse_input(TEST_INPUT); + let orbits = parse_input(TEST_INPUT1); assert_eq!(number_of_orbits(&orbits), 42); } + + #[test] + fn test_orbital_transfers() { + let orbits = parse_input(TEST_INPUT2); + assert_eq!(orbital_transfers(&orbits, "YOU", "SAN"), 4); + } }