use std::collections::HashMap; use std::collections::VecDeque; pub fn run() { let input = std::fs::read_to_string("input/day06.txt").unwrap(); let orbits: Vec<_> = input .lines() .map(|line| { let mut s = line.split(")"); (s.next().unwrap(), s.next().unwrap()) }) .collect(); task1(&orbits); task2(&orbits); } fn task1(orbit_list: &Vec<(&str, &str)>) { let mut queue = VecDeque::new(); queue.push_back((0, "COM")); // com is where everything floats around let sum: i32 = (0..) .scan((orbit_list, queue), |(all, queue), _| { if let Some((depth, next)) = queue.pop_front() { all.iter() .filter(|(a, _)| *a == next) .for_each(|(_, b)| queue.push_back((depth + 1, b))); Some(depth) } else { None } }) .sum(); println!("Task 1: there are {} direct and indirect orbits", sum); } fn task2(orbit_list: &Vec<(&str, &str)>) { let mut queue = VecDeque::new(); queue.push_back("COM"); // com is where everything floats around let parents: HashMap<_, _> = (0..) .scan((orbit_list, queue), |(all, queue), _| { if let Some(next) = queue.pop_front() { let children = all .iter() .filter(|(a, _)| *a == next) .map(|(_, b)| *b) .collect::>(); children.iter().for_each(|b| queue.push_back(b)); Some( children .into_iter() .map(|child| (child, next)) .collect::>(), ) } else { None } }) .flatten() .collect(); // graph maps from the name of an object A to all objects that either orbit // A or that A directly orbits let ancestors = |start: &str| { let mut result = std::iter::successors(Some(start.to_string()), |last| { parents.get(&last.as_ref()).map(|l| l.to_string()) }) .collect::>(); result.reverse(); result }; let a_san = ancestors("SAN"); let a_you = ancestors("YOU"); let last_common_ancestor = a_san .iter() .zip(a_you.iter()) .take_while(|(a, b)| a == b) .map(|(a, _)| a) .last() .unwrap(); let dist_to_ancestor = |ancestors: &Vec, target: &String| { ancestors.iter().rev().position(|x| x == target).unwrap() }; let result = dist_to_ancestor(&a_san, &last_common_ancestor) - 1 + dist_to_ancestor(&a_you, &last_common_ancestor) - 1; // two times -1 because we search for the path length for yours and santas orbit-center println!("Task 2: distance is {}", result); }