generated from PlexSheep/rs-base
add interactive solver #4
|
@ -14,6 +14,7 @@ use wordle_analyzer::game::response::GuessResponse;
|
||||||
use wordle_analyzer::solve::{BuiltinSolverNames, Solver};
|
use wordle_analyzer::solve::{BuiltinSolverNames, Solver};
|
||||||
use wordle_analyzer::wlist::builtin::BuiltinWList;
|
use wordle_analyzer::wlist::builtin::BuiltinWList;
|
||||||
use wordle_analyzer::wlist::word::Word;
|
use wordle_analyzer::wlist::word::Word;
|
||||||
|
use wordle_analyzer::wlist::WordList;
|
||||||
use wordle_analyzer::{self, game};
|
use wordle_analyzer::{self, game};
|
||||||
|
|
||||||
#[derive(Parser, Clone, Debug)]
|
#[derive(Parser, Clone, Debug)]
|
||||||
|
@ -69,10 +70,24 @@ enum ReplCommand {
|
||||||
Solve,
|
Solve,
|
||||||
/// Show the current state of the game
|
/// Show the current state of the game
|
||||||
Show,
|
Show,
|
||||||
|
/// Display data about the wordlist
|
||||||
|
Wl {
|
||||||
|
#[command(subcommand)]
|
||||||
|
cmd: WlCommand,
|
||||||
|
},
|
||||||
/// Leave the Repl
|
/// Leave the Repl
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand, Debug, EnumIter, Clone, Default)]
|
||||||
|
enum WlCommand {
|
||||||
|
#[default]
|
||||||
|
Stats,
|
||||||
|
Top {
|
||||||
|
amount: usize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
Logger::builder()
|
Logger::builder()
|
||||||
|
@ -124,6 +139,7 @@ fn help_guess_interactive(cli: Cli) -> anyhow::Result<()> {
|
||||||
// only None if the repl has not stepped yet
|
// only None if the repl has not stepped yet
|
||||||
match repl.command().to_owned().unwrap() {
|
match repl.command().to_owned().unwrap() {
|
||||||
ReplCommand::Exit => break,
|
ReplCommand::Exit => break,
|
||||||
|
ReplCommand::Wl { cmd } => wlcommand_handler(&cli, &cmd, &wl)?,
|
||||||
ReplCommand::Show => {
|
ReplCommand::Show => {
|
||||||
println!("{}", game);
|
println!("{}", game);
|
||||||
}
|
}
|
||||||
|
@ -151,6 +167,21 @@ fn help_guess_interactive(cli: Cli) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wlcommand_handler(cli: &Cli, cmd: &WlCommand, wl: &impl WordList) -> anyhow::Result<()> {
|
||||||
|
match cmd {
|
||||||
|
WlCommand::Stats => {
|
||||||
|
println!("{wl}")
|
||||||
|
}
|
||||||
|
WlCommand::Top { amount } => {
|
||||||
|
println!();
|
||||||
|
for s in wl.n_most_likely(*amount).iter() {
|
||||||
|
println!("\t\"{}\":\t{:.08}%", s.0, s.1 * 100.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn play_native_non_interactive(cli: Cli) -> anyhow::Result<()> {
|
fn play_native_non_interactive(cli: Cli) -> anyhow::Result<()> {
|
||||||
let wl = BuiltinWList::default();
|
let wl = BuiltinWList::default();
|
||||||
let builder = game::Game::builder(&wl)
|
let builder = game::Game::builder(&wl)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::fmt::{write, Debug};
|
use std::fmt::{write, Debug, Display};
|
||||||
|
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
|
@ -54,3 +54,9 @@ impl Debug for BuiltinWList {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for BuiltinWList {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{self:#?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use rand::seq::IteratorRandom;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Display;
|
||||||
use std::ops::RangeBounds;
|
use std::ops::RangeBounds;
|
||||||
|
|
||||||
#[cfg(feature = "builtin")]
|
#[cfg(feature = "builtin")]
|
||||||
|
@ -14,7 +15,7 @@ use crate::error::WResult;
|
||||||
|
|
||||||
pub type AnyWordlist = Box<dyn WordList>;
|
pub type AnyWordlist = Box<dyn WordList>;
|
||||||
|
|
||||||
pub trait WordList: Clone + std::fmt::Debug + Default + Sync {
|
pub trait WordList: Clone + std::fmt::Debug + Default + Sync + Display {
|
||||||
fn solutions(&self) -> ManyWordDatas {
|
fn solutions(&self) -> ManyWordDatas {
|
||||||
let wmap = self.wordmap().clone();
|
let wmap = self.wordmap().clone();
|
||||||
let threshold = wmap.threshold();
|
let threshold = wmap.threshold();
|
||||||
|
@ -41,6 +42,18 @@ pub trait WordList: Clone + std::fmt::Debug + Default + Sync {
|
||||||
fn total_freq(&self) -> Frequency {
|
fn total_freq(&self) -> Frequency {
|
||||||
self.wordmap().values().map(|a| a.to_owned()).sum()
|
self.wordmap().values().map(|a| a.to_owned()).sum()
|
||||||
}
|
}
|
||||||
|
fn sort_likelihood(&self) -> Vec<WordData> {
|
||||||
|
let wmap = self.wordmap();
|
||||||
|
let mut wpairs: Vec<(_, _)> = wmap.iter().collect();
|
||||||
|
wpairs.sort_by(|a, b| a.1.partial_cmp(b.1).unwrap().reverse());
|
||||||
|
wpairs
|
||||||
|
.iter()
|
||||||
|
.map(|v| (v.0.to_owned(), v.1.to_owned()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
fn n_most_likely(&self, n: usize) -> Vec<WordData> {
|
||||||
|
self.sort_likelihood().into_iter().take(n).collect()
|
||||||
|
}
|
||||||
fn over_threashold(&self) -> WordMap {
|
fn over_threashold(&self) -> WordMap {
|
||||||
let wmap = self.wordmap();
|
let wmap = self.wordmap();
|
||||||
let threshold = wmap.threshold();
|
let threshold = wmap.threshold();
|
||||||
|
|
|
@ -10,6 +10,7 @@ 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 WordData = (Word, Frequency);
|
pub type WordData = (Word, Frequency);
|
||||||
|
pub type WordDataRef<'wl> = (&'wl Word, &'wl Frequency);
|
||||||
pub type ManyWordsRef<'a> = Vec<&'a Word>;
|
pub type ManyWordsRef<'a> = Vec<&'a Word>;
|
||||||
pub type ManyWordDatas = Vec<(Word, Frequency)>;
|
pub type ManyWordDatas = Vec<(Word, Frequency)>;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue