2
\$\begingroup\$

I created a rust implementation of hangman as a command line version. The user can enter characters to find out the desired word.

I really appreciate any helpful comment which highlights how I could improve the code and in particular make more "rustacean".

use std::io;
use std::collections::HashSet;

fn extract_char(line: &str) -> char{
    line.trim().chars().nth(0).expect("Please input a single character.")
}

fn get_current_guess(word: &str, chars: &HashSet<char>) -> String {
    word.chars().map(|x| if chars.contains(&x) {x} else {'_'}).collect()
}


fn main() {
    println!("Welcome to Hangman!");

    let word = "declaration";
    let mut user_chars: HashSet<char> = HashSet::new();
    let max_incorrect_guesses = 5;
    let mut incorrect_guesses = 0;

    loop {
        println!("Please input a single char:");
        let mut current_input = String::new();

        io::stdin()
            .read_line(&mut current_input)
            .expect("Failed to read input.");

        let current_char = extract_char(&current_input);
        if user_chars.contains(&current_char) {
            println!("You already chose {}.", current_char);
            continue
        }
        else if !word.contains(current_char){
            incorrect_guesses += 1;
            println!("{} is not in word.", current_char);
            println!("Number of incorrect guesses is now {}", incorrect_guesses);
        }

        user_chars.insert(current_char);
        if incorrect_guesses > max_incorrect_guesses {
            println!("You have reached the maximum number of incorrect guesses.");
            println!("The correct word is {}.", word);
            break
        }

        println!("Your current guess is {:?}", get_current_guess(&word, &user_chars));
    }
}
\$\endgroup\$

1 Answer 1

0
\$\begingroup\$
fn extract_char(line: &str) -> char{
    line.trim().chars().nth(0).expect("Please input a single character.")
}

This doesn't actually check if the user entered a single character, just if they entered at least one. It also panics on an error in user input which would normally be bad, but maybe its okay for this learning excercsize. You can actually simplify by using the parse() method:

fn extract_char(line: &str) -> char{
    line.trim().parse().expect("Please input a single character.")
}

This asks rust to parse the string into a char and it know how to do that properly. Also worth looking at is the text_io create which provides some macros to simplify the text input.

    if user_chars.contains(&current_char) {
        println!("You already chose {}.", current_char);
        continue
    }

You should use insert rather then contains. insert returns false if the set already contains the item. Thus is allows insertion and checking if the set already had the element in one call.

        continue
    }
    else if !word.contains(current_char){

The else is redundant with the continue. Both are useful sometimes, but I'd suggest not doing them both together.

Gameplay wise:

  1. There appears to be no win condition
  2. It doesn't show me the number of spaces before I start guessing.
\$\endgroup\$
1
  • \$\begingroup\$ Thank you very much for your hints. \$\endgroup\$ Mar 21, 2023 at 20:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.