From a5e22349f6edf699b19bb0e924254770ddeef54d Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Fri, 22 Mar 2024 15:43:41 +0100 Subject: [PATCH] generic solver --- src/bin/solve/simple.rs | 11 ++++------- src/solve/mod.rs | 40 +++++++++++++++++++++++++++++++++++----- src/solve/naive/mod.rs | 26 ++++++++++++++++++++++++++ src/solve/stupid/mod.rs | 11 ++++++++++- 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/bin/solve/simple.rs b/src/bin/solve/simple.rs index ebe58c4..a71b947 100644 --- a/src/bin/solve/simple.rs +++ b/src/bin/solve/simple.rs @@ -7,7 +7,7 @@ use libpt::log::*; use wordle_analyzer::game::response::GuessResponse; -use wordle_analyzer::solve::{stupid, BuiltinSolvers, Solver}; +use wordle_analyzer::solve::{stupid, BuiltinSolverNames, NaiveSolver, Solver, StupidSolver}; use wordle_analyzer::wlist::builtin::BuiltinWList; use wordle_analyzer::wlist::word::Word; use wordle_analyzer::{self, game}; @@ -28,8 +28,8 @@ struct Cli { #[arg(short, long)] verbose: bool, /// which solver to use - #[arg(short, long, default_value_t = BuiltinSolvers::default())] - solver: BuiltinSolvers, + #[arg(short, long, default_value_t = BuiltinSolverNames::default())] + solver: BuiltinSolverNames, } fn main() -> anyhow::Result<()> { @@ -46,10 +46,7 @@ fn main() -> anyhow::Result<()> { .length(cli.length) .max_steps(cli.max_steps) .precompute(cli.precompute); - let solver = match cli.solver { - BuiltinSolvers::Naive => stupid::StupidSolver::build(&wl)?, - _ => todo!(), - }; + let solver = cli.solver.to_solver(&wl); let mut game = builder.build()?; debug!("{game:#?}"); diff --git a/src/solve/mod.rs b/src/solve/mod.rs index cdbe15b..b84e9b3 100644 --- a/src/solve/mod.rs +++ b/src/solve/mod.rs @@ -10,9 +10,11 @@ use crate::{ }; pub mod naive; +pub use naive::NaiveSolver; pub mod stupid; +pub use stupid::StupidSolver; -pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug { +pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug + Sized { fn build(wordlist: &'wl WL) -> WResult; fn guess_for(&self, game: &Game<'wl, WL>) -> Word; fn play(&self, game: &mut Game<'wl, WL>) -> WResult { @@ -34,17 +36,33 @@ pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug { } Ok(Summary::from(games)) } + fn boxed(self) -> Box { + Box::new(self) + } +} + +#[derive(Debug, Clone)] +pub enum AnyBuiltinSolver<'wl, WL: WordList> { + Naive(NaiveSolver<'wl, WL>), + Stupid(StupidSolver<'wl, WL>), } -#[non_exhaustive] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub enum BuiltinSolvers { +pub enum BuiltinSolverNames { #[default] Naive, Stupid, } +impl BuiltinSolverNames { + pub fn to_solver<'wl, WL: WordList>(&self, wl: &'wl WL) -> AnyBuiltinSolver<'wl, WL> { + match self { + Self::Naive => NaiveSolver::build(wl).unwrap().into(), + Self::Stupid => StupidSolver::build(wl).unwrap().into(), + } + } +} -impl FromStr for BuiltinSolvers { +impl FromStr for BuiltinSolverNames { type Err = Error; fn from_str(s: &str) -> Result { match s.to_lowercase().as_str() { @@ -55,8 +73,20 @@ impl FromStr for BuiltinSolvers { } } -impl Display for BuiltinSolvers { +impl Display for BuiltinSolverNames { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) } } + +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), + } + } +} diff --git a/src/solve/naive/mod.rs b/src/solve/naive/mod.rs index 8b13789..a8c98de 100644 --- a/src/solve/naive/mod.rs +++ b/src/solve/naive/mod.rs @@ -1 +1,27 @@ +use libpt::log::info; +use crate::wlist::word::Word; +use crate::wlist::WordList; + +use super::{AnyBuiltinSolver, Solver}; + +#[derive(Debug, Clone)] +pub struct NaiveSolver<'wl, WL> { + wl: &'wl WL, +} + +impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> { + fn build(wordlist: &'wl WL) -> crate::error::WResult { + info!("using naive solver"); + Ok(Self { wl: wordlist }) + } + fn guess_for(&self, game: &crate::game::Game) -> Word { + self.wl.rand_word().0 + } +} + +impl<'wl, WL: WordList> From> for AnyBuiltinSolver<'wl, WL> { + fn from(value: NaiveSolver<'wl, WL>) -> Self { + Self::Naive(value) + } +} diff --git a/src/solve/stupid/mod.rs b/src/solve/stupid/mod.rs index 2637b11..2aa1d61 100644 --- a/src/solve/stupid/mod.rs +++ b/src/solve/stupid/mod.rs @@ -1,7 +1,9 @@ +use libpt::log::info; + use crate::wlist::word::Word; use crate::wlist::WordList; -use super::Solver; +use super::{AnyBuiltinSolver, Solver}; #[derive(Debug, Clone)] pub struct StupidSolver<'wl, WL> { @@ -10,9 +12,16 @@ pub struct StupidSolver<'wl, WL> { impl<'wl, WL: WordList> Solver<'wl, WL> for StupidSolver<'wl, WL> { fn build(wordlist: &'wl WL) -> crate::error::WResult { + info!("using stupid solver"); Ok(Self { wl: wordlist }) } fn guess_for(&self, game: &crate::game::Game) -> Word { self.wl.rand_word().0 } } + +impl<'wl, WL: WordList> From> for AnyBuiltinSolver<'wl, WL> { + fn from(value: StupidSolver<'wl, WL>) -> Self { + Self::Stupid(value) + } +}