Add messy day 8
parent
35023c79a2
commit
33362cef62
|
|
@ -5,4 +5,6 @@ edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
colored = "3.0.0"
|
colored = "3.0.0"
|
||||||
|
itertools = "0.14.0"
|
||||||
|
petgraph = "0.8.3"
|
||||||
regex = "1.12.2"
|
regex = "1.12.2"
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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) {
|
const COORD_SPACE: usize = 1000;
|
||||||
( 0, 0 )
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,10 @@ pub fn str_to_i16(s : &str) -> Option<i16> {
|
||||||
s.trim().to_string().parse::<i16>().ok()
|
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> {
|
// pub fn str_to_i32(s : &str) -> Option<i32> {
|
||||||
// s.trim().to_string().parse::<i32>().ok()
|
// s.trim().to_string().parse::<i32>().ok()
|
||||||
// }
|
// }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue