diff --git a/src/day6.rs b/src/day6.rs new file mode 100644 index 0000000..7f68117 --- /dev/null +++ b/src/day6.rs @@ -0,0 +1,160 @@ +use std::collections::BTreeSet; +use std::collections::HashMap; + +#[derive(Debug)] +struct OrbitMap { + ids: Vec, +} + +impl OrbitMap { + fn new(n: usize) -> Self { + Self { + ids: (0..n).collect::>(), + } + } + + fn orbit_around(&mut self, base: usize, orbiter: usize) { + self.ids[orbiter] = base; + //println!("{:?}", self.ids); + } + + fn range(&self, idx: usize) -> usize { + let mut i = idx; + let mut cnt = 0; + while i != self.ids[i] { + cnt += 1; + i = self.ids[i]; + } + cnt + } + + fn range_to(&self, idx: usize, limit: usize) -> usize { + let mut i = idx; + let mut cnt = 0; + while i != limit { + i = self.ids[i]; + cnt += 1; + } + cnt - 1 + } + + fn path(&self, idx: usize) -> BTreeSet { + let mut i = idx; + let mut res = BTreeSet::new(); + while i != self.ids[i] { + res.insert(i); + i = self.ids[i]; + } + res + } + + fn distance(&self, p: usize, q: usize) -> usize { + let ppath = self.path(p); + let qpath = self.path(q); + let common_roots = ppath.intersection(&qpath); + + common_roots + .map(|cr| self.range_to(p, *cr) + self.range_to(q, *cr)) + .min() + .unwrap() + } +} + +fn get_pairs(input: &str) -> Vec> { + input + .lines() + .map(|line| line.split(")").map(String::from).collect::>()) + .collect() +} + +fn get_space_objects(input: &str) -> HashMap { + let items = input + .lines() + .map(|line| line.split(")").map(String::from).collect::>()) + .flatten(); + + let mut space_objects: HashMap = HashMap::new(); + let mut n = 0; + items.for_each(|x| { + if !space_objects.contains_key(&x) { + space_objects.insert(x, n); + n += 1; + } + }); + //println!("{:?}", space_objects); + + space_objects +} + +fn calculate_map(input: &str) -> usize { + let space_objects = get_space_objects(input); + let pairs = get_pairs(input); + let mut orbit_map = OrbitMap::new(space_objects.len()); + + for pair in pairs { + //println!("{:?}", pair); + let base = space_objects.get(&pair[0]).unwrap(); + let orbiter = space_objects.get(&pair[1]).unwrap(); + orbit_map.orbit_around(*base, *orbiter); + } + //println!("{:?}", orbit_map.ids); + (0..orbit_map.ids.len()).map(|i| orbit_map.range(i)).sum() +} + +fn calculate_distance(input: &str) -> usize { + let space_objects = get_space_objects(input); + let pairs = get_pairs(input); + let mut orbit_map = OrbitMap::new(space_objects.len()); + + for pair in pairs { + //println!("{:?}", pair); + let base = space_objects.get(&pair[0]).unwrap(); + let orbiter = space_objects.get(&pair[1]).unwrap(); + orbit_map.orbit_around(*base, *orbiter); + } + //println!("{:?}", orbit_map.ids); + let me = *space_objects.get("YOU").unwrap(); + let santa = *space_objects.get("SAN").unwrap(); + orbit_map.distance(me, santa) +} + +pub fn main() -> std::io::Result<()> { + let input = std::include_str!("../day6-input.txt").trim(); + println!("part1 = {:?}", calculate_map(input)); + println!("part2 = {:?}", calculate_distance(input)); + Ok(()) +} + +#[test] +fn test_day6_part1() { + let input = "COM)B\n\ + B)C\n\ + C)D\n\ + D)E\n\ + E)F\n\ + B)G\n\ + G)H\n\ + D)I\n\ + E)J\n\ + J)K\n\ + K)L"; + assert_eq!(calculate_map(input), 42); +} + +#[test] +fn test_day6_part2() { + let input = "COM)B\n\ + B)C\n\ + C)D\n\ + D)E\n\ + E)F\n\ + B)G\n\ + G)H\n\ + D)I\n\ + E)J\n\ + J)K\n\ + K)L\n\ + K)YOU\n\ + I)SAN"; + assert_eq!(calculate_distance(input), 4); +}