generated from PlexSheep/rs-base
refactor(solve): try to hack the idea of "idk the solution yet" into the game
This commit is contained in:
parent
44ed7210c4
commit
6a9a99aa51
|
@ -34,6 +34,7 @@ rayon = "1.10.0"
|
|||
regex = "1.10.3"
|
||||
serde = { version = "1.0.197", optional = true, features = ["serde_derive"] }
|
||||
serde_json = { version = "1.0.114", optional = true }
|
||||
strum = "0.26.3"
|
||||
# serde_with = "3.7.0"
|
||||
thiserror = "1.0.58"
|
||||
|
||||
|
|
|
@ -2,15 +2,19 @@
|
|||
// #![warn(missing_docs)]
|
||||
#![warn(missing_debug_implementations)]
|
||||
|
||||
use std::process::exit;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use libpt::cli::{
|
||||
console::style,
|
||||
indicatif,
|
||||
repl::{DefaultRepl, Repl},
|
||||
strum,
|
||||
};
|
||||
use libpt::log::*;
|
||||
use strum::IntoEnumIterator;
|
||||
use strum::{EnumIter, IntoEnumIterator};
|
||||
|
||||
use wordle_analyzer::game::response::GuessResponse;
|
||||
use wordle_analyzer::game::{response::GuessResponse, Game, GameBuilder};
|
||||
|
||||
use wordle_analyzer::solve::{BuiltinSolverNames, Solver};
|
||||
use wordle_analyzer::wlist::builtin::BuiltinWList;
|
||||
|
@ -35,6 +39,30 @@ struct Cli {
|
|||
/// which solver to use
|
||||
#[arg(short, long, default_value_t = BuiltinSolverNames::default())]
|
||||
solver: BuiltinSolverNames,
|
||||
|
||||
/// set if the solver should play a full native game without interaction
|
||||
#[arg(short, long)]
|
||||
non_interactive: bool,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug, EnumIter, Clone)]
|
||||
enum ReplCommand {
|
||||
/// Let the user input the response to the last guess
|
||||
///
|
||||
/// Format:
|
||||
///
|
||||
/// 'x' means wrong character
|
||||
///
|
||||
/// 'p' means present character
|
||||
///
|
||||
/// 'c' means correct character
|
||||
Response { encoded: String },
|
||||
/// Let the user input a word they guessed
|
||||
Guess { your_guess: String },
|
||||
/// Let the solver make a guess
|
||||
Solve,
|
||||
/// Leave the Repl
|
||||
Exit,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
|
@ -45,8 +73,59 @@ fn main() -> anyhow::Result<()> {
|
|||
.unwrap();
|
||||
trace!("dumping CLI: {:#?}", cli);
|
||||
|
||||
// let repl = libpt::cli::repl::DefaultRepl::<ReplCommand>::default();
|
||||
if cli.non_interactive {
|
||||
play_native_non_interactive(cli)?;
|
||||
exit(0);
|
||||
}
|
||||
help_guess_interactive(cli)
|
||||
}
|
||||
|
||||
fn help_guess_interactive(cli: Cli) -> anyhow::Result<()> {
|
||||
let wl = BuiltinWList::default();
|
||||
let builder = game::Game::builder(&wl)
|
||||
.length(cli.length)
|
||||
.max_steps(cli.max_steps)
|
||||
.precompute(cli.precompute);
|
||||
let solver = cli.solver.to_solver(&wl);
|
||||
let mut game = builder.build()?;
|
||||
|
||||
let mut repl = libpt::cli::repl::DefaultRepl::<ReplCommand>::default();
|
||||
|
||||
debug!("entering the repl");
|
||||
loop {
|
||||
// repl.step() should be at the start of your loop
|
||||
// It is here that the repl will get the user input, validate it, and so on
|
||||
match repl.step() {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
// if the user requested the help, print in blue, otherwise in red as it's just an
|
||||
// error
|
||||
if let libpt::cli::repl::error::Error::Parsing(e) = &e {
|
||||
if e.kind() == clap::error::ErrorKind::DisplayHelp {
|
||||
println!("{}", style(e).cyan());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
println!("{}", style(e).red().bold());
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// now we can match our defined commands
|
||||
//
|
||||
// only None if the repl has not stepped yet
|
||||
match repl.command().to_owned().unwrap() {
|
||||
ReplCommand::Exit => break,
|
||||
ReplCommand::Guess { your_guess } => {
|
||||
println!("{}", game.guess(your_guess)?)
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn play_native_non_interactive(cli: Cli) -> anyhow::Result<()> {
|
||||
let wl = BuiltinWList::default();
|
||||
let builder = game::Game::builder(&wl)
|
||||
.length(cli.length)
|
||||
|
@ -72,6 +151,5 @@ fn main() -> anyhow::Result<()> {
|
|||
} else {
|
||||
println!("You lose! The solution was {:?}.", game.solution());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ where
|
|||
precompute: bool,
|
||||
max_steps: usize,
|
||||
step: usize,
|
||||
solution: WordData,
|
||||
solution: Option<WordData>,
|
||||
wordlist: &'wl WL,
|
||||
finished: bool,
|
||||
responses: Vec<GuessResponse>,
|
||||
|
@ -57,7 +57,7 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
|||
precompute,
|
||||
max_steps,
|
||||
step: 0,
|
||||
solution,
|
||||
solution: Some(solution),
|
||||
wordlist: wlist,
|
||||
finished: false,
|
||||
responses: Vec::new(),
|
||||
|
@ -72,6 +72,8 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
|||
/// A [GuessResponse] will be formulated, showing us which letters are correctly placed, in the
|
||||
/// solution, or just wrong.
|
||||
///
|
||||
/// Note that you do not need to use the [GuessResponse], it is appended to the game state.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the length of the [Word] is wrong It will also error
|
||||
|
@ -88,34 +90,36 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
|||
}
|
||||
self.step += 1;
|
||||
|
||||
let mut compare_solution = self.solution.0.clone();
|
||||
let mut evaluation = Vec::new();
|
||||
let mut status: Status;
|
||||
for (idx, c) in guess.chars().enumerate() {
|
||||
if compare_solution.chars().nth(idx) == Some(c) {
|
||||
status = Status::Matched;
|
||||
compare_solution.replace_range(idx..idx + 1, "_");
|
||||
} else if compare_solution.contains(c) {
|
||||
status = Status::Exists;
|
||||
compare_solution = compare_solution.replacen(c, "_", 1);
|
||||
} else {
|
||||
status = Status::None
|
||||
}
|
||||
evaluation.push((c, status));
|
||||
}
|
||||
|
||||
let response = GuessResponse::new(guess, evaluation, self);
|
||||
self.responses.push(response.clone());
|
||||
self.finished = response.finished();
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub fn evaluate(mut solution: WordData, guess: Word) -> Vec<()> {
|
||||
let mut evaluation = Vec::new();
|
||||
let mut status: Status;
|
||||
for (idx, c) in guess.chars().enumerate() {
|
||||
if solution.0.chars().nth(idx) == Some(c) {
|
||||
status = Status::Matched;
|
||||
solution.0.replace_range(idx..idx + 1, "_");
|
||||
} else if solution.0.contains(c) {
|
||||
status = Status::Exists;
|
||||
solution.0 = solution.0.replacen(c, "_", 1);
|
||||
} else {
|
||||
status = Status::None
|
||||
}
|
||||
evaluation.push((c, status));
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn length(&self) -> usize {
|
||||
self.length
|
||||
}
|
||||
|
||||
pub fn solution(&self) -> &WordData {
|
||||
&self.solution
|
||||
pub fn solution(&self) -> Option<&WordData> {
|
||||
self.solution.as_ref()
|
||||
}
|
||||
|
||||
pub fn step(&self) -> usize {
|
||||
|
|
Loading…
Reference in New Issue