dramatically reduce memory usage
ACQUEST ADZ ALKY AMPING ARF AVOW BAH JEUX
This commit is contained in:
parent
ed49037643
commit
37ffabc867
1 changed files with 27 additions and 16 deletions
43
src/main.rs
43
src/main.rs
|
|
@ -1,6 +1,4 @@
|
||||||
use std::{
|
use std::{
|
||||||
array,
|
|
||||||
collections::HashSet,
|
|
||||||
env,
|
env,
|
||||||
io::{self, BufRead, BufReader},
|
io::{self, BufRead, BufReader},
|
||||||
process,
|
process,
|
||||||
|
|
@ -22,25 +20,39 @@ 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 (len, path) = solve(&mut dictionary, target);
|
let Some((len, path)) = solve(&mut dictionary, target) else {
|
||||||
|
println!("failed :(");
|
||||||
|
process::exit(1);
|
||||||
|
};
|
||||||
println!("{len}: {}", path.into_iter().collect::<Vec<_>>().join(" "));
|
println!("{len}: {}", path.into_iter().collect::<Vec<_>>().join(" "));
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_SOLUTION_LENGTH: u8 = 200;
|
const MAX_SOLUTION_LENGTH: u8 = 200;
|
||||||
|
|
||||||
fn solve(dictionary: &mut [(String, LetterSet)], target: LetterSet) -> (u8, HashSet<String>) {
|
fn solve(dictionary: &mut [(String, LetterSet)], target: LetterSet) -> Option<(u8, Vec<&str>)> {
|
||||||
let mut bests = (0..=LetterSet::FULL.to_index())
|
let mut bests = (0..=LetterSet::FULL.to_index())
|
||||||
.map(|_| (u8::MAX, HashSet::new()))
|
.map(|_| (u8::MAX, None))
|
||||||
.collect::<Box<[_]>>();
|
.collect::<Box<[_]>>();
|
||||||
println!("allocated!");
|
println!("allocated!");
|
||||||
bests[LetterSet::FULL.to_index()] = (0, HashSet::new());
|
bests[LetterSet::FULL.to_index()] = (0, None);
|
||||||
|
|
||||||
dictionary.sort_by_key(|(word, ls)| word.len() - usize::from(ls.len()));
|
dictionary.sort_by_key(|(word, ls)| word.len() - usize::from(ls.len()));
|
||||||
println!("sorted!");
|
println!("sorted!");
|
||||||
|
|
||||||
score(dictionary, &mut bests, target.negation(), 0);
|
score(dictionary, &mut bests, target.negation(), 0);
|
||||||
|
|
||||||
bests[target.negation().to_index()].clone()
|
let (len, start) = bests[target.negation().to_index()];
|
||||||
|
let start = start?;
|
||||||
|
|
||||||
|
let mut path = vec![start];
|
||||||
|
let mut done = LetterSet::from(start);
|
||||||
|
|
||||||
|
while let (_, Some(word)) = bests[done.to_index()] {
|
||||||
|
path.push(word);
|
||||||
|
done = done.union(LetterSet::from(word));
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((len, path))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: perhaps bottom up? (pick or no pick) (real potential!) (not obvious how to do path)
|
// TODO: perhaps bottom up? (pick or no pick) (real potential!) (not obvious how to do path)
|
||||||
|
|
@ -48,9 +60,9 @@ fn solve(dictionary: &mut [(String, LetterSet)], target: LetterSet) -> (u8, Hash
|
||||||
// length doesn't include spaces. i think that's okay
|
// length doesn't include spaces. i think that's okay
|
||||||
// bests is sorta inverted; the keys are completed letters
|
// bests is sorta inverted; the keys are completed letters
|
||||||
// assumes that `bests[LetterSet::FULL] == (0, Vec::new())`
|
// assumes that `bests[LetterSet::FULL] == (0, Vec::new())`
|
||||||
fn score(
|
fn score<'d>(
|
||||||
dictionary: &[(String, LetterSet)],
|
dictionary: &'d [(String, LetterSet)],
|
||||||
bests: &mut [(u8, HashSet<String>)],
|
bests: &mut [(u8, Option<&'d str>)],
|
||||||
done_letters: LetterSet,
|
done_letters: LetterSet,
|
||||||
length: u8,
|
length: u8,
|
||||||
) -> u8 {
|
) -> u8 {
|
||||||
|
|
@ -63,7 +75,7 @@ fn score(
|
||||||
return known;
|
return known;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some((word, ls, score)) = dictionary
|
let Some((word, score)) = dictionary
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(word, ls)| {
|
.filter(|(word, ls)| {
|
||||||
(!ls.difference(done_letters).is_empty())
|
(!ls.difference(done_letters).is_empty())
|
||||||
|
|
@ -73,16 +85,15 @@ fn score(
|
||||||
let word_len = u8::try_from(word.len()).unwrap();
|
let word_len = u8::try_from(word.len()).unwrap();
|
||||||
let new_length = word_len.saturating_add(length);
|
let new_length = word_len.saturating_add(length);
|
||||||
let rest_score = score(dictionary, bests, done_letters.union(*ls), new_length);
|
let rest_score = score(dictionary, bests, done_letters.union(*ls), new_length);
|
||||||
(word, ls, word_len.saturating_add(rest_score))
|
(word, word_len.saturating_add(rest_score))
|
||||||
})
|
})
|
||||||
.take(2000)
|
.take(1000)
|
||||||
.min_by_key(|(_, _, score)| *score)
|
.min_by_key(|(_, score)| *score)
|
||||||
else {
|
else {
|
||||||
return u8::MAX;
|
return u8::MAX;
|
||||||
};
|
};
|
||||||
|
|
||||||
bests[done_letters.to_index()].0 = score;
|
bests[done_letters.to_index()].0 = score;
|
||||||
bests[done_letters.to_index()].1 = bests[done_letters.union(*ls).to_index()].1.clone();
|
bests[done_letters.to_index()].1 = Some(word);
|
||||||
bests[done_letters.to_index()].1.insert(word.clone());
|
|
||||||
score
|
score
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue