From 7df6f2ab51558230a3b41848bf7769458461b8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Tue, 10 Feb 2026 10:41:56 +0100 Subject: [PATCH] Add solution for "Day 7: Laboratories", part 1 and 2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 6 +++++ src/main.rs | 2 +- src/solvers.rs | 1 + src/solvers/laboratories.rs | 45 +++++++++++++++++++++++++++++++++++++ tests/examples.rs | 8 +++++++ tests/full_data.rs | 8 +++++++ 8 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 src/solvers/laboratories.rs diff --git a/Cargo.lock b/Cargo.lock index f0e465d..5ca4e79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,8 +7,8 @@ name = "advent_of_code_2025" version = "0.1.0" dependencies = [ "grid", + "memchr", "primes", - "regex", "sanitise-file-name", "scan_fmt", ] diff --git a/Cargo.toml b/Cargo.toml index 2b1ae2f..679764e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] grid = "1.0.0" +memchr = "2.7.6" primes = "0.4.0" -regex = "1.12.2" sanitise-file-name = "1.0.0" scan_fmt = "0.2.6" diff --git a/README.md b/README.md index 397a8a0..e2335fc 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,12 @@ From the input data, we construct a [`MultiInterval`](src/common/interval.rs), w We implement two different ways to collect numbers from the input. For part 1, numbers separated by space are read line by line, stored in a two-dimensional array and then aggregated in columns. While for part 2, each column of characters in the input data represents a number, and empty columns are interpreted as the separators between blocks for aggregation. +### Day 7: Laboratories + +:mag_right: Puzzle: , :white_check_mark: Solver: [`Laboratories`](src/solvers/laboratories.rs) + +Going row by row, for each column in the input data we count the number of different beam paths that reach that column in that row. When a beam is split, the count for that column is added to both columns the beam is split into. For part 1 we count the splits, and for parts 2 we sum the count for all columns of the final row. + ### Day 8: Playground :mag_right: Puzzle: , :white_check_mark: Solver: [`Playground`](src/solvers/playground.rs) diff --git a/src/main.rs b/src/main.rs index eae05a1..a063ce1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ fn main() { solvers::run(solvers::printing_department::PrintingDepartment {}); solvers::run(solvers::cafeteria::Cafeteria {}); solvers::run(solvers::trash_compactor::TrashCompactor {}); - // Laboratories + solvers::run(solvers::laboratories::Laboratories {}); solvers::run(solvers::playground::Playground::new(None)); solvers::run(solvers::movie_theater::MovieTheater {}); // Factory diff --git a/src/solvers.rs b/src/solvers.rs index 98136fb..f7de0de 100644 --- a/src/solvers.rs +++ b/src/solvers.rs @@ -7,6 +7,7 @@ use std::path::Path; pub mod cafeteria; pub mod gift_shop; +pub mod laboratories; pub mod lobby; pub mod movie_theater; pub mod playground; diff --git a/src/solvers/laboratories.rs b/src/solvers/laboratories.rs new file mode 100644 index 0000000..589ce16 --- /dev/null +++ b/src/solvers/laboratories.rs @@ -0,0 +1,45 @@ +use crate::solvers::Solver; +use memchr::{memchr, memchr_iter}; +use std::io::BufRead; + +pub struct Laboratories {} + +impl Laboratories { + const START_CHAR: u8 = b'S'; + const SPLITTER_CHAR: u8 = b'^'; + + fn start_beam(line: &str) -> Vec { + let mut beams = vec![0; line.len()]; + if let Some(s) = memchr(Self::START_CHAR, line.as_bytes()) { + beams[s] = 1; + } + beams + } + + fn split_beams(line: &str, mut beams: Vec, mut splits: u64) -> (Vec, u64) { + for s in memchr_iter(Self::SPLITTER_CHAR, line.as_bytes()) { + if beams[s] > 0 { + splits += 1; + beams[s - 1] += beams[s]; + beams[s + 1] += beams[s]; + beams[s] = 0; + } + } + (beams, splits) + } +} + +impl Solver for Laboratories { + const PUZZLE_INDEX: u8 = 7; + const PUZZLE_NAME: &'static str = "Laboratories"; + + fn process_data(&self, mut reader: R) -> (u64, u64) { + let line = reader.by_ref().lines().next().unwrap().unwrap(); + let mut beams = Self::start_beam(&line); + let mut splits = 0; + for line in reader.lines().map_while(Result::ok) { + (beams, splits) = Self::split_beams(&line, beams, splits); + } + (splits, beams.iter().sum()) + } +} diff --git a/tests/examples.rs b/tests/examples.rs index 196a1bf..be6bab3 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -59,6 +59,14 @@ fn trash_compactor() { ); } +#[test] +fn laboratories() { + assert_eq!( + Ok((21, 40)), + solvers::run_solver(solvers::laboratories::Laboratories {}, &EXAMPLE_PATHS) + ); +} + #[test] fn playground() { assert_eq!( diff --git a/tests/full_data.rs b/tests/full_data.rs index 63f0bb7..e815d75 100644 --- a/tests/full_data.rs +++ b/tests/full_data.rs @@ -57,6 +57,14 @@ fn trash_compactor() { ); } +#[test] +fn laboratories() { + assert_eq!( + Ok((1541, 80158285728929)), + solvers::run_solver(solvers::laboratories::Laboratories {}, &solvers::DATA_PATHS) + ); +} + #[test] fn playground() { assert_eq!(