From 0b83b26b2092d412c01918b4a439e3ff6858c3eb Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Mon, 22 Jul 2024 15:15:05 +0200 Subject: [PATCH] feat(solver): interactive input of responses #3 --- src/bin/solve/simple.rs | 4 ++-- src/game/evaluation.rs | 10 +++++++--- src/game/mod.rs | 25 +++++++++++++++++------- src/game/response.rs | 43 ++++++++++++++--------------------------- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/bin/solve/simple.rs b/src/bin/solve/simple.rs index 450cdc9..c5573b1 100644 --- a/src/bin/solve/simple.rs +++ b/src/bin/solve/simple.rs @@ -8,7 +8,7 @@ use libpt::cli::{repl::Repl, strum}; use libpt::log::*; use strum::{EnumIter, IntoEnumIterator}; -use wordle_analyzer::game::response::Evaluation; +use wordle_analyzer::game::evaluation::Evaluation; use wordle_analyzer::game::response::GuessResponse; use wordle_analyzer::solve::{BuiltinSolverNames, Solver}; @@ -80,7 +80,7 @@ fn main() -> anyhow::Result<()> { fn help_guess_interactive(cli: Cli) -> anyhow::Result<()> { let wl = BuiltinWList::default(); - let builder = game::Game::builder(&wl) + let builder = game::GameBuilder::new(&wl, false) .length(cli.length) .max_steps(cli.max_steps) .precompute(cli.precompute); diff --git a/src/game/evaluation.rs b/src/game/evaluation.rs index d99cb4d..5f3b778 100644 --- a/src/game/evaluation.rs +++ b/src/game/evaluation.rs @@ -3,11 +3,12 @@ use std::str::FromStr; use super::response::Status; +pub type EvaluationUnit = (char, Status); + #[derive(Debug, Clone, PartialEq, Default)] pub struct Evaluation { inner: Vec, } -pub type EvaluationUnit = (char, Status); impl IntoIterator for Evaluation { type Item = EvaluationUnit; @@ -27,7 +28,10 @@ impl From> for Evaluation { impl FromStr for Evaluation { type Err = Infallible; fn from_str(s: &str) -> Result { - // TODO: make this proper - Ok(vec![('x', Status::None)].into()) + let mut v: Vec = Vec::new(); + for c in s.chars() { + v.push((c, Status::from(c))) + } + Ok(v.into()) } } diff --git a/src/game/mod.rs b/src/game/mod.rs index a1f36d4..f977362 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -14,7 +14,7 @@ use evaluation::*; pub mod summary; -use self::response::{Evaluation, Status}; +use self::response::Status; #[derive(Debug, Clone, PartialEq)] pub struct Game<'wl, WL> @@ -35,7 +35,7 @@ where impl<'wl, WL: WordList> Game<'wl, WL> { /// get a new [`GameBuilder`] pub fn builder(wl: &'wl WL) -> GameBuilder<'wl, WL> { - GameBuilder::new(wl) + GameBuilder::new(wl, true) } /// Create a [Game] of wordle /// @@ -54,15 +54,19 @@ impl<'wl, WL: WordList> Game<'wl, WL> { precompute: bool, max_steps: usize, wlist: &'wl WL, + generate_solution: bool, ) -> GameResult { // TODO: check if the length is in the range bounds of the wordlist - let solution = wlist.rand_solution(); let game: Game<'wl, WL> = Game { length, precompute, max_steps, step: 0, - solution: Some(solution), + solution: if generate_solution { + Some(wlist.rand_solution()) + } else { + None + }, wordlist: wlist, finished: false, responses: Vec::new(), @@ -203,26 +207,33 @@ pub struct GameBuilder<'wl, WL: WordList> { precompute: bool, max_steps: usize, wordlist: &'wl WL, + generate_solution: bool, } impl<'wl, WL: WordList> GameBuilder<'wl, WL> { /// make a new [GameBuilder] /// /// We need a [WordList], so provide one here. - pub fn new(wl: &'wl WL) -> Self { + pub fn new(wl: &'wl WL, generate_solution: bool) -> Self { Self { length: super::DEFAULT_WORD_LENGTH, precompute: false, max_steps: super::DEFAULT_MAX_STEPS, wordlist: wl, + generate_solution, } } /// build a [`Game`] with the stored configuration pub fn build(&'wl self) -> GameResult> { trace!("{:#?}", self); - let game: Game = - Game::build(self.length, self.precompute, self.max_steps, self.wordlist)?; + let game: Game = Game::build( + self.length, + self.precompute, + self.max_steps, + self.wordlist, + self.generate_solution, + )?; Ok(game) } diff --git a/src/game/response.rs b/src/game/response.rs index 966c9a0..58a9915 100644 --- a/src/game/response.rs +++ b/src/game/response.rs @@ -7,7 +7,7 @@ use std::convert::Infallible; use std::fmt::Display; use std::str::FromStr; -use super::Game; +use super::{Evaluation, Game}; #[derive(Debug, Clone, PartialEq, Copy, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -15,34 +15,6 @@ pub struct AtomicEvaluation { char: char, status: Status, } -#[derive(Debug, Clone, PartialEq, Default)] -pub struct Evaluation { - inner: Vec, -} -pub type EvaluationUnit = (char, Status); - -impl IntoIterator for Evaluation { - type Item = EvaluationUnit; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.inner.into_iter() - } -} - -impl From> for Evaluation { - fn from(value: Vec) -> Self { - Self { inner: value } - } -} - -impl FromStr for Evaluation { - type Err = Infallible; - fn from_str(s: &str) -> Result { - // TODO: make this proper - Ok(vec![('x', Status::None)].into()) - } -} #[derive(Debug, Clone, PartialEq)] // #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -63,6 +35,19 @@ pub enum Status { Matched = 2, } +impl From for Status { + fn from(value: char) -> Self { + let value = value.to_ascii_lowercase(); // let's not deal with unicode here, wordle is + // ASCII centric anyway + match value { + 'x' => Self::None, + 'f' | 'e' => Self::Exists, + 'c' | 'm' => Self::Matched, + _ => Self::None, + } + } +} + impl GuessResponse { pub(crate) fn new(guess: &Word, status: Evaluation, game: &Game) -> Self { let new = Self {