Решение на Wordle от Билян Хаджи

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

Към профила на Билян Хаджи

Резултати

  • 17 точки от тестове
  • 0 бонус точки
  • 17 точки общо
  • 13 успешни тест(а)
  • 2 неуспешни тест(а)

Код

use std::collections::HashSet;
use std::fmt;
#[derive(Debug, Clone, Copy)]
pub enum GameStatus {
InProgress,
Won,
Lost,
}
#[derive(Debug)]
pub enum GameError {
NotInAlphabet(char),
WrongLength { expected: usize, actual: usize },
GameIsOver(GameStatus),
}
#[derive(Debug)]
pub struct Game {
pub status: GameStatus,
pub attempts: u8,
// Каквито други полета ви трябват
alphabet: HashSet<char>,
to_be_guessed: String,
guesses_history: Vec<Word>,
max_guess_count: u8
}
#[derive(Debug, Clone)]
pub struct Word {
// Каквито полета ви трябват
value: String,
letters: Vec<Letter>
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum LetterStatus {
NotPresent,
PresentWrongSpot,
PresentRightSpot
}
#[derive(Debug, Clone)]
pub struct Letter {
value: char,
status: LetterStatus
}
impl Game {
/// Конструира нова игра с думи/букви от дадената в `alphabet` азбука. Alphabet е просто низ,
/// в който всеки символ е отделна буква, който вероятно искате да си запазите някак за после.
///
/// Подадената дума с `word` трябва да има само букви от тази азбука. Иначе очакваме да върнете
/// `GameError::NotInAlphabet` грешка с първия символ в `word`, който не е от азбуката.
///
/// Началното състояние на играта е `InProgress` а началния брой опити `attempts` е 0.
///
pub fn new(alphabet: &str, word: &str) -> Result<Self, GameError> {
let alphabet_set = Self::distinct_chars(&alphabet);
match Self::validate_word_conforms_to_alphabet(&alphabet_set, &word) {
Some(err) => Err(err),
None => {
let status = GameStatus::InProgress;
let attempts = 0;
let to_be_guessed = String::from(word);
let guesses_history = vec!();
let max_guess_count = 5;
let game = Game {
status, attempts, alphabet: alphabet_set, to_be_guessed, guesses_history, max_guess_count
};
Ok(game)
}
}
}
fn validate_word_conforms_to_alphabet(alphabet_set: &HashSet<char>, word: &str) -> Option<GameError> {
let word_letters = Self::distinct_chars(&word);
for &word_letter in word_letters.iter() {
if !alphabet_set.contains(&word_letter) {
return Some(GameError::NotInAlphabet(word_letter));
}
}
None
}
fn distinct_chars(str: &str) -> HashSet<char> {
let mut set = HashSet::new();
for c in str.chars() {
set.insert(c);
}
set
}
/// Опитва се да познае търсената дума. Опита е в `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> {
match self.status {
GameStatus::InProgress => {
match self.validate_guess_length(guess) {
Some(err) => Err(err),
None => {
match Self::validate_word_conforms_to_alphabet(&self.alphabet, guess) {
Some(err) => Err(err),
None => {
self.attempts += 1;
let letters = self.generate_letter_state(guess);
let word = Word {value: String::from(guess), letters};
self.guesses_history.push(word.clone());
if word.all_letters_match_guess() {
self.status = GameStatus::Won;
} else if self.attempts >= self.max_guess_count {
self.status = GameStatus::Lost;
}
Ok(word)
}
}
}
}
},
_ => Err::<Word, GameError>(GameError::GameIsOver(self.status))
}
}
fn generate_letter_state(&self, guess: &str) -> Vec<Letter> {
let mut letters = vec!();
for (c1, c2) in guess.chars().zip(self.to_be_guessed.chars()) {
let letter_status;
if c1 == c2 {
letter_status = LetterStatus::PresentRightSpot;
} else if self.to_be_guessed.contains(&c1.to_string()) {
letter_status = LetterStatus::PresentWrongSpot;
} else {
letter_status = LetterStatus::NotPresent;
}
letters.push(Letter{value: c1, status: letter_status});
}
letters
}
fn validate_guess_length(&self, guess: &str) -> Option<GameError> {
let guess_length = guess.len();
let to_be_guessed_length = self.to_be_guessed.len();
if guess_length != to_be_guessed_length {
Some(GameError::WrongLength{expected: to_be_guessed_length, actual: guess_length})
} else {
None
}
}
}
impl Word {
pub fn all_letters_match_guess(&self) -> bool {
self.letters.iter().all(|letter| letter.status == LetterStatus::PresentRightSpot)
}
}
impl fmt::Display for Letter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let uppercased_letter = self.value.to_uppercase();
match self.status {
LetterStatus::PresentRightSpot => write!(f, "[{}]", uppercased_letter),
LetterStatus::PresentWrongSpot => write!(f, "({})", uppercased_letter),
LetterStatus::NotPresent => write!(f, ">{}<", uppercased_letter)
}
}
}
impl fmt::Display for Word {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for l in self.letters.iter() {
write!(f, "{}", l).unwrap();
}
Ok(())
}
}
impl fmt::Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for _ in 0..self.to_be_guessed.chars().count() {
write!(f, "|_|").unwrap();
}
let history_len = self.guesses_history.len();
if history_len > 0 {
write!(f, "\n").unwrap();
}
for (i, word) in self.guesses_history.iter().enumerate() {
write!(f, "{}", word).unwrap();
if i != history_len - 1 {
write!(f, "\n").unwrap();
}
}
Ok(())
}
}

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

Compiling solution v0.1.0 (/tmp/d20230111-3772066-qyvsr1/solution)
warning: field `value` is never read
  --> src/lib.rs:32:5
   |
30 | pub struct Word {
   |            ---- field in this struct
31 |     // Каквито полета ви трябват
32 |     value: String,
   |     ^^^^^
   |
   = note: `Word` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis
   = note: `#[warn(dead_code)]` on by default

warning: `solution` (lib) generated 1 warning
    Finished test [unoptimized + debuginfo] target(s) in 0.91s
     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_2 ... ok
test solution_test::test_game_state_3 ... 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_guess ... ok
test solution_test::test_word_not_in_alphabet_on_construction_cyrrilic ... FAILED
test solution_test::test_word_not_in_alphabet_on_guess_cyrillic ... FAILED
test solution_test::test_wrong_length ... ok

failures:

---- solution_test::test_word_not_in_alphabet_on_construction_cyrrilic stdout ----
thread 'solution_test::test_word_not_in_alphabet_on_construction_cyrrilic' panicked at 'Expression Err(NotInAlphabet('а')) does not match the pattern "Err(GameError::NotInAlphabet('о'))"', tests/solution_test.rs:27:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- solution_test::test_word_not_in_alphabet_on_guess_cyrillic stdout ----
thread 'solution_test::test_word_not_in_alphabet_on_guess_cyrillic' panicked at 'Expression Err(WrongLength { expected: 4, actual: 8 }) does not match the pattern "Err(GameError::NotInAlphabet('х'))"', tests/solution_test.rs:46:5


failures:
    solution_test::test_word_not_in_alphabet_on_construction_cyrrilic
    solution_test::test_word_not_in_alphabet_on_guess_cyrillic

test result: FAILED. 13 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--test solution_test`

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

Билян качи първо решение на 24.11.2022 00:12 (преди почти 3 години)