generated from PlexSheep/rs-base
improve naive solver #13
|
@ -126,34 +126,60 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
||||||
|
|
||||||
/// Generates an [Evaluation] for a given solution and guess.
|
/// Generates an [Evaluation] for a given solution and guess.
|
||||||
pub(crate) fn evaluate(solution: WordData, guess: &Word) -> Evaluation {
|
pub(crate) fn evaluate(solution: WordData, guess: &Word) -> Evaluation {
|
||||||
let mut evaluation = Vec::new();
|
let solution = solution.0;
|
||||||
|
let mut evaluation: Vec<(char, Status)> = vec![('!', Status::None); solution.len()];
|
||||||
let mut status: Status;
|
let mut status: Status;
|
||||||
let mut buf = solution.0.clone();
|
let mut buf: Vec<char> = solution.chars().collect();
|
||||||
|
|
||||||
for ((idx, c_guess), c_sol) in guess.chars().enumerate().zip(solution.0.chars()) {
|
#[cfg(debug_assertions)]
|
||||||
|
let buflen = solution.len();
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(buflen, buf.len());
|
||||||
|
assert_eq!(buflen, evaluation.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
// first the correct solutions
|
||||||
|
for ((idx, c_guess), c_sol) in guess.chars().enumerate().zip(solution.chars()) {
|
||||||
if c_guess == c_sol {
|
if c_guess == c_sol {
|
||||||
status = Status::Matched;
|
status = Status::Matched;
|
||||||
buf.replace_range(idx..idx + 1, "_");
|
buf[idx] = '!';
|
||||||
} else if buf.contains(c_guess)
|
evaluation[idx] = (c_guess, status);
|
||||||
&& buf
|
|
||||||
.char_indices()
|
|
||||||
.filter(|c| c.1 == c_guess)
|
|
||||||
.filter(|c| {
|
|
||||||
guess
|
|
||||||
.chars()
|
|
||||||
.nth(c.0)
|
|
||||||
.expect("the evaluations are somehow different lengths")
|
|
||||||
== c.1
|
|
||||||
})
|
|
||||||
.count()
|
|
||||||
== 0
|
|
||||||
{
|
|
||||||
status = Status::Exists;
|
|
||||||
buf = buf.replacen(c_guess, "_", 1);
|
|
||||||
} else {
|
|
||||||
status = Status::None
|
|
||||||
}
|
}
|
||||||
evaluation.push((c_guess, status));
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(buflen, buf.len());
|
||||||
|
assert_eq!(buflen, evaluation.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
// then check if the char exists, but was not guessed to be at the correct position
|
||||||
|
//
|
||||||
|
// We split this up, because finding the "exists" chars at the same time as the "correct"
|
||||||
|
// chars causes bugs
|
||||||
|
for ((idx, c_guess), c_sol) in guess.chars().enumerate().zip(solution.chars()) {
|
||||||
|
if c_guess == c_sol {
|
||||||
|
continue;
|
||||||
|
} else if buf.contains(&c_guess) {
|
||||||
|
status = Status::Exists;
|
||||||
|
// replace that char in the buffer to signal that is has been paired with the
|
||||||
|
// current char
|
||||||
|
let idx_of_a_match = buf
|
||||||
|
.iter()
|
||||||
|
.position(|c| *c == c_guess)
|
||||||
|
.expect("did not find a character in a string even though we know it exists");
|
||||||
|
buf[idx_of_a_match] = '!';
|
||||||
|
} else {
|
||||||
|
status = Status::None;
|
||||||
|
}
|
||||||
|
evaluation[idx] = (c_guess, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(buflen, buf.len());
|
||||||
|
assert_eq!(buflen, evaluation.len());
|
||||||
}
|
}
|
||||||
evaluation.into()
|
evaluation.into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,11 +47,12 @@ fn test_eval_simple() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_eval_reoccuring_char() -> anyhow::Result<()> {
|
fn test_eval_reoccuring_char0() -> anyhow::Result<()> {
|
||||||
let wl = wordlist();
|
let wl = wordlist();
|
||||||
let builder = game::Game::builder(&wl)
|
let builder = game::Game::builder(&wl)
|
||||||
.solution(Some(wl.get_word(&Word::from("nines")).unwrap()))
|
.solution(Some(wl.get_word(&Word::from("nines")).unwrap()))
|
||||||
.precompute(false);
|
.precompute(false);
|
||||||
|
info!("solution=nines");
|
||||||
|
|
||||||
let mut game = builder.build()?;
|
let mut game = builder.build()?;
|
||||||
let guess = Word::from("pines");
|
let guess = Word::from("pines");
|
||||||
|
@ -110,3 +111,25 @@ fn test_eval_reoccuring_char() -> anyhow::Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_eval_reoccuring_char1() -> anyhow::Result<()> {
|
||||||
|
let wl = wordlist();
|
||||||
|
let builder = game::Game::builder(&wl)
|
||||||
|
.solution(Some(wl.get_word(&Word::from("fatty")).unwrap()))
|
||||||
|
.precompute(false);
|
||||||
|
info!("solution=fatty");
|
||||||
|
|
||||||
|
let mut game = builder.build()?;
|
||||||
|
let guess = Word::from("state");
|
||||||
|
game.guess(&guess, None)?;
|
||||||
|
let correct = Evaluation::build(&guess, "xffcx")?;
|
||||||
|
info!(
|
||||||
|
"{} =? {}",
|
||||||
|
*game.last_response().unwrap().evaluation(),
|
||||||
|
correct
|
||||||
|
);
|
||||||
|
assert_eq!(*game.last_response().unwrap().evaluation(), correct);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue