generated from PlexSheep/rs-base
feat(naive): try to fix naive solver screwing up in less than 1% of cases WIP
cargo devel CI / cargo CI (push) Failing after 1m51s
Details
cargo devel CI / cargo CI (push) Failing after 1m51s
Details
This commit is contained in:
parent
c76c1d2d78
commit
aac3e8804e
|
@ -3,6 +3,7 @@ use std::collections::HashMap;
|
||||||
use libpt::log::{debug, info, trace};
|
use libpt::log::{debug, info, trace};
|
||||||
|
|
||||||
use crate::error::{SolverError, WResult};
|
use crate::error::{SolverError, WResult};
|
||||||
|
use crate::game::evaluation::Evaluation;
|
||||||
use crate::wlist::word::{Word, WordData};
|
use crate::wlist::word::{Word, WordData};
|
||||||
use crate::wlist::WordList;
|
use crate::wlist::WordList;
|
||||||
|
|
||||||
|
@ -29,15 +30,12 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
|
||||||
/// word, but don't know the position of.
|
/// word, but don't know the position of.
|
||||||
fn guess_for(&self, game: &crate::game::Game<WL>) -> WResult<Word> {
|
fn guess_for(&self, game: &crate::game::Game<WL>) -> WResult<Word> {
|
||||||
let mut pattern: String = ".".repeat(game.length());
|
let mut pattern: String = ".".repeat(game.length());
|
||||||
// char and then the indexes we tried for that already
|
// indexes we tried for that char and the number of occurences
|
||||||
let mut other_chars: HashMap<char, Vec<usize>> = HashMap::new();
|
let mut other_chars: HashMap<char, (Vec<usize>, usize)> = HashMap::new();
|
||||||
// a hash map telling how many of the characters may be in a correct word (+1)
|
|
||||||
// if the value for a char is 2 => it may be in the solution 1 time
|
|
||||||
// if the value for a char is 1 => it may not be in the solution
|
|
||||||
let mut wrong_chars: Vec<char> = Vec::new();
|
|
||||||
let responses = game.responses().iter().enumerate();
|
let responses = game.responses().iter().enumerate();
|
||||||
for (_idx, response) in responses {
|
for (_idx, response) in responses {
|
||||||
for (idx, p) in response.evaluation().clone().into_iter().enumerate() {
|
let evaluation: &Evaluation = response.evaluation();
|
||||||
|
for (idx, p) in evaluation.clone().into_iter().enumerate() {
|
||||||
match p.1 {
|
match p.1 {
|
||||||
Status::Matched => {
|
Status::Matched => {
|
||||||
pattern.replace_range(idx..idx + 1, &p.0.to_string());
|
pattern.replace_range(idx..idx + 1, &p.0.to_string());
|
||||||
|
@ -45,14 +43,19 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
|
||||||
Status::Exists => {
|
Status::Exists => {
|
||||||
other_chars.entry(p.0).or_default();
|
other_chars.entry(p.0).or_default();
|
||||||
let v = other_chars.get_mut(&p.0).unwrap();
|
let v = other_chars.get_mut(&p.0).unwrap();
|
||||||
v.push(idx);
|
v.0.push(idx);
|
||||||
|
|
||||||
|
// TODO: count how many times the char occurs
|
||||||
|
v.1 =
|
||||||
|
v.1.min(evaluation.guess().chars().filter(|c| *c == p.0).count());
|
||||||
|
}
|
||||||
|
Status::None => {
|
||||||
|
other_chars.entry(p.0).or_default();
|
||||||
}
|
}
|
||||||
Status::None => wrong_chars.push(p.0),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("other chars: {:?}", other_chars);
|
debug!("other chars: {:?}", other_chars);
|
||||||
debug!("wrong chars: {:?}", wrong_chars);
|
|
||||||
|
|
||||||
// get all words that have the correct chars on the same positions
|
// get all words that have the correct chars on the same positions
|
||||||
let mut matches: Vec<WordData> = game.wordlist().get_words_matching(&pattern)?;
|
let mut matches: Vec<WordData> = game.wordlist().get_words_matching(&pattern)?;
|
||||||
|
@ -68,33 +71,19 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
|
||||||
for other in other_chars.iter() {
|
for other in other_chars.iter() {
|
||||||
if p.0.contains(*other.0) {
|
if p.0.contains(*other.0) {
|
||||||
let mut already_tried: Vec<(_, _)> = Vec::new();
|
let mut already_tried: Vec<(_, _)> = Vec::new();
|
||||||
for spot in other.1 {
|
for spot in &other.1 .0 {
|
||||||
already_tried.push((*spot, *other.0));
|
already_tried.push((spot, *other.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.0.chars().filter(|c| *c == *other.0).count() > other.1 .1 {
|
||||||
|
return false; // the char occurs too often in that word
|
||||||
|
}
|
||||||
for c in p.0.char_indices() {
|
for c in p.0.char_indices() {
|
||||||
if c.1 == *other.0 && other.1.contains(&c.0) {
|
if c.1 == *other.0 && other.1 .0.contains(&c.0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if other.1 .1 != 0 {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
})
|
|
||||||
// only words that do not contain the letters we know are wrong
|
|
||||||
.filter(|p| {
|
|
||||||
for wrong in &wrong_chars {
|
|
||||||
let in_other = other_chars.iter().filter(|v| *v.0 == *wrong).count()
|
|
||||||
+ pattern.chars().filter(|v| *v == *wrong).count();
|
|
||||||
if p.0.contains(*wrong) {
|
|
||||||
// HACK: something is still not quite right here, we basically ignore all
|
|
||||||
// wrong chars if they occur in other_chars at least once, which can't be
|
|
||||||
// fully correct.
|
|
||||||
if in_other > 0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue