From 714aac0d86063200e85e61a14e38bcc3a016b437 Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Thu, 1 Aug 2024 15:46:32 +0200 Subject: [PATCH] feat(naive): try to fix naive solver screwing up in less than 1% of cases WIP --- src/solve/naive/mod.rs | 54 ++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/src/solve/naive/mod.rs b/src/solve/naive/mod.rs index 5548615..3ab6637 100644 --- a/src/solve/naive/mod.rs +++ b/src/solve/naive/mod.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use libpt::log::{debug, info, trace}; use crate::error::{SolverError, WResult}; +use crate::game::evaluation::Evaluation; use crate::wlist::word::{Word, WordData}; use crate::wlist::WordList; @@ -29,30 +30,35 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> { /// word, but don't know the position of. fn guess_for(&self, game: &crate::game::Game) -> WResult { let mut pattern: String = ".".repeat(game.length()); - // char and then the indexes we tried for that already - let mut other_chars: HashMap> = 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 = Vec::new(); + // indexes we tried for that char and the number of occurences + let mut other_chars: HashMap, usize)> = HashMap::new(); let responses = game.responses().iter().enumerate(); 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 { Status::Matched => { pattern.replace_range(idx..idx + 1, &p.0.to_string()); + + other_chars.entry(p.0).or_default(); + let v = other_chars.get_mut(&p.0).unwrap(); + v.1 += 1; } Status::Exists => { other_chars.entry(p.0).or_default(); 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 += 1; + } + Status::None => { + other_chars.entry(p.0).or_default(); } - Status::None => wrong_chars.push(p.0), } } } debug!("other chars: {:?}", other_chars); - debug!("wrong chars: {:?}", wrong_chars); // get all words that have the correct chars on the same positions let mut matches: Vec = game.wordlist().get_words_matching(&pattern)?; @@ -68,33 +74,19 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> { for other in other_chars.iter() { if p.0.contains(*other.0) { let mut already_tried: Vec<(_, _)> = Vec::new(); - for spot in other.1 { - already_tried.push((*spot, *other.0)); + for spot in &other.1 .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() { - if c.1 == *other.0 && other.1.contains(&c.0) { + if c.1 == *other.0 && other.1 .0.contains(&c.0) { return false; } } - } else { - 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; - } + } else if other.1 .1 != 0 { return false; } }