generated from PlexSheep/rs-base
bench work
This commit is contained in:
parent
98cb455a3c
commit
d9ffa03e88
17
Cargo.toml
17
Cargo.toml
|
@ -13,9 +13,9 @@ keywords = ["wordle", "benchmark"]
|
|||
default-run = "wordlec"
|
||||
|
||||
[features]
|
||||
default = ["game", "bench", "tui", "solve", "builtin_wlist", "serde"]
|
||||
builtin_wlist = ["dep:serde_json", "serde"]
|
||||
game = ["builtin_wlist"]
|
||||
default = ["game", "bench", "tui", "solve", "builtin", "serde"]
|
||||
builtin = ["dep:serde_json", "serde"]
|
||||
game = []
|
||||
solve = ["game"]
|
||||
tui = ["cli"]
|
||||
cli = ["dep:clap"]
|
||||
|
@ -36,14 +36,19 @@ thiserror = "1.0.58"
|
|||
[[bin]]
|
||||
name = "wordlec"
|
||||
path = "src/bin/game/cli.rs"
|
||||
required-features = ["game", "cli"]
|
||||
required-features = ["game", "cli", "builtin"]
|
||||
|
||||
[[bin]]
|
||||
name = "wordlet"
|
||||
path = "src/bin/game/tui.rs"
|
||||
required-features = ["tui", "game"]
|
||||
required-features = ["tui", "game", "builtin"]
|
||||
|
||||
[[bin]]
|
||||
name = "wordlesolve"
|
||||
path = "src/bin/solve/simple.rs"
|
||||
required-features = ["solve", "cli"]
|
||||
required-features = ["solve", "cli", "builtin"]
|
||||
|
||||
[[bin]]
|
||||
name = "wordlebench"
|
||||
path = "src/bin/bench/cli.rs"
|
||||
required-features = ["solve", "cli", "bench", "builtin"]
|
||||
|
|
|
@ -1,5 +1,33 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
pub trait Benchmark: Clone + Sized + Debug {
|
||||
use libpt::log::debug;
|
||||
|
||||
use crate::error::WResult;
|
||||
use crate::wlist::WordList;
|
||||
|
||||
pub trait Benchmark<'wl, WL: WordList>: Clone + Sized + Debug {
|
||||
fn build(wordlist: &'wl WL) -> WResult<Self>;
|
||||
fn play(&self) -> WResult<usize>;
|
||||
fn bench(&self, n: usize) -> WResult<(usize, f64)> {
|
||||
// PERF: it would be better to make this multithreaded
|
||||
let mut absolute: usize = 0;
|
||||
let part = n / 20;
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
for i in 0..n {
|
||||
// TODO: limit execution time for the following, perhaps async
|
||||
absolute += self.play()?;
|
||||
if i % part == part - 1 {
|
||||
debug!(
|
||||
"{} / {n}\t ratio: {} \t elapsed: {:?}",
|
||||
i + 1,
|
||||
absolute as f64 / n as f64,
|
||||
start.elapsed()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((absolute, absolute as f64 / n as f64))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
#![warn(clippy::all)]
|
||||
// #![warn(missing_docs)]
|
||||
#![warn(missing_debug_implementations)]
|
||||
|
||||
use clap::Parser;
|
||||
use libpt::log::*;
|
||||
|
||||
use wordle_analyzer::game::response::GuessResponse;
|
||||
|
||||
use wordle_analyzer::solve::{BuiltinSolverNames, 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 = BuiltinSolverNames::default())]
|
||||
solver: BuiltinSolverNames,
|
||||
}
|
||||
|
||||
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 = cli.solver.to_solver(&wl);
|
||||
let mut game = builder.build()?;
|
||||
|
||||
debug!("{game:#?}");
|
||||
|
||||
let mut response: GuessResponse;
|
||||
let mut _guess: Word;
|
||||
loop {
|
||||
response = solver.make_a_move(&mut game)?;
|
||||
println!("{}. guess: {response}", game.step() - 1);
|
||||
|
||||
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(())
|
||||
}
|
|
@ -54,7 +54,7 @@ fn main() -> anyhow::Result<()> {
|
|||
let mut response: GuessResponse;
|
||||
let mut _guess: Word;
|
||||
loop {
|
||||
response = solver.play(&mut game)?;
|
||||
response = solver.make_a_move(&mut game)?;
|
||||
println!("{}. guess: {response}", game.step() - 1);
|
||||
|
||||
if response.finished() {
|
||||
|
|
|
@ -15,6 +15,8 @@ pub struct GuessResponse {
|
|||
evaluation: Evaluation,
|
||||
finish: bool,
|
||||
solution: WordData,
|
||||
step: usize,
|
||||
max_steps: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -40,6 +42,8 @@ impl GuessResponse {
|
|||
evaluation: status,
|
||||
finish,
|
||||
solution: game.solution().clone(),
|
||||
step: game.step(),
|
||||
max_steps: game.max_steps(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,32 +9,34 @@ use crate::{
|
|||
},
|
||||
};
|
||||
|
||||
#[cfg(feature = "builtin")]
|
||||
pub mod naive;
|
||||
#[cfg(feature = "builtin")]
|
||||
pub use naive::NaiveSolver;
|
||||
#[cfg(feature = "builtin")]
|
||||
pub mod stupid;
|
||||
#[cfg(feature = "builtin")]
|
||||
pub use stupid::StupidSolver;
|
||||
|
||||
pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug + Sized {
|
||||
fn build(wordlist: &'wl WL) -> WResult<Self>;
|
||||
fn guess_for(&self, game: &Game<'wl, WL>) -> Word;
|
||||
fn play(&self, game: &mut Game<'wl, WL>) -> WResult<GuessResponse> {
|
||||
Ok(game.guess(self.guess_for(&game))?)
|
||||
fn make_a_move(&self, game: &mut Game<'wl, WL>) -> WResult<GuessResponse> {
|
||||
Ok(game.guess(self.guess_for(game))?)
|
||||
}
|
||||
fn solve(&self, game: &mut Game<'wl, WL>) -> WResult<Option<WordData>> {
|
||||
fn play(&self, game: &mut Game<'wl, WL>) -> WResult<GuessResponse> {
|
||||
let mut resp: GuessResponse;
|
||||
loop {
|
||||
resp = self.play(game)?;
|
||||
resp = self.make_a_move(game)?;
|
||||
if game.finished() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(resp.solution())
|
||||
Ok(resp)
|
||||
}
|
||||
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))
|
||||
fn solve(&self, game: &Game<'wl, WL>) -> WResult<Option<WordData>> {
|
||||
let mut game = game.clone();
|
||||
Ok(self.play(&mut game)?.solution())
|
||||
}
|
||||
fn boxed(self) -> Box<Self> {
|
||||
Box::new(self)
|
||||
|
|
|
@ -6,7 +6,7 @@ use regex::Regex;
|
|||
use std::collections::HashMap;
|
||||
use std::ops::RangeBounds;
|
||||
|
||||
#[cfg(feature = "builtin_wlist")]
|
||||
#[cfg(feature = "builtin")]
|
||||
pub mod builtin;
|
||||
pub mod word;
|
||||
use word::*;
|
||||
|
|
Loading…
Reference in New Issue