From d9d84f8a11044cf55ed1d2a440dd1cdb88eafdca Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Tue, 23 Jul 2024 11:22:12 +0200 Subject: [PATCH] feat(solve): add wl commands for show and top words --- src/bin/solve/simple.rs | 31 +++++++++++++++++++++++++++++++ src/wlist/builtin.rs | 8 +++++++- src/wlist/mod.rs | 15 ++++++++++++++- src/wlist/word.rs | 1 + 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/bin/solve/simple.rs b/src/bin/solve/simple.rs index 622fcc0..8da8854 100644 --- a/src/bin/solve/simple.rs +++ b/src/bin/solve/simple.rs @@ -14,6 +14,7 @@ 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::wlist::WordList; use wordle_analyzer::{self, game}; #[derive(Parser, Clone, Debug)] @@ -69,10 +70,24 @@ enum ReplCommand { Solve, /// Show the current state of the game Show, + /// Display data about the wordlist + Wl { + #[command(subcommand)] + cmd: WlCommand, + }, /// Leave the Repl Exit, } +#[derive(Subcommand, Debug, EnumIter, Clone, Default)] +enum WlCommand { + #[default] + Stats, + Top { + amount: usize, + }, +} + fn main() -> anyhow::Result<()> { let cli = Cli::parse(); Logger::builder() @@ -124,6 +139,7 @@ fn help_guess_interactive(cli: Cli) -> anyhow::Result<()> { // only None if the repl has not stepped yet match repl.command().to_owned().unwrap() { ReplCommand::Exit => break, + ReplCommand::Wl { cmd } => wlcommand_handler(&cli, &cmd, &wl)?, ReplCommand::Show => { println!("{}", game); } @@ -151,6 +167,21 @@ fn help_guess_interactive(cli: Cli) -> anyhow::Result<()> { 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<()> { let wl = BuiltinWList::default(); let builder = game::Game::builder(&wl) diff --git a/src/wlist/builtin.rs b/src/wlist/builtin.rs index 3204376..116e66f 100644 --- a/src/wlist/builtin.rs +++ b/src/wlist/builtin.rs @@ -1,4 +1,4 @@ -use std::fmt::{write, Debug}; +use std::fmt::{write, Debug, Display}; 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:#?}") + } +} diff --git a/src/wlist/mod.rs b/src/wlist/mod.rs index 155ec24..0e7a28e 100644 --- a/src/wlist/mod.rs +++ b/src/wlist/mod.rs @@ -3,6 +3,7 @@ use rand::seq::IteratorRandom; use regex::Regex; use std::collections::HashMap; +use std::fmt::Display; use std::ops::RangeBounds; #[cfg(feature = "builtin")] @@ -14,7 +15,7 @@ use crate::error::WResult; pub type AnyWordlist = Box; -pub trait WordList: Clone + std::fmt::Debug + Default + Sync { +pub trait WordList: Clone + std::fmt::Debug + Default + Sync + Display { fn solutions(&self) -> ManyWordDatas { let wmap = self.wordmap().clone(); let threshold = wmap.threshold(); @@ -41,6 +42,18 @@ pub trait WordList: Clone + std::fmt::Debug + Default + Sync { fn total_freq(&self) -> Frequency { self.wordmap().values().map(|a| a.to_owned()).sum() } + fn sort_likelihood(&self) -> Vec { + 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 { + self.sort_likelihood().into_iter().take(n).collect() + } fn over_threashold(&self) -> WordMap { let wmap = self.wordmap(); let threshold = wmap.threshold(); diff --git a/src/wlist/word.rs b/src/wlist/word.rs index 1defc1f..b4f55ce 100644 --- a/src/wlist/word.rs +++ b/src/wlist/word.rs @@ -10,6 +10,7 @@ pub type Frequency = f64; // PERF: Hash for String is probably a bottleneck pub type Word = String; pub type WordData = (Word, Frequency); +pub type WordDataRef<'wl> = (&'wl Word, &'wl Frequency); pub type ManyWordsRef<'a> = Vec<&'a Word>; pub type ManyWordDatas = Vec<(Word, Frequency)>;