generated from PlexSheep/rs-base
add interactive solver #4
|
@ -128,7 +128,7 @@ fn help_guess_interactive(cli: Cli) -> anyhow::Result<()> {
|
||||||
println!("{}", game);
|
println!("{}", game);
|
||||||
}
|
}
|
||||||
ReplCommand::Solve => {
|
ReplCommand::Solve => {
|
||||||
let best_guess = solver.guess_for(&game);
|
let best_guess = solver.guess_for(&game)?;
|
||||||
println!("best guess: {best_guess}");
|
println!("best guess: {best_guess}");
|
||||||
}
|
}
|
||||||
ReplCommand::Guess {
|
ReplCommand::Guess {
|
||||||
|
|
11
src/error.rs
11
src/error.rs
|
@ -13,6 +13,11 @@ pub enum Error {
|
||||||
#[from]
|
#[from]
|
||||||
source: GameError,
|
source: GameError,
|
||||||
},
|
},
|
||||||
|
#[error("Solver Error")]
|
||||||
|
SolverError {
|
||||||
|
#[from]
|
||||||
|
source: SolverError,
|
||||||
|
},
|
||||||
#[error("Benchmark Error")]
|
#[error("Benchmark Error")]
|
||||||
BenchError {
|
BenchError {
|
||||||
#[from]
|
#[from]
|
||||||
|
@ -53,3 +58,9 @@ pub enum BenchError {
|
||||||
#[error("Trying to modify a finished report")]
|
#[error("Trying to modify a finished report")]
|
||||||
ModifyFinishedReport,
|
ModifyFinishedReport,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Error)]
|
||||||
|
pub enum SolverError {
|
||||||
|
#[error("Wordlist has no matches for the gamestate")]
|
||||||
|
NoMatches,
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ pub struct AtomicEvaluation {
|
||||||
pub struct GuessResponse {
|
pub struct GuessResponse {
|
||||||
guess: Word,
|
guess: Word,
|
||||||
evaluation: Evaluation,
|
evaluation: Evaluation,
|
||||||
finish: bool,
|
|
||||||
solution: Option<WordData>,
|
solution: Option<WordData>,
|
||||||
step: usize,
|
step: usize,
|
||||||
max_steps: usize,
|
max_steps: usize,
|
||||||
|
@ -50,10 +49,9 @@ impl From<char> for Status {
|
||||||
|
|
||||||
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 mut new = Self {
|
||||||
guess: guess.to_owned(),
|
guess: guess.to_owned(),
|
||||||
evaluation: status,
|
evaluation: status,
|
||||||
finish: game.step() > game.max_steps(),
|
|
||||||
solution: game.solution().cloned(),
|
solution: game.solution().cloned(),
|
||||||
step: game.step(),
|
step: game.step(),
|
||||||
max_steps: game.max_steps(),
|
max_steps: game.max_steps(),
|
||||||
|
@ -62,7 +60,7 @@ impl GuessResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finished(&self) -> bool {
|
pub fn finished(&self) -> bool {
|
||||||
self.finish
|
self.step() > self.max_steps() || self.won()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn won(&self) -> bool {
|
pub fn won(&self) -> bool {
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
|
|
||||||
#[cfg(feature = "builtin")]
|
#[cfg(feature = "builtin")]
|
||||||
pub mod naive;
|
pub mod naive;
|
||||||
|
use libpt::log::debug;
|
||||||
#[cfg(feature = "builtin")]
|
#[cfg(feature = "builtin")]
|
||||||
pub use naive::NaiveSolver;
|
pub use naive::NaiveSolver;
|
||||||
#[cfg(feature = "builtin")]
|
#[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
|
/// 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).
|
/// 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]
|
/// Make a singular step for a [Game]
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// This function will return an error if [guess_for](Solver::guess_for) fails.
|
/// 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> {
|
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].
|
/// 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> {
|
fn build(wordlist: &'wl WL) -> WResult<Self> {
|
||||||
Ok(Self::Naive(NaiveSolver::build(wordlist)?))
|
Ok(Self::Naive(NaiveSolver::build(wordlist)?))
|
||||||
}
|
}
|
||||||
fn guess_for(&self, game: &Game<'wl, WL>) -> Word {
|
fn guess_for(&self, game: &Game<'wl, WL>) -> WResult<Word> {
|
||||||
match self {
|
debug!("solver: {self:?}");
|
||||||
Self::Naive(solver) => solver.guess_for(game),
|
Ok(match self {
|
||||||
Self::Stupid(solver) => solver.guess_for(game),
|
Self::Naive(solver) => solver.guess_for(game)?,
|
||||||
}
|
Self::Stupid(solver) => solver.guess_for(game)?,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use libpt::log::{info, trace};
|
use libpt::log::{info, trace};
|
||||||
|
|
||||||
|
use crate::error::{Error, SolverError, WResult};
|
||||||
use crate::wlist::word::{ManyWordDatas, Word};
|
use crate::wlist::word::{ManyWordDatas, Word};
|
||||||
use crate::wlist::WordList;
|
use crate::wlist::WordList;
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
|
||||||
info!("using naive solver");
|
info!("using naive solver");
|
||||||
Ok(Self { wl: wordlist })
|
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
|
// HACK: hardcoded length
|
||||||
let mut pattern: String = String::from(".....");
|
let mut pattern: String = String::from(".....");
|
||||||
let mut other_chars: Vec<char> = Vec::new();
|
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())
|
.map(|v| v.to_owned())
|
||||||
.collect();
|
.collect();
|
||||||
matches[0].0.to_owned() // FIXME: panicks in interactive solve, when I insert bullshit and
|
if matches.is_empty() {
|
||||||
// pretend that there is a solution #5 It also crashes in
|
return Err(SolverError::NoMatches.into());
|
||||||
// non-interactive mode
|
}
|
||||||
|
Ok(matches[0].0.to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use libpt::log::info;
|
use libpt::log::info;
|
||||||
|
|
||||||
|
use crate::error::WResult;
|
||||||
use crate::wlist::word::Word;
|
use crate::wlist::word::Word;
|
||||||
use crate::wlist::WordList;
|
use crate::wlist::WordList;
|
||||||
|
|
||||||
|
@ -15,8 +16,8 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for StupidSolver<'wl, WL> {
|
||||||
info!("using stupid solver");
|
info!("using stupid solver");
|
||||||
Ok(Self { wl: wordlist })
|
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> {
|
||||||
self.wl.rand_word().0
|
Ok(self.wl.rand_word().0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue