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 libpt::log::*;
use strum::{EnumIter, IntoEnumIterator}; 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::game::response::GuessResponse;
use wordle_analyzer::solve::{BuiltinSolverNames, Solver}; use wordle_analyzer::solve::{BuiltinSolverNames, Solver};
@ -80,7 +80,7 @@ fn main() -> anyhow::Result<()> {
fn help_guess_interactive(cli: Cli) -> anyhow::Result<()> { fn help_guess_interactive(cli: Cli) -> anyhow::Result<()> {
let wl = BuiltinWList::default(); let wl = BuiltinWList::default();
let builder = game::Game::builder(&wl) let builder = game::GameBuilder::new(&wl, false)
.length(cli.length) .length(cli.length)
.max_steps(cli.max_steps) .max_steps(cli.max_steps)
.precompute(cli.precompute); .precompute(cli.precompute);

View File

@ -3,11 +3,12 @@ use std::str::FromStr;
use super::response::Status; use super::response::Status;
pub type EvaluationUnit = (char, Status);
#[derive(Debug, Clone, PartialEq, Default)] #[derive(Debug, Clone, PartialEq, Default)]
pub struct Evaluation { pub struct Evaluation {
inner: Vec<EvaluationUnit>, inner: Vec<EvaluationUnit>,
} }
pub type EvaluationUnit = (char, Status);
impl IntoIterator for Evaluation { impl IntoIterator for Evaluation {
type Item = EvaluationUnit; type Item = EvaluationUnit;
@ -27,7 +28,10 @@ impl From<Vec<EvaluationUnit>> for Evaluation {
impl FromStr for Evaluation { impl FromStr for Evaluation {
type Err = Infallible; type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
// TODO: make this proper let mut v: Vec<EvaluationUnit> = Vec::new();
Ok(vec![('x', Status::None)].into()) 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; pub mod summary;
use self::response::{Evaluation, Status}; use self::response::Status;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Game<'wl, WL> pub struct Game<'wl, WL>
@ -35,7 +35,7 @@ where
impl<'wl, WL: WordList> Game<'wl, WL> { impl<'wl, WL: WordList> Game<'wl, WL> {
/// get a new [`GameBuilder`] /// get a new [`GameBuilder`]
pub fn builder(wl: &'wl WL) -> GameBuilder<'wl, WL> { pub fn builder(wl: &'wl WL) -> GameBuilder<'wl, WL> {
GameBuilder::new(wl) GameBuilder::new(wl, true)
} }
/// Create a [Game] of wordle /// Create a [Game] of wordle
/// ///
@ -54,15 +54,19 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
precompute: bool, precompute: bool,
max_steps: usize, max_steps: usize,
wlist: &'wl WL, wlist: &'wl WL,
generate_solution: bool,
) -> GameResult<Self> { ) -> GameResult<Self> {
// TODO: check if the length is in the range bounds of the wordlist // TODO: check if the length is in the range bounds of the wordlist
let solution = wlist.rand_solution();
let game: Game<'wl, WL> = Game { let game: Game<'wl, WL> = Game {
length, length,
precompute, precompute,
max_steps, max_steps,
step: 0, step: 0,
solution: Some(solution), solution: if generate_solution {
Some(wlist.rand_solution())
} else {
None
},
wordlist: wlist, wordlist: wlist,
finished: false, finished: false,
responses: Vec::new(), responses: Vec::new(),
@ -203,26 +207,33 @@ pub struct GameBuilder<'wl, WL: WordList> {
precompute: bool, precompute: bool,
max_steps: usize, max_steps: usize,
wordlist: &'wl WL, wordlist: &'wl WL,
generate_solution: bool,
} }
impl<'wl, WL: WordList> GameBuilder<'wl, WL> { impl<'wl, WL: WordList> GameBuilder<'wl, WL> {
/// make a new [GameBuilder] /// make a new [GameBuilder]
/// ///
/// We need a [WordList], so provide one here. /// 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 { Self {
length: super::DEFAULT_WORD_LENGTH, length: super::DEFAULT_WORD_LENGTH,
precompute: false, precompute: false,
max_steps: super::DEFAULT_MAX_STEPS, max_steps: super::DEFAULT_MAX_STEPS,
wordlist: wl, wordlist: wl,
generate_solution,
} }
} }
/// build a [`Game`] with the stored configuration /// build a [`Game`] with the stored configuration
pub fn build(&'wl self) -> GameResult<Game<'wl, WL>> { pub fn build(&'wl self) -> GameResult<Game<'wl, WL>> {
trace!("{:#?}", self); trace!("{:#?}", self);
let game: Game<WL> = let game: Game<WL> = Game::build(
Game::build(self.length, self.precompute, self.max_steps, self.wordlist)?; self.length,
self.precompute,
self.max_steps,
self.wordlist,
self.generate_solution,
)?;
Ok(game) Ok(game)
} }

View File

@ -7,7 +7,7 @@ use std::convert::Infallible;
use std::fmt::Display; use std::fmt::Display;
use std::str::FromStr; use std::str::FromStr;
use super::Game; use super::{Evaluation, Game};
#[derive(Debug, Clone, PartialEq, Copy, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Copy, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -15,34 +15,6 @@ pub struct AtomicEvaluation {
char: char, char: char,
status: Status, 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)] #[derive(Debug, Clone, PartialEq)]
// #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] // #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -63,6 +35,19 @@ pub enum Status {
Matched = 2, 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 { impl GuessResponse {
pub(crate) fn new<WL: WordList>(guess: &Word, status: Evaluation, game: &Game<WL>) -> Self { pub(crate) fn new<WL: WordList>(guess: &Word, status: Evaluation, game: &Game<WL>) -> Self {
let new = Self { let new = Self {