diff --git a/src/solve/naive/mod.rs b/src/solve/naive/mod.rs index 09fc63c..669e751 100644 --- a/src/solve/naive/mod.rs +++ b/src/solve/naive/mod.rs @@ -1,10 +1,8 @@ -use core::panic; use std::collections::HashMap; use libpt::log::{debug, info, trace}; use crate::error::{SolverError, WResult}; -use crate::game::response; use crate::wlist::word::{Word, WordData}; use crate::wlist::WordList; @@ -31,7 +29,8 @@ 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()); - let mut other_chars: Vec = Vec::new(); + // 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 @@ -43,13 +42,19 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> { Status::Matched => { pattern.replace_range(idx..idx + 1, &p.0.to_string()); } - Status::Exists => other_chars.push(p.0), + Status::Exists => { + other_chars.entry(p.0).or_default(); + let v = other_chars.get_mut(&p.0).unwrap(); + v.push(idx); + } 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)?; if matches.is_empty() { return Err(SolverError::NoMatches(game.solution().cloned()).into()); @@ -60,10 +65,21 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> { .filter(|p| !game.made_guesses().contains(&&p.0)) // only words that do contain the chars we know exist .filter(|p| { - for other in &other_chars { - if p.0.contains(*other) { - // TODO: account for chars that occur multiple times - continue; + 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)); + } + + if p.0 + .char_indices() + .filter(|ci| ci.1 == *other.0 && !already_tried.contains(ci)) + .count() + < 1 + { + return false; + } } else { return false; } @@ -73,13 +89,13 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> { // 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) { - let mut tmp = 0; - let in_other = other_chars.iter().filter(|v| **v == *wrong).count() - + pattern.chars().filter(|v| *v == *wrong).count(); - // TODO: account for chars that occur multiple times - if in_other > tmp { - tmp += 1; + // 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;