Решение на Wordle от Даниел Георгиев

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

Към профила на Даниел Георгиев

Резултати

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

Код

use std::collections::HashSet;
#[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<String>,
word : Vec<String>,
word_chars_set : HashSet<String>,
history : String,
}
#[derive(Debug)]
enum LetterState {
ExactMatch(String),
PartialMatch(String),
NoMatch(String),
}
#[derive(Debug)]
pub struct Word {
letter_states : Vec<LetterState>,
}
impl Game {
/// Конструира нова игра с думи/букви от дадената в `alphabet` азбука. Alphabet е просто низ,
/// в който всеки символ е отделна буква, който вероятно искате да си запазите някак за после.
///
/// Подадената дума с `word` трябва да има само букви от тази азбука. Иначе очакваме да върнете
/// `GameError::NotInAlphabet` грешка с първия символ в `word`, който не е от азбуката.
///
/// Началното състояние на играта е `InProgress` а началния брой опити `attempts` е 0.
///
pub fn new(alphabet: &str, word: &str) -> Result<Self, GameError> {
let alphabet_chars_set = alphabet.chars()
.map(|c| c.to_uppercase().collect())
.collect::<HashSet<String>>();
let mut word_vec = Vec::<String>::new();
let mut history = String::new();
for c in word.chars() {
let letter_upper = c.to_uppercase().collect::<String>();
if !alphabet_chars_set.contains(&letter_upper) {
return Err(GameError::NotInAlphabet(c))
}
word_vec.push(letter_upper);
history.push_str("|_|");
}
let word_chars_set : HashSet<String> = word_vec.iter()
.cloned()
.collect();
Ok(
Self{
status : GameStatus::InProgress,
attempts : 0,
alphabet : alphabet_chars_set,
word : word_vec,
word_chars_set,
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 let GameStatus::InProgress = self.status {
} else {
return Err(
GameError::GameIsOver(self.status)
)
}
let guess_char_count = guess.chars().count();
if self.word.len() != guess_char_count {
return Err(
GameError::WrongLength {
expected : self.word.len(),
actual : guess_char_count
}
)
}
let mut word_res = Vec::<LetterState>::new();
let mut correct_letter_guesses : usize = 0;
for it in self.word.iter().zip(guess.chars()) {
let (word_char, guess_char) = it;
let guess_char_upper = guess_char.to_uppercase()
.collect::<String>();
if !self.alphabet.contains(&guess_char_upper) {
return Err(
GameError::NotInAlphabet(guess_char)
)
}
if word_char == &guess_char_upper {
word_res.push(LetterState::ExactMatch(guess_char_upper));
correct_letter_guesses += 1;
} else if self.word_chars_set.contains(&guess_char_upper) {
word_res.push(LetterState::PartialMatch(guess_char_upper));
} else {
word_res.push(LetterState::NoMatch(guess_char_upper));
}
}
self.attempts += 1;
if correct_letter_guesses == self.word.len() {
self.status = GameStatus::Won;
} else if self.attempts == 5 {
self.status = GameStatus::Lost;
};
let result = Word { letter_states : word_res };
self.history.push('\n');
self.history.push_str(result.to_string().as_str());
Ok(result)
}
}
use std::fmt;
impl fmt::Display for Word {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for letter in self.letter_states.iter() {
match letter {
LetterState::ExactMatch(l) => write!(f, "[{}]", l)?,
LetterState::PartialMatch(l) => write!(f, "({})", l)?,
LetterState::NoMatch(l) => write!(f, ">{}<", l)?
};
}
Ok(())
}
}
impl fmt::Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.history)
}
}

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

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

running 15 tests
test solution_test::test_game_display_cyrillic ... ok
test solution_test::test_game_display ... ok
test solution_test::test_game_state_1 ... ok
test solution_test::test_game_display_german ... 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_not_in_alphabet_on_construction ... ok
test solution_test::test_word_display_with_repetitions ... ok
test solution_test::test_word_not_in_alphabet_on_guess ... ok
test solution_test::test_word_not_in_alphabet_on_construction_cyrrilic ... ok
test solution_test::test_wrong_length ... ok
test solution_test::test_word_not_in_alphabet_on_guess_cyrillic ... ok

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

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

Даниел качи първо решение на 22.11.2022 19:09 (преди почти 3 години)

Даниел качи решение на 22.11.2022 19:13 (преди почти 3 години)

use std::collections::HashSet;
#[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<String>,
word : Vec<String>,
word_chars_set : HashSet<String>,
history : String,
}
#[derive(Debug)]
enum LetterState {
ExactMatch(String),
PartialMatch(String),
NoMatch(String),
}
#[derive(Debug)]
pub struct Word {
letter_states : Vec<LetterState>,
}
impl Game {
/// Конструира нова игра с думи/букви от дадената в `alphabet` азбука. Alphabet е просто низ,
/// в който всеки символ е отделна буква, който вероятно искате да си запазите някак за после.
///
/// Подадената дума с `word` трябва да има само букви от тази азбука. Иначе очакваме да върнете
/// `GameError::NotInAlphabet` грешка с първия символ в `word`, който не е от азбуката.
///
/// Началното състояние на играта е `InProgress` а началния брой опити `attempts` е 0.
///
pub fn new(alphabet: &str, word: &str) -> Result<Self, GameError> {
let alphabet_chars_set = alphabet.chars()
.map(|c| c.to_uppercase().collect())
.collect::<HashSet<String>>();
let mut word_vec = Vec::<String>::new();
let mut history = String::new();
for c in word.chars() {
let letter_upper = c.to_uppercase().collect::<String>();
if !alphabet_chars_set.contains(&letter_upper) {
return Err(GameError::NotInAlphabet(c))
}
word_vec.push(letter_upper);
history.push_str("|_|");
}
let word_chars_set : HashSet<String> = word_vec.iter()
.cloned()
.collect();
Ok(
Self{
status : GameStatus::InProgress,
attempts : 0,
alphabet : alphabet_chars_set,
word : word_vec,
word_chars_set,
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 let GameStatus::InProgress = self.status {
} else {
return Err(
GameError::GameIsOver(self.status)
)
}
let guess_char_count = guess.chars().count();
if self.word.len() != guess_char_count {
return Err(
GameError::WrongLength {
expected : self.word.len(),
actual : guess_char_count
}
)
}
let mut word_res = Vec::<LetterState>::new();
let mut correct_letter_guesses : usize = 0;
for it in self.word.iter().zip(guess.chars()) {
let (word_char, guess_char) = it;
let guess_char_upper = guess_char.to_uppercase()
.collect::<String>();
if !self.alphabet.contains(&guess_char_upper) {
return Err(
GameError::NotInAlphabet(guess_char)
)
}
if word_char == &guess_char_upper {
word_res.push(LetterState::ExactMatch(guess_char_upper));
correct_letter_guesses += 1;
} else if self.word_chars_set.contains(&guess_char_upper) {
word_res.push(LetterState::PartialMatch(guess_char_upper));
} else {
word_res.push(LetterState::NoMatch(guess_char_upper));
}
}
self.attempts += 1;
if correct_letter_guesses == self.word.len() {
self.status = GameStatus::Won;
} else if self.attempts == 5 {
self.status = GameStatus::Lost;
};
let result = Word { letter_states : word_res };
self.history.push('\n');
- self.history.push_str(format!("{}", result).as_str());
+ self.history.push_str(result.to_string().as_str());
Ok(result)
}
}
use std::fmt;
impl fmt::Display for Word {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for letter in self.letter_states.iter() {
match letter {
LetterState::ExactMatch(l) => write!(f, "[{}]", l)?,
LetterState::PartialMatch(l) => write!(f, "({})", l)?,
LetterState::NoMatch(l) => write!(f, ">{}<", l)?
};
}
Ok(())
}
}
impl fmt::Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.history)
}
}