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"
|
regex = "1.10.3"
|
||||||
serde = { version = "1.0.197", optional = true, features = ["serde_derive"] }
|
serde = { version = "1.0.197", optional = true, features = ["serde_derive"] }
|
||||||
serde_json = { version = "1.0.114", optional = true }
|
serde_json = { version = "1.0.114", optional = true }
|
||||||
|
strum = "0.26.3"
|
||||||
# serde_with = "3.7.0"
|
# serde_with = "3.7.0"
|
||||||
thiserror = "1.0.58"
|
thiserror = "1.0.58"
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,19 @@
|
||||||
// #![warn(missing_docs)]
|
// #![warn(missing_docs)]
|
||||||
#![warn(missing_debug_implementations)]
|
#![warn(missing_debug_implementations)]
|
||||||
|
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use libpt::cli::{
|
use libpt::cli::{
|
||||||
|
console::style,
|
||||||
|
indicatif,
|
||||||
repl::{DefaultRepl, Repl},
|
repl::{DefaultRepl, Repl},
|
||||||
strum,
|
strum,
|
||||||
};
|
};
|
||||||
use libpt::log::*;
|
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::solve::{BuiltinSolverNames, Solver};
|
||||||
use wordle_analyzer::wlist::builtin::BuiltinWList;
|
use wordle_analyzer::wlist::builtin::BuiltinWList;
|
||||||
|
@ -35,6 +39,30 @@ struct Cli {
|
||||||
/// which solver to use
|
/// which solver to use
|
||||||
#[arg(short, long, default_value_t = BuiltinSolverNames::default())]
|
#[arg(short, long, default_value_t = BuiltinSolverNames::default())]
|
||||||
solver: BuiltinSolverNames,
|
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<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
|
@ -45,8 +73,59 @@ fn main() -> anyhow::Result<()> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
trace!("dumping CLI: {:#?}", cli);
|
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 wl = BuiltinWList::default();
|
||||||
let builder = game::Game::builder(&wl)
|
let builder = game::Game::builder(&wl)
|
||||||
.length(cli.length)
|
.length(cli.length)
|
||||||
|
@ -72,6 +151,5 @@ fn main() -> anyhow::Result<()> {
|
||||||
} else {
|
} else {
|
||||||
println!("You lose! The solution was {:?}.", game.solution());
|
println!("You lose! The solution was {:?}.", game.solution());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ where
|
||||||
precompute: bool,
|
precompute: bool,
|
||||||
max_steps: usize,
|
max_steps: usize,
|
||||||
step: usize,
|
step: usize,
|
||||||
solution: WordData,
|
solution: Option<WordData>,
|
||||||
wordlist: &'wl WL,
|
wordlist: &'wl WL,
|
||||||
finished: bool,
|
finished: bool,
|
||||||
responses: Vec<GuessResponse>,
|
responses: Vec<GuessResponse>,
|
||||||
|
@ -57,7 +57,7 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
||||||
precompute,
|
precompute,
|
||||||
max_steps,
|
max_steps,
|
||||||
step: 0,
|
step: 0,
|
||||||
solution,
|
solution: Some(solution),
|
||||||
wordlist: wlist,
|
wordlist: wlist,
|
||||||
finished: false,
|
finished: false,
|
||||||
responses: Vec::new(),
|
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
|
/// A [GuessResponse] will be formulated, showing us which letters are correctly placed, in the
|
||||||
/// solution, or just wrong.
|
/// solution, or just wrong.
|
||||||
///
|
///
|
||||||
|
/// Note that you do not need to use the [GuessResponse], it is appended to the game state.
|
||||||
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// This function will return an error if the length of the [Word] is wrong It will also error
|
/// 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;
|
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);
|
let response = GuessResponse::new(guess, evaluation, self);
|
||||||
self.responses.push(response.clone());
|
self.responses.push(response.clone());
|
||||||
self.finished = response.finished();
|
self.finished = response.finished();
|
||||||
Ok(response)
|
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 {
|
pub fn length(&self) -> usize {
|
||||||
self.length
|
self.length
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn solution(&self) -> &WordData {
|
pub fn solution(&self) -> Option<&WordData> {
|
||||||
&self.solution
|
self.solution.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&self) -> usize {
|
pub fn step(&self) -> usize {
|
||||||
|
|
Loading…
Reference in New Issue