Add messy day 8

bram
Bram 2025-12-08 16:43:02 +01:00
parent 35023c79a2
commit 33362cef62
4 changed files with 1133 additions and 3 deletions

View File

@ -5,4 +5,6 @@ edition = "2024"
[dependencies]
colored = "3.0.0"
itertools = "0.14.0"
petgraph = "0.8.3"
regex = "1.12.2"

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,129 @@
// use crate::utils;
use crate::utils;
use itertools::Itertools;
use petgraph::unionfind::UnionFind;
use std::collections::{BinaryHeap, HashMap};
pub fn answer(_text: String) -> (u32, u32) {
( 0, 0 )
const COORD_SPACE: usize = 1000;
const MAX_PAIRS: usize = 1000;
pub fn answer(text: String) -> (usize, u32) {
// Get coordinates
let coords: [Coord; COORD_SPACE] = text.trim()
.split_whitespace()
.filter_map(Coord::from)
.collect::<Vec<Coord>>()
.try_into()
.unwrap();
// Find all equivalence classes
let pairs = PairQueue::from(&coords);
let mut uf = UnionFind::new(COORD_SPACE);
for ( c1, c2 ) in pairs.pairs.iter().rev().map(|cp| (cp.c1, cp.c2)) {
// println!("Coord {c1} ({:?}) and coord {c2} ({:?}) are close together!", coords[c1], coords[c2]);
uf.union(c1, c2);
}
println!("{:?}", uf);
// Collect sizes of equivalence classes
let mut groups: HashMap<usize, usize> = HashMap::new();
for x in uf.into_labeling().iter() {
*groups.entry(*x).or_insert(0) += 1;
}
println!("{:?}", groups);
let mut equiv_class_sizes : Vec<isize> = groups
.values()
.map(|v| -1 * (*v as isize))
.collect();
equiv_class_sizes.sort_unstable();
println!("{:?}", equiv_class_sizes);
( (equiv_class_sizes[0] * equiv_class_sizes[1] * equiv_class_sizes[2]).abs() as usize
// 87048 too high
, 0
)
}
#[derive(Debug)]
struct Coord { x: u64, y: u64, z: u64, }
impl Coord {
fn dist_euclid(&self, other: &Coord) -> i64 {
( self.x.abs_diff(other.x).pow(2)
+ self.y.abs_diff(other.y).pow(2)
+ self.z.abs_diff(other.z).pow(2)
) as i64
}
fn from(s: &str) -> Option<Coord> {
let ( x, yz ) = s.split_once(",")?;
let ( y, z ) = yz.split_once(",")?;
Some(Coord {
x: utils::str_to_u64(x)?,
y: utils::str_to_u64(y)?,
z: utils::str_to_u64(z)?,
})
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct CoordPair {
distance: i64,
c1 : usize,
c2 : usize,
}
struct PairQueue {
max_distance: i64,
pairs: BinaryHeap<CoordPair>,
}
impl PairQueue {
fn from(coords: &[Coord; COORD_SPACE]) -> PairQueue {
let pairs = coords
.iter()
.enumerate()
.combinations(2);
let mut queue = PairQueue::new();
for pair in pairs {
let (i, c1) = pair[0];
let (j, c2) = pair[1];
queue.insert(
CoordPair { distance: c1.dist_euclid(c2), c1: i, c2: j }
);
}
queue
}
fn insert(&mut self, pair: CoordPair) {
// println!("At max: {} (size {}) | Distance = {} | Max distance = {} (too large: {})", self.pairs.len() >= MAX_PAIRS, self.pairs.len(), pair.distance, self.max_distance, pair.distance >= self.max_distance);
if self.pairs.len() >= MAX_PAIRS && pair.distance >= self.max_distance {
// println!("STOPPING!");
return;
}
self.max_distance = self.pairs
.peek()
.map(|cp| cp.distance)
.unwrap_or(pair.distance)
.max(pair.distance);
// println!("Going on! Self distance = {}, pair distance = {}", self.max_distance, pair.distance);
self.pairs.push(pair);
if self.pairs.len() > MAX_PAIRS {
self.pairs.pop();
// println!("Popping {:?}", self.pairs.pop());
}
}
fn new() -> PairQueue {
PairQueue {
max_distance: 0,
pairs: BinaryHeap::with_capacity(COORD_SPACE + 1)
}
}
}

View File

@ -28,6 +28,10 @@ pub fn str_to_i16(s : &str) -> Option<i16> {
s.trim().to_string().parse::<i16>().ok()
}
pub fn str_to_i64(s : &str) -> Option<i64> {
s.trim().to_string().parse::<i64>().ok()
}
// pub fn str_to_i32(s : &str) -> Option<i32> {
// s.trim().to_string().parse::<i32>().ok()
// }