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"
|
default-run = "wordlec"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["game", "bench", "tui", "solve", "builtin_wlist", "serde"]
|
default = ["game", "bench", "tui", "solve", "builtin", "serde"]
|
||||||
builtin_wlist = ["dep:serde_json", "serde"]
|
builtin = ["dep:serde_json", "serde"]
|
||||||
game = ["builtin_wlist"]
|
game = []
|
||||||
solve = ["game"]
|
solve = ["game"]
|
||||||
tui = ["cli"]
|
tui = ["cli"]
|
||||||
cli = ["dep:clap"]
|
cli = ["dep:clap"]
|
||||||
|
@ -36,14 +36,19 @@ thiserror = "1.0.58"
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "wordlec"
|
name = "wordlec"
|
||||||
path = "src/bin/game/cli.rs"
|
path = "src/bin/game/cli.rs"
|
||||||
required-features = ["game", "cli"]
|
required-features = ["game", "cli", "builtin"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "wordlet"
|
name = "wordlet"
|
||||||
path = "src/bin/game/tui.rs"
|
path = "src/bin/game/tui.rs"
|
||||||
required-features = ["tui", "game"]
|
required-features = ["tui", "game", "builtin"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "wordlesolve"
|
name = "wordlesolve"
|
||||||
path = "src/bin/solve/simple.rs"
|
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;
|
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 response: GuessResponse;
|
||||||
let mut _guess: Word;
|
let mut _guess: Word;
|
||||||
loop {
|
loop {
|
||||||
response = solver.play(&mut game)?;
|
response = solver.make_a_move(&mut game)?;
|
||||||
println!("{}. guess: {response}", game.step() - 1);
|
println!("{}. guess: {response}", game.step() - 1);
|
||||||
|
|
||||||
if response.finished() {
|
if response.finished() {
|
||||||
|
|
|
@ -15,6 +15,8 @@ pub struct GuessResponse {
|
||||||
evaluation: Evaluation,
|
evaluation: Evaluation,
|
||||||
finish: bool,
|
finish: bool,
|
||||||
solution: WordData,
|
solution: WordData,
|
||||||
|
step: usize,
|
||||||
|
max_steps: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
@ -40,6 +42,8 @@ impl GuessResponse {
|
||||||
evaluation: status,
|
evaluation: status,
|
||||||
finish,
|
finish,
|
||||||
solution: game.solution().clone(),
|
solution: game.solution().clone(),
|
||||||
|
step: game.step(),
|
||||||
|
max_steps: game.max_steps(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,32 +9,34 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "builtin")]
|
||||||
pub mod naive;
|
pub mod naive;
|
||||||
|
#[cfg(feature = "builtin")]
|
||||||
pub use naive::NaiveSolver;
|
pub use naive::NaiveSolver;
|
||||||
|
#[cfg(feature = "builtin")]
|
||||||
pub mod stupid;
|
pub mod stupid;
|
||||||
|
#[cfg(feature = "builtin")]
|
||||||
pub use stupid::StupidSolver;
|
pub use stupid::StupidSolver;
|
||||||
|
|
||||||
pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug + Sized {
|
pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug + Sized {
|
||||||
fn build(wordlist: &'wl WL) -> WResult<Self>;
|
fn build(wordlist: &'wl WL) -> WResult<Self>;
|
||||||
fn guess_for(&self, game: &Game<'wl, WL>) -> Word;
|
fn guess_for(&self, game: &Game<'wl, WL>) -> Word;
|
||||||
fn play(&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))?)
|
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;
|
let mut resp: GuessResponse;
|
||||||
loop {
|
loop {
|
||||||
resp = self.play(game)?;
|
resp = self.make_a_move(game)?;
|
||||||
if game.finished() {
|
if game.finished() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(resp.solution())
|
Ok(resp)
|
||||||
}
|
}
|
||||||
fn play_n(&self, games: &'wl mut Vec<Game<'wl, WL>>) -> WResult<Summary<'wl, WL>> {
|
fn solve(&self, game: &Game<'wl, WL>) -> WResult<Option<WordData>> {
|
||||||
for game in games.iter_mut() {
|
let mut game = game.clone();
|
||||||
self.play(game)?;
|
Ok(self.play(&mut game)?.solution())
|
||||||
}
|
|
||||||
Ok(Summary::from(games))
|
|
||||||
}
|
}
|
||||||
fn boxed(self) -> Box<Self> {
|
fn boxed(self) -> Box<Self> {
|
||||||
Box::new(self)
|
Box::new(self)
|
||||||
|
|
|
@ -6,7 +6,7 @@ use regex::Regex;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::RangeBounds;
|
use std::ops::RangeBounds;
|
||||||
|
|
||||||
#[cfg(feature = "builtin_wlist")]
|
#[cfg(feature = "builtin")]
|
||||||
pub mod builtin;
|
pub mod builtin;
|
||||||
pub mod word;
|
pub mod word;
|
||||||
use word::*;
|
use word::*;
|
||||||
|
|
Loading…
Reference in New Issue