generated from PlexSheep/rs-base
too much generics, idk
This commit is contained in:
parent
4367e7fc58
commit
ce9686f7bf
|
@ -16,7 +16,7 @@ default-run = "wordlec"
|
|||
default = ["game", "bench", "tui", "solve", "builtin_wlist", "serde"]
|
||||
builtin_wlist = ["dep:serde_json", "serde"]
|
||||
game = ["builtin_wlist"]
|
||||
solve = []
|
||||
solve = ["game"]
|
||||
tui = ["cli"]
|
||||
cli = ["dep:clap"]
|
||||
bench = []
|
||||
|
@ -45,4 +45,4 @@ required-features = ["tui", "game"]
|
|||
[[bin]]
|
||||
name = "wordlesolve"
|
||||
path = "src/bin/solve/simple.rs"
|
||||
required-features = ["game", "solve", "cli"]
|
||||
required-features = ["solve", "cli"]
|
||||
|
|
|
@ -39,11 +39,10 @@ fn main() -> anyhow::Result<()> {
|
|||
debug!("dumping CLI: {:#?}", cli);
|
||||
|
||||
let wl = BuiltinWList::default();
|
||||
let builder = game::Game::builder()
|
||||
let builder = game::Game::builder(&wl)
|
||||
.length(cli.length)
|
||||
.max_steps(cli.max_steps)
|
||||
.precompute(cli.precompute)
|
||||
.wordlist(wl);
|
||||
.precompute(cli.precompute);
|
||||
let mut game = builder.build()?;
|
||||
|
||||
debug!("{game:#?}");
|
||||
|
|
|
@ -1,3 +1,78 @@
|
|||
fn main() {
|
||||
unimplemented!();
|
||||
#![warn(clippy::all)]
|
||||
// #![warn(missing_docs)]
|
||||
#![warn(missing_debug_implementations)]
|
||||
use std::io::Write;
|
||||
|
||||
use clap::Parser;
|
||||
use libpt::log::*;
|
||||
use wordle_analyzer::error::GameError;
|
||||
use wordle_analyzer::game::response::GuessResponse;
|
||||
|
||||
use wordle_analyzer::game::Game;
|
||||
use wordle_analyzer::solve::{stupid, BuiltinSolvers, Solver};
|
||||
use wordle_analyzer::wlist::builtin::BuiltinWList;
|
||||
use wordle_analyzer::wlist::word::Word;
|
||||
use wordle_analyzer::{self, game};
|
||||
|
||||
#[derive(Parser, Clone, Debug)]
|
||||
#[command(version, about, long_about, author)]
|
||||
struct Cli {
|
||||
/// precompute all possibilities for better performance at runtime
|
||||
#[arg(short, long)]
|
||||
precompute: bool,
|
||||
/// how long should the word be?
|
||||
#[arg(short, long, default_value_t = wordle_analyzer::DEFAULT_WORD_LENGTH)]
|
||||
length: usize,
|
||||
/// how many times can we guess?
|
||||
#[arg(short, long, default_value_t = wordle_analyzer::DEFAULT_MAX_STEPS)]
|
||||
max_steps: usize,
|
||||
/// more verbose logs
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
/// which solver to use
|
||||
#[arg(short, long, default_value_t = BuiltinSolvers::default())]
|
||||
solver: BuiltinSolvers,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let cli = Cli::parse();
|
||||
if cli.verbose {
|
||||
Logger::build_mini(Some(Level::TRACE))?;
|
||||
} else {
|
||||
Logger::build_mini(Some(Level::INFO))?;
|
||||
}
|
||||
debug!("dumping CLI: {:#?}", cli);
|
||||
|
||||
let wl = BuiltinWList::default();
|
||||
let builder = game::Game::builder(&wl)
|
||||
.length(cli.length)
|
||||
.max_steps(cli.max_steps)
|
||||
.precompute(cli.precompute);
|
||||
let solver = match cli.solver {
|
||||
BuiltinSolvers::Naive => {
|
||||
stupid::StupidSolver::build(&wl)?
|
||||
},
|
||||
_ => todo!()
|
||||
};
|
||||
let mut game = builder.build()?;
|
||||
|
||||
debug!("{game:#?}");
|
||||
|
||||
let mut response: GuessResponse;
|
||||
let mut guess: Word;
|
||||
loop {
|
||||
response = solver.play(&mut game)?;
|
||||
println!("{response}");
|
||||
|
||||
if response.finished() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if response.won() {
|
||||
println!("You win! You took {} guesses.", game.step() - 1);
|
||||
} else {
|
||||
println!("You lose! The solution was {:?}.", game.solution());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@ pub enum Error {
|
|||
#[from]
|
||||
source: anyhow::Error,
|
||||
},
|
||||
// for `FromStr` of `BuiltinSolver`
|
||||
#[error("Unknown builtin solver")]
|
||||
UnknownBuiltinSolver
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Error)]
|
||||
|
|
|
@ -7,6 +7,8 @@ use libpt::log::debug;
|
|||
pub mod response;
|
||||
use response::GuessResponse;
|
||||
|
||||
pub mod summary;
|
||||
|
||||
use self::response::Status;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -26,8 +28,8 @@ where
|
|||
|
||||
impl<'wl, WL: WordList> Game<'wl, WL> {
|
||||
/// get a new [`GameBuilder`]
|
||||
pub fn builder() -> GameBuilder<WL> {
|
||||
GameBuilder::default()
|
||||
pub fn builder(wl: &'wl WL) -> GameBuilder<'wl, WL> {
|
||||
GameBuilder::new(wl)
|
||||
}
|
||||
/// Create a [Game] of wordle
|
||||
///
|
||||
|
@ -97,7 +99,7 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
|||
evaluation.push((c, status));
|
||||
}
|
||||
|
||||
let mut response = GuessResponse::new(guess, evaluation, self.step, self.max_steps);
|
||||
let mut response = GuessResponse::new(guess, evaluation, &self);
|
||||
self.finished = response.finished();
|
||||
Ok(response)
|
||||
}
|
||||
|
@ -113,6 +115,14 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
|||
pub fn step(&self) -> usize {
|
||||
self.step
|
||||
}
|
||||
|
||||
pub fn finished(&self) -> bool {
|
||||
self.finished
|
||||
}
|
||||
|
||||
pub fn max_steps(&self) -> usize {
|
||||
self.max_steps
|
||||
}
|
||||
}
|
||||
|
||||
/// Build and Configure a [`Game`]
|
||||
|
@ -126,9 +136,11 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
|||
///
|
||||
/// ```
|
||||
/// # use wordle_analyzer::game::*;
|
||||
/// # use wordle_analyzer::wlist::builtin::BuiltinWList;
|
||||
/// # use anyhow::Result;
|
||||
/// # fn main() -> Result<()> {
|
||||
/// let game: Game = GameBuilder::default()
|
||||
/// let wl = BuiltinWList::default();
|
||||
/// let game: Game<_> = GameBuilder::new(&wl)
|
||||
/// .build()?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
|
@ -136,9 +148,11 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
|||
///
|
||||
/// ```
|
||||
/// # use wordle_analyzer::game::*;
|
||||
/// # use wordle_analyzer::wlist::builtin::BuiltinWList;
|
||||
/// # use anyhow::Result;
|
||||
/// # fn main() -> Result<()> {
|
||||
/// let game: Game = Game::builder()
|
||||
/// let wl = BuiltinWList::default();
|
||||
/// let game: Game<_> = Game::builder(&wl)
|
||||
/// .length(5)
|
||||
/// .precompute(false)
|
||||
/// .max_steps(6)
|
||||
|
@ -148,19 +162,31 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
|||
/// ```
|
||||
///
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct GameBuilder<WL: WordList> {
|
||||
pub struct GameBuilder<'wl, WL: WordList> {
|
||||
length: usize,
|
||||
precompute: bool,
|
||||
max_steps: usize,
|
||||
wordlist: WL,
|
||||
wordlist: &'wl WL,
|
||||
}
|
||||
|
||||
impl<'wl, WL: WordList> GameBuilder<'wl, WL> {
|
||||
/// make a new [GameBuilder]
|
||||
///
|
||||
/// We need a [WordList], so provide one here.
|
||||
pub fn new(wl: &'wl WL) -> Self {
|
||||
Self {
|
||||
length: super::DEFAULT_WORD_LENGTH,
|
||||
precompute: false,
|
||||
max_steps: super::DEFAULT_MAX_STEPS,
|
||||
wordlist: wl
|
||||
}
|
||||
}
|
||||
|
||||
impl<WL: WordList> GameBuilder<WL> {
|
||||
/// build a [`Game`] with the stored configuration
|
||||
pub fn build(&self) -> GameResult<Game<WL>> {
|
||||
pub fn build(&self) -> GameResult<Game<'wl, WL>> {
|
||||
debug!("{:#?}", self);
|
||||
let game: Game<WL> =
|
||||
Game::build(self.length, self.precompute, self.max_steps, &self.wordlist)?;
|
||||
Game::build(self.length, self.precompute, self.max_steps, self.wordlist)?;
|
||||
Ok(game)
|
||||
}
|
||||
|
||||
|
@ -194,19 +220,8 @@ impl<WL: WordList> GameBuilder<WL> {
|
|||
///
|
||||
/// The builder can be used multiple times. Each [`Game`] will have a immutable reference to
|
||||
/// `wl`.
|
||||
pub fn wordlist(mut self, wl: WL) -> Self {
|
||||
pub fn wordlist(mut self, wl: &'wl WL) -> Self {
|
||||
self.wordlist = wl;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<WL: WordList> Default for GameBuilder<WL> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
length: super::DEFAULT_WORD_LENGTH,
|
||||
precompute: false,
|
||||
max_steps: super::DEFAULT_MAX_STEPS,
|
||||
wordlist: WL::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
use crate::wlist::word::Word;
|
||||
use crate::wlist::word::{Word, WordData};
|
||||
use crate::wlist::WordList;
|
||||
use anyhow::Ok;
|
||||
use colored::{ColoredString, Colorize};
|
||||
use libpt::log::debug;
|
||||
use std::fmt::Display;
|
||||
|
||||
use super::Game;
|
||||
|
||||
pub type Evaluation = Vec<(char, Status)>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct GuessResponse {
|
||||
guess: Word,
|
||||
evaluation: Evaluation,
|
||||
step: usize,
|
||||
finish: bool,
|
||||
win: bool,
|
||||
solution: WordData,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -23,29 +25,21 @@ pub enum Status {
|
|||
}
|
||||
|
||||
impl GuessResponse {
|
||||
pub(crate) fn new(
|
||||
guess: Word,
|
||||
status: Vec<(char, Status)>,
|
||||
step: usize,
|
||||
max_step: usize,
|
||||
) -> Self {
|
||||
let mut win = false;
|
||||
let mut finish: bool = if step > max_step {
|
||||
pub(crate) fn new<WL: WordList>(guess: Word, status: Vec<(char, Status)>, game: &Game<WL>) -> Self {
|
||||
let finish: bool = if game.step() > game.max_steps() {
|
||||
true
|
||||
} else {
|
||||
let mut matched = true;
|
||||
for p in &status {
|
||||
matched &= p.1 == Status::Matched;
|
||||
}
|
||||
win = matched;
|
||||
win
|
||||
matched
|
||||
};
|
||||
Self {
|
||||
guess,
|
||||
evaluation: status,
|
||||
step,
|
||||
finish,
|
||||
win,
|
||||
solution: game.solution().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +48,15 @@ impl GuessResponse {
|
|||
}
|
||||
|
||||
pub fn won(&self) -> bool {
|
||||
self.win
|
||||
self.guess == self.solution.0
|
||||
}
|
||||
|
||||
pub fn solution(&self) -> Option<WordData> {
|
||||
if self.won() {
|
||||
Some(self.solution.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
use crate::wlist::WordList;
|
||||
|
||||
use super::Game;
|
||||
|
||||
pub struct Summary<'wl, WL: WordList> {
|
||||
data: &'wl Vec<Game<'wl, WL>>,
|
||||
}
|
||||
|
||||
impl<'wl, WL: WordList> From<&'wl Vec<Game<'wl, WL>>> for Summary<'wl, WL> {
|
||||
fn from(value: &'wl Vec<Game<'wl, WL>>) -> Self {
|
||||
Summary { data: value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'wl, WL: WordList> From<&'wl mut Vec<Game<'wl, WL>>> for Summary<'wl, WL> {
|
||||
fn from(value: &'wl mut Vec<Game<'wl, WL>>) -> Self {
|
||||
Summary { data: value }
|
||||
}
|
||||
}
|
|
@ -12,6 +12,6 @@ pub mod bench;
|
|||
pub mod error;
|
||||
#[cfg(feature = "game")]
|
||||
pub mod game;
|
||||
#[cfg(feature = "solvers")]
|
||||
pub mod solvers;
|
||||
#[cfg(feature = "solve")]
|
||||
pub mod solve;
|
||||
pub mod wlist;
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use crate::{
|
||||
error::{Error, WResult},
|
||||
game::{response::*, summary::Summary, Game},
|
||||
wlist::{word::WordData, WordList},
|
||||
};
|
||||
|
||||
pub mod naive;
|
||||
pub mod stupid;
|
||||
|
||||
pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug {
|
||||
fn build(wordlist: &'wl WL) -> WResult<Self>;
|
||||
fn play(&self, game: &mut Game<'wl, WL>) -> WResult<GuessResponse>;
|
||||
fn solve(&self, game: &mut Game<'wl, WL>) -> WResult<Option<WordData>> {
|
||||
let mut resp: GuessResponse;
|
||||
loop {
|
||||
resp = self.play(game)?;
|
||||
if game.finished() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(resp.solution())
|
||||
}
|
||||
fn play_n(&self, games: &'wl mut Vec<Game<'wl, WL>>) -> WResult<Summary<'wl, WL>> {
|
||||
for game in games.iter_mut() {
|
||||
self.play(game)?;
|
||||
}
|
||||
Ok(Summary::from(games))
|
||||
}
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum BuiltinSolvers {
|
||||
#[default]
|
||||
Naive,
|
||||
Stupid,
|
||||
}
|
||||
|
||||
impl FromStr for BuiltinSolvers {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"naive" => Ok(Self::Naive),
|
||||
"stupid" => Ok(Self::Stupid),
|
||||
_ => Err(Self::Err::UnknownBuiltinSolver),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BuiltinSolvers {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
use crate::wlist::WordList;
|
||||
|
||||
use super::Solver;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StupidSolver<'wl, WL> {
|
||||
wl: &'wl WL,
|
||||
}
|
||||
|
||||
impl<'wl, WL: WordList> Solver<'wl, WL> for StupidSolver<'wl, WL> {
|
||||
fn build(wordlist: &'wl WL) -> crate::error::WResult<Self> {
|
||||
Ok(Self { wl: wordlist })
|
||||
}
|
||||
fn play(
|
||||
&self,
|
||||
game: &mut crate::game::Game<'wl, WL>,
|
||||
) -> crate::error::WResult<super::GuessResponse> {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
use crate::{
|
||||
error::WResult,
|
||||
game::{response::*, Game},
|
||||
wlist::{word::WordData, WordList},
|
||||
};
|
||||
|
||||
pub trait Solver<'wl, WL: WordList>: Clone + Default {
|
||||
fn build(wordlist: WL) -> WResult<Self>;
|
||||
fn build_game(&self) -> Game<'wl, WL>;
|
||||
fn play(game: &mut Game<'wl, WL>) -> Game<'wl, WL>;
|
||||
fn solve(game: &mut Game<'wl, WL>) -> WResult<WordData>;
|
||||
}
|
Loading…
Reference in New Issue