From 396c9730003e259324ee223bf0fbd5bfbd154470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Mon, 13 Jul 2026 21:19:41 +0200 Subject: [PATCH] Add solution for "Day 10: Factory", part 1 --- Cargo.lock | 16 ++++++++++ Cargo.toml | 1 + src/main.rs | 2 +- src/solvers.rs | 1 + src/solvers/factory.rs | 67 ++++++++++++++++++++++++++++++++++++++++++ tests/examples.rs | 8 +++++ tests/full_data.rs | 8 +++++ 7 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 src/solvers/factory.rs diff --git a/Cargo.lock b/Cargo.lock index 8c48120..b7ca8be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,6 +9,7 @@ dependencies = [ "bitflags", "grapherity", "grid", + "itertools", "memchr", "primes", "sanitise-file-name", @@ -42,6 +43,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + [[package]] name = "grapherity" version = "0.2.1" @@ -57,6 +64,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b40ca9252762c466af32d0b1002e91e4e1bc5398f77455e55474deb466355ff5" +[[package]] +name = "itertools" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" +dependencies = [ + "either", +] + [[package]] name = "memchr" version = "2.8.2" diff --git a/Cargo.toml b/Cargo.toml index 0e1217b..a584d9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" bitflags = "2.13.0" grapherity = "0.2.1" grid = "1.0.0" +itertools = "0.15.0" memchr = "2.7.6" primes = "0.4.0" sanitise-file-name = "1.0.0" diff --git a/src/main.rs b/src/main.rs index a063ce1..9603d06 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ fn main() { solvers::run(solvers::laboratories::Laboratories {}); solvers::run(solvers::playground::Playground::new(None)); solvers::run(solvers::movie_theater::MovieTheater {}); - // Factory + solvers::run(solvers::factory::Factory {}); // Reactor // ChristmasTreeFarm } diff --git a/src/solvers.rs b/src/solvers.rs index f7de0de..ddc0fb3 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 factory; pub mod gift_shop; pub mod laboratories; pub mod lobby; diff --git a/src/solvers/factory.rs b/src/solvers/factory.rs new file mode 100644 index 0000000..4474e5c --- /dev/null +++ b/src/solvers/factory.rs @@ -0,0 +1,67 @@ +use crate::solvers::Solver; +use itertools::Itertools; +use std::io::BufRead; + +pub struct Factory {} + +impl Factory { + const INDICATOR_ON_CHAR: u8 = b'#'; + + // Turns a string like "[..##.]", interpreted as a binary number with low-significance bit left, into a decimal + // integer, e.g. 0 * 1 + 0 * 2 + 1 * 4 + 1 * 8 + 0 * 16 = 12. + fn indicators(s: &str) -> u16 { + s.bytes() + .enumerate() + .filter(|&(_, c)| c == Self::INDICATOR_ON_CHAR) + .fold(0, |acc, (i, _)| acc + (1 << (i - 1))) + } + + // Turns a string like "(0,3,4)", interpreted as the set of digits of a binary number that are one, into a decimal + // integer, e.g. 2^0 + 2^3 + 2^4 = 25. + fn button(s: &str) -> u16 { + s[1..s.len() - 1] + .split(',') + .map(|b| b.parse().expect("button index should be a number")) + .fold(0, |acc, x| acc + 2_u16.pow(x)) + } + + fn find_min_button_presses(indicators: u16, buttons: &[u16]) -> u64 { + if buttons.contains(&indicators) { + 1 + } else { + let len = buttons.len(); + for k in 2..len { + if buttons + .iter() + .combinations(k) + .any(|combination| combination.iter().fold(0, |acc, &x| acc ^ x) == indicators) + { + return k as u64; + } + } + len as u64 + } + } +} + +impl Solver for Factory { + const PUZZLE_INDEX: u8 = 10; + const PUZZLE_NAME: &'static str = "Factory"; + + fn process_data(&self, reader: R) -> (u64, u64) { + let mut part1 = 0; + let mut buttons = Vec::new(); + for line in reader.lines().map_while(Result::ok) { + buttons.clear(); + let mut split = line.split(' ').into_iter(); + let indicators = Self::indicators(split.next().expect("missing indicator lights")); + let mut current = split.next().expect("missing button wiring schematics"); + while let Some(next) = split.next() { + buttons.push(Self::button(current)); + current = next; + } + part1 += Self::find_min_button_presses(indicators, &buttons); + } + (part1, 0) + } +} diff --git a/tests/examples.rs b/tests/examples.rs index 7e6906f..1edcf56 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -85,3 +85,11 @@ fn movie_theater() { solvers::run_solver(solvers::movie_theater::MovieTheater {}, &EXAMPLE_PATHS) ); } + +#[test] +fn factory() { + assert_eq!( + Ok((7, 0)), + solvers::run_solver(solvers::factory::Factory {}, &EXAMPLE_PATHS) + ); +} diff --git a/tests/full_data.rs b/tests/full_data.rs index c9d696a..613764c 100644 --- a/tests/full_data.rs +++ b/tests/full_data.rs @@ -86,3 +86,11 @@ fn movie_theater() { ) ); } + +#[test] +fn factory() { + assert_eq!( + Ok((409, 0)), + solvers::run_solver(solvers::factory::Factory {}, &solvers::DATA_PATHS) + ); +}