Решение на Hangman от Десислава Цветкова

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

Към профила на Десислава Цветкова

Резултати

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

Код

use std::fmt::Display;
use std::fmt;
use std::str::FromStr;
#[derive(Debug)]
pub enum GameError {
ParseError(String),
BadGuess(String),
InvalidSolution(String),
GameOver,
}
use GameError::*;
impl GameError {
fn get_error(&self) -> String {
match *self {
ParseError(ref message) => format!("ParseError {:?}", message),
BadGuess(ref message) => format!("BadGuess {:?}", message),
InvalidSolution(ref message) => format!("InvalidSolution {:?}", message),
GameOver => String::from("The end")
}
}
}
impl Display for GameError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.get_error())
}
}
#[derive(Debug)]
pub enum Command {
TryLetter(char),
TryWord(String),
Info,
Help,
Quit,
}
use Command::*;
impl Command {
fn is_same_command(command: Vec<&str>, command_parts: &Vec<&str>) -> bool {
if command_parts.len() >= command.len() {
command_parts.iter().zip(command).all(|(string, subcommand)| {
subcommand.starts_with(string)
})
} else {
false
}
}
}
impl FromStr for Command {
type Err = GameError;
fn from_str(proposed_string: &str) -> Result<Self, Self::Err> {
let formatted = proposed_string.to_lowercase();
let formatted = formatted.trim();
let command_parts:Vec<_> = formatted.split_whitespace().collect();
if proposed_string == "" {
Err(ParseError(String::from("Empty string")))
} else if Command::is_same_command(vec!["try", "word"], &command_parts) {
match command_parts.get(2) {
Some(part) => Ok(TryWord(String::from(*part))),
None => Err(ParseError(String::from(proposed_string))),
}
} else if Command::is_same_command(vec!["try", "letter"], &command_parts) {
match command_parts.get(2) {
Some(part) => if part.chars().count() == 1 {
Ok(TryLetter(part.chars().nth(0).unwrap()))
} else {
Err(ParseError(String::from(proposed_string)))
},
None => Err(ParseError(String::from(proposed_string)))
}
} else if Command::is_same_command(vec!["info"], &command_parts) {
Ok(Info)
} else if Command::is_same_command(vec!["help"], &command_parts) {
Ok(Help)
} else if Command::is_same_command(vec!["quit"], &command_parts) {
Ok(Quit)
} else {
Err(ParseError(String::from(proposed_string)))
}
}

Добра работа с is_same_command, четимо се получава. Аз бих извадил метода извън Command namespace-а -- private функция, локална за модула. Но е вярно, че имаме няколко структури наоколо. Нещо, което да обмислиш, в случай, че задачата беше разбита на няколко модула.

}
use std::collections::HashSet;
#[derive(Debug, PartialEq)]
enum GameState {
Won,
Lost,
Going,
}
pub struct Game {
pub attempted_letters: HashSet<char>,
pub attempted_words: HashSet<String>,
pub attempts_remaining: u32,
solution: String,
state: GameState,
}
impl Game {
pub fn new(solution: &str, attempts: u32) -> Result<Self, GameError> {
if solution == "" || !solution.chars().all(char::is_alphabetic) {
Err(InvalidSolution(String::from("Invalid game!")))
} else {
Ok(Game {
attempted_letters: HashSet::new(),
attempted_words: HashSet::new(),
attempts_remaining: attempts,
solution: String::from(solution).to_lowercase(),
state: GameState::Going
})
}
}
}
impl Game {
fn reduce_attempts(&mut self) -> () {
self.attempts_remaining = self.attempts_remaining - 1;
if self.attempts_remaining <= 0 {
self.state = GameState::Lost;
}
}
pub fn guess_letter(&mut self, guess: char) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_letters.contains(&guess) {
return Err(BadGuess(String::from("You have already tried this letter")))
}
self.attempted_letters.insert(guess);
if self.solution.contains(guess) {
self.has_guessed_all();
Ok(true)
} else {
self.reduce_attempts();
Ok(false)
}
}
fn has_guessed_all(&mut self) {
if (self.solution.chars().collect::<HashSet<_>>()).is_subset(&self.attempted_letters) {
self.state = GameState::Won;
}
}
pub fn guess_word(&mut self, guess: &str) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_words.contains(guess) {
return Err(BadGuess(String::from("You have already tried this word")))
}
self.attempted_words.insert(String::from(guess));
if self.solution == guess {
self.state = GameState::Won;
Ok(true)
} else {
self.reduce_attempts();
Ok(false)
}
}
pub fn is_over(&self) -> bool {
self.state == GameState::Lost || self.state == GameState::Won
}
fn draw_game(&self) -> String {
let matched:Vec<String> = self.solution.chars().map(|c| {
if self.attempted_letters.contains(&c) {
c.to_string()
} else {
String::from("_")
}
}).collect();
matched.join(" ")
}
}
impl Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let presentation = match self.state {
GameState::Won => format!("You won! ^_^\nThe word was: {}", self.solution),
GameState::Lost => format!("You lost! :/\nThe word was: {}", self.solution),
GameState::Going => format!("Attempts remaining: {}\nGuess: {}", self.attempts_remaining, self.draw_game())
};
write!(f, "{}", presentation)
}
}

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

Compiling solution v0.1.0 (file:///tmp/d20171210-6053-wbu8xy/solution)
    Finished dev [unoptimized + debuginfo] target(s) in 6.14 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

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

Десислава качи първо решение на 07.12.2017 01:08 (преди почти 8 години)

Десислава качи решение на 07.12.2017 01:11 (преди почти 8 години)

use std::fmt::Display;
use std::fmt::Write;
use std::fmt;
use std::str::FromStr;
use std::iter::repeat;
#[derive(Debug)]
pub enum GameError {
ParseError(String),
BadGuess(String),
InvalidSolution(String),
GameOver,
}
use GameError::*;
impl GameError {
fn get_error(&self) -> String {
match *self {
ParseError(ref message) => format!("ParseError {:?}", message),
BadGuess(ref message) => format!("BadGuess {:?}", message),
InvalidSolution(ref message) => format!("InvalidSolution {:?}", message),
GameOver => String::from("The end")
}
}
}
impl Display for GameError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.get_error())
}
}
#[derive(Debug)]
pub enum Command {
TryLetter(char),
TryWord(String),
Info,
Help,
Quit,
}
use Command::*;
impl Command {
fn is_same_command(command: Vec<&str>, command_parts: &Vec<&str>) -> bool {
if command_parts.len() >= command.len() {
command_parts.iter().zip(command).all(|(string, subcommand)| {
subcommand.contains(string)
})
} else {
false
}
}
}
impl FromStr for Command {
type Err = GameError;
fn from_str(proposed_string: &str) -> Result<Self, Self::Err> {
let formatted = proposed_string.to_lowercase();
let formatted = formatted.trim();
let command_parts:Vec<_> = formatted.split(" ").collect();
if proposed_string == "" {
Err(ParseError(String::from("Empty string")))
} else if Command::is_same_command(vec!["try", "word"], &command_parts) {
Ok(TryWord(String::from(command_parts[2])))
} else if Command::is_same_command(vec!["try", "letter"], &command_parts) {
if command_parts[2].len() == 1 {
Ok(TryLetter(command_parts[2].chars().nth(0).unwrap()))
} else {
Err(ParseError(String::from(proposed_string)))
}
} else if Command::is_same_command(vec!["info"], &command_parts) {
Ok(Info)
} else if Command::is_same_command(vec!["help"], &command_parts) {
Ok(Help)
} else if Command::is_same_command(vec!["quit"], &command_parts) {
Ok(Quit)
} else {
Err(ParseError(String::from(proposed_string)))
}
}
}
use std::collections::HashSet;
#[derive(Debug, PartialEq)]
enum GameState {
Won,
Lost,
Going,
}
pub struct Game {
pub attempted_letters: HashSet<char>,
pub attempted_words: HashSet<String>,
pub attempts_remaining: u32,
solution: String,
state: GameState,
}
impl Game {
pub fn new(solution: &str, attempts: u32) -> Result<Self, GameError> {
if solution == "" || !solution.chars().all(char::is_alphabetic) {
Err(InvalidSolution(String::from("Invalid game!")))
} else {
Ok(Game {
attempted_letters: HashSet::new(),
attempted_words: HashSet::new(),
attempts_remaining: attempts,
solution: String::from(solution),
state: GameState::Going
})
}
}
}
impl Game {
fn reduce_attempts(&mut self) -> () {
self.attempts_remaining = self.attempts_remaining - 1;
if self.attempts_remaining <= 0 {
self.state = GameState::Lost;
}
}
pub fn guess_letter(&mut self, guess: char) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_letters.contains(&guess) {
return Err(BadGuess(String::from("You have already tried this letter")))
}
self.attempted_letters.insert(guess);
- match self.solution.contains(guess) {
- true => {
- self.has_guessed_all();
- Ok(true)
- }
- false => {
- self.reduce_attempts();
- Ok(false)
- }
+ if self.solution.contains(guess) {
+ self.has_guessed_all();
+ Ok(true)
+ } else {
+ self.reduce_attempts();
+ Ok(false)
}
}
fn has_guessed_all(&mut self) {
if self.attempted_letters == self.solution.chars().collect::<HashSet<_>>() {
self.state = GameState::Won;
}
}
pub fn guess_word(&mut self, guess: &str) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_words.contains(guess) {
return Err(BadGuess(String::from("You have already tried this word")))
}
self.attempted_words.insert(String::from(guess));
- match self.solution == guess {
- true => {
- self.state = GameState::Won;
- Ok(true)
- },
- false => {
- self.reduce_attempts();
- Ok(false)
- }
+ if self.solution == guess {
+ self.state = GameState::Won;
+ Ok(true)
+ } else {
+ self.reduce_attempts();
+ Ok(false)
}
}
pub fn is_over(&self) -> bool {
self.state == GameState::Lost || self.state == GameState::Won
}
fn draw_game(&self) -> String {
let matched:Vec<String> = self.solution.chars().map(|c| {
if self.attempted_letters.contains(&c) {
c.to_string()
} else {
String::from("_")
}
}).collect();
matched.join(" ")
}
}
impl Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let presentation = match self.state {
GameState::Won => format!("You won! ^_^\nThe word was: {}", self.solution),
GameState::Lost => format!("You lost! :/\nThe word was: {}", self.solution),
GameState::Going => format!("Attempts remaining: {}\nGuess: {}", self.attempts_remaining, self.draw_game())
};
write!(f, "{}", presentation)
}
}

Десислава качи решение на 07.12.2017 13:43 (преди почти 8 години)

use std::fmt::Display;
-use std::fmt::Write;
use std::fmt;
use std::str::FromStr;
-use std::iter::repeat;
#[derive(Debug)]
pub enum GameError {
ParseError(String),
BadGuess(String),
InvalidSolution(String),
GameOver,
}
use GameError::*;
impl GameError {
fn get_error(&self) -> String {
match *self {
ParseError(ref message) => format!("ParseError {:?}", message),
BadGuess(ref message) => format!("BadGuess {:?}", message),
InvalidSolution(ref message) => format!("InvalidSolution {:?}", message),
GameOver => String::from("The end")
}
}
}
impl Display for GameError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.get_error())
}
}
#[derive(Debug)]
pub enum Command {
TryLetter(char),
TryWord(String),
Info,
Help,
Quit,
}
use Command::*;
impl Command {
fn is_same_command(command: Vec<&str>, command_parts: &Vec<&str>) -> bool {
if command_parts.len() >= command.len() {
command_parts.iter().zip(command).all(|(string, subcommand)| {
subcommand.contains(string)
})
} else {
false
}
}
}
impl FromStr for Command {
type Err = GameError;
fn from_str(proposed_string: &str) -> Result<Self, Self::Err> {
let formatted = proposed_string.to_lowercase();
let formatted = formatted.trim();
let command_parts:Vec<_> = formatted.split(" ").collect();
if proposed_string == "" {
Err(ParseError(String::from("Empty string")))
} else if Command::is_same_command(vec!["try", "word"], &command_parts) {
Ok(TryWord(String::from(command_parts[2])))
} else if Command::is_same_command(vec!["try", "letter"], &command_parts) {
- if command_parts[2].len() == 1 {
+ if command_parts[2].chars().count() == 1 {
Ok(TryLetter(command_parts[2].chars().nth(0).unwrap()))
} else {
Err(ParseError(String::from(proposed_string)))
}
} else if Command::is_same_command(vec!["info"], &command_parts) {
Ok(Info)
} else if Command::is_same_command(vec!["help"], &command_parts) {
Ok(Help)
} else if Command::is_same_command(vec!["quit"], &command_parts) {
Ok(Quit)
} else {
Err(ParseError(String::from(proposed_string)))
}
}
}
use std::collections::HashSet;
#[derive(Debug, PartialEq)]
enum GameState {
Won,
Lost,
Going,
}
pub struct Game {
pub attempted_letters: HashSet<char>,
pub attempted_words: HashSet<String>,
pub attempts_remaining: u32,
solution: String,
state: GameState,
}
impl Game {
pub fn new(solution: &str, attempts: u32) -> Result<Self, GameError> {
if solution == "" || !solution.chars().all(char::is_alphabetic) {
Err(InvalidSolution(String::from("Invalid game!")))
} else {
Ok(Game {
attempted_letters: HashSet::new(),
attempted_words: HashSet::new(),
attempts_remaining: attempts,
- solution: String::from(solution),
+ solution: String::from(solution).to_lowercase(),
state: GameState::Going
})
}
}
}
impl Game {
fn reduce_attempts(&mut self) -> () {
self.attempts_remaining = self.attempts_remaining - 1;
if self.attempts_remaining <= 0 {
self.state = GameState::Lost;
}
}
pub fn guess_letter(&mut self, guess: char) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_letters.contains(&guess) {
return Err(BadGuess(String::from("You have already tried this letter")))
}
self.attempted_letters.insert(guess);
if self.solution.contains(guess) {
self.has_guessed_all();
Ok(true)
} else {
self.reduce_attempts();
Ok(false)
}
}
fn has_guessed_all(&mut self) {
if self.attempted_letters == self.solution.chars().collect::<HashSet<_>>() {
self.state = GameState::Won;
}
}
pub fn guess_word(&mut self, guess: &str) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_words.contains(guess) {
return Err(BadGuess(String::from("You have already tried this word")))
}
self.attempted_words.insert(String::from(guess));
if self.solution == guess {
self.state = GameState::Won;
Ok(true)
} else {
self.reduce_attempts();
Ok(false)
}
}
pub fn is_over(&self) -> bool {
self.state == GameState::Lost || self.state == GameState::Won
}
fn draw_game(&self) -> String {
let matched:Vec<String> = self.solution.chars().map(|c| {
if self.attempted_letters.contains(&c) {
c.to_string()
} else {
String::from("_")
}
}).collect();
matched.join(" ")
}
}
impl Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let presentation = match self.state {
GameState::Won => format!("You won! ^_^\nThe word was: {}", self.solution),
GameState::Lost => format!("You lost! :/\nThe word was: {}", self.solution),
GameState::Going => format!("Attempts remaining: {}\nGuess: {}", self.attempts_remaining, self.draw_game())
};
write!(f, "{}", presentation)
}
}

Десислава качи решение на 07.12.2017 16:42 (преди почти 8 години)

use std::fmt::Display;
use std::fmt;
use std::str::FromStr;
#[derive(Debug)]
pub enum GameError {
ParseError(String),
BadGuess(String),
InvalidSolution(String),
GameOver,
}
use GameError::*;
impl GameError {
fn get_error(&self) -> String {
match *self {
ParseError(ref message) => format!("ParseError {:?}", message),
BadGuess(ref message) => format!("BadGuess {:?}", message),
InvalidSolution(ref message) => format!("InvalidSolution {:?}", message),
GameOver => String::from("The end")
}
}
}
impl Display for GameError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.get_error())
}
}
#[derive(Debug)]
pub enum Command {
TryLetter(char),
TryWord(String),
Info,
Help,
Quit,
}
use Command::*;
impl Command {
fn is_same_command(command: Vec<&str>, command_parts: &Vec<&str>) -> bool {
+
+ println!("{:?}", command);
+ println!("{:?}", command_parts);
if command_parts.len() >= command.len() {
command_parts.iter().zip(command).all(|(string, subcommand)| {
- subcommand.contains(string)
+ subcommand.starts_with(string)
})
} else {
false
}
}
}
impl FromStr for Command {
type Err = GameError;
fn from_str(proposed_string: &str) -> Result<Self, Self::Err> {
let formatted = proposed_string.to_lowercase();
let formatted = formatted.trim();
- let command_parts:Vec<_> = formatted.split(" ").collect();
+ let command_parts:Vec<_> = formatted.split_whitespace().collect();
if proposed_string == "" {
Err(ParseError(String::from("Empty string")))
} else if Command::is_same_command(vec!["try", "word"], &command_parts) {
- Ok(TryWord(String::from(command_parts[2])))
+ match command_parts.get(2) {
+ Some(part) => Ok(TryWord(String::from(*part))),
+ None => Err(ParseError(String::from(proposed_string))),
+ }
+
} else if Command::is_same_command(vec!["try", "letter"], &command_parts) {
- if command_parts[2].chars().count() == 1 {
- Ok(TryLetter(command_parts[2].chars().nth(0).unwrap()))
- } else {
- Err(ParseError(String::from(proposed_string)))
+ match command_parts.get(2) {
+ Some(part) => if part.chars().count() == 1 {
+ Ok(TryLetter(part.chars().nth(0).unwrap()))
+ } else {
+ Err(ParseError(String::from(proposed_string)))
+ },
+ None => Err(ParseError(String::from(proposed_string)))
}
} else if Command::is_same_command(vec!["info"], &command_parts) {
Ok(Info)
} else if Command::is_same_command(vec!["help"], &command_parts) {
Ok(Help)
} else if Command::is_same_command(vec!["quit"], &command_parts) {
Ok(Quit)
} else {
Err(ParseError(String::from(proposed_string)))
}
}
}
use std::collections::HashSet;
#[derive(Debug, PartialEq)]
enum GameState {
Won,
Lost,
Going,
}
pub struct Game {
pub attempted_letters: HashSet<char>,
pub attempted_words: HashSet<String>,
pub attempts_remaining: u32,
solution: String,
state: GameState,
}
impl Game {
pub fn new(solution: &str, attempts: u32) -> Result<Self, GameError> {
if solution == "" || !solution.chars().all(char::is_alphabetic) {
Err(InvalidSolution(String::from("Invalid game!")))
} else {
Ok(Game {
attempted_letters: HashSet::new(),
attempted_words: HashSet::new(),
attempts_remaining: attempts,
solution: String::from(solution).to_lowercase(),
state: GameState::Going
})
}
}
}
impl Game {
fn reduce_attempts(&mut self) -> () {
self.attempts_remaining = self.attempts_remaining - 1;
if self.attempts_remaining <= 0 {
self.state = GameState::Lost;
}
}
pub fn guess_letter(&mut self, guess: char) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_letters.contains(&guess) {
return Err(BadGuess(String::from("You have already tried this letter")))
}
self.attempted_letters.insert(guess);
if self.solution.contains(guess) {
self.has_guessed_all();
Ok(true)
} else {
self.reduce_attempts();
Ok(false)
}
}
fn has_guessed_all(&mut self) {
if self.attempted_letters == self.solution.chars().collect::<HashSet<_>>() {
self.state = GameState::Won;
}
}
pub fn guess_word(&mut self, guess: &str) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_words.contains(guess) {
return Err(BadGuess(String::from("You have already tried this word")))
}
self.attempted_words.insert(String::from(guess));
if self.solution == guess {
self.state = GameState::Won;
Ok(true)
} else {
self.reduce_attempts();
Ok(false)
}
}
pub fn is_over(&self) -> bool {
self.state == GameState::Lost || self.state == GameState::Won
}
fn draw_game(&self) -> String {
let matched:Vec<String> = self.solution.chars().map(|c| {
if self.attempted_letters.contains(&c) {
c.to_string()
} else {
String::from("_")
}
}).collect();
matched.join(" ")
}
}
impl Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let presentation = match self.state {
GameState::Won => format!("You won! ^_^\nThe word was: {}", self.solution),
GameState::Lost => format!("You lost! :/\nThe word was: {}", self.solution),
GameState::Going => format!("Attempts remaining: {}\nGuess: {}", self.attempts_remaining, self.draw_game())
};
write!(f, "{}", presentation)
}
}

Десислава качи решение на 07.12.2017 16:42 (преди почти 8 години)

use std::fmt::Display;
use std::fmt;
use std::str::FromStr;
#[derive(Debug)]
pub enum GameError {
ParseError(String),
BadGuess(String),
InvalidSolution(String),
GameOver,
}
use GameError::*;
impl GameError {
fn get_error(&self) -> String {
match *self {
ParseError(ref message) => format!("ParseError {:?}", message),
BadGuess(ref message) => format!("BadGuess {:?}", message),
InvalidSolution(ref message) => format!("InvalidSolution {:?}", message),
GameOver => String::from("The end")
}
}
}
impl Display for GameError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.get_error())
}
}
#[derive(Debug)]
pub enum Command {
TryLetter(char),
TryWord(String),
Info,
Help,
Quit,
}
use Command::*;
impl Command {
fn is_same_command(command: Vec<&str>, command_parts: &Vec<&str>) -> bool {
-
- println!("{:?}", command);
- println!("{:?}", command_parts);
if command_parts.len() >= command.len() {
command_parts.iter().zip(command).all(|(string, subcommand)| {
subcommand.starts_with(string)
})
} else {
false
}
}
}
impl FromStr for Command {
type Err = GameError;
fn from_str(proposed_string: &str) -> Result<Self, Self::Err> {
let formatted = proposed_string.to_lowercase();
let formatted = formatted.trim();
let command_parts:Vec<_> = formatted.split_whitespace().collect();
if proposed_string == "" {
Err(ParseError(String::from("Empty string")))
} else if Command::is_same_command(vec!["try", "word"], &command_parts) {
match command_parts.get(2) {
Some(part) => Ok(TryWord(String::from(*part))),
None => Err(ParseError(String::from(proposed_string))),
}
} else if Command::is_same_command(vec!["try", "letter"], &command_parts) {
match command_parts.get(2) {
Some(part) => if part.chars().count() == 1 {
Ok(TryLetter(part.chars().nth(0).unwrap()))
} else {
Err(ParseError(String::from(proposed_string)))
},
None => Err(ParseError(String::from(proposed_string)))
}
} else if Command::is_same_command(vec!["info"], &command_parts) {
Ok(Info)
} else if Command::is_same_command(vec!["help"], &command_parts) {
Ok(Help)
} else if Command::is_same_command(vec!["quit"], &command_parts) {
Ok(Quit)
} else {
Err(ParseError(String::from(proposed_string)))
}
}
}
use std::collections::HashSet;
#[derive(Debug, PartialEq)]
enum GameState {
Won,
Lost,
Going,
}
pub struct Game {
pub attempted_letters: HashSet<char>,
pub attempted_words: HashSet<String>,
pub attempts_remaining: u32,
solution: String,
state: GameState,
}
impl Game {
pub fn new(solution: &str, attempts: u32) -> Result<Self, GameError> {
if solution == "" || !solution.chars().all(char::is_alphabetic) {
Err(InvalidSolution(String::from("Invalid game!")))
} else {
Ok(Game {
attempted_letters: HashSet::new(),
attempted_words: HashSet::new(),
attempts_remaining: attempts,
solution: String::from(solution).to_lowercase(),
state: GameState::Going
})
}
}
}
impl Game {
fn reduce_attempts(&mut self) -> () {
self.attempts_remaining = self.attempts_remaining - 1;
if self.attempts_remaining <= 0 {
self.state = GameState::Lost;
}
}
pub fn guess_letter(&mut self, guess: char) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_letters.contains(&guess) {
return Err(BadGuess(String::from("You have already tried this letter")))
}
self.attempted_letters.insert(guess);
if self.solution.contains(guess) {
self.has_guessed_all();
Ok(true)
} else {
self.reduce_attempts();
Ok(false)
}
}
fn has_guessed_all(&mut self) {
if self.attempted_letters == self.solution.chars().collect::<HashSet<_>>() {
self.state = GameState::Won;
}
}
pub fn guess_word(&mut self, guess: &str) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_words.contains(guess) {
return Err(BadGuess(String::from("You have already tried this word")))
}
self.attempted_words.insert(String::from(guess));
if self.solution == guess {
self.state = GameState::Won;
Ok(true)
} else {
self.reduce_attempts();
Ok(false)
}
}
pub fn is_over(&self) -> bool {
self.state == GameState::Lost || self.state == GameState::Won
}
fn draw_game(&self) -> String {
let matched:Vec<String> = self.solution.chars().map(|c| {
if self.attempted_letters.contains(&c) {
c.to_string()
} else {
String::from("_")
}
}).collect();
matched.join(" ")
}
}
impl Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let presentation = match self.state {
GameState::Won => format!("You won! ^_^\nThe word was: {}", self.solution),
GameState::Lost => format!("You lost! :/\nThe word was: {}", self.solution),
GameState::Going => format!("Attempts remaining: {}\nGuess: {}", self.attempts_remaining, self.draw_game())
};
write!(f, "{}", presentation)
}
}

Десислава качи решение на 08.12.2017 12:27 (преди почти 8 години)

use std::fmt::Display;
use std::fmt;
use std::str::FromStr;
#[derive(Debug)]
pub enum GameError {
ParseError(String),
BadGuess(String),
InvalidSolution(String),
GameOver,
}
use GameError::*;
impl GameError {
fn get_error(&self) -> String {
match *self {
ParseError(ref message) => format!("ParseError {:?}", message),
BadGuess(ref message) => format!("BadGuess {:?}", message),
InvalidSolution(ref message) => format!("InvalidSolution {:?}", message),
GameOver => String::from("The end")
}
}
}
impl Display for GameError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.get_error())
}
}
#[derive(Debug)]
pub enum Command {
TryLetter(char),
TryWord(String),
Info,
Help,
Quit,
}
use Command::*;
impl Command {
fn is_same_command(command: Vec<&str>, command_parts: &Vec<&str>) -> bool {
if command_parts.len() >= command.len() {
command_parts.iter().zip(command).all(|(string, subcommand)| {
subcommand.starts_with(string)
})
} else {
false
}
}
}
impl FromStr for Command {
type Err = GameError;
fn from_str(proposed_string: &str) -> Result<Self, Self::Err> {
let formatted = proposed_string.to_lowercase();
let formatted = formatted.trim();
let command_parts:Vec<_> = formatted.split_whitespace().collect();
if proposed_string == "" {
Err(ParseError(String::from("Empty string")))
} else if Command::is_same_command(vec!["try", "word"], &command_parts) {
match command_parts.get(2) {
Some(part) => Ok(TryWord(String::from(*part))),
None => Err(ParseError(String::from(proposed_string))),
}
} else if Command::is_same_command(vec!["try", "letter"], &command_parts) {
match command_parts.get(2) {
Some(part) => if part.chars().count() == 1 {
Ok(TryLetter(part.chars().nth(0).unwrap()))
} else {
Err(ParseError(String::from(proposed_string)))
},
None => Err(ParseError(String::from(proposed_string)))
}
} else if Command::is_same_command(vec!["info"], &command_parts) {
Ok(Info)
} else if Command::is_same_command(vec!["help"], &command_parts) {
Ok(Help)
} else if Command::is_same_command(vec!["quit"], &command_parts) {
Ok(Quit)
} else {
Err(ParseError(String::from(proposed_string)))
}
}

Добра работа с is_same_command, четимо се получава. Аз бих извадил метода извън Command namespace-а -- private функция, локална за модула. Но е вярно, че имаме няколко структури наоколо. Нещо, което да обмислиш, в случай, че задачата беше разбита на няколко модула.

}
use std::collections::HashSet;
#[derive(Debug, PartialEq)]
enum GameState {
Won,
Lost,
Going,
}
pub struct Game {
pub attempted_letters: HashSet<char>,
pub attempted_words: HashSet<String>,
pub attempts_remaining: u32,
solution: String,
state: GameState,
}
impl Game {
pub fn new(solution: &str, attempts: u32) -> Result<Self, GameError> {
if solution == "" || !solution.chars().all(char::is_alphabetic) {
Err(InvalidSolution(String::from("Invalid game!")))
} else {
Ok(Game {
attempted_letters: HashSet::new(),
attempted_words: HashSet::new(),
attempts_remaining: attempts,
solution: String::from(solution).to_lowercase(),
state: GameState::Going
})
}
}
}
impl Game {
fn reduce_attempts(&mut self) -> () {
self.attempts_remaining = self.attempts_remaining - 1;
if self.attempts_remaining <= 0 {
self.state = GameState::Lost;
}
}
pub fn guess_letter(&mut self, guess: char) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_letters.contains(&guess) {
return Err(BadGuess(String::from("You have already tried this letter")))
}
self.attempted_letters.insert(guess);
if self.solution.contains(guess) {
self.has_guessed_all();
Ok(true)
} else {
self.reduce_attempts();
Ok(false)
}
}
fn has_guessed_all(&mut self) {
- if self.attempted_letters == self.solution.chars().collect::<HashSet<_>>() {
+ if (self.solution.chars().collect::<HashSet<_>>()).is_subset(&self.attempted_letters) {
self.state = GameState::Won;
}
}
pub fn guess_word(&mut self, guess: &str) -> Result<bool, GameError> {
if self.is_over() {
return Err(GameOver)
}
if self.attempted_words.contains(guess) {
return Err(BadGuess(String::from("You have already tried this word")))
}
self.attempted_words.insert(String::from(guess));
if self.solution == guess {
self.state = GameState::Won;
Ok(true)
} else {
self.reduce_attempts();
Ok(false)
}
}
pub fn is_over(&self) -> bool {
self.state == GameState::Lost || self.state == GameState::Won
}
fn draw_game(&self) -> String {
let matched:Vec<String> = self.solution.chars().map(|c| {
if self.attempted_letters.contains(&c) {
c.to_string()
} else {
String::from("_")
}
}).collect();
matched.join(" ")
}
}
impl Display for Game {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let presentation = match self.state {
GameState::Won => format!("You won! ^_^\nThe word was: {}", self.solution),
GameState::Lost => format!("You lost! :/\nThe word was: {}", self.solution),
GameState::Going => format!("Attempts remaining: {}\nGuess: {}", self.attempts_remaining, self.draw_game())
};
write!(f, "{}", presentation)
}
}