a lifetime of problems
cargo devel CI / cargo CI (push) Successful in 2m7s Details

This commit is contained in:
Christoph J. Scherr 2024-03-31 16:33:56 +02:00
parent 7b6dd82953
commit 3857604000
Signed by: PlexSheep
GPG Key ID: 7CDD0B14851A08EF
6 changed files with 130 additions and 34 deletions

31
src/bench/builtin.rs Normal file
View File

@ -0,0 +1,31 @@
use crate::game::{Game, GameBuilder};
use crate::solve::Solver;
use crate::wlist::WordList;
use super::Benchmark;
#[derive(Debug, Clone)]
pub struct BuiltinBenchmark<'wl, WL: WordList, SL: Solver<'wl, WL>> {
wordlist: &'wl WL,
solver: SL,
builder: GameBuilder<'wl, WL>,
}
impl<'wl, WL: WordList, SL: Solver<'wl, WL>> Benchmark<'wl, WL, SL>
for BuiltinBenchmark<'wl, WL, SL>
{
fn build(wordlist: &'wl WL, solver: SL) -> crate::error::WResult<Self> {
let builder: GameBuilder<_> = Game::builder(wordlist);
Ok(Self {
wordlist,
solver,
builder,
})
}
fn solver(&self) -> &SL {
&self.solver
}
fn builder(&'wl self) -> &'wl crate::game::GameBuilder<'wl, WL> {
&self.builder
}
}

View File

@ -3,31 +3,49 @@ use std::fmt::Debug;
use libpt::log::debug; use libpt::log::debug;
use crate::error::WResult; use crate::error::WResult;
use crate::game::response::GuessResponse;
use crate::game::{Game, GameBuilder};
use crate::solve::Solver;
use crate::wlist::WordList; use crate::wlist::WordList;
pub trait Benchmark<'wl, WL: WordList>: Clone + Sized + Debug { pub mod report;
fn build(wordlist: &'wl WL) -> WResult<Self>; use report::*;
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;
#[cfg(feature = "builtin")]
pub mod builtin;
pub trait Benchmark<'wl, WL, SL>: Clone + Sized + Debug
where
WL: WordList,
WL: 'wl,
SL: Solver<'wl, WL>,
{
fn build(wordlist: &'wl WL, solver: SL) -> WResult<Self>;
fn builder(&'wl self) -> &'wl GameBuilder<'wl, WL>;
fn make_game(&'wl self) -> WResult<Game<'wl, WL>> {
Ok(self.builder().build()?)
}
fn solver(&'wl self) -> &'wl SL;
fn play(&'wl self) -> WResult<GuessResponse> {
// FIXME: wth why does the lifetime break here?
let mut game: Game<'wl, WL> = self.make_game()?;
todo!()
}
fn bench(&'wl self, n: usize) -> WResult<Report> {
// PERF: it would be better to make this multithreaded
let part = n / 20;
let mut report = Report::new();
let start = std::time::Instant::now(); let start = std::time::Instant::now();
for i in 0..n { for i in 0..n {
// TODO: limit execution time for the following, perhaps async // TODO: limit execution time for the following, perhaps async
absolute += self.play()?; report.add(self.play()?);
if i % part == part - 1 { if i % part == part - 1 {
debug!( debug!("{}", report);
"{} / {n}\t ratio: {} \t elapsed: {:?}",
i + 1,
absolute as f64 / n as f64,
start.elapsed()
);
} }
} }
Ok((absolute, absolute as f64 / n as f64)) Ok(report)
} }
} }

45
src/bench/report.rs Normal file
View File

@ -0,0 +1,45 @@
use std::fmt::Display;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::game::response::GuessResponse;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Report {
data: Vec<GuessResponse>,
}
impl Report {
pub fn new() -> Self {
Self { data: Vec::new() }
}
pub fn add(&mut self, data: GuessResponse) {
self.data.push(data)
}
pub fn n(&self) -> usize {
self.data.len()
}
pub fn win_ratio(&self) -> usize {
todo!()
}
pub fn avg_score(&self) -> usize {
todo!()
}
}
impl Display for Report {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"n: {}, win_ratio: {}, avg_score: {}",
self.n(),
self.win_ratio(),
self.avg_score()
)
}
}

View File

@ -47,25 +47,9 @@ fn main() -> anyhow::Result<()> {
.max_steps(cli.max_steps) .max_steps(cli.max_steps)
.precompute(cli.precompute); .precompute(cli.precompute);
let solver = cli.solver.to_solver(&wl); let solver = cli.solver.to_solver(&wl);
let mut game = builder.build()?; let bench = cli.solver.to_solver(&wl);
debug!("{game:#?}"); todo!();
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(()) Ok(())
} }

View File

@ -203,7 +203,7 @@ impl<'wl, WL: WordList> GameBuilder<'wl, WL> {
} }
/// build a [`Game`] with the stored configuration /// build a [`Game`] with the stored configuration
pub fn build(&self) -> GameResult<Game<'wl, WL>> { pub fn build(&'wl self) -> GameResult<Game<'wl, WL>> {
debug!("{:#?}", self); debug!("{:#?}", self);
let game: Game<WL> = 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)?;

View File

@ -3,13 +3,22 @@ use crate::wlist::WordList;
use anyhow::Ok; use anyhow::Ok;
use colored::{ColoredString, Colorize}; use colored::{ColoredString, Colorize};
use libpt::log::debug; use libpt::log::debug;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::fmt::Display; use std::fmt::Display;
use super::Game; use super::Game;
#[derive(Debug, Clone, PartialEq, Copy, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct AtomicEvaluation {
char: char,
status: Status,
}
pub type Evaluation = Vec<(char, Status)>; pub type Evaluation = Vec<(char, Status)>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GuessResponse { pub struct GuessResponse {
guess: Word, guess: Word,
evaluation: Evaluation, evaluation: Evaluation,
@ -20,6 +29,7 @@ pub struct GuessResponse {
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Status { pub enum Status {
None = 0, None = 0,
Exists = 1, Exists = 1,
@ -70,6 +80,14 @@ impl GuessResponse {
pub fn guess(&self) -> &Word { pub fn guess(&self) -> &Word {
&self.guess &self.guess
} }
pub fn step(&self) -> usize {
self.step
}
pub fn max_steps(&self) -> usize {
self.max_steps
}
} }
impl Display for GuessResponse { impl Display for GuessResponse {