feat: make attempts dynamic

This commit is contained in:
itsscb 2024-09-09 13:40:01 +02:00
parent 492d6b8920
commit 5e1c5b3f07

View File

@ -1,24 +1,22 @@
use super::charstatus::{compare_strings, CharStatus}; use super::charstatus::{compare_strings, CharStatus};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
type Tries = usize; type Attempts = usize;
const MAX_TRIES: Tries = 5;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Game { pub struct Game {
pub word: Option<String>, word: Option<String>,
pub submitted_words: Vec<Vec<CharStatus<String>>>, submitted_words: Vec<Vec<CharStatus<String>>>,
tries: Tries, max_attempts: Attempts,
status: Status, status: Status,
} }
impl Game { impl Game {
#[must_use] #[must_use]
pub const fn new() -> Self { pub const fn new(max_attempts: Attempts) -> Self {
Self { Self {
word: None, word: None,
tries: 0, max_attempts,
submitted_words: Vec::new(), submitted_words: Vec::new(),
status: Status::New, status: Status::New,
} }
@ -35,7 +33,6 @@ impl Game {
if let Some(ref word) = self.word { if let Some(ref word) = self.word {
let res = compare_strings(word, &answer.to_uppercase()); let res = compare_strings(word, &answer.to_uppercase());
self.submitted_words.push(res); self.submitted_words.push(res);
self.tries += 1;
self.status = self.current_status(); self.status = self.current_status();
} }
} }
@ -44,24 +41,16 @@ impl Game {
pub fn current_status(&self) -> Status { pub fn current_status(&self) -> Status {
self.word.as_ref().map_or(Status::New, |_| { self.word.as_ref().map_or(Status::New, |_| {
let word_count = self.submitted_words.len(); let word_count = self.submitted_words.len();
match self.tries { match word_count {
0 => Status::New, 0 => Status::New,
1..MAX_TRIES => self i => self
.submitted_words
.last()
.map_or(Status::InProgress, |words| {
if words.iter().all(|v| matches!(v, CharStatus::Match(_))) {
Status::Win(word_count)
} else {
Status::InProgress
}
}),
_ => self
.submitted_words .submitted_words
.last() .last()
.map_or(Status::Lose(word_count), |words| { .map_or(Status::Lose(word_count), |words| {
if words.iter().all(|v| matches!(v, CharStatus::Match(_))) { if words.iter().all(|v| matches!(v, CharStatus::Match(_))) {
Status::Win(word_count) Status::Win(word_count)
} else if i < self.max_attempts {
Status::InProgress
} else { } else {
Status::Lose(word_count) Status::Lose(word_count)
} }
@ -73,7 +62,7 @@ impl Game {
impl Default for Game { impl Default for Game {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new(5)
} }
} }
@ -81,8 +70,8 @@ impl Default for Game {
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub enum Status { pub enum Status {
New, New,
Win(Tries), Win(Attempts),
Lose(Tries), Lose(Attempts),
InProgress, InProgress,
} }
@ -96,29 +85,35 @@ mod test {
assert_eq!( assert_eq!(
Game { Game {
word: None, word: None,
tries: 0, max_attempts: 5,
submitted_words: Vec::new(), submitted_words: Vec::new(),
status: Status::New, status: Status::New,
}, },
Game::new() Game::default()
); );
} }
#[test] #[test]
#[allow(clippy::field_reassign_with_default)]
fn start() { fn start() {
let word: String = random_word(5); let word: String = random_word(5);
let want = Game { let want = Game {
word: Some(word.to_uppercase()), word: Some(word.to_uppercase()),
submitted_words: Vec::new(), submitted_words: Vec::new(),
tries: 0, max_attempts: 5,
status: Status::InProgress, status: Status::InProgress,
}; };
let mut got = Game::new(); let mut got = Game::default();
got.start(&word); got.start(&word);
assert_eq!(got, want); assert_eq!(got, want);
let mut got = Game::default();
got.word = Some(word.to_uppercase());
assert_ne!(got, want);
} }
#[test] #[test]
@ -132,11 +127,11 @@ mod test {
&word.to_uppercase(), &word.to_uppercase(),
&answer.to_uppercase(), &answer.to_uppercase(),
)], )],
tries: 1, max_attempts: 5,
status: Status::InProgress, status: Status::InProgress,
}; };
let mut got = Game::new(); let mut got = Game::default();
got.start(word); got.start(word);
got.submit_answer(answer); got.submit_answer(answer);
@ -145,7 +140,7 @@ mod test {
#[test] #[test]
fn current_status() { fn current_status() {
let mut got = Game::new(); let mut got = Game::default();
assert_eq!(got.current_status(), Status::New); assert_eq!(got.current_status(), Status::New);
@ -154,7 +149,7 @@ mod test {
let want = Game { let want = Game {
word: Some(word.to_uppercase()), word: Some(word.to_uppercase()),
submitted_words: Vec::new(), submitted_words: Vec::new(),
tries: 0, max_attempts: 5,
status: Status::InProgress, status: Status::InProgress,
}; };
got.start(word); got.start(word);
@ -168,7 +163,7 @@ mod test {
&word.to_uppercase(), &word.to_uppercase(),
&answer.to_uppercase(), &answer.to_uppercase(),
)], )],
tries: 1, max_attempts: 5,
status: Status::InProgress, status: Status::InProgress,
}; };
got.submit_answer(answer); got.submit_answer(answer);
@ -180,12 +175,12 @@ mod test {
got.submit_answer(answer); got.submit_answer(answer);
assert_eq!(got.current_status(), Status::Lose(5)); assert_eq!(got.current_status(), Status::Lose(5));
let mut got = Game::new(); let mut got = Game::default();
got.start(word); got.start(word);
got.submit_answer(word); got.submit_answer(word);
assert_eq!(got.current_status(), Status::Win(1)); assert_eq!(got.current_status(), Status::Win(1));
let mut got = Game::new(); let mut got = Game::default();
got.start(word); got.start(word);
got.submit_answer(answer); got.submit_answer(answer);
got.submit_answer(answer); got.submit_answer(answer);