Решение на Wordle от Теодор Борисов
Резултати
- 19 точки от тестове
- 0 бонус точки
- 19 точки общо
- 14 успешни тест(а)
- 1 неуспешни тест(а)
Код
#[derive(Debug)]
pub enum GameStatus {
InProgress,
Won,
Lost,
}
#[derive(Debug)]
pub enum GameError {
NotInAlphabet(char),
WrongLength { expected: usize, actual: usize },
GameIsOver(GameStatus),
EmptyString()
}
#[derive(Debug)]
pub struct Game {
pub status: GameStatus,
pub attempts: u8,
pub word: String,
pub alphabet: String,
pub vec: Vec<String>
}
#[derive(Debug)]
pub struct Word {
pub guess: String,
pub word: String,
}
impl Game {
/// Проверява дали думата е с букви от азбуката
pub fn validate_word(alphabet: &str, word: &str) -> usize {
for i in 1..=word.chars().count() {
let mut is_found = 0;
for j in 1..=alphabet.chars().count() {
if word.chars().nth(i - 1).unwrap() == alphabet.chars().nth(j - 1).unwrap() {
is_found = 1;
break;
}
}
if is_found == 0 {
return i;
}
}
return 0;
}
/// Ако думата е с букви от азбуката, създава се нова игра
pub fn new(alphabet: &str, word: &str) -> Result<Self, GameError> {
if word.chars().count() == 0 {
return Err(GameError::EmptyString());
}
let is_found = Game::validate_word(alphabet, word);
if is_found != 0 {
return Err(GameError::NotInAlphabet(word.chars().nth(is_found - 1).unwrap()));
}
return Ok(Game{ status: GameStatus::InProgress, attempts: 0, word: word.to_string(), alphabet: alphabet.to_string(), vec: vec!["".to_string()] });
}
/// Проверява дали guess е валидна, дали статуса на играта е InProgress.
/// Ако guess е търсената дума статуса на играта се променя на Won.
/// Ако са направени 5 опита, статуса се променя на Lost.
/// Ако дължината на guess е различна от търсената дума връщаме грешка
/// с очаквания брой символи и текущият брой символи
/// Ако в guess има символ, който не е от азбуката, връщаме символа
pub fn guess_word(&mut self, guess: &str) -> Result<Word, GameError> {
if self.attempts == 5 && matches!(self.status, GameStatus::InProgress) {
self.status = GameStatus::Lost;
}
if matches!(self.status, GameStatus::Won) {
return Err(GameError::GameIsOver(GameStatus::Won));
}
if matches!(self.status, GameStatus::Lost) {
return Err(GameError::GameIsOver(GameStatus::Lost));
}
if self.word.chars().count() != guess.chars().count() {
return Err(GameError::WrongLength { expected: self.word.chars().count(), actual: guess.chars().count() });
}
let result = Game::validate_word(&self.alphabet, guess);
if result != 0 {
return Err(GameError::NotInAlphabet(guess.chars().nth(result - 1).unwrap()));
}
self.vec.push(guess.to_string());
self.attempts += 1;
let guess_word = Word { guess: guess.to_string(), word: self.word.to_string() };
let correct_word = Word { guess: self.word.to_string(), word: self.word.to_string() };
if guess_word.to_string() == correct_word.to_string() {
self.status = GameStatus::Won;
}
return Ok(guess_word);
}
}
use std::fmt;
impl fmt::Display for Word {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.word.chars().count() {
if self.word.chars().nth(i).unwrap() == self.guess.chars().nth(i).unwrap() {
if self.guess.chars().nth(i).unwrap().is_ascii() {
write!(f, "[{}]", self.guess.chars().nth(i).unwrap().to_ascii_uppercase())?;
}
else {
write!(f, "[{}]", self.guess.chars().nth(i).unwrap().to_uppercase())?;
}
}
else {
let mut not_contain = 0;
for j in 0..self.word.chars().count() {
if i != j {
if self.word.chars().nth(j).unwrap() == self.guess.chars().nth(i).unwrap() {
if self.guess.chars().nth(i).unwrap().is_ascii() {
write!(f, "({})", self.guess.chars().nth(i).unwrap().to_ascii_uppercase())?;
}
else {
write!(f, "({})", self.guess.chars().nth(i).unwrap().to_uppercase())?;
}
not_contain = 1;
break;
}
}
}
if not_contain == 0 {
if self.guess.chars().nth(i).unwrap().is_ascii() {
write!(f, ">{}<", self.guess.chars().nth(i).unwrap().to_ascii_uppercase())?;
}
else {
write!(f, ">{}<", self.guess.chars().nth(i).unwrap().to_uppercase())?;
}
}
}
}
Ok(())
}
}
impl fmt::Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for k in 0..self.vec.len() {
if k == 0 {
for _ in 0..self.word.chars().count() {
write!(f, "|_|")?;
}
}
else {
writeln!(f)?;
for i in 0..self.word.chars().count() {
if self.word.chars().nth(i) == self.vec[k].chars().nth(i) {
if self.word.chars().nth(i).unwrap().is_ascii() {
write!(f, "[{}]", self.word.chars().nth(i).unwrap().to_ascii_uppercase())?;
}
else {
write!(f, "[{}]", self.word.chars().nth(i).unwrap().to_uppercase())?;
}
}
else {
let mut not_contain = 0;
for j in 0..self.word.chars().count() {
if i != j {
if self.word.chars().nth(j) == self.vec[k].chars().nth(i) {
if self.vec[k].chars().nth(i).unwrap().is_ascii() {
write!(f, "({})", self.vec[k].chars().nth(i).unwrap().to_ascii_uppercase())?;
}
else {
write!(f, "({})", self.vec[k].chars().nth(i).unwrap().to_uppercase())?;
}
not_contain = 1;
break;
}
}
}
if not_contain == 0 {
if self.vec[k].chars().nth(i).unwrap().is_ascii() {
write!(f, ">{}<", self.vec[k].chars().nth(i).unwrap().to_ascii_uppercase())?;
}
else {
write!(f, ">{}<", self.vec[k].chars().nth(i).unwrap().to_uppercase())?;
}
}
}
}
}
}
Ok(())
}
}
#[test]
fn test_basic() {
let english_letters = "abcdefghijklmnopqrstuvwxyz";
assert!(Game::new(english_letters, "!!!").is_err());
let mut game = Game::new(&String::from(english_letters), "abc").unwrap();
assert!(matches!(game.status, GameStatus::InProgress));
assert_eq!(game.attempts, 0);
assert_eq!(game.to_string(), "|_||_||_|");
assert_eq!(game.guess_word("abc").unwrap().to_string(), "[A][B][C]");
}
#[test]
fn test_make_symbols() {
let english_letters = "abcdefghijklmnopqrstuvwxyz!.,";
let mut game = Game::new(&String::from(english_letters), "!.,").unwrap();
assert_eq!(game.guess_word("ddd").unwrap().to_string(), ">D<>D<>D<");
assert_eq!(game.guess_word("!.,").unwrap().to_string(), "[!][.][,]");
}
#[test]
fn test_make_a_lot_of_attemps() {
let english_letters = "abcdefghijklmnopqrstuvwxyz";
let mut game = Game::new(&String::from(english_letters), "abc").unwrap();
assert_eq!(game.guess_word("ddd").unwrap().to_string(), ">D<>D<>D<");
assert_eq!(game.guess_word("bbb").unwrap().to_string(), "(B)[B](B)");
assert_eq!(game.guess_word("fbv").unwrap().to_string(), ">F<[B]>V<");
assert_eq!(game.guess_word("cbn").unwrap().to_string(), "(C)[B]>N<");
assert_eq!(game.guess_word("gbc").unwrap().to_string(), ">G<[B][C]");
assert!(game.guess_word("abc").is_err());
assert_eq!(game.to_string(), "|_||_||_|\n>D<>D<>D<\n(B)[B](B)\n>F<[B]>V<\n(C)[B]>N<\n>G<[B][C]");
}
#[test]
fn test_empty_string() {
let english_letters = "abcdefghijklmnopqrstuvwxyz";
assert!(Game::new(&String::from(english_letters), "").is_err());
}
#[test]
fn test_wrong_length() {
let english_letters = "abcdefghijklmnopqrstuvwxyz";
let mut game = Game::new(&String::from(english_letters), "abc").unwrap();
assert!(game.guess_word("dddd").is_err());
assert!(matches!(game.status, GameStatus::InProgress));
assert_eq!(game.attempts, 0);
assert_eq!(game.to_string(), "|_||_||_|");
}
#[test]
fn test_won() {
let english_letters = "abcdefghijklmnopqrstuvwxyz";
let mut game = Game::new(&String::from(english_letters), "abc").unwrap();
assert_eq!(game.to_string(), "|_||_||_|");
assert_eq!(game.guess_word("cba").unwrap().to_string(), "(C)[B](A)");
assert_eq!(game.guess_word("abc").unwrap().to_string(), "[A][B][C]");
assert!(game.guess_word("abc").is_err());
assert_eq!(game.attempts, 2);
}
#[test]
fn test_wrong_alphabet_when_create() {
let english_letters = "cdefghijklmnopqrstuvwxyz";
assert!(Game::new(english_letters, "!!!").is_err());
}
#[test]
fn test_wrong_alphabet_when_guess() {
let english_letters = "abcyz";
let mut game = Game::new(&String::from(english_letters), "abc").unwrap();
assert_eq!(game.to_string(), "|_||_||_|");
assert!(game.guess_word("ghn").is_err());
assert_eq!(game.attempts, 0);
assert_eq!(game.to_string(), "|_||_||_|");
}
#[test]
fn test_make_a_lot_of_attemps_bg() {
let bulgarian_letters = "абвгдежзийклмнопрстуфхцчшщъьюя";
let mut game = Game::new(&String::from(bulgarian_letters), "къща").unwrap();
assert_eq!(game.guess_word("абвг").unwrap().to_string(), "(А)>Б<>В<>Г<");
assert_eq!(game.guess_word("дежа").unwrap().to_string(), ">Д<>Е<>Ж<[А]");
assert_eq!(game.guess_word("зийа").unwrap().to_string(), ">З<>И<>Й<[А]");
assert_eq!(game.guess_word("клма").unwrap().to_string(), "[К]>Л<>М<[А]");
assert_eq!(game.guess_word("кноа").unwrap().to_string(), "[К]>Н<>О<[А]");
assert!(game.guess_word("кпра").is_err());
assert_eq!(game.to_string(), "|_||_||_||_|\n(А)>Б<>В<>Г<\n>Д<>Е<>Ж<[А]\n>З<>И<>Й<[А]\n[К]>Л<>М<[А]\n[К]>Н<>О<[А]");
}
#[test]
fn test_wrong_length_bg() {
let bulgarian_letters = "абвгдежзийклмнопрстуфхцчшщъьюя";
let mut game = Game::new(&String::from(bulgarian_letters), "къща").unwrap();
assert!(game.guess_word("абвгд").is_err());
assert!(matches!(game.status, GameStatus::InProgress));
assert_eq!(game.attempts, 0);
assert_eq!(game.to_string(), "|_||_||_||_|");
}
#[test]
fn test_won_bg() {
let bulgarian_letters = "абвгдежзийклмнопрстуфхцчшщъьюя";
let mut game = Game::new(&String::from(bulgarian_letters), "къща").unwrap();
assert_eq!(game.to_string(), "|_||_||_||_|");
assert_eq!(game.guess_word("тъща").unwrap().to_string(), ">Т<[Ъ][Щ][А]");
assert_eq!(game.guess_word("къща").unwrap().to_string(), "[К][Ъ][Щ][А]");
assert!(game.guess_word("лллл").is_err());
assert_eq!(game.attempts, 2);
}
#[test]
fn test_wrong_alphabet_when_create_bg() {
let bulgarian_letters = "абвгдежзийклмнопрстуфхцчшщъьюя";
assert!(Game::new(bulgarian_letters, "!!!").is_err());
}
#[test]
fn test_wrong_alphabet_when_guess_bg() {
let english_letters = "абвге";
let mut game = Game::new(&String::from(english_letters), "абв").unwrap();
assert_eq!(game.to_string(), "|_||_||_|");
assert!(game.guess_word("дже").is_err());
assert_eq!(game.attempts, 0);
assert_eq!(game.to_string(), "|_||_||_|");
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20230111-3772066-o9aa2j/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_state_1 ... ok test solution_test::test_game_state_2 ... FAILED test solution_test::test_game_display_german ... 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 ... 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_word_not_in_alphabet_on_guess_cyrillic ... ok test solution_test::test_wrong_length ... ok failures: ---- solution_test::test_game_state_2 stdout ---- thread 'solution_test::test_game_state_2' panicked at 'Expression InProgress does not match the pattern "GameStatus::Lost"', tests/solution_test.rs:159:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: solution_test::test_game_state_2 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`