doesn't work

This commit is contained in:
mehbark 2026-07-07 20:24:00 -04:00
parent 211368ee45
commit d3f89edddf

View file

@ -1,6 +1,6 @@
use std::{ use std::{
cmp, array,
collections::{HashMap, hash_map::Entry}, collections::HashSet,
env, env,
io::{self, BufRead, BufReader}, io::{self, BufRead, BufReader},
process, process,
@ -22,85 +22,62 @@ fn main() {
let target = env::args().nth(1).map_or(LetterSet::FULL, LetterSet::from); let target = env::args().nth(1).map_or(LetterSet::FULL, LetterSet::from);
println!("letter count: {}", target.len()); println!("letter count: {}", target.len());
let Some((len, path)) = solve(&mut dictionary, target) else { let (len, path) = solve(&mut dictionary, target);
println!("failed :("); println!("{len}: {}", path.into_iter().collect::<Vec<_>>().join(" "));
process::exit(1);
};
println!("{len}: {}", path.join(" "));
} }
fn solve(dictionary: &mut [(String, LetterSet)], target: LetterSet) -> Option<(u16, Vec<String>)> { const MAX_SOLUTION_LENGTH: u8 = 50;
let mut bests = HashMap::new();
bests.insert(LetterSet::EMPTY, (0, Vec::new()));
// WORDS WITH DUPES MUST BE AT THE END! fn solve(dictionary: &mut [(String, LetterSet)], target: LetterSet) -> (u8, HashSet<String>) {
dictionary.sort_by_key(|(word, ls)| { let mut bests = (0..=LetterSet::FULL.to_index())
let dupes = word.len() - usize::from(ls.len()); .map(|_| (u8::MAX, HashSet::new()))
(dupes, cmp::Reverse(ls.len())) .collect::<Box<[_]>>();
}); println!("allocated!");
bests[LetterSet::FULL.to_index()] = (0, HashSet::new());
for (word, ls) in dictionary.iter() { score(dictionary, &mut bests, LetterSet::EMPTY, 0);
let len = u16::try_from(word.len()).unwrap();
match bests.entry(*ls) {
Entry::Occupied(mut occupied) => {
if occupied.get().0 > len {
occupied.insert((len, vec![word.clone()]));
}
}
Entry::Vacant(vacant) => {
vacant.insert((len, vec![word.clone()]));
}
}
}
score(dictionary, &mut bests, target); bests[target.negation().to_index()].clone()
bests.get(&target).cloned()
} }
// TODO: perhaps bottom up? (pick or no pick) (real potential!) // TODO: perhaps bottom up? (pick or no pick) (real potential!) (not obvious how to do path)
// the problem is that i'm not *improving* scores, i use the best one immediately // the problem is that i'm not *improving* scores, i use the best one immediately
// 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())` // bests is sorta inverted; the keys are completed letters
// assumes that `bests[LetterSet::FULL] == (0, Vec::new())`
fn score( fn score(
dictionary: &[(String, LetterSet)], dictionary: &[(String, LetterSet)],
bests: &mut HashMap<LetterSet, (u16, Vec<String>)>, bests: &mut [(u8, HashSet<String>)],
remaining: LetterSet, done_letters: LetterSet,
) -> u16 { length: u8,
if let Some(min) = bests.get(&remaining) { ) -> u8 {
return min.0; assert!(length <= MAX_SOLUTION_LENGTH);
let known = bests[done_letters.to_index()].0;
if known < u8::MAX {
return known;
} }
let Some((word, ls, score)) = dictionary for (i, (word, ls)) in dictionary
.iter() .iter()
.filter(|(_, ls)| { .enumerate()
ls.intersection(remaining.negation()).is_empty() .filter(|(_, (_, ls))| !ls.difference(done_letters).is_empty())
|| !remaining.intersection(*ls).is_empty() {
//&& ls.intersection(remaining.negation()).len() <= 1 let keep_letters = done_letters.union(*ls);
}) let keep_length = length.saturating_add(u8::try_from(word.len()).unwrap());
.map(|(word, ls)| {
let rest_score = score(dictionary, bests, remaining.difference(*ls));
(
word,
ls,
(u16::try_from(word.len()).unwrap()).saturating_add(rest_score),
)
})
.min_by_key(|(_, _, score)| *score)
else {
return u16::MAX;
};
if score == u16::MAX { if keep_length > MAX_SOLUTION_LENGTH {
return score; continue;
} }
let remaining_after_word = remaining.difference(*ls); let keep = score(dictionary, bests, keep_letters, keep_length);
let (_score, path) = bests
.get(&remaining_after_word) let existing = bests[done_letters.to_index()].0;
.expect("we already inserted this"); if keep < existing {
let mut path = path.clone(); bests[done_letters.to_index()].0 = keep;
path.push(word.clone()); bests[done_letters.to_index()].1.insert(word.clone());
bests.insert(remaining, (score, path)); }
score }
bests[done_letters.to_index()].0
} }