add interactive solver #4

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

View File

@ -128,7 +128,7 @@ fn help_guess_interactive(cli: Cli) -> anyhow::Result<()> {
println!("{}", game);
}
ReplCommand::Solve => {
let best_guess = solver.guess_for(&game);
let best_guess = solver.guess_for(&game)?;
println!("best guess: {best_guess}");
}
ReplCommand::Guess {

View File

@ -13,6 +13,11 @@ pub enum Error {
#[from]
source: GameError,
},
#[error("Solver Error")]
SolverError {
#[from]
source: SolverError,
},
#[error("Benchmark Error")]
BenchError {
#[from]
@ -53,3 +58,9 @@ pub enum BenchError {
#[error("Trying to modify a finished report")]
ModifyFinishedReport,
}
#[derive(Debug, Clone, Error)]
pub enum SolverError {
#[error("Wordlist has no matches for the gamestate")]
NoMatches,
}

View File

@ -21,7 +21,6 @@ pub struct AtomicEvaluation {
pub struct GuessResponse {
guess: Word,
evaluation: Evaluation,
finish: bool,
solution: Option<WordData>,
step: usize,
max_steps: usize,
@ -50,10 +49,9 @@ impl From<char> for Status {
impl GuessResponse {
pub(crate) fn new<WL: WordList>(guess: &Word, status: Evaluation, game: &Game<WL>) -> Self {
let new = Self {
let mut new = Self {
guess: guess.to_owned(),
evaluation: status,
finish: game.step() > game.max_steps(),
solution: game.solution().cloned(),
step: game.step(),
max_steps: game.max_steps(),
@ -62,7 +60,7 @@ impl GuessResponse {
}
pub fn finished(&self) -> bool {
self.finish
self.step() > self.max_steps() || self.won()
}
pub fn won(&self) -> bool {

View File

@ -11,6 +11,7 @@ use crate::{
#[cfg(feature = "builtin")]
pub mod naive;
use libpt::log::debug;
#[cfg(feature = "builtin")]
pub use naive::NaiveSolver;
#[cfg(feature = "builtin")]
@ -44,14 +45,14 @@ pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug + Sized + Sync {
///
/// Each [Solver] needs to implement this method themselves, many other methods rely on this to
/// play the [Game], such as [play](Solver::play) or [solve](Solver::solve).
fn guess_for(&self, game: &Game<'wl, WL>) -> Word;
fn guess_for(&self, game: &Game<'wl, WL>) -> WResult<Word>;
/// Make a singular step for a [Game]
///
/// # Errors
///
/// This function will return an error if [guess_for](Solver::guess_for) fails.
fn make_a_move(&self, game: &mut Game<'wl, WL>) -> WResult<GuessResponse> {
Ok(game.guess(self.guess_for(game), None)?)
Ok(game.guess(self.guess_for(game)?, None)?)
}
/// Play a [Game] and return the last [GuessResponse].
///
@ -146,10 +147,11 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for AnyBuiltinSolver<'wl, WL> {
fn build(wordlist: &'wl WL) -> WResult<Self> {
Ok(Self::Naive(NaiveSolver::build(wordlist)?))
}
fn guess_for(&self, game: &Game<'wl, WL>) -> Word {
match self {
Self::Naive(solver) => solver.guess_for(game),
Self::Stupid(solver) => solver.guess_for(game),
}
fn guess_for(&self, game: &Game<'wl, WL>) -> WResult<Word> {
debug!("solver: {self:?}");
Ok(match self {
Self::Naive(solver) => solver.guess_for(game)?,
Self::Stupid(solver) => solver.guess_for(game)?,
})
}
}

View File

@ -1,5 +1,6 @@
use libpt::log::{info, trace};
use crate::error::{Error, SolverError, WResult};
use crate::wlist::word::{ManyWordDatas, Word};
use crate::wlist::WordList;
@ -15,7 +16,7 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
info!("using naive solver");
Ok(Self { wl: wordlist })
}
fn guess_for(&self, game: &crate::game::Game<WL>) -> Word {
fn guess_for(&self, game: &crate::game::Game<WL>) -> WResult<Word> {
// HACK: hardcoded length
let mut pattern: String = String::from(".....");
let mut other_chars: Vec<char> = Vec::new();
@ -54,9 +55,10 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
})
.map(|v| v.to_owned())
.collect();
matches[0].0.to_owned() // FIXME: panicks in interactive solve, when I insert bullshit and
// pretend that there is a solution #5 It also crashes in
// non-interactive mode
if matches.is_empty() {
return Err(SolverError::NoMatches.into());
}
Ok(matches[0].0.to_owned())
}
}

View File

@ -1,5 +1,6 @@
use libpt::log::info;
use crate::error::WResult;
use crate::wlist::word::Word;
use crate::wlist::WordList;
@ -15,8 +16,8 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for StupidSolver<'wl, WL> {
info!("using stupid solver");
Ok(Self { wl: wordlist })
}
fn guess_for(&self, game: &crate::game::Game<WL>) -> Word {
self.wl.rand_word().0
fn guess_for(&self, game: &crate::game::Game<WL>) -> WResult<Word> {
Ok(self.wl.rand_word().0)
}
}