From ff8b8dac0c0d9d01321441237e1d0b3d6fc6f38f Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Wed, 10 Dec 2025 08:39:51 +0100 Subject: [PATCH] 2025 day 10 part 1 in Rust --- 2025/day10/.gitignore | 1 + 2025/day10/Cargo.toml | 6 +++ 2025/day10/sample.txt | 3 ++ 2025/day10/src/main.rs | 103 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 2025/day10/.gitignore create mode 100644 2025/day10/Cargo.toml create mode 100644 2025/day10/sample.txt create mode 100644 2025/day10/src/main.rs diff --git a/2025/day10/.gitignore b/2025/day10/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/2025/day10/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/2025/day10/Cargo.toml b/2025/day10/Cargo.toml new file mode 100644 index 0000000..8902ce5 --- /dev/null +++ b/2025/day10/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "solve" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/2025/day10/sample.txt b/2025/day10/sample.txt new file mode 100644 index 0000000..dd91d7b --- /dev/null +++ b/2025/day10/sample.txt @@ -0,0 +1,3 @@ +[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7} +[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2} +[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5} diff --git a/2025/day10/src/main.rs b/2025/day10/src/main.rs new file mode 100644 index 0000000..8ac062d --- /dev/null +++ b/2025/day10/src/main.rs @@ -0,0 +1,103 @@ +use std::collections::VecDeque; +use std::env; +use std::fs; +use std::io; + +fn parse_line(line: &str) -> (u32, Vec) { + let mut buttons = vec![]; + let mut target = 0; + + let mut it = line.chars(); + + for (i, c) in it.by_ref().skip(1).enumerate() { + match c { + '#' => target |= 1 << i, + '.' => (), + _ => break, + } + } + + loop { + match it.nth(1) { + Some('{') => break, + Some('(') => (), + other => panic!("Unexpected character \"{other:?}\" in: {line}"), + } + + let mut button = 0; + + while let Some(c) = it.next() { + let d = c.to_digit(10).unwrap(); + button |= 1 << d; + + if let Some(')') = it.next() { + break; + } + } + + buttons.push(button); + } + + (target, buttons) +} + +fn minimum_clicks(target: u32, buttons: &[u32]) -> i32 { + let max = buttons + .iter() + .map(|s| 32 - s.leading_zeros()) + .max() + .unwrap_or(0); + let possible = 2 << max; + let mut seen = vec![false; possible]; + let mut todo = VecDeque::new(); + todo.push_back((0, 0)); + + while let Some((steps, state)) = todo.pop_front() { + for &button in buttons { + let next = state ^ button; + + if next == target { + return steps + 1; + } else if !seen[next as usize] { + seen[next as usize] = true; + todo.push_back((steps + 1, next)); + } + } + } + + unreachable!("Did not find target"); +} + +fn solve(input: &str) -> i32 { + let mut total_clicks = 0; + for line in input.trim().lines() { + let (target, buttons) = parse_line(line); + total_clicks += minimum_clicks(target, &buttons); + } + + total_clicks +} + +fn main() -> io::Result<()> { + if let Some(path) = env::args_os().nth(1) { + let input = fs::read_to_string(path)?; + + println!("{}", solve(&input)); + Ok(()) + } else { + eprintln!("Usage: {} INPUT_FILE", env::args().next().unwrap()); + std::process::exit(1); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const SAMPLE: &str = include_str!("../sample.txt"); + + #[test] + fn test_part1() { + assert_eq!(7, solve(SAMPLE)); + } +}