use std::collections::HashMap; fn copy_to_array(a: &mut [char; 3], b: &str) { assert_eq!(b.len(), 3); let mut x = 0; for c in b.chars() { a[x] = c; x += 1; } } fn main() { { let test_map = get_map_from_file("test"); assert_eq!(test_map.get("COM").unwrap().distance_to_com(&test_map), 0); assert_eq!(test_map.get("B").unwrap().distance_to_com(&test_map), 1); assert_eq!(test_map.get("D").unwrap().distance_to_com(&test_map), 3); assert_eq!(test_map.get("L").unwrap().distance_to_com(&test_map), 7); let f_parents = test_map.get("F").unwrap().parents(&test_map); assert_eq!(f_parents, vec!["E", "D", "C", "B", "COM"]); let l_parents = test_map.get("L").unwrap().parents(&test_map); assert_eq!(l_parents, vec!["K", "J", "E", "D", "C", "B", "COM"]); assert_eq!(first_common(f_parents, l_parents), "E"); let mut x: i32 = 0; for val in test_map.values() { x += val.distance_to_com(&test_map); } assert_eq!(x, 42); } { let test_map2 = get_map_from_file("test2"); let you = test_map2.get("YOU").unwrap(); let san = test_map2.get("SAN").unwrap(); println!("{:?}", you); println!("{:?}", san); println!("{:?}", you.parents(&test_map2)); println!("{:?}", san.parents(&test_map2)); let parent = first_common(you.parents(&test_map2), san.parents(&test_map2)); println!("First common parent of YOU and SAN: '{}'", parent); println!("Distance from YOU to {}: {}", parent, you.distance_to(&parent, &test_map2)); println!("Distance from SAN to {}: {}", parent, san.distance_to(&parent, &test_map2)); println!("[Test2] Transfers required to go from YOU to SAN: {}", you.distance_to(&parent, &test_map2) + san.distance_to(&parent, &test_map2) - 2); } let map = get_map_from_file("input"); let mut x: i32 = 0; for val in map.values() { x += val.distance_to_com(&map); } println!("[Part 1] Total indirect and direct orbits: {}", x); let you = map.get("YOU").unwrap(); let you_parents = you.parents(&map); let san = map.get("SAN").unwrap(); let san_parents = san.parents(&map); let common_parent = first_common(you_parents, san_parents); println!("First common parent of YOU and SAN: '{}'", common_parent); println!("Distance from YOU to {}: {}", common_parent, you.distance_to(&common_parent, &map)); println!("Distance from SAN to {}: {}", common_parent, san.distance_to(&common_parent, &map)); println!("[Part 2] Transfers required to go from YOU to SAN: {}", you.distance_to(&common_parent, &map) + san.distance_to(&common_parent, &map) - 2); } fn first_common(a: Vec, b: Vec) -> String { let mut x: Option = None; for v_a in a.iter() { let mut iter: usize = 0; for v_b in b.iter() { if v_a == v_b { x = Some(iter); break; } iter += 1; } if x.is_some() { break; } } return b[x.unwrap()].clone(); } fn get_map_from_file(file: &str) -> HashMap { let contents = std::fs::read_to_string(file) .expect("Failed to read file 'input'"); let it = contents.split("\n"); let mut map: HashMap = HashMap::new(); for line in it { let s = String::from(line); s.trim(); if s.is_empty() { break; } { let values: Vec<&str> = s.split(")").collect(); //println!("Line: {}", line); assert_eq!(values.len(), 2); //assert_eq!(values[0].len(), 3); //assert_eq!(values[1].len(), 3); for v in values { if !map.contains_key(v) { let n = Node { id: v.to_string(), parent: None, children: Vec::new(), }; map.insert(v.to_string(), n); } } } let values: Vec<&str> = s.split(")").collect(); { let mut node = map.get_mut(values[1]).unwrap(); if !node.parent.is_some() { node.parent = Some(values[0].to_string()); } } { let mut node = map.get_mut(values[0]).unwrap(); if !node.children.contains(&values[1].to_string()) { node.children.push(values[1].to_string()); } } } return map; } #[derive(Debug)] struct Node { parent: Option, id: String, children: Vec, } impl Node { fn distance_to(&self, to: &str, map: &HashMap) -> i32 { if self.id == to { return 0; } let parent = self.parent.as_ref().unwrap().clone(); return map.get(&parent).unwrap().distance_to(to, map) + 1; } fn distance_to_com(&self, map: &HashMap) -> i32 { return self.distance_to("COM", map); } fn parents(&self, map: &HashMap) -> Vec { let mut parents: Vec = Vec::new(); if self.parent.is_some() { parents.push(self.parent.as_ref().unwrap().clone()); let parent = map.get(&self.parent.as_ref().unwrap().clone()).unwrap(); for v in parent.parents(map) { parents.push(v); } } return parents; } } impl PartialEq for Node { fn eq(&self, other: &Self) -> bool { self.id == other.id } }