Решение на Wordle от Антон Янчев
Резултати
- 19 точки от тестове
- 0 бонус точки
- 19 точки общо
- 14 успешни тест(а)
- 1 неуспешни тест(а)
Код
use std::fmt;
use std::collections::HashSet;
use std::collections::HashMap;
#[derive(Debug, Copy, Clone, PartialEq)]
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,
// Каквито други полета ви трябват
pub alphabet : HashSet<char>,
pub correct_word : Word,
pub history : String
}
#[derive(Debug)]
pub enum Letter {
Unknown(char),
FullMatch(char),
PartialMatch(char),
NoMatch(char),
}
#[derive(Debug)]
pub struct Word {
// Каквито полета ви трябват
pub letters: Vec<Letter>
}
impl Word {
pub fn new(word: &str) -> Self
{
let mut letters = Vec::new();
for c in word.chars() {
letters.push(Letter::Unknown(c));
}
Word { letters }
}
// Maps the letters to their index
pub fn to_hashmap(&self) -> HashMap<&char, usize>
{
let mut map = HashMap::new();
for (i,letter) in self.letters.iter().enumerate() {
match letter
{
Letter::Unknown(c) => map.insert(c,i),
Letter::FullMatch(c) => map.insert(c,i),
Letter::PartialMatch(c) => map.insert(c,i),
Letter::NoMatch(c) => map.insert(c,i)
};
}
map
}
}
impl Game {
/// Конструира нова игра с думи/букви от дадената в `alphabet` азбука. Alphabet е просто низ,
/// в който всеки символ е отделна буква, който вероятно искате да си запазите някак за после.
///
/// Подадената дума с `word` трябва да има само букви от тази азбука. Иначе очакваме да върнете
/// `GameError::NotInAlphabet` грешка с първия символ в `word`, който не е от азбуката.
///
/// Началното състояние на играта е `InProgress` а началния брой опити `attempts` е 0.
///
pub fn new(alphabet: &str, word: &str) -> Result<Self, GameError> {
let alphabet_set: HashSet<char> = alphabet.chars().collect();
for c in word.chars() {
if !alphabet_set.contains(&c) {
return Err(GameError::NotInAlphabet(c))
}
}
let correct_word = Word::new(word);
let history = std::iter::repeat("|_|").take(word.chars().count()).collect::<String>();
Ok(Game {status: GameStatus::InProgress, attempts: 0, alphabet: alphabet_set, correct_word, 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> {
let correct_len = self.correct_word.letters.len();
let guess_len = guess.chars().count();
let correct_letters = self.correct_word.to_hashmap();
let mut result = Word::new(guess);
let mut failed_to_guess = false;
match &self.status {
GameStatus::InProgress => (),
_ => return Err(GameError::GameIsOver(self.status))
}
if correct_len != guess_len
{
return Err(GameError::WrongLength {expected: correct_len, actual: guess_len})
}
for c in guess.chars() {
if !self.alphabet.contains(&c) {
return Err(GameError::NotInAlphabet(c))
}
}
for (i,c) in guess.chars().enumerate() {
if correct_letters.contains_key(&c) // checks if letter is a partial match
{
if i == *correct_letters.get(&c).unwrap() // checks if letter is a full match
{
result.letters[i] = Letter::FullMatch(c);
}else {
result.letters[i] = Letter::PartialMatch(c);
failed_to_guess = true;
}
}else{
result.letters[i] = Letter::NoMatch(c);
failed_to_guess = true;
}
}
self.attempts = self.attempts + 1;
if self.attempts == 5 {
self.status = GameStatus::Lost;
}
if !failed_to_guess {
self.status = GameStatus::Won;
}
self.history.push('\n');
self.history.push_str(&result.to_string());
Ok(result)
}
}
impl fmt::Display for Word {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut result = String::new();
for letter in &self.letters {
match letter
{
Letter::FullMatch(c) => result.push_str(&format!("[{}]", c.to_uppercase())),
Letter::PartialMatch(c) => result.push_str(&format!("({})", c.to_uppercase())),
Letter::NoMatch(c) => result.push_str(&format!(">{}<", c.to_uppercase())),
Letter::Unknown(c) => result.push_str(&format!("{}", c.to_uppercase()))
}
}
write!(f, "{}", result)
}
}
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-1qpaoxm/solution) 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_german ... ok test solution_test::test_word_display_bulgarian ... ok test solution_test::test_word_not_in_alphabet_on_construction ... ok test solution_test::test_word_display_with_repetitions ... FAILED 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_word_not_in_alphabet_on_guess_cyrillic ... ok test solution_test::test_wrong_length ... ok failures: ---- solution_test::test_word_display_with_repetitions stdout ---- thread 'solution_test::test_word_display_with_repetitions' panicked at 'assertion failed: `(left == right)` left: `"(O)(O)(P)>S<"`, right: `"(O)[O](P)>S<"`', tests/solution_test.rs:67:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: solution_test::test_word_display_with_repetitions test result: FAILED. 14 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass `--test solution_test`