ineffective noodling

This commit is contained in:
mehbark 2026-07-07 17:29:46 -04:00
parent 42c1c51e71
commit 4dd2ee21fc

View file

@ -1,7 +1,9 @@
use std::{ use std::{
collections::HashMap, cmp,
collections::{HashMap, hash_map::Entry},
env, env,
io::{self, BufRead, BufReader}, io::{self, BufRead, BufReader},
process,
}; };
use crate::letterset::LetterSet; use crate::letterset::LetterSet;
@ -9,7 +11,7 @@ use crate::letterset::LetterSet;
mod letterset; mod letterset;
fn main() { fn main() {
let dictionary: Vec<_> = BufReader::new(io::stdin().lock()) let mut dictionary: Vec<_> = BufReader::new(io::stdin().lock())
.lines() .lines()
.map(|line| { .map(|line| {
let word = line.unwrap(); let word = line.unwrap();
@ -18,24 +20,46 @@ fn main() {
}) })
.collect(); .collect();
println!( let target = env::args().nth(1).map_or(LetterSet::FULL, LetterSet::from);
"{:#?}", println!("letter count: {}", target.len());
solve( let Some((len, path)) = solve(&mut dictionary, target) else {
&dictionary, println!("failed :(");
env::args().nth(1).map_or(LetterSet::FULL, LetterSet::from) process::exit(1);
) };
); println!("{len}: {}", path.join(" "));
} }
fn solve(dictionary: &[(String, LetterSet)], target: LetterSet) -> Option<(u16, Vec<String>)> { fn solve(dictionary: &mut [(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()));
// WORDS WITH DUPES MUST BE AT THE END!
dictionary.sort_by_key(|(word, ls)| {
let dupes = word.len() - usize::from(ls.len());
(dupes, cmp::Reverse(ls.len()))
});
for (word, ls) in dictionary.iter() {
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); score(dictionary, &mut bests, target);
bests.get(&target).cloned() bests.get(&target).cloned()
} }
// TODO: perhaps bottom up? (pick or no pick) (real potential!)
// 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())` // assumes that `bests[LetterSet::EMPTY] == (0, Vec::new())`
fn score( fn score(
@ -49,16 +73,17 @@ fn score(
let Some((word, ls, score)) = dictionary let Some((word, ls, score)) = dictionary
.iter() .iter()
.filter(|(_, ls)| !remaining.intersection(*ls).is_empty()) .filter(|(_, ls)| {
ls.intersection(remaining.negation()).is_empty()
|| !remaining.intersection(*ls).is_empty()
//&& ls.intersection(remaining.negation()).len() <= 1
})
.map(|(word, ls)| { .map(|(word, ls)| {
let rest_score = score(dictionary, bests, remaining.difference(*ls));
( (
word, word,
ls, ls,
(u16::try_from(word.len()).unwrap()).saturating_add(score( (u16::try_from(word.len()).unwrap()).saturating_add(rest_score),
dictionary,
bests,
remaining.difference(*ls),
)),
) )
}) })
.min_by_key(|(_, _, score)| *score) .min_by_key(|(_, _, score)| *score)