From 203402971b68d3eecc9f9f254ccd1023eadaa7c8 Mon Sep 17 00:00:00 2001 From: Jan Doumont Date: Mon, 8 Dec 2025 23:40:41 +0100 Subject: [PATCH] day8 --- src/day5.rs | 46 ++++++++-------- src/day8.rs | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 11 ++-- 3 files changed, 184 insertions(+), 28 deletions(-) create mode 100644 src/day8.rs diff --git a/src/day5.rs b/src/day5.rs index 303dc81..6e9d9a8 100644 --- a/src/day5.rs +++ b/src/day5.rs @@ -1,4 +1,4 @@ -use std::cmp; +// use std::cmp; #[derive(Copy, Clone, Debug)] struct UintInclusiveRange { @@ -18,29 +18,29 @@ impl UintInclusiveRange { value >= self.start && value <= self.end } - fn overlaps(&self, other: &UintInclusiveRange) -> bool { - (self.start >= other.start && self.start <= other.end) - || (self.end >= other.start && self.end <= other.end) - || (self.start <= other.start && self.end >= other.end) - || (self.start >= other.start && self.end <= other.end) - } + // fn overlaps(&self, other: &UintInclusiveRange) -> bool { + // (self.start >= other.start && self.start <= other.end) + // || (self.end >= other.start && self.end <= other.end) + // || (self.start <= other.start && self.end >= other.end) + // || (self.start >= other.start && self.end <= other.end) + // } - fn join(&self, other: &UintInclusiveRange) -> UintInclusiveRange { - println!( - "Joining {:?} and {:?} into {:?}", - self, - other, - UintInclusiveRange::new( - cmp::min(self.start, other.start), - cmp::max(self.end, other.end), - ) - ); - assert!(self.overlaps(&other)); - UintInclusiveRange::new( - cmp::min(self.start, other.start), - cmp::max(self.end, other.end), - ) - } + // fn join(&self, other: &UintInclusiveRange) -> UintInclusiveRange { + // println!( + // "Joining {:?} and {:?} into {:?}", + // self, + // other, + // UintInclusiveRange::new( + // cmp::min(self.start, other.start), + // cmp::max(self.end, other.end), + // ) + // ); + // assert!(self.overlaps(&other)); + // UintInclusiveRange::new( + // cmp::min(self.start, other.start), + // cmp::max(self.end, other.end), + // ) + // } fn size(self) -> u64 { self.end - self.start + 1 diff --git a/src/day8.rs b/src/day8.rs new file mode 100644 index 0000000..07c6d7e --- /dev/null +++ b/src/day8.rs @@ -0,0 +1,155 @@ +use std::collections::HashSet; + +#[aoc(day8, part1)] +pub fn part1(input: &str) -> i64 { + let nodes = parse(input); + let distance_matrix = distances(nodes); + let mut circuits = make_circuits(distance_matrix, 1000); + circuits.sort_unstable_by(|x, y| y.len().cmp(&x.len())); + circuits.iter().take(3).fold(1, |x, y| x * y.len() as i64) +} + +#[aoc(day8, part2)] +pub fn part2(input: &str) -> i64 { + let nodes = parse(input); + let distance_matrix = distances(nodes.clone()); + let last_nodes = fully_connect(distance_matrix).unwrap(); + println!("{:?}", last_nodes); + nodes[last_nodes.0][0] * nodes[last_nodes.1][0] +} + +fn parse(input: &str) -> Vec> { + input + .lines() + .map(|line| { + line.split(',') + .map(|num| num.parse::().unwrap()) + .collect::>() + }) + .collect() +} + +fn distances(nodes: Vec>) -> Vec> { + (0..nodes.len()) + .map(|j| { + { + ((j + 1)..nodes.len()).map(|i| { + (0..3) + .map(|k| (nodes[i][k] - nodes[j][k]).pow(2) as f64) + .sum::() + .sqrt() + }) + } + .collect::>() + }) + .collect() +} + +fn make_circuits(distance_matrix: Vec>, n_connections: u32) -> Vec> { + let mut distances_sorted = distance_matrix + .into_iter() + .enumerate() + .flat_map(|(i, row)| { + row.into_iter() + .enumerate() + .map(move |(j, elem)| (i, j, elem)) + }) + .collect::>(); + distances_sorted.sort_unstable_by(|x, y| x.2.partial_cmp(&y.2).unwrap()); + + let mut circuits: Vec> = Vec::new(); + + for (i, j, _) in distances_sorted.iter().take(n_connections as usize) { + let init = HashSet::from([*i, *j + 1 + *i]); + let (to_merge, mut existing): (Vec>, Vec>) = circuits + .into_iter() + .partition(|c| c.contains(i) || c.contains(&(*j + 1 + *i))); + // println!("{:?} {} {}", i, j + 1 + i, d); + assert!(to_merge.len() < 3); + let new_circuit: HashSet = to_merge + .iter() + .flatten() + .chain(init.iter()) + .copied() + .collect(); + existing.push(new_circuit); + circuits = existing; + } + circuits +} +fn fully_connect(distance_matrix: Vec>) -> Option<(usize, usize)> { + let n_nodes = distance_matrix.len(); + let mut distances_sorted = distance_matrix + .into_iter() + .enumerate() + .flat_map(|(i, row)| { + row.into_iter() + .enumerate() + .map(move |(j, elem)| (i, j, elem)) + }) + .collect::>(); + distances_sorted.sort_unstable_by(|x, y| x.2.partial_cmp(&y.2).unwrap()); + + let mut circuits: Vec> = Vec::new(); + + let mut result: Option<(usize, usize)> = None; + + for (i, j, _) in distances_sorted.iter() { + let init = HashSet::from([*i, *j + 1 + *i]); + let (to_merge, mut existing): (Vec>, Vec>) = circuits + .into_iter() + .partition(|c| c.contains(i) || c.contains(&(*j + 1 + *i))); + assert!(to_merge.len() < 3); + let new_circuit: HashSet = to_merge + .iter() + .flatten() + .chain(init.iter()) + .copied() + .collect(); + existing.push(new_circuit); + circuits = existing; + if circuits.len() == 1 && circuits[0].len() == n_nodes { + result = Some((*i, *j + 1 + *i)); + break; + } + } + result +} + +#[cfg(test)] +mod tests { + use super::*; + + const EXAMPLE_INPUT: &str = "\ +162,817,812 +57,618,57 +906,360,560 +592,479,940 +352,342,300 +466,668,158 +542,29,236 +431,825,988 +739,650,466 +52,470,668 +216,146,977 +819,987,18 +117,168,530 +805,96,715 +346,949,466 +970,615,88 +941,993,340 +862,61,35 +984,92,344 +425,690,689 +"; + + #[test] + fn test_part1() { + assert_eq!(part1(EXAMPLE_INPUT), 20); + } + + #[test] + fn test_part2() { + assert_eq!(part2(EXAMPLE_INPUT), 25272); + } +} diff --git a/src/lib.rs b/src/lib.rs index 024cf9f..945232b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,12 +3,13 @@ extern crate aoc_runner; #[macro_use] extern crate aoc_runner_derive; -// pub mod day1; +pub mod day1; // pub mod day2; -// pub mod day3; -// pub mod day4; -// pub mod day5; -// pub mod day6; +pub mod day3; +pub mod day4; +pub mod day5; +pub mod day6; pub mod day7; +pub mod day8; aoc_lib! { year = 2025 }