From 1222162bd6802c2876fb9101c51b76585f12f068 Mon Sep 17 00:00:00 2001 From: mehbark Date: Tue, 7 Jul 2026 15:52:57 -0400 Subject: [PATCH] dramatically less cloning --- .gitignore | 3 +++ Cargo.toml | 3 +++ src/main.rs | 67 +++++++++++++++++++++++++++++++++++------------------ 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index ea8c4bf..3a5d1af 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /target +perf.data +perf.data.old +flamegraph.svg diff --git a/Cargo.toml b/Cargo.toml index f19b8bd..5741868 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] + +[profile.release] +debug = true diff --git a/src/main.rs b/src/main.rs index b65462d..05a45ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use std::{ collections::HashMap, + env, io::{self, BufRead, BufReader}, }; @@ -13,43 +14,63 @@ fn main() { .collect::>() .unwrap(); + println!( + "{:#?}", + solve( + &dictionary, + LetterSet::from( + env::args() + .nth(1) + .expect("give me the letters you want NOW") + ) + ) + ); +} + +fn solve(dictionary: &[String], target: LetterSet) -> Option<(u16, Vec)> { let mut bests = HashMap::new(); - let best = solve(dictionary.as_slice(), &mut bests, LetterSet::FULL); - println!("{best:?}"); + bests.insert(LetterSet::EMPTY, (0, Vec::new())); + + score(dictionary, &mut bests, target); + + bests.get(&target).cloned() } // length doesn't include spaces. i think that's okay -fn solve( +// assumes that `bests[LetterSet::EMPTY] == (0, Vec::new())` +fn score( dictionary: &[String], bests: &mut HashMap)>, remaining: LetterSet, -) -> (u16, Vec) { - if remaining.is_empty() { - return (0, Vec::new()); - } - +) -> u16 { if let Some(min) = bests.get(&remaining) { - return min.clone(); + return min.0; } - let best = dictionary + let Some((word, score)) = dictionary .iter() - .filter(|word| remaining != remaining.difference(LetterSet::from(word.as_bytes()))) + .filter(|word| remaining != remaining.difference(LetterSet::from(word))) .map(|word| { - let (score, mut path) = solve( - dictionary, - bests, - remaining.difference(LetterSet::from(word)), - ); - path.push(word.clone()); ( - (u16::try_from(word.len()).unwrap()).saturating_add(score), - path, + word, + (u16::try_from(word.len()).unwrap()).saturating_add(score( + dictionary, + bests, + remaining.difference(LetterSet::from(word)), + )), ) }) - .min() - .unwrap_or((u16::MAX, Vec::new())); + .min_by_key(|(_, score)| *score) + else { + return u16::MAX; + }; - bests.insert(remaining, best.clone()); - best + let remaining_after_word = remaining.difference(LetterSet::from(word)); + let (_score, path) = bests + .get(&remaining_after_word) + .expect("we already inserted this"); + let mut path = path.clone(); + path.push(word.clone()); + bests.insert(remaining, (score, path)); + score }