From 6c267b66a5f21a62774f2ad349aa46dc3da40c23 Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Thu, 21 Mar 2024 11:17:01 +0100 Subject: [PATCH] structure of Game (very cool) my commits are super professional --- Cargo.toml | 17 ++++++-- src/bench/mod.rs | 0 src/bin/cliwordle.rs | 3 -- src/bin/game/cli.rs | 39 ++++++++++++++++++ src/bin/game/tui.rs | 0 src/game/mod.rs | 87 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 +++ src/solvers/mod.rs | 0 src/solvers/naive/mod.rs | 0 9 files changed, 144 insertions(+), 7 deletions(-) create mode 100644 src/bench/mod.rs delete mode 100644 src/bin/cliwordle.rs create mode 100644 src/bin/game/cli.rs create mode 100644 src/bin/game/tui.rs create mode 100644 src/game/mod.rs create mode 100644 src/solvers/mod.rs create mode 100644 src/solvers/naive/mod.rs diff --git a/Cargo.toml b/Cargo.toml index d9d8b3c..6915c1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,16 +10,25 @@ readme = "README.md" homepage = "https://git.cscherr.de/PlexSheep/wordle-analyzer" repository = "https://git.cscherr.de/PlexSheep/wordle-analyzer" keywords = ["wordle", "benchmark"] -default-run = "wordle" +default-run = "wordlec" [features] -default = ["game", "bench"] +default = ["game", "bench", "tui"] game = [] +tui = ["game"] bench = [] [dependencies] +anyhow = "1.0.81" +clap = { version = "4.5.3", features = ["derive"] } +libpt = "0.4.2" [[bin]] -name = "cliwordle" -path = "src/bin/cliwordle.rs" +name = "wordlec" +path = "src/bin/game/cli.rs" required-features = ["game"] + +[[bin]] +name = "wordlet" +path = "src/bin/game/tui.rs" +required-features = ["tui", "game"] diff --git a/src/bench/mod.rs b/src/bench/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/bin/cliwordle.rs b/src/bin/cliwordle.rs deleted file mode 100644 index ee80563..0000000 --- a/src/bin/cliwordle.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - unimplemented!(); -} diff --git a/src/bin/game/cli.rs b/src/bin/game/cli.rs new file mode 100644 index 0000000..9bbd785 --- /dev/null +++ b/src/bin/game/cli.rs @@ -0,0 +1,39 @@ +use clap::Parser; +use libpt::log::*; +use wordle_analyzer::{game,self}; + +#[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 +} + +fn main() -> anyhow::Result<()> { + let cli = Cli::parse(); + Logger::build_mini(Some(Level::TRACE))?; + debug!("dumping CLI: {:#?}", cli); + + let game = game::Game::builder() + .length(cli.length) + .precompute(cli.precompute).build()?; + + Ok(()) +} + +fn get_word(cli: &Cli) -> String { + let mut word = String::new(); + + todo!("get user input"); + todo!("validate user input"); + + assert_eq!(word.len(), cli.length); + word +} diff --git a/src/bin/game/tui.rs b/src/bin/game/tui.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/game/mod.rs b/src/game/mod.rs new file mode 100644 index 0000000..98f94b6 --- /dev/null +++ b/src/game/mod.rs @@ -0,0 +1,87 @@ +pub struct Game { + length: usize, + precompute: bool, + max_steps: usize, + step: usize, + solution: String +} + +impl Game { + /// get a new [`GameBuilder`] + pub fn builder() -> GameBuilder { + GameBuilder::default() + } + /// Create a [Game] of wordle + /// + /// This method will load the wordlist, determine if a word may be used as a solution for a + /// game, and select a solution at random. + /// + /// It will also set a few values to their initial state. + /// + /// Don't use this method directly, instead, make use of the [`GameBuilder`]. + /// + /// # Errors + /// + /// This function will return an error if . + pub(crate) fn build(length: usize, precompute: bool, max_steps: usize) -> anyhow::Result<(Self)> { + let mut game = Game { + length, precompute, max_steps, + step: 0, + solution: String::default() // we actually set this later + }; + + + // TODO: load wordlist of possible answers + // TODO: select one as a solution at random + // NOTE: The possible answers should be determined with a wordlist that has the + // frequencies/probabilities of the words. We then use a sigmoid function to determine if a + // word can be a solution based on that value. Only words above some threshold of + // commonness will be available as solutions then. Next, we choose one of the allowed words + // randomly. + todo!(); + } +} + +impl Default for Game { + fn default() -> Self { + GameBuilder::default() + .build() + .expect("could not build game with defaults") + } +} + +pub struct GameBuilder { + length: usize, + precompute: bool, + max_steps: usize +} + +impl GameBuilder { + /// build a [`Game`] with the stored configuration + pub fn build(self) -> anyhow::Result { + let game: Game = Game::build(self.length, self.precompute, self.max_steps)?; + Ok(game) + } + + /// Sets the precompute of this [`GameBuilder`]. + pub fn precompute(mut self, precompute: bool) -> Self { + self.precompute = precompute; + self + } + + /// Sets the length of this [`GameBuilder`]. + pub fn length(mut self, length: usize) -> Self { + self.length = length; + self + } +} + +impl Default for GameBuilder { + fn default() -> Self { + Self { + length: super::DEFAULT_WORD_LENGTH, + precompute: false, + max_steps: super::DEFAULT_MAX_STEPS + } + } +} diff --git a/src/lib.rs b/src/lib.rs index e69de29..79a48d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -0,0 +1,5 @@ +pub const DEFAULT_WORD_LENGTH: usize = 5; +pub const DEFAULT_MAX_STEPS: usize = 6; + +pub mod game; +pub mod solvers; diff --git a/src/solvers/mod.rs b/src/solvers/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/solvers/naive/mod.rs b/src/solvers/naive/mod.rs new file mode 100644 index 0000000..e69de29