From 610b404ab7fb86b442ce30b1735eb1efa9491312 Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Mon, 22 Jul 2024 16:34:35 +0200 Subject: [PATCH] fix(game): fix #6 and #5 --- src/bin/solve/simple.rs | 2 +- src/error.rs | 11 +++++++++++ src/game/response.rs | 6 ++---- src/solve/mod.rs | 16 +++++++++------- src/solve/naive/mod.rs | 10 ++++++---- src/solve/stupid/mod.rs | 5 +++-- 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/bin/solve/simple.rs b/src/bin/solve/simple.rs index d0d13cf..3c8673d 100644 --- a/src/bin/solve/simple.rs +++ b/src/bin/solve/simple.rs @@ -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 { diff --git a/src/error.rs b/src/error.rs index dbed13d..88b34f9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -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, +} diff --git a/src/game/response.rs b/src/game/response.rs index 58a9915..280b0f0 100644 --- a/src/game/response.rs +++ b/src/game/response.rs @@ -21,7 +21,6 @@ pub struct AtomicEvaluation { pub struct GuessResponse { guess: Word, evaluation: Evaluation, - finish: bool, solution: Option, step: usize, max_steps: usize, @@ -50,10 +49,9 @@ impl From for Status { impl GuessResponse { pub(crate) fn new(guess: &Word, status: Evaluation, game: &Game) -> 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 { diff --git a/src/solve/mod.rs b/src/solve/mod.rs index 5ef34c9..456911f 100644 --- a/src/solve/mod.rs +++ b/src/solve/mod.rs @@ -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; /// 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 { - 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 { 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 { + debug!("solver: {self:?}"); + Ok(match self { + Self::Naive(solver) => solver.guess_for(game)?, + Self::Stupid(solver) => solver.guess_for(game)?, + }) } } diff --git a/src/solve/naive/mod.rs b/src/solve/naive/mod.rs index d70b752..0cb9313 100644 --- a/src/solve/naive/mod.rs +++ b/src/solve/naive/mod.rs @@ -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) -> Word { + fn guess_for(&self, game: &crate::game::Game) -> WResult { // HACK: hardcoded length let mut pattern: String = String::from("....."); let mut other_chars: Vec = 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()) } } diff --git a/src/solve/stupid/mod.rs b/src/solve/stupid/mod.rs index 2aa1d61..e4df9e7 100644 --- a/src/solve/stupid/mod.rs +++ b/src/solve/stupid/mod.rs @@ -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) -> Word { - self.wl.rand_word().0 + fn guess_for(&self, game: &crate::game::Game) -> WResult { + Ok(self.wl.rand_word().0) } }