generated from PlexSheep/rs-base
refactor: game without solution seems to become possible?
cargo devel CI / cargo CI (push) Successful in 1m54s
Details
cargo devel CI / cargo CI (push) Successful in 1m54s
Details
This commit is contained in:
parent
e9a2223fc0
commit
1f8b85a152
|
@ -51,7 +51,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
let mut guess: Word;
|
let mut guess: Word;
|
||||||
loop {
|
loop {
|
||||||
guess = get_word(&cli, game.step())?;
|
guess = get_word(&cli, game.step())?;
|
||||||
response = match game.guess(guess) {
|
response = match game.guess(guess, None) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(err) => match err {
|
Err(err) => match err {
|
||||||
GameError::GuessHasWrongLength(len) => {
|
GameError::GuessHasWrongLength(len) => {
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
// #![warn(missing_docs)]
|
// #![warn(missing_docs)]
|
||||||
#![warn(missing_debug_implementations)]
|
#![warn(missing_debug_implementations)]
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::{Parser, Subcommand};
|
||||||
|
use libpt::cli::console::style;
|
||||||
use libpt::cli::{repl::Repl, strum};
|
use libpt::cli::{repl::Repl, strum};
|
||||||
use libpt::log::*;
|
use libpt::log::*;
|
||||||
use strum::{EnumIter, IntoEnumIterator};
|
use strum::{EnumIter, IntoEnumIterator};
|
||||||
|
|
||||||
|
use wordle_analyzer::game::response::Evaluation;
|
||||||
use wordle_analyzer::game::{response::GuessResponse, Game, GameBuilder};
|
use wordle_analyzer::game::{response::GuessResponse, Game, GameBuilder};
|
||||||
|
|
||||||
use wordle_analyzer::solve::{BuiltinSolverNames, Solver};
|
use wordle_analyzer::solve::{BuiltinSolverNames, Solver};
|
||||||
|
@ -50,8 +52,11 @@ enum ReplCommand {
|
||||||
///
|
///
|
||||||
/// 'c' means correct character
|
/// 'c' means correct character
|
||||||
Response { encoded: String },
|
Response { encoded: String },
|
||||||
/// Let the user input a word they guessed
|
/// Let the user input a word and the response for that word
|
||||||
Guess { your_guess: String },
|
Guess {
|
||||||
|
your_guess: String,
|
||||||
|
evalutation: Evaluation,
|
||||||
|
},
|
||||||
/// Let the solver make a guess
|
/// Let the solver make a guess
|
||||||
Solve,
|
Solve,
|
||||||
/// Leave the Repl
|
/// Leave the Repl
|
||||||
|
@ -68,7 +73,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
if cli.non_interactive {
|
if cli.non_interactive {
|
||||||
play_native_non_interactive(cli)?;
|
play_native_non_interactive(cli)?;
|
||||||
exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
help_guess_interactive(cli)
|
help_guess_interactive(cli)
|
||||||
}
|
}
|
||||||
|
@ -109,8 +114,11 @@ 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::Guess { your_guess } => {
|
ReplCommand::Guess {
|
||||||
println!("{}", game.guess(your_guess)?)
|
your_guess,
|
||||||
|
evalutation,
|
||||||
|
} => {
|
||||||
|
println!("{}", game.guess(your_guess, Some(evalutation))?)
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use core::panic;
|
||||||
|
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::wlist::word::{ManyWordsRef, Word, WordData};
|
use crate::wlist::word::{ManyWordsRef, Word, WordData};
|
||||||
use crate::wlist::WordList;
|
use crate::wlist::WordList;
|
||||||
|
@ -9,7 +11,7 @@ use response::GuessResponse;
|
||||||
|
|
||||||
pub mod summary;
|
pub mod summary;
|
||||||
|
|
||||||
use self::response::Status;
|
use self::response::{Evaluation, Status};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Game<'wl, WL>
|
pub struct Game<'wl, WL>
|
||||||
|
@ -78,7 +80,7 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
||||||
///
|
///
|
||||||
/// 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
|
||||||
/// if the game is finished.
|
/// if the game is finished.
|
||||||
pub fn guess(&mut self, guess: Word) -> GameResult<GuessResponse> {
|
pub fn guess(&mut self, guess: Word, eval: Option<Evaluation>) -> GameResult<GuessResponse> {
|
||||||
if guess.len() != self.length {
|
if guess.len() != self.length {
|
||||||
return Err(GameError::GuessHasWrongLength(guess.len()));
|
return Err(GameError::GuessHasWrongLength(guess.len()));
|
||||||
}
|
}
|
||||||
|
@ -90,13 +92,20 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
||||||
}
|
}
|
||||||
self.step += 1;
|
self.step += 1;
|
||||||
|
|
||||||
let response = GuessResponse::new(guess, evaluation, self);
|
let response;
|
||||||
|
if eval.is_some() && self.solution.is_none() {
|
||||||
|
response = GuessResponse::new(&guess, eval.unwrap(), self);
|
||||||
|
} else if let Some(solution) = self.solution.clone() {
|
||||||
|
response = GuessResponse::new(&guess, Self::evaluate(solution, &guess), self);
|
||||||
|
} else {
|
||||||
|
panic!("there is neither an evaluation nor a predefined solution for this guess");
|
||||||
|
}
|
||||||
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<()> {
|
pub fn evaluate(mut solution: WordData, guess: &Word) -> Evaluation {
|
||||||
let mut evaluation = Vec::new();
|
let mut evaluation = Vec::new();
|
||||||
let mut status: Status;
|
let mut status: Status;
|
||||||
for (idx, c) in guess.chars().enumerate() {
|
for (idx, c) in guess.chars().enumerate() {
|
||||||
|
@ -111,7 +120,7 @@ impl<'wl, WL: WordList> Game<'wl, WL> {
|
||||||
}
|
}
|
||||||
evaluation.push((c, status));
|
evaluation.push((c, status));
|
||||||
}
|
}
|
||||||
todo!()
|
evaluation.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn length(&self) -> usize {
|
pub fn length(&self) -> usize {
|
||||||
|
|
|
@ -3,7 +3,9 @@ use crate::wlist::WordList;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::convert::Infallible;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use super::Game;
|
use super::Game;
|
||||||
|
|
||||||
|
@ -13,15 +15,42 @@ pub struct AtomicEvaluation {
|
||||||
char: char,
|
char: char,
|
||||||
status: Status,
|
status: Status,
|
||||||
}
|
}
|
||||||
pub type Evaluation = Vec<(char, Status)>;
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
|
pub struct Evaluation {
|
||||||
|
inner: Vec<EvaluationUnit>,
|
||||||
|
}
|
||||||
|
pub type EvaluationUnit = (char, Status);
|
||||||
|
|
||||||
|
impl IntoIterator for Evaluation {
|
||||||
|
type Item = EvaluationUnit;
|
||||||
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.inner.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<EvaluationUnit>> for Evaluation {
|
||||||
|
fn from(value: Vec<EvaluationUnit>) -> Self {
|
||||||
|
Self { inner: value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Evaluation {
|
||||||
|
type Err = Infallible;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
// TODO: make this proper
|
||||||
|
Ok(vec![('x', Status::None)].into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
// #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct GuessResponse {
|
pub struct GuessResponse {
|
||||||
guess: Word,
|
guess: Word,
|
||||||
evaluation: Evaluation,
|
evaluation: Evaluation,
|
||||||
finish: bool,
|
finish: bool,
|
||||||
solution: WordData,
|
solution: Option<WordData>,
|
||||||
step: usize,
|
step: usize,
|
||||||
max_steps: usize,
|
max_steps: usize,
|
||||||
}
|
}
|
||||||
|
@ -35,24 +64,16 @@ pub enum Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GuessResponse {
|
impl GuessResponse {
|
||||||
pub(crate) fn new<WL: WordList>(
|
pub(crate) fn new<WL: WordList>(guess: &Word, status: Evaluation, game: &Game<WL>) -> Self {
|
||||||
guess: Word,
|
let new = Self {
|
||||||
status: Vec<(char, Status)>,
|
guess: guess.to_owned(),
|
||||||
game: &Game<WL>,
|
|
||||||
) -> Self {
|
|
||||||
let finish: bool = if game.step() > game.max_steps() {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
guess == game.solution().0
|
|
||||||
};
|
|
||||||
Self {
|
|
||||||
guess,
|
|
||||||
evaluation: status,
|
evaluation: status,
|
||||||
finish,
|
finish: game.step() > game.max_steps(),
|
||||||
solution: game.solution().clone(),
|
solution: game.solution().cloned(),
|
||||||
step: game.step(),
|
step: game.step(),
|
||||||
max_steps: game.max_steps(),
|
max_steps: game.max_steps(),
|
||||||
}
|
};
|
||||||
|
new
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finished(&self) -> bool {
|
pub fn finished(&self) -> bool {
|
||||||
|
@ -60,18 +81,18 @@ impl GuessResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn won(&self) -> bool {
|
pub fn won(&self) -> bool {
|
||||||
self.guess == self.solution.0
|
let mut ok = true;
|
||||||
|
for i in self.evaluation.clone().into_iter() {
|
||||||
|
ok &= i.1 == Status::Matched
|
||||||
|
}
|
||||||
|
ok
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn solution(&self) -> Option<WordData> {
|
pub fn solution(&self) -> Option<WordData> {
|
||||||
if self.won() {
|
self.solution.clone()
|
||||||
Some(self.solution.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evaluation(&self) -> &[(char, Status)] {
|
pub fn evaluation(&self) -> &Evaluation {
|
||||||
&self.evaluation
|
&self.evaluation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +111,7 @@ impl GuessResponse {
|
||||||
|
|
||||||
impl Display for GuessResponse {
|
impl Display for GuessResponse {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
for s in &self.evaluation {
|
for s in self.evaluation.clone().into_iter() {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}",
|
"{}",
|
||||||
|
|
|
@ -51,7 +51,7 @@ pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug + Sized + Sync {
|
||||||
///
|
///
|
||||||
/// This function will return an error if [guess_for](Solver::guess_for) fails.
|
/// This function will return an error if [guess_for](Solver::guess_for) fails.
|
||||||
fn make_a_move(&self, game: &mut Game<'wl, WL>) -> WResult<GuessResponse> {
|
fn make_a_move(&self, game: &mut Game<'wl, WL>) -> WResult<GuessResponse> {
|
||||||
Ok(game.guess(self.guess_for(game))?)
|
Ok(game.guess(self.guess_for(game), None)?)
|
||||||
}
|
}
|
||||||
/// Play a [Game] and return the last [GuessResponse].
|
/// Play a [Game] and return the last [GuessResponse].
|
||||||
///
|
///
|
||||||
|
|
|
@ -21,7 +21,13 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
|
||||||
let mut other_chars: Vec<char> = Vec::new();
|
let mut other_chars: Vec<char> = Vec::new();
|
||||||
let response = game.last_response();
|
let response = game.last_response();
|
||||||
if response.is_some() {
|
if response.is_some() {
|
||||||
for (idx, p) in response.unwrap().evaluation().iter().enumerate() {
|
for (idx, p) in response
|
||||||
|
.unwrap()
|
||||||
|
.evaluation()
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
if p.1 == Status::Matched {
|
if p.1 == Status::Matched {
|
||||||
pattern.replace_range(idx..idx + 1, &p.0.to_string());
|
pattern.replace_range(idx..idx + 1, &p.0.to_string());
|
||||||
} else if p.1 == Status::Exists {
|
} else if p.1 == Status::Exists {
|
||||||
|
|
Loading…
Reference in New Issue