:)

let's try to use this datastructure, ok?

+49 -13
+20 -5
src/day8.rs
··· 1 1 use itertools::Itertools; 2 2 3 - use crate::spatial::Point3D; 3 + use crate::{spatial::Point3D, union_find::UnionFind}; 4 4 5 - pub fn day8_part1(input: &str) -> String { 5 + pub fn day8_part1(input: &str, connection_limit: usize) -> String { 6 6 let boxes = parse(input); 7 7 let mut pairs = boxes 8 8 .iter() ··· 11 11 .map(|(left, right)| (left.euclidean_distance(right), left, right)) 12 12 .collect_vec(); 13 13 pairs.sort_by(|(ld, _, _), (rd, _, _)| ld.partial_cmp(rd).unwrap()); 14 - pairs.truncate(1000); 15 - 16 - pairs.len().to_string() 14 + let distanceless_pairs = pairs 15 + .into_iter() 16 + .map(|(_, l, r)| (l, r)) 17 + .take(connection_limit) 18 + .collect_vec(); 19 + 20 + let mut ufo = UnionFind::default(); 21 + 22 + for (&l, &r) in distanceless_pairs { 23 + let l = ufo.make_set(l); 24 + let r = ufo.make_set(r); 25 + ufo.union(l, r); 26 + } 27 + 28 + let mut rss = ufo.root_sizes(); 29 + rss.sort(); 30 + let product = rss.pop().unwrap() * rss.pop().unwrap() * rss.pop().unwrap(); 31 + product.to_string() 17 32 } 18 33 pub fn day8_part2(input: &str) -> String { 19 34 todo!()
+4 -4
src/lib.rs
··· 130 130 131 131 #[test] 132 132 fn day8_part1_test() { 133 - // let test_result = day8::day8_part1(include_str!("../input/day8.test.txt")); 134 - // assert_eq!(test_result, "40"); 135 - let result = day8::day8_part1(include_str!("../input/day8.txt")); 136 - assert_eq!(result, "1490"); 133 + let test_result = day8::day8_part1(include_str!("../input/day8.test.txt"), 10); 134 + assert_eq!(test_result, "40"); 135 + let result = day8::day8_part1(include_str!("../input/day8.txt"), 1000); 136 + assert_eq!(result, "90036"); 137 137 } 138 138 // #[test] 139 139 // fn day8_part2_test() {
+4 -1
src/spatial.rs
··· 8 8 pub col: usize, 9 9 } 10 10 11 - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 11 + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 12 12 pub struct Point3D { 13 13 pub x: usize, 14 14 pub y: usize, ··· 21 21 + (self.y as isize - other.y as isize).abs().pow(2) 22 22 + (self.z as isize - other.z as isize).abs().pow(2)) as f64) 23 23 .sqrt() 24 + } 25 + pub fn format(&self) -> String { 26 + format!("{},{},{}", self.x, self.y, self.z) 24 27 } 25 28 } 26 29
+21 -3
src/union_find.rs
··· 1 + use crate::spatial::Point3D; 2 + 1 3 pub struct UnionFind<N> { 2 4 nodes: Vec<Node<N>>, 3 5 } ··· 14 16 { 15 17 //returns a pointer to this element that can be used in union and find operations later 16 18 pub fn make_set(&mut self, element: N) -> usize { 17 - let index = self.nodes.iter().enumerate().find(|(_, node)| node.inner == element); 19 + let index = self 20 + .nodes 21 + .iter() 22 + .enumerate() 23 + .find(|(_, node)| node.inner == element); 18 24 if let Some(index) = index { 19 25 index.0 20 26 } else { ··· 36 42 //take the opportunity to optimize?? 37 43 let mut x_index; 38 44 let mut x_reference = &mut self.nodes[element]; 39 - 45 + 40 46 while x_reference.parent != root_index { 41 47 let parent_index = x_reference.parent; 42 48 x_reference.parent = root_index; ··· 57 63 } 58 64 root_index 59 65 } 60 - 66 + } 67 + impl UnionFind<Point3D> { 61 68 pub fn union(&mut self, mut x_index: usize, mut y_index: usize) { 69 + // println!("unifying {} with {}", self.nodes[x_index].inner.format(), self.nodes[y_index].inner.format()); 62 70 x_index = self.find(x_index); 63 71 y_index = self.find(y_index); 64 72 ··· 72 80 73 81 self.nodes[y_index].parent = x_index; 74 82 self.nodes[x_index].size += self.nodes[y_index].size; 83 + // println!("sizes: {:?}", self.root_sizes()); 84 + } 85 + 86 + pub fn root_sizes(&self) -> Vec<usize> { 87 + self.nodes 88 + .iter() 89 + .enumerate() 90 + .filter(|(index, node)| node.parent == *index) 91 + .map(|(index, node)| node.size) 92 + .collect() 75 93 } 76 94 } 77 95