Решение на Wordle от Никола Николов

Обратно към всички решения

Към профила на Никола Николов

Резултати

  • 20 точки от тестове
  • 0 бонус точки
  • 20 точки общо
  • 15 успешни тест(а)
  • 0 неуспешни тест(а)

Код

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum GameStatus {
InProgress,
Won,
Lost,
}
#[derive(Debug, PartialEq)]
pub enum GameError {
NotInAlphabet(char),
WrongLength { expected: usize, actual: usize },
GameIsOver(GameStatus),
}
#[derive(Debug, PartialEq)]
pub struct Game {
pub status: GameStatus,
pub attempts: u8,
// Каквито други полета ви трябват
pub alphabet: String,
pub word: String,
pub attempts_history: String
}
#[derive(Debug, PartialEq)]
pub struct Word {
// Каквито полета ви трябват
letters: Vec<Letter>,
}
#[derive(Debug, PartialEq)]
enum Letter {
FullMatch(char),
PartialMatch(char),
NoMatch(char),
}
impl Game {
/// Конструира нова игра с думи/букви от дадената в `alphabet` азбука. Alphabet е просто низ,
/// в който всеки символ е отделна буква, който вероятно искате да си запазите някак за после.
///
/// Подадената дума с `word` трябва да има само букви от тази азбука. Иначе очакваме да върнете
/// `GameError::NotInAlphabet` грешка с първия символ в `word`, който не е от азбуката.
///
/// Началното състояние на играта е `InProgress` а началния брой опити `attempts` е 0.
///
pub fn new(alphabet: &str, word: &str) -> Result<Self, GameError> {
let mut attempts_history = String::new();
for c in word.chars() {
if !alphabet.contains(c) {
return Err(GameError::NotInAlphabet(c))
}
attempts_history.push_str("|_|")
}
Ok(
Self {
status: GameStatus::InProgress,
attempts: 0,
alphabet: String::from(alphabet),
word: String::from(word),
attempts_history
}
)
}
/// Опитва се да познае търсената дума. Опита е в `guess`.
///
/// Ако играта е приключила, тоест статуса ѝ е `Won` или `Lost`, очакваме да върнете
/// `GameIsOver` със статуса, с който е приключила.
///
/// Ако `guess` има различен брой букви от търсената дума, очакваме да върнете
/// `GameError::WrongLength`. Полето `expected` на грешката трябва да съдържа броя букви на
/// търсената дума, а `actual` да е броя букви на опита `guess`.
///
/// Ако `guess` има правилния брой букви, но има буква, която не е от азбуката на играта,
/// очакваме `GameError::NotInAlphabet` както по-горе, с първия символ от `guess`, който не е
/// от азбуката.
///
/// Метода приема `&mut self`, защото всеки валиден опит (такъв, който не връща грешка) се
/// запазва в играта за по-нататък. Метода връща `Word`, което описва освен самите символи на
/// `guess`, и как тези символи са се напаснали на търсената дума. Също така инкрементира
/// `attempts` с 1.
///
/// След опита за напасване на думата, ако всички букви са уцелени на правилните места,
/// очакваме `state` полето да се промени на `Won`. Иначе, ако `attempts` са станали 5,
/// състоянието трябва да е `Lost`.
///
pub fn guess_word(&mut self, guess: &str) -> Result<Word, GameError> {
if self.status == GameStatus::Won || self.status == GameStatus::Lost {
return Err(GameError::GameIsOver(self.status))
}
if guess.chars().count() != self.word.chars().count() {
return Err(GameError::WrongLength { expected: self.word.chars().count(), actual: guess.chars().count() })
}
for c in guess.chars() {
if !self.alphabet.contains(c) {
return Err(GameError::NotInAlphabet(c))
}
}
self.attempts += 1;
if guess == self.word {
self.status = GameStatus::Won
}
else if self.attempts >= 5 {
self.status = GameStatus::Lost
}
let mut letters: Vec<Letter> = Vec::new();
for (idx, c) in guess.chars().enumerate() {
if c == self.word.chars().nth(idx).unwrap() {
letters.push(Letter::FullMatch(c))
}
else if self.word.contains(c) {
letters.push(Letter::PartialMatch(c))
}
else {
letters.push(Letter::NoMatch(c))
}
}
let word = Word { letters };
self.attempts_history.push_str("\n");
self.attempts_history.push_str(&word.to_string());
Ok(
word
)
}
}
use std::fmt;
impl fmt::Display for Word {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut result = String::new();
for l in &self.letters {
match l {
Letter::FullMatch(c) => result.push_str(&String::from(format!("[{}]", c.to_uppercase().to_string()))),
Letter::PartialMatch(c) => result.push_str(&String::from(format!("({})", c.to_uppercase().to_string()))),
Letter::NoMatch(c) => result.push_str(&String::from(format!(">{}<", c.to_uppercase().to_string()))),
}
}
f.write_str(&result)
}
}
impl fmt::Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.attempts_history)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn it_returns_not_in_alphabet_error_when_creating_a_game_with_incorrect_word() {
let alphabet = "abc";
let game = Game::new(alphabet, "aby");
assert_eq!(game, Err(GameError::NotInAlphabet('y')));
}
#[test]
pub fn it_returns_not_in_alphabet_error_when_creating_a_game_with_incorrect_cyrillic_word() {
let alphabet = "абв";
let game = Game::new(alphabet, "агроном");
assert_eq!(game, Err(GameError::NotInAlphabet('г')));
}
#[test]
pub fn it_creates_a_game_with_the_correct_state() {
let alphabet = "abcd";
let game = Game::new(alphabet, "dabb").unwrap();
assert_eq!(game.status, GameStatus::InProgress);
assert_eq!(game.attempts, 0);
assert_eq!(game.alphabet, "abcd");
assert_eq!(game.word, "dabb");
assert_eq!(game.attempts_history, "|_||_||_||_|")
}
#[test]
pub fn it_returns_game_is_over_error_when_trying_to_guess_word_in_ended_game() {
let alphabet = "abcd";
let mut game = Game::new(alphabet, "ab").unwrap();
game.status = GameStatus::Lost;
assert_eq!(game.guess_word("ss"), Err(GameError::GameIsOver(GameStatus::Lost)))
}
#[test]
pub fn it_returns_wrong_length_error_when_trying_to_guess_word_with_wrong_length() {
let alphabet = "abcd";
let mut game = Game::new(alphabet, "ab").unwrap();
assert_eq!(game.guess_word("aaa"), Err(GameError::WrongLength { expected: 2, actual: 3 }))
}
#[test]
pub fn it_returns_not_in_alphabet_error_when_trying_to_guess_word_with_invalid_character() {
let alphabet = "abcd";
let mut game = Game::new(alphabet, "ab").unwrap();
assert_eq!(game.guess_word("au"), Err(GameError::NotInAlphabet('u') ))
}
#[test]
pub fn it_wins_the_game_after_making_a_correct_guess() {
let alphabet = "abcd";
let mut game = Game::new(alphabet, "abc").unwrap();
game.guess_word("abc").unwrap();
assert_eq!(game.status, GameStatus::Won);
}
#[test]
pub fn it_wins_the_game_after_making_a_correct_guess_with_cyrillic() {
let alphabet = "абвг";
let mut game = Game::new(alphabet, "абв").unwrap();
game.guess_word("абв").unwrap();
assert_eq!(game.status, GameStatus::Won);
}
#[test]
pub fn it_loses_the_game_after_running_out_of_attempts() {
let alphabet = "abcd";
let mut game = Game::new(alphabet, "abc").unwrap();
game.guess_word("aaa").unwrap();
game.guess_word("aaa").unwrap();
game.guess_word("aaa").unwrap();
game.guess_word("aaa").unwrap();
game.guess_word("aaa").unwrap();
assert_eq!(game.status, GameStatus::Lost);
}
#[test]
pub fn it_displays_the_correct_state_of_the_guessed_word() {
let english_letters = "abcdefghijklmnopqrstuvwxyz";
let mut game = Game::new(english_letters, "rebus").unwrap();
assert_eq!(game.guess_word("route").unwrap().to_string(), "[R]>O<(U)>T<(E)");
assert_eq!(game.guess_word("rules").unwrap().to_string(), "[R](U)>L<(E)[S]");
assert_eq!(game.guess_word("rebus").unwrap().to_string(), "[R][E][B][U][S]");
}
#[test]
pub fn it_displays_the_correct_state_of_the_guessed_word_when_having_duplicates() {
let english_letters = "abcdefghijklmnopqrstuvwxyz";
let mut game = Game::new(english_letters, "foobar").unwrap();
assert_eq!(game.guess_word("oopsie").unwrap().to_string(), "(O)[O]>P<>S<>I<>E<")
}
#[test]
pub fn it_displays_the_correct_state_of_the_guessed_word_when_using_german() {
let german_letters = "abcdefghijklmnopqrstuvwxyzäöüß";
let mut game = Game::new(german_letters, "süß").unwrap();
assert_eq!(game.guess_word("füß").unwrap().to_string(), ">F<[Ü][SS]")
}
#[test]
pub fn it_displays_the_correct_state_of_the_guessed_word_when_using_cyrillic() {
let alphabet = "абвг";
let mut game = Game::new(alphabet, "абв").unwrap();
assert_eq!(game.guess_word("агб").unwrap().to_string(), "[А]>Г<(Б)")
}
#[test]
pub fn it_displays_the_correct_history_of_the_game() {
let english_letters = "abcdefghijklmnopqrstuvwxyz";
let mut game = Game::new(english_letters, "rebus").unwrap();
game.guess_word("route").unwrap();
game.guess_word("rebus").unwrap();
assert_eq!(game.to_string(), "|_||_||_||_||_|\n[R]>O<(U)>T<(E)\n[R][E][B][U][S]");
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20230111-3772066-1wqtvmd/solution)
    Finished test [unoptimized + debuginfo] target(s) in 0.77s
     Running tests/solution_test.rs (target/debug/deps/solution_test-0edbea2040daef01)

running 15 tests
test solution_test::test_game_display ... ok
test solution_test::test_game_display_cyrillic ... ok
test solution_test::test_game_display_german ... ok
test solution_test::test_game_state_1 ... ok
test solution_test::test_game_state_3 ... ok
test solution_test::test_game_state_2 ... ok
test solution_test::test_word_display ... ok
test solution_test::test_word_display_bulgarian ... ok
test solution_test::test_word_display_german ... ok
test solution_test::test_word_display_with_repetitions ... ok
test solution_test::test_word_not_in_alphabet_on_construction ... ok
test solution_test::test_word_not_in_alphabet_on_construction_cyrrilic ... ok
test solution_test::test_word_not_in_alphabet_on_guess ... ok
test solution_test::test_word_not_in_alphabet_on_guess_cyrillic ... ok
test solution_test::test_wrong_length ... ok

test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

История (1 версия и 0 коментара)

Никола качи първо решение на 23.11.2022 23:34 (преди почти 3 години)