add interactive solver #4

Merged
cscherrNT merged 29 commits from feat/interactive-solver into devel 2024-07-25 15:19:54 +02:00
4 changed files with 41 additions and 41 deletions
Showing only changes of commit 0b83b26b20 - Show all commits

View File

@ -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);

View File

@ -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<EvaluationUnit>,
}
pub type EvaluationUnit = (char, Status);
impl IntoIterator for Evaluation {
type Item = EvaluationUnit;
@ -27,7 +28,10 @@ impl From<Vec<EvaluationUnit>> for Evaluation {
impl FromStr for Evaluation {
type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
// TODO: make this proper
Ok(vec![('x', Status::None)].into())
let mut v: Vec<EvaluationUnit> = Vec::new();
for c in s.chars() {
v.push((c, Status::from(c)))
}
Ok(v.into())
}
}

View File

@ -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<Self> {
// 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<Game<'wl, WL>> {
trace!("{:#?}", self);
let game: Game<WL> =
Game::build(self.length, self.precompute, self.max_steps, self.wordlist)?;
let game: Game<WL> = Game::build(
self.length,
self.precompute,
self.max_steps,
self.wordlist,
self.generate_solution,
)?;
Ok(game)
}

View File

@ -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<EvaluationUnit>,
}
pub type EvaluationUnit = (char, Status);
impl IntoIterator for Evaluation {
type Item = EvaluationUnit;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
impl From<Vec<EvaluationUnit>> for Evaluation {
fn from(value: Vec<EvaluationUnit>) -> Self {
Self { inner: value }
}
}
impl FromStr for Evaluation {
type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
// 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<char> 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<WL: WordList>(guess: &Word, status: Evaluation, game: &Game<WL>) -> Self {
let new = Self {