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