precompute word lettersets

This commit is contained in:
mehbark 2026-07-07 16:12:38 -04:00
parent 0ce60e52ff
commit 42c1c51e71

View file

@ -9,10 +9,14 @@ use crate::letterset::LetterSet;
mod letterset;
fn main() {
let dictionary: Vec<String> = BufReader::new(io::stdin().lock())
let dictionary: Vec<_> = BufReader::new(io::stdin().lock())
.lines()
.collect::<Result<_, _>>()
.unwrap();
.map(|line| {
let word = line.unwrap();
let ls = LetterSet::from(&word);
(word, ls)
})
.collect();
println!(
"{:#?}",
@ -23,7 +27,7 @@ fn main() {
);
}
fn solve(dictionary: &[String], target: LetterSet) -> Option<(u16, Vec<String>)> {
fn solve(dictionary: &[(String, LetterSet)], target: LetterSet) -> Option<(u16, Vec<String>)> {
let mut bests = HashMap::new();
bests.insert(LetterSet::EMPTY, (0, Vec::new()));
@ -35,7 +39,7 @@ fn solve(dictionary: &[String], target: LetterSet) -> Option<(u16, Vec<String>)>
// length doesn't include spaces. i think that's okay
// assumes that `bests[LetterSet::EMPTY] == (0, Vec::new())`
fn score(
dictionary: &[String],
dictionary: &[(String, LetterSet)],
bests: &mut HashMap<LetterSet, (u16, Vec<String>)>,
remaining: LetterSet,
) -> u16 {
@ -43,25 +47,30 @@ fn score(
return min.0;
}
let Some((word, score)) = dictionary
let Some((word, ls, score)) = dictionary
.iter()
.filter(|word| remaining != remaining.difference(LetterSet::from(word)))
.map(|word| {
.filter(|(_, ls)| !remaining.intersection(*ls).is_empty())
.map(|(word, ls)| {
(
word,
ls,
(u16::try_from(word.len()).unwrap()).saturating_add(score(
dictionary,
bests,
remaining.difference(LetterSet::from(word)),
remaining.difference(*ls),
)),
)
})
.min_by_key(|(_, score)| *score)
.min_by_key(|(_, _, score)| *score)
else {
return u16::MAX;
};
let remaining_after_word = remaining.difference(LetterSet::from(word));
if score == u16::MAX {
return score;
}
let remaining_after_word = remaining.difference(*ls);
let (_score, path) = bests
.get(&remaining_after_word)
.expect("we already inserted this");