Day 8
This commit is contained in:
parent
47c7362687
commit
aade7c356e
1 changed files with 183 additions and 0 deletions
183
src/bin/day8.rs
Normal file
183
src/bin/day8.rs
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use aoc_2025::{load, print_res};
|
||||||
|
use bstr::BString;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Point3 {
|
||||||
|
pub x: u64,
|
||||||
|
pub y: u64,
|
||||||
|
pub z: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point3 {
|
||||||
|
pub fn dist2(&self, other: &Point3) -> u64 {
|
||||||
|
self.x.abs_diff(other.x).pow(2)
|
||||||
|
+ self.y.abs_diff(other.y).pow(2)
|
||||||
|
+ self.z.abs_diff(other.z).pow(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parsed = Vec<Point3>;
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn parsing(input: &BString) -> color_eyre::Result<Parsed> {
|
||||||
|
str::from_utf8(input)?
|
||||||
|
.lines()
|
||||||
|
.map(|v| {
|
||||||
|
let Some((x, r)) = v.split_once(',') else {
|
||||||
|
color_eyre::eyre::bail!("Invalid coordinates: {v}");
|
||||||
|
};
|
||||||
|
let Some((y, z)) = r.split_once(',') else {
|
||||||
|
color_eyre::eyre::bail!("Invalid coordinates: {v}");
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Point3 {
|
||||||
|
x: x.parse()?,
|
||||||
|
y: y.parse()?,
|
||||||
|
z: z.parse()?,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
struct UnionFindEntry {
|
||||||
|
parent: u16,
|
||||||
|
size: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct UnionFind {
|
||||||
|
entries: Vec<UnionFindEntry>,
|
||||||
|
set_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnionFind {
|
||||||
|
pub fn new(size: usize) -> Self {
|
||||||
|
assert!(size <= u16::MAX as usize);
|
||||||
|
let mut entries = Vec::with_capacity(size);
|
||||||
|
for i in 0..size as u16 {
|
||||||
|
entries.push(UnionFindEntry { parent: i, size: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
entries,
|
||||||
|
set_count: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find(&mut self, mut x: u16) -> u16 {
|
||||||
|
if self.entries[x as usize].parent != x {
|
||||||
|
let mut root = x;
|
||||||
|
|
||||||
|
while self.entries[root as usize].parent != root {
|
||||||
|
root = self.entries[root as usize].parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
while self.entries[x as usize].parent != root {
|
||||||
|
let parent = self.entries[x as usize].parent;
|
||||||
|
self.entries[x as usize].parent = root;
|
||||||
|
x = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
root
|
||||||
|
} else {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn union(&mut self, a: u16, b: u16) {
|
||||||
|
let mut ra = self.find(a);
|
||||||
|
let mut rb = self.find(b);
|
||||||
|
|
||||||
|
if ra == rb {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.entries[ra as usize].size < self.entries[rb as usize].size {
|
||||||
|
std::mem::swap(&mut ra, &mut rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.entries[rb as usize].parent = ra;
|
||||||
|
self.entries[ra as usize].size += self.entries[rb as usize].size;
|
||||||
|
self.set_count -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sets(&self) -> impl Iterator<Item = (u16, usize)> {
|
||||||
|
self.entries.iter().enumerate().filter_map(|(i, e)| {
|
||||||
|
if e.parent as usize == i {
|
||||||
|
Some((e.parent, e.size as usize))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_count(&self) -> usize {
|
||||||
|
self.set_count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn part1(input: Parsed) {
|
||||||
|
let mut pairs: Vec<_> = (0..input.len())
|
||||||
|
.flat_map(|ia| ((ia + 1)..input.len()).map(move |ib| (ia, ib)))
|
||||||
|
.collect();
|
||||||
|
pairs.sort_unstable_by_key(|&(ia, ib)| input[ia].dist2(&input[ib]));
|
||||||
|
|
||||||
|
let mut uf = UnionFind::new(input.len());
|
||||||
|
for &(ia, ib) in pairs.iter().take(1000) {
|
||||||
|
uf.union(ia as u16, ib as u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sets: Vec<_> = uf.sets().collect();
|
||||||
|
sets.sort_unstable_by_key(|&(_, s)| s);
|
||||||
|
|
||||||
|
let mut largests = 1;
|
||||||
|
for _ in 0..3 {
|
||||||
|
largests *= sets.pop().unwrap().1;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_res!("Size product is: {largests}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn part2(input: Parsed) {
|
||||||
|
let mut pairs: Vec<_> = (0..input.len())
|
||||||
|
.flat_map(|ia| ((ia + 1)..input.len()).map(move |ib| (ia, ib)))
|
||||||
|
.collect();
|
||||||
|
pairs.sort_unstable_by_key(|&(ia, ib)| input[ia].dist2(&input[ib]));
|
||||||
|
|
||||||
|
let mut uf = UnionFind::new(input.len());
|
||||||
|
for &(ia, ib) in &pairs {
|
||||||
|
uf.union(ia as u16, ib as u16);
|
||||||
|
if uf.set_count() == 1 {
|
||||||
|
print_res!("X product of last boxes: {}", input[ia].x * input[ib].x);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Not all boxes have been connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() -> color_eyre::Result<()> {
|
||||||
|
let context = load()?;
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let parsed = parsing(&context.input)?;
|
||||||
|
let elapsed = humantime::format_duration(start.elapsed());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
if context.part == 1 {
|
||||||
|
part1(parsed);
|
||||||
|
} else {
|
||||||
|
part2(parsed);
|
||||||
|
}
|
||||||
|
let elapsed_part = humantime::format_duration(start.elapsed());
|
||||||
|
|
||||||
|
println!(" Parsing: {elapsed}");
|
||||||
|
println!(" Solving: {elapsed_part}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue