dramatically less cloning

This commit is contained in:
mehbark 2026-07-07 15:52:57 -04:00
parent 8cba1ef0ce
commit 1222162bd6
3 changed files with 50 additions and 23 deletions

3
.gitignore vendored
View file

@ -1 +1,4 @@
/target
perf.data
perf.data.old
flamegraph.svg

View file

@ -4,3 +4,6 @@ version = "0.1.0"
edition = "2024"
[dependencies]
[profile.release]
debug = true

View file

@ -1,5 +1,6 @@
use std::{
collections::HashMap,
env,
io::{self, BufRead, BufReader},
};
@ -13,43 +14,63 @@ fn main() {
.collect::<Result<_, _>>()
.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<String>)> {
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<LetterSet, (u16, Vec<String>)>,
remaining: LetterSet,
) -> (u16, Vec<String>) {
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(
(
word,
(u16::try_from(word.len()).unwrap()).saturating_add(score(
dictionary,
bests,
remaining.difference(LetterSet::from(word)),
);
path.push(word.clone());
(
(u16::try_from(word.len()).unwrap()).saturating_add(score),
path,
)),
)
})
.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
}