day10: small performance boost

This commit is contained in:
2025-12-09 22:45:33 -08:00
parent 73b44b1377
commit 0a5e5c8798

View File

@@ -1,7 +1,6 @@
use std::{collections::BinaryHeap, iter::repeat_n}; use std::{collections::BinaryHeap, hash::Hash, iter::repeat_n};
use aoc_runner_derive::{aoc, aoc_generator}; use aoc_runner_derive::{aoc, aoc_generator};
use itertools::Itertools;
use regex::Regex; use regex::Regex;
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@@ -54,6 +53,19 @@ struct Machine<'a> {
lights: Vec<bool>, lights: Vec<bool>,
} }
impl<'a> Eq for Machine<'a> {}
impl<'a> PartialEq for Machine<'a> {
fn eq(&self, other: &Self) -> bool {
self.lights == other.lights
}
}
impl<'a> Hash for Machine<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.lights.hash(state)
}
}
impl<'a> Machine<'a> { impl<'a> Machine<'a> {
/// Get the state after pressing `button`, returns None if the state is as desired /// Get the state after pressing `button`, returns None if the state is as desired
fn press(&self, button: usize) -> Option<Self> { fn press(&self, button: usize) -> Option<Self> {
@@ -85,7 +97,7 @@ impl<'a> Machine<'a> {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct PressSet<'a> { struct PressSet<'a> {
machine: Machine<'a>, machine: Machine<'a>,
presses: Vec<usize>, presses: usize,
} }
// NOTE: All compares are reversed so our max heap becomes a min heap // NOTE: All compares are reversed so our max heap becomes a min heap
@@ -93,41 +105,41 @@ impl<'a> Eq for PressSet<'a> {}
impl<'a> PartialEq for PressSet<'a> { impl<'a> PartialEq for PressSet<'a> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
other.presses.len().eq(&self.presses.len()) other.presses.eq(&self.presses)
} }
} }
impl<'a> PartialOrd for PressSet<'a> { impl<'a> PartialOrd for PressSet<'a> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
other.presses.len().partial_cmp(&self.presses.len()) Some(self.cmp(other))
} }
} }
impl<'a> Ord for PressSet<'a> { impl<'a> Ord for PressSet<'a> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering { fn cmp(&self, other: &Self) -> std::cmp::Ordering {
other.presses.len().cmp(&self.presses.len()) other.presses.cmp(&self.presses)
} }
} }
fn find_best<'a>(md: &'a MachineDefinition) -> Vec<usize> { fn find_best(md: &MachineDefinition) -> usize {
let m = md.create(); let m = md.create();
let mut to_check = BinaryHeap::new(); let mut to_check = BinaryHeap::new();
for next in m.next_states() { for next in m.next_states() {
if let Some(new_m) = next.1 { if let Some(new_m) = next.1 {
to_check.push(PressSet { to_check.push(PressSet {
presses: vec![next.0], presses: 1,
machine: new_m.clone(), machine: new_m.clone(),
}) })
} else { } else {
// what we found a solution on the first move? // what we found a solution on the first move?
return vec![next.0]; return 1;
} }
} }
while let Some(candidate) = to_check.pop() { while let Some(candidate) = to_check.pop() {
let cm = candidate.machine.clone(); let cm = candidate.machine.clone();
for next in cm.next_states() { for next in cm.next_states() {
let mut presses = candidate.presses.clone(); let presses = candidate.presses + 1;
presses.push(next.0);
if let Some(new_m) = next.1 { if let Some(new_m) = next.1 {
to_check.push(PressSet { to_check.push(PressSet {
presses, presses,
@@ -147,17 +159,17 @@ fn parse(input: &str) -> Vec<MachineDefinition> {
} }
#[aoc(day10, part1)] #[aoc(day10, part1)]
fn part1(input: &Vec<MachineDefinition>) -> u64 { fn part1(input: &[MachineDefinition]) -> u64 {
input input
.into_iter() .iter()
.map(|md| find_best(md)) .map(find_best)
// .inspect(|sol| println!(" [{sol:?}]")) // .inspect(|sol| println!(" [{sol:?}]"))
.map(|sol| sol.len() as u64) .map(|sol| sol as u64)
.sum() .sum()
} }
#[aoc(day10, part2)] #[aoc(day10, part2)]
fn part2(input: &Vec<MachineDefinition>) -> u64 { fn part2(input: &[MachineDefinition]) -> u64 {
0 0
} }
@@ -178,7 +190,7 @@ mod tests {
} }
#[rstest] #[rstest]
#[case(EXAMPLE, 0)] #[case(EXAMPLE, 33)]
fn part2_example(#[case] input: &str, #[case] expected: u64) { fn part2_example(#[case] input: &str, #[case] expected: u64) {
assert_eq!(part2(&parse(input)), expected); assert_eq!(part2(&parse(input)), expected);
} }