From af1a2ee36c41c99a073a9ea2a5b6dcfce2716a5e Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sat, 3 Aug 2024 18:51:53 +0200 Subject: [PATCH] fix(evaluation): added more evaluation tests and fixed #21 --- src/game/evaluation.rs | 36 ++++++++++++--------- src/game/mod.rs | 31 ++++++++++-------- src/game/response.rs | 13 +------- tests/game.rs | 71 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 103 insertions(+), 48 deletions(-) diff --git a/src/game/evaluation.rs b/src/game/evaluation.rs index eddff1e..3e5fdc7 100644 --- a/src/game/evaluation.rs +++ b/src/game/evaluation.rs @@ -1,3 +1,7 @@ +use std::fmt::Display; +use std::io::Write; + +use colored::Colorize; use libpt::cli::console::{style, StyledObject}; use crate::wlist::word::Word; @@ -15,21 +19,6 @@ pub struct Evaluation { } impl Evaluation { - /// Display the evaluation color coded - pub fn colorized_display(&self) -> Vec> { - let mut buf = Vec::new(); - for e in self.inner.iter() { - let mut c = style(e.0.to_string()); - if e.1 == Status::Matched { - c = c.green(); - } else if e.1 == Status::Exists { - c = c.yellow(); - } - buf.push(c); - } - buf - } - /// The first string is the word the evaluation is for, The second string defines how the /// characters of the first string match the solution. /// @@ -108,3 +97,20 @@ impl From<&Evaluation> for Word { Word::from(value.inner.iter().map(|v| v.0).collect::()) } } + +impl Display for Evaluation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for s in &self.inner { + write!( + f, + "{}", + match s.1 { + Status::None => s.0.to_string().into(), + Status::Exists => s.0.to_string().yellow(), + Status::Matched => s.0.to_string().green(), + } + )?; + } + std::fmt::Result::Ok(()) + } +} diff --git a/src/game/mod.rs b/src/game/mod.rs index 9b34f65..1841997 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -29,7 +29,6 @@ where solution: Option, wordlist: &'wl WL, responses: Vec, - // TODO: keep track of the letters the user has tried } impl<'wl, WL: WordList> Game<'wl, WL> { @@ -126,15 +125,29 @@ impl<'wl, WL: WordList> Game<'wl, WL> { } /// Generates an [Evaluation] for a given solution and guess. - pub(crate) fn evaluate(mut solution: WordData, guess: &Word) -> Evaluation { + pub(crate) fn evaluate(solution: WordData, guess: &Word) -> Evaluation { let mut evaluation = Vec::new(); let mut status: Status; let mut buf = solution.0.clone(); + for ((idx, c_guess), c_sol) in guess.chars().enumerate().zip(solution.0.chars()) { if c_guess == c_sol { status = Status::Matched; buf.replace_range(idx..idx + 1, "_"); - } else if buf.contains(c_guess) { + } else if buf.contains(c_guess) + && 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 { @@ -359,16 +372,8 @@ impl<'wl, WL: WordList> Display for Game<'wl, WL> { self.step(), self.solution(), )?; - for s in self - .responses() - .iter() - .map(|v| v.evaluation().to_owned().colorized_display()) - { - write!(f, "\"")?; - for si in s { - write!(f, "{si}")?; - } - write!(f, "\", ")?; + for s in self.responses() { + write!(f, "\"{s}\",")?; } Ok(()) } diff --git a/src/game/response.rs b/src/game/response.rs index 8b4bd00..01aac99 100644 --- a/src/game/response.rs +++ b/src/game/response.rs @@ -92,17 +92,6 @@ impl GuessResponse { impl Display for GuessResponse { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for s in self.evaluation.clone().into_iter() { - write!( - f, - "{}", - match s.1 { - Status::None => s.0.to_string().into(), - Status::Exists => s.0.to_string().yellow(), - Status::Matched => s.0.to_string().green(), - } - )?; - } - std::fmt::Result::Ok(()) + write!(f, "{}", self.evaluation()) } } diff --git a/tests/game.rs b/tests/game.rs index dd658b1..31eef13 100644 --- a/tests/game.rs +++ b/tests/game.rs @@ -1,6 +1,7 @@ -use wordle_analyzer::error::GameError; +use test_log::test; // set the log level with an envvar: `RUST_LOG=trace cargo test` + +use libpt::log::info; use wordle_analyzer::game::evaluation::Evaluation; -use wordle_analyzer::game::response::GuessResponse; use wordle_analyzer::wlist::builtin::BuiltinWList; use wordle_analyzer::wlist::WordList; @@ -23,10 +24,25 @@ fn test_eval_simple() -> anyhow::Result<()> { let mut game = builder.build()?; let guess = Word::from("slate"); game.guess(&guess, None)?; - assert_eq!( + let correct = Evaluation::build(&guess, "xxccc")?; + info!( + "{} =? {}", *game.last_response().unwrap().evaluation(), - Evaluation::build(&guess, "xxccc")? + correct ); + assert_eq!(*game.last_response().unwrap().evaluation(), correct); + + let mut game = builder.build()?; + let guess = Word::from("about"); + game.guess(&guess, None)?; + let correct = Evaluation::build(&guess, "fxxxf")?; + info!( + "{} =? {}", + *game.last_response().unwrap().evaluation(), + correct + ); + assert_eq!(*game.last_response().unwrap().evaluation(), correct); + Ok(()) } @@ -40,18 +56,57 @@ fn test_eval_reoccuring_char() -> anyhow::Result<()> { let mut game = builder.build()?; let guess = Word::from("pines"); game.guess(&guess, None)?; - assert_eq!( + let correct = Evaluation::build(&guess, "xcccc")?; + info!( + "{} =? {}", *game.last_response().unwrap().evaluation(), - Evaluation::build(&guess, "xcccc")? + correct ); + assert_eq!(*game.last_response().unwrap().evaluation(), correct); let mut game = builder.build()?; let guess = Word::from("sides"); game.guess(&guess, None)?; - assert_eq!( + let correct = Evaluation::build(&guess, "xcxcc")?; + info!( + "{} =? {}", *game.last_response().unwrap().evaluation(), - Evaluation::build(&guess, "xcxcc")? + correct ); + assert_eq!(*game.last_response().unwrap().evaluation(), correct); + + let mut game = builder.build()?; + let guess = Word::from("ninja"); + game.guess(&guess, None)?; + let correct = Evaluation::build(&guess, "cccxx")?; + info!( + "{} =? {}", + *game.last_response().unwrap().evaluation(), + correct + ); + assert_eq!(*game.last_response().unwrap().evaluation(), correct); + + let mut game = builder.build()?; + let guess = Word::from("which"); + game.guess(&guess, None)?; + let correct = Evaluation::build(&guess, "xxfxx")?; + info!( + "{} =? {}", + *game.last_response().unwrap().evaluation(), + correct + ); + assert_eq!(*game.last_response().unwrap().evaluation(), correct); + + let mut game = builder.build()?; + let guess = Word::from("indie"); + game.guess(&guess, None)?; + let correct = Evaluation::build(&guess, "ffxxf")?; + info!( + "{} =? {}", + *game.last_response().unwrap().evaluation(), + correct + ); + assert_eq!(*game.last_response().unwrap().evaluation(), correct); Ok(()) }