From 73b44b1377b668dda7114b39d6a89e861f68dc1b Mon Sep 17 00:00:00 2001 From: Keenan Tims Date: Tue, 9 Dec 2025 22:13:52 -0800 Subject: [PATCH] day10: part1 --- .aoc_tiles/tiles/2025/10.png | Bin 0 -> 5851 bytes README.md | 5 +- src/day10.rs | 185 +++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 .aoc_tiles/tiles/2025/10.png create mode 100644 src/day10.rs diff --git a/.aoc_tiles/tiles/2025/10.png b/.aoc_tiles/tiles/2025/10.png new file mode 100644 index 0000000000000000000000000000000000000000..60bcc90128d874d82c82dd7a336a8935a35e1c9d GIT binary patch literal 5851 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md index b97cb02..8897295 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- 2025 - 17 ⭐ - Rust + 2025 - 18 ⭐ - Rust

@@ -29,4 +29,7 @@ + + + diff --git a/src/day10.rs b/src/day10.rs new file mode 100644 index 0000000..0d33b39 --- /dev/null +++ b/src/day10.rs @@ -0,0 +1,185 @@ +use std::{collections::BinaryHeap, iter::repeat_n}; + +use aoc_runner_derive::{aoc, aoc_generator}; +use itertools::Itertools; +use regex::Regex; + +#[derive(Clone, Debug, Default)] +struct MachineDefinition { + desired: Vec, + buttons: Vec>, + joltages: Vec, +} + +impl MachineDefinition { + fn create<'a>(&'a self) -> Machine<'a> { + Machine { + d: self, + lights: Vec::from_iter(repeat_n(false, self.desired.len())), + } + } +} + +impl From<&str> for MachineDefinition { + fn from(value: &str) -> Self { + let parse_re = Regex::new( + r##"\[(?[.#]+)\] (?(\([0-9,]+\) ?)+) \{(?[0-9,]+)\}"##, + ) + .unwrap(); + + let parts = parse_re.captures(value).unwrap(); + + MachineDefinition { + desired: parts["desired"].chars().map(|c| c == '#').collect(), + buttons: parts["buttons"] + .split_ascii_whitespace() + .map(|s| { + s[1..s.len() - 1] + .split(',') + .map(|n| n.parse().unwrap()) + .collect() + }) + .collect(), + joltages: parts["joltages"] + .split(',') + .map(|n| n.parse().unwrap()) + .collect(), + } + } +} + +#[derive(Clone, Debug)] +struct Machine<'a> { + d: &'a MachineDefinition, + lights: Vec, +} + +impl<'a> Machine<'a> { + /// Get the state after pressing `button`, returns None if the state is as desired + fn press(&self, button: usize) -> Option { + let mut new_state = self.lights.clone(); + for light in &self.d.buttons[button] { + new_state[*light] = !new_state[*light] + } + if new_state == self.d.desired { + None + } else { + Some(Machine { + d: self.d, + lights: new_state, + }) + } + } + + /// Get the possible states from the current position + fn next_states(&self) -> Vec<(usize, Option>)> { + self.d + .buttons + .iter() + .enumerate() + .map(|(i, _but)| (i, self.press(i))) + .collect() + } +} + +#[derive(Debug, Clone)] +struct PressSet<'a> { + machine: Machine<'a>, + presses: Vec, +} + +// NOTE: All compares are reversed so our max heap becomes a min heap +impl<'a> Eq for PressSet<'a> {} + +impl<'a> PartialEq for PressSet<'a> { + fn eq(&self, other: &Self) -> bool { + other.presses.len().eq(&self.presses.len()) + } +} + +impl<'a> PartialOrd for PressSet<'a> { + fn partial_cmp(&self, other: &Self) -> Option { + other.presses.len().partial_cmp(&self.presses.len()) + } +} + +impl<'a> Ord for PressSet<'a> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + other.presses.len().cmp(&self.presses.len()) + } +} + +fn find_best<'a>(md: &'a MachineDefinition) -> Vec { + let m = md.create(); + let mut to_check = BinaryHeap::new(); + for next in m.next_states() { + if let Some(new_m) = next.1 { + to_check.push(PressSet { + presses: vec![next.0], + machine: new_m.clone(), + }) + } else { + // what we found a solution on the first move? + return vec![next.0]; + } + } + while let Some(candidate) = to_check.pop() { + let cm = candidate.machine.clone(); + for next in cm.next_states() { + let mut presses = candidate.presses.clone(); + presses.push(next.0); + if let Some(new_m) = next.1 { + to_check.push(PressSet { + presses, + machine: new_m.clone(), + }) + } else { + return presses; + } + } + } + panic!() +} + +#[aoc_generator(day10)] +fn parse(input: &str) -> Vec { + input.lines().map(|l| l.into()).collect() +} + +#[aoc(day10, part1)] +fn part1(input: &Vec) -> u64 { + input + .into_iter() + .map(|md| find_best(md)) + // .inspect(|sol| println!(" [{sol:?}]")) + .map(|sol| sol.len() as u64) + .sum() +} + +#[aoc(day10, part2)] +fn part2(input: &Vec) -> u64 { + 0 +} + +#[cfg(test)] +mod tests { + use rstest::rstest; + + use super::*; + + const EXAMPLE: &str = "[.##.] (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}"; + + #[rstest] + #[case(EXAMPLE, 7)] + fn part1_example(#[case] input: &str, #[case] expected: u64) { + assert_eq!(part1(&parse(input)), expected); + } + + #[rstest] + #[case(EXAMPLE, 0)] + fn part2_example(#[case] input: &str, #[case] expected: u64) { + assert_eq!(part2(&parse(input)), expected); + } +} diff --git a/src/lib.rs b/src/lib.rs index b38dc0b..4831a4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ mod day1; +mod day10; mod day2; mod day3; mod day4;