This commit is contained in:
2025-12-08 23:40:41 +01:00
parent c6c159ca4e
commit 203402971b
3 changed files with 184 additions and 28 deletions

View File

@@ -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

155
src/day8.rs Normal file
View File

@@ -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<Vec<i64>> {
input
.lines()
.map(|line| {
line.split(',')
.map(|num| num.parse::<i64>().unwrap())
.collect::<Vec<i64>>()
})
.collect()
}
fn distances(nodes: Vec<Vec<i64>>) -> Vec<Vec<f64>> {
(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::<f64>()
.sqrt()
})
}
.collect::<Vec<f64>>()
})
.collect()
}
fn make_circuits(distance_matrix: Vec<Vec<f64>>, n_connections: u32) -> Vec<HashSet<usize>> {
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::<Vec<(usize, usize, f64)>>();
distances_sorted.sort_unstable_by(|x, y| x.2.partial_cmp(&y.2).unwrap());
let mut circuits: Vec<HashSet<usize>> = 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<HashSet<usize>>, Vec<HashSet<usize>>) = 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<usize> = to_merge
.iter()
.flatten()
.chain(init.iter())
.copied()
.collect();
existing.push(new_circuit);
circuits = existing;
}
circuits
}
fn fully_connect(distance_matrix: Vec<Vec<f64>>) -> 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::<Vec<(usize, usize, f64)>>();
distances_sorted.sort_unstable_by(|x, y| x.2.partial_cmp(&y.2).unwrap());
let mut circuits: Vec<HashSet<usize>> = 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<HashSet<usize>>, Vec<HashSet<usize>>) = circuits
.into_iter()
.partition(|c| c.contains(i) || c.contains(&(*j + 1 + *i)));
assert!(to_merge.len() < 3);
let new_circuit: HashSet<usize> = 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);
}
}

View File

@@ -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 }