feat(naive): don't repeat the same char on the same index, unless it is matched #2
cargo devel CI / cargo CI (push) Failing after 1m51s Details

This commit is contained in:
Christoph J. Scherr 2024-07-31 10:51:14 +02:00
parent 970c1be143
commit 4b7e9433b9
1 changed files with 30 additions and 14 deletions

View File

@ -1,10 +1,8 @@
use core::panic;
use std::collections::HashMap; 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::response;
use crate::wlist::word::{Word, WordData}; use crate::wlist::word::{Word, WordData};
use crate::wlist::WordList; 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. /// 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());
let mut other_chars: Vec<char> = Vec::new(); // char and then the indexes we tried for that already
let mut other_chars: HashMap<char, Vec<usize>> = HashMap::new();
// a hash map telling how many of the characters may be in a correct word (+1) // 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 2 => it may be in the solution 1 time
// if the value for a char is 1 => it may not be in the solution // 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 => { Status::Matched => {
pattern.replace_range(idx..idx + 1, &p.0.to_string()); 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), Status::None => wrong_chars.push(p.0),
} }
} }
} }
debug!("other chars: {:?}", other_chars); debug!("other chars: {:?}", other_chars);
debug!("wrong chars: {:?}", wrong_chars); debug!("wrong chars: {:?}", wrong_chars);
// 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)?;
if matches.is_empty() { if matches.is_empty() {
return Err(SolverError::NoMatches(game.solution().cloned()).into()); 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)) .filter(|p| !game.made_guesses().contains(&&p.0))
// only words that do contain the chars we know exist // only words that do contain the chars we know exist
.filter(|p| { .filter(|p| {
for other in &other_chars { for other in other_chars.iter() {
if p.0.contains(*other) { if p.0.contains(*other.0) {
// TODO: account for chars that occur multiple times let mut already_tried: Vec<(_, _)> = Vec::new();
continue; 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 { } else {
return false; 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 // only words that do not contain the letters we know are wrong
.filter(|p| { .filter(|p| {
for wrong in &wrong_chars { for wrong in &wrong_chars {
if p.0.contains(*wrong) { let in_other = other_chars.iter().filter(|v| *v.0 == *wrong).count()
let mut tmp = 0;
let in_other = other_chars.iter().filter(|v| **v == *wrong).count()
+ pattern.chars().filter(|v| *v == *wrong).count(); + pattern.chars().filter(|v| *v == *wrong).count();
// TODO: account for chars that occur multiple times if p.0.contains(*wrong) {
if in_other > tmp { // HACK: something is still not quite right here, we basically ignore all
tmp += 1; // wrong chars if they occur in other_chars at least once, which can't be
// fully correct.
if in_other > 0 {
continue; continue;
} }
return false; return false;