generated from PlexSheep/rs-base
reuse wordlist
This commit is contained in:
parent
df15d117ef
commit
02d67cdd0c
|
@ -13,10 +13,10 @@ keywords = ["wordle", "benchmark"]
|
||||||
default-run = "wordlec"
|
default-run = "wordlec"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["game", "bench", "tui", "solvers", "builtin_wlist", "serde"]
|
default = ["game", "bench", "tui", "solve", "builtin_wlist", "serde"]
|
||||||
builtin_wlist = ["dep:serde_json", "serde"]
|
builtin_wlist = ["dep:serde_json", "serde"]
|
||||||
game = ["builtin_wlist"]
|
game = ["builtin_wlist"]
|
||||||
solvers = []
|
solve = []
|
||||||
tui = ["cli"]
|
tui = ["cli"]
|
||||||
cli = ["dep:clap"]
|
cli = ["dep:clap"]
|
||||||
bench = []
|
bench = []
|
||||||
|
@ -41,3 +41,8 @@ required-features = ["game", "cli"]
|
||||||
name = "wordlet"
|
name = "wordlet"
|
||||||
path = "src/bin/game/tui.rs"
|
path = "src/bin/game/tui.rs"
|
||||||
required-features = ["tui", "game"]
|
required-features = ["tui", "game"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "wordlesolve"
|
||||||
|
path = "src/bin/solve/simple.rs"
|
||||||
|
required-features = ["game", "solve", "cli"]
|
||||||
|
|
|
@ -39,11 +39,13 @@ fn main() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
debug!("dumping CLI: {:#?}", cli);
|
debug!("dumping CLI: {:#?}", cli);
|
||||||
|
|
||||||
let mut game = game::Game::<BuiltinWList>::builder()
|
let wl = BuiltinWList::default();
|
||||||
|
let builder = game::Game::builder()
|
||||||
.length(cli.length)
|
.length(cli.length)
|
||||||
.max_steps(cli.max_steps)
|
.max_steps(cli.max_steps)
|
||||||
.precompute(cli.precompute)
|
.precompute(cli.precompute)
|
||||||
.build()?;
|
.wordlist(wl);
|
||||||
|
let mut game = builder.build()?;
|
||||||
|
|
||||||
debug!("{game:#?}");
|
debug!("{game:#?}");
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type WResult<T> = std::result::Result<T, Error>;
|
||||||
pub type GameResult<T> = std::result::Result<T, GameError>;
|
pub type GameResult<T> = std::result::Result<T, GameError>;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::wlist::word::{Solution, Word};
|
use crate::wlist::word::{WordData, Word};
|
||||||
use crate::wlist::WordList;
|
use crate::wlist::WordList;
|
||||||
|
|
||||||
pub mod response;
|
|
||||||
use libpt::log::debug;
|
use libpt::log::debug;
|
||||||
|
|
||||||
|
pub mod response;
|
||||||
use response::GuessResponse;
|
use response::GuessResponse;
|
||||||
|
|
||||||
use self::response::Status;
|
use self::response::Status;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Game<WL>
|
pub struct Game<'wl, WL>
|
||||||
where
|
where
|
||||||
WL: WordList,
|
WL: WordList,
|
||||||
{
|
{
|
||||||
|
@ -17,13 +18,13 @@ where
|
||||||
precompute: bool,
|
precompute: bool,
|
||||||
max_steps: usize,
|
max_steps: usize,
|
||||||
step: usize,
|
step: usize,
|
||||||
solution: Solution,
|
solution: WordData,
|
||||||
wordlist: WL,
|
wordlist: &'wl WL,
|
||||||
finished: bool,
|
finished: bool,
|
||||||
// TODO: keep track of the letters the user has tried
|
// TODO: keep track of the letters the user has tried
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<WL: WordList> Game<WL> {
|
impl<'wl, WL: WordList> Game<'wl, WL> {
|
||||||
/// get a new [`GameBuilder`]
|
/// get a new [`GameBuilder`]
|
||||||
pub fn builder() -> GameBuilder<WL> {
|
pub fn builder() -> GameBuilder<WL> {
|
||||||
GameBuilder::default()
|
GameBuilder::default()
|
||||||
|
@ -44,30 +45,33 @@ impl<WL: WordList> Game<WL> {
|
||||||
length: usize,
|
length: usize,
|
||||||
precompute: bool,
|
precompute: bool,
|
||||||
max_steps: usize,
|
max_steps: usize,
|
||||||
wlist: WL,
|
wlist: &'wl WL,
|
||||||
) -> GameResult<Self> {
|
) -> GameResult<Self> {
|
||||||
// TODO: check if the length is in the range bounds of the wordlist
|
// TODO: check if the length is in the range bounds of the wordlist
|
||||||
let solution = wlist.rand_solution();
|
let solution = wlist.rand_solution();
|
||||||
let game = Game {
|
let game: Game<'wl, WL> = Game {
|
||||||
length,
|
length,
|
||||||
precompute,
|
precompute,
|
||||||
max_steps,
|
max_steps,
|
||||||
step: 1,
|
step: 1,
|
||||||
solution,
|
solution,
|
||||||
wordlist: wlist,
|
wordlist: &wlist,
|
||||||
finished: false,
|
finished: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(game)
|
Ok(game)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(mut self) -> Self {
|
/// Make a new guess
|
||||||
self.solution = self.wordlist.rand_solution();
|
///
|
||||||
self.step = 1;
|
/// The word will be evaluated against the [solution](Game::solution) of the [Game].
|
||||||
self.finished = false;
|
/// A [GuessResponse] will be formulated, showing us which letters are correctly placed, in the
|
||||||
self
|
/// solution, or just wrong.
|
||||||
}
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This function will return an error if the length of the [Word] is wrong It will also error
|
||||||
|
/// if the game is finished.
|
||||||
pub fn guess(&mut self, guess: Word) -> GameResult<GuessResponse> {
|
pub fn guess(&mut self, guess: Word) -> GameResult<GuessResponse> {
|
||||||
if guess.len() != self.length {
|
if guess.len() != self.length {
|
||||||
return Err(GameError::GuessHasWrongLength);
|
return Err(GameError::GuessHasWrongLength);
|
||||||
|
@ -102,7 +106,7 @@ impl<WL: WordList> Game<WL> {
|
||||||
self.length
|
self.length
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn solution(&self) -> &Solution {
|
pub fn solution(&self) -> &WordData {
|
||||||
&self.solution
|
&self.solution
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,10 +157,10 @@ pub struct GameBuilder<WL: WordList> {
|
||||||
|
|
||||||
impl<WL: WordList> GameBuilder<WL> {
|
impl<WL: WordList> GameBuilder<WL> {
|
||||||
/// build a [`Game`] with the stored configuration
|
/// build a [`Game`] with the stored configuration
|
||||||
pub fn build(self) -> GameResult<Game<WL>> {
|
pub fn build(&self) -> GameResult<Game<WL>> {
|
||||||
debug!("{:#?}", self);
|
debug!("{:#?}", self);
|
||||||
let game: Game<WL> =
|
let game: Game<WL> =
|
||||||
Game::build(self.length, self.precompute, self.max_steps, WL::default())?;
|
Game::build(self.length, self.precompute, self.max_steps, &self.wordlist)?;
|
||||||
Ok(game)
|
Ok(game)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +189,15 @@ impl<WL: WordList> GameBuilder<WL> {
|
||||||
debug!("max steps: {:#?}", self.max_steps);
|
debug!("max steps: {:#?}", self.max_steps);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the wordlist for the builder
|
||||||
|
///
|
||||||
|
/// The builder can be used multiple times. Each [`Game`] will have a immutable reference to
|
||||||
|
/// `wl`.
|
||||||
|
pub fn wordlist(mut self, wl: WL) -> Self {
|
||||||
|
self.wordlist = wl;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<WL: WordList> Default for GameBuilder<WL> {
|
impl<WL: WordList> Default for GameBuilder<WL> {
|
||||||
|
|
|
@ -4,10 +4,12 @@ use colored::{ColoredString, Colorize};
|
||||||
use libpt::log::debug;
|
use libpt::log::debug;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
pub type Evaluation = Vec<(char, Status)>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct GuessResponse {
|
pub struct GuessResponse {
|
||||||
guess: Word,
|
guess: Word,
|
||||||
evaluation: Vec<(char, Status)>,
|
evaluation: Evaluation,
|
||||||
step: usize,
|
step: usize,
|
||||||
finish: bool,
|
finish: bool,
|
||||||
win: bool,
|
win: bool,
|
||||||
|
|
|
@ -1 +1,12 @@
|
||||||
|
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>;
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,9 @@ impl super::WordList for BuiltinWList {
|
||||||
fn wordmap(&self) -> &super::WordMap {
|
fn wordmap(&self) -> &super::WordMap {
|
||||||
&self.words
|
&self.words
|
||||||
}
|
}
|
||||||
|
fn get_word(&self, word: &Word) -> Option<super::WordData> {
|
||||||
|
self.words.get(&word)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BuiltinWList {
|
impl Default for BuiltinWList {
|
||||||
|
|
|
@ -8,15 +8,17 @@ pub mod builtin;
|
||||||
pub mod word;
|
pub mod word;
|
||||||
use word::*;
|
use word::*;
|
||||||
|
|
||||||
|
use crate::error::WResult;
|
||||||
|
|
||||||
pub type AnyWordlist = Box<dyn WordList>;
|
pub type AnyWordlist = Box<dyn WordList>;
|
||||||
|
|
||||||
pub trait WordList: Clone + std::fmt::Debug + Default {
|
pub trait WordList: Clone + std::fmt::Debug + Default {
|
||||||
fn solutions(&self) -> ManySolutions {
|
fn solutions(&self) -> ManyWordDatas {
|
||||||
let wmap = self.wordmap();
|
let wmap = self.wordmap();
|
||||||
let threshold = wmap.threshold();
|
let threshold = wmap.threshold();
|
||||||
wmap.iter().filter(|i| *i.1 > threshold).collect()
|
wmap.iter().filter(|i| *i.1 > threshold).collect()
|
||||||
}
|
}
|
||||||
fn rand_solution(&self) -> Solution {
|
fn rand_solution(&self) -> WordData {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let sol = *self.solutions().iter().choose(&mut rng).unwrap();
|
let sol = *self.solutions().iter().choose(&mut rng).unwrap();
|
||||||
(sol.0.to_owned(), sol.1.to_owned())
|
(sol.0.to_owned(), sol.1.to_owned())
|
||||||
|
@ -39,4 +41,5 @@ pub trait WordList: Clone + std::fmt::Debug + Default {
|
||||||
}
|
}
|
||||||
WordMap::new(hm)
|
WordMap::new(hm)
|
||||||
}
|
}
|
||||||
|
fn get_word(&self, word: &Word) -> Option<WordData>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{write, Display};
|
use std::fmt::write;
|
||||||
use std::iter::Sum;
|
|
||||||
use std::ops::RangeFull;
|
|
||||||
|
|
||||||
use libpt::log::debug;
|
use libpt::log::debug;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
@ -11,8 +9,9 @@ pub type Frequency = f64;
|
||||||
|
|
||||||
// PERF: Hash for String is probably a bottleneck
|
// PERF: Hash for String is probably a bottleneck
|
||||||
pub type Word = String;
|
pub type Word = String;
|
||||||
pub type ManySolutions<'a> = Vec<(&'a Word, &'a Frequency)>;
|
pub type WordData = (Word, Frequency);
|
||||||
pub type Solution = (Word, Frequency);
|
pub type ManyWords<'a> = Vec<&'a Word>;
|
||||||
|
pub type ManyWordDatas<'a> = Vec<(&'a Word, &'a Frequency)>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
@ -35,6 +34,7 @@ impl WordMap {
|
||||||
self.inner.iter()
|
self.inner.iter()
|
||||||
}
|
}
|
||||||
pub fn freq_range(&self) -> std::ops::Range<Frequency> {
|
pub fn freq_range(&self) -> std::ops::Range<Frequency> {
|
||||||
|
// TODO: calculate this instead of estimating like this
|
||||||
return 0.1e-10..1e-6;
|
return 0.1e-10..1e-6;
|
||||||
let lowest: Frequency = todo!();
|
let lowest: Frequency = todo!();
|
||||||
let highest: Frequency = todo!();
|
let highest: Frequency = todo!();
|
||||||
|
@ -64,6 +64,12 @@ impl WordMap {
|
||||||
pub fn inner(&self) -> &HashMap<Word, Frequency> {
|
pub fn inner(&self) -> &HashMap<Word, Frequency> {
|
||||||
&self.inner
|
&self.inner
|
||||||
}
|
}
|
||||||
|
pub fn get(&self, word: &Word) -> Option<WordData> {
|
||||||
|
match self.inner.get(word) {
|
||||||
|
Some(f) => Some((word.clone(), *f)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for WordMap {
|
impl std::fmt::Debug for WordMap {
|
||||||
|
|
Loading…
Reference in New Issue