From 76b1e3cf897d93426d1eddd93333517d168deb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Tue, 9 Dec 2025 10:20:49 +0100 Subject: [PATCH] Add solution for "Day 8: Playground", part 1 --- README.md | 6 ++- src/main.rs | 5 +++ src/solvers.rs | 1 + src/solvers/playground.rs | 95 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/solvers/playground.rs diff --git a/README.md b/README.md index 17cda32..f75d8f3 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,11 @@ This project does not contain the puzzle or example inputs as per the [copyright ### Day 6: Trash Compactor -:mag_right: Puzzle: , :white_check_mark: Solver: [`Trash Compactor`](src/solvers/trash_compactor.rs) +:mag_right: Puzzle: , :white_check_mark: Solver: [`TrashCompactor`](src/solvers/trash_compactor.rs) + +### Day 8: Playground + +:mag_right: Puzzle: , :white_check_mark: Solver: [`Playground`](src/solvers/playground.rs) ## Tests diff --git a/src/main.rs b/src/main.rs index db059e1..170399e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,12 @@ use advent_of_code_2025::solvers; fn main() { println!("### Advent of Code 2025 ###\n"); + // SecretEntrance + // GiftShop + // Lobby solvers::run(solvers::printing_department::PrintingDepartment {}); solvers::run(solvers::cafeteria::Cafeteria {}); solvers::run(solvers::trash_compactor::TrashCompactor {}); + // Laboratories + solvers::run(solvers::playground::Playground::new(None)); } diff --git a/src/solvers.rs b/src/solvers.rs index df406e4..01918bd 100644 --- a/src/solvers.rs +++ b/src/solvers.rs @@ -6,6 +6,7 @@ use std::path; use std::path::Path; pub mod cafeteria; +pub mod playground; pub mod printing_department; pub mod trash_compactor; diff --git a/src/solvers/playground.rs b/src/solvers/playground.rs new file mode 100644 index 0000000..b6962a8 --- /dev/null +++ b/src/solvers/playground.rs @@ -0,0 +1,95 @@ +use crate::solvers::Solver; +use std::collections::{BTreeMap, HashSet}; +use std::io::BufRead; + +pub struct Playground { + connections: usize, +} + +impl Playground { + pub fn new(connections: Option) -> Playground { + Playground { + connections: connections.unwrap_or(1000), + } + } + + // Collects all junction box coordinates. + fn junction_boxes(reader: R) -> Vec<(u64, u64, u64)> { + let mut junction_boxes = Vec::new(); + for line in reader.lines().map_while(Result::ok) { + let j: Vec = line.split(',').map(|s| s.parse().unwrap()).collect(); + junction_boxes.push((j[0], j[1], j[2])); + } + junction_boxes + } + + // Maps the closest pairs of junction boxes to their distances, up to the maximum number of + // connections. + fn distances<'a>( + &self, + junction_boxes: &'a Vec<(u64, u64, u64)>, + ) -> BTreeMap { + let mut distances = BTreeMap::new(); + for i in 0..junction_boxes.len() { + let (_, right) = junction_boxes.split_at(i + 1); + for b in right { + let d = Self::distance_sqr(&junction_boxes[i], b); + distances.insert(d, (&junction_boxes[i], b)); + if distances.len() > self.connections { + distances.pop_last(); + } + } + } + distances + } + + fn circuit_sizes(distances: &BTreeMap) -> u64 { + let mut circuits: Vec> = Vec::new(); + for junction_boxes in distances.values() { + let index_a = circuits.iter().position(|c| c.contains(&junction_boxes.0)); + let index_b = circuits.iter().position(|c| c.contains(&junction_boxes.1)); + if let Some(index_a) = index_a { + if let Some(index_b) = index_b { + if index_a != index_b { + let (low, high) = if index_a < index_b { + (index_a, index_b) + } else { + (index_b, index_a) + }; + let mut c = circuits.remove(high); + circuits[low].extend(c.drain()); + } + } else { + circuits[index_a].insert(junction_boxes.1); + } + } else { + if let Some(index_b) = index_b { + circuits[index_b].insert(junction_boxes.0); + } else { + let mut set = HashSet::new(); + set.insert(junction_boxes.0); + set.insert(junction_boxes.1); + circuits.push(set); + } + } + } + circuits.sort_by(|a, b| b.len().cmp(&a.len())); + circuits.iter().take(3).map(|c| c.len() as u64).product() + } + + fn distance_sqr(a: &(u64, u64, u64), b: &(u64, u64, u64)) -> u64 { + a.0.abs_diff(b.0).pow(2) + a.1.abs_diff(b.1).pow(2) + a.2.abs_diff(b.2).pow(2) + } +} + +impl Solver for Playground { + const PUZZLE_INDEX: u8 = 8; + const PUZZLE_NAME: &'static str = "Playground"; + + fn process_data(&self, reader: R) -> (u64, u64) { + let junction_boxes = Self::junction_boxes(reader); + let distances = self.distances(&junction_boxes); + + (Self::circuit_sizes(&distances), 0) + } +}