Решение на Hangman от Андрей

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

Към профила на Андрей

Резултати

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

Код

use std::collections::HashSet;
use std::fmt::{self, Display, Write};
use std::iter::FromIterator;
use std::str::FromStr;
#[derive(Debug)]
pub enum GameError {
ParseError(String),
BadGuess(String),
InvalidSolution(String),
GameOver,
}
impl Display for GameError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
&GameError::ParseError(ref input) => &input,
&GameError::BadGuess(ref message) => &message,
&GameError::InvalidSolution(ref word) => &word,
&GameError::GameOver => "Game is already over!",
})
}
}
#[derive(Debug)]
pub enum Command {
TryLetter(char),
TryWord(String),
Info,
Help,
Quit,
}
impl FromStr for Command {
type Err = GameError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim().to_lowercase();
macro_rules! err {
() => {
Err(GameError::ParseError(format!("Invalid command: {:?}. Try the 'help' command for a list of valid commands", s)))
}
}
match s.chars().nth(0) {
Some('q') => Ok(Command::Quit),
Some('i') => Ok(Command::Info),
Some('h') => Ok(Command::Help),
Some('t') => {
let words = s.split_whitespace().collect::<Vec<&str>>();
let guess = match words.get(2) {
Some(word) => word,
None => return err!(),
};
let command = match words.get(1).and_then(|s| s.chars().nth(0)) {
Some(c) => c,
None => return err!(),
};
if command == 'l' {
if guess.chars().count() > 1 {
err!()
} else if let Some(c) = guess.chars().nth(0) {
Ok(Command::TryLetter(c))
} else {
err!()
}
} else if command == 'w' {
Ok(Command::TryWord(String::from(*guess)))
} else {
err!()
}
},
_ => err!(),
}
}
}
pub enum GameState {
InProgress,
Won,
Lost,
}
pub struct Game {
pub attempted_letters: HashSet<char>,
pub attempted_words: HashSet<String>,
pub attempts_remaining: u32,
state: GameState,
solution: String,
solution_letters: HashSet<char>
}
impl Game {
pub fn new(solution: &str, attempts: u32) -> Result<Self, GameError> {
if solution.is_empty() {
return Err(GameError::InvalidSolution(String::new()))
}
if !solution.chars().all(char::is_alphabetic) {
return Err(GameError::InvalidSolution(String::from(solution)))
}
let solution = String::from(solution);
let attempted_letters = HashSet::new();
let attempted_words = HashSet::new();
let solution_letters = HashSet::from_iter(solution.chars());
Ok(Game {
solution, solution_letters,
attempted_letters, attempted_words,
attempts_remaining: attempts,
state: GameState::InProgress,
})
}
pub fn guess_letter(&mut self, guess: char) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameError::GameOver);
}
if self.attempted_letters.contains(&guess) {
return Err(GameError::BadGuess(String::from("already attempted this letter!")));
}
self.attempted_letters.insert(guess);
if self.attempted_letters.is_superset(&self.solution_letters) {
self.state = GameState::Won;
Ok(true)
} else if self.solution.chars().find(|c| *c == guess).is_some() {
Ok(true)
} else {
self.attempts_remaining -= 1;
if self.attempts_remaining == 0 {
self.state = GameState::Lost;
}
Ok(false)
}
}
pub fn guess_word(&mut self, guess: &str) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameError::GameOver);
}
if self.attempted_words.contains(guess) {
return Err(GameError::BadGuess(String::from("already attempted this word!")));
}
self.attempted_words.insert(String::from(guess));
if guess == self.solution {
self.state = GameState::Won;
Ok(true)
} else {
self.attempts_remaining -= 1;
if self.attempts_remaining == 0 {
self.state = GameState::Lost;
}
Ok(false)
}
}
pub fn is_over(&self) -> bool {
match self.state {
GameState::InProgress => false,
_ => true,
}
}
}
impl Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut chars = self.solution.chars();
match self.state {
GameState::Won => {
return f.write_fmt(format_args!("You won! ^_^\nThe word was: {}", self.solution))
},
GameState::Lost => {
return f.write_fmt(format_args!("You lost! :/\nThe word was: {}", self.solution))
},
GameState::InProgress => f.write_fmt(format_args!("Guesses remaining: {}\n", self.attempts_remaining))?,
}
if let Some(letter) = chars.next() {
if self.attempted_letters.contains(&letter) {
f.write_char(letter)?;
} else {
f.write_char('_')?;
}
while let Some(letter) = chars.next() {
f.write_char(' ')?;
if self.attempted_letters.contains(&letter) {
f.write_char(letter)?;
} else {
f.write_char('_')?;
}
}
}
Ok(())
}
}

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

Compiling solution v0.1.0 (file:///tmp/d20171210-6053-1mbr9tf/solution)
    Finished dev [unoptimized + debuginfo] target(s) in 5.39 secs
     Running target/debug/deps/solution-3f98bfa5c86a5dd9

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/solution_test-3d9e4ea2eafbbc82

running 15 tests
test solution_test::test_command_parsing_cyrillic ... ok
test solution_test::test_command_parsing_extra_stuff ... ok
test solution_test::test_command_parsing_full_words ... ok
test solution_test::test_command_parsing_partial_words ... ok
test solution_test::test_command_parsing_spacing ... ok
test solution_test::test_command_parsing_special ... ok
test solution_test::test_game_basic ... ok
test solution_test::test_game_cyrillic ... ok
test solution_test::test_game_display ... ok
test solution_test::test_game_error ... ok
test solution_test::test_game_guess_basic ... ok
test solution_test::test_game_guess_state_lose ... ok
test solution_test::test_game_guess_state_won ... ok
test solution_test::test_game_guess_word ... ok
test solution_test::test_game_over_guesses ... ok

test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests solution

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

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

Андрей качи първо решение на 29.11.2017 21:43 (преди почти 8 години)