hello,

last time I made a fibonacci series generator in Rust and now I have made something different :)

use std::io;

fn main() {
    let mut input: String = String::new();
    let stdin = io::stdin();

    let x = rand::random::<u32>() % 101;
    let mut attempts = 0;

    loop {
        println!("Guess a number from 0 to 100:");
        stdin.read_line(&mut input);
        input = input.to_string().replace("\n", ""); // removing the \n
        let user_input: u32 = input.parse::<u32>().unwrap();
        if x == user_input {
            println!("You won! attempts: {attempts}");
            break;
        }
        else if x < user_input {
            println!("too big");
            attempts += 1;
        }
        else {
            println!("too small");
            attempts += 1;
        }
        input.clear()
    }
}

feel free to give me suggestion :)

  • nous@programming.dev
    link
    fedilink
    English
    arrow-up
    21
    ·
    3 days ago

    The biggest/only real problem is the .unwrap(). This will cause the program to exit with an error message if the user inputs an invalid value. Which is not a great user experience. Better to reject the input and ask them again (aka start the loop again). You can do this with a match on the returned value of parse with a message and a continue on Err (good time to learn about enums and pattern matching as well).

    A minor improvement can be done to this:

            input = input.to_string().replace("\n", ""); // removing the \n
            let user_input: u32 = input.parse::<u32>().unwrap();
    

    By replacing it with:

            let user_input: u32 = input.trim().parse::<u32>().unwrap();
    

    Which has a few advantages:

    • it removes all white space, including tabs and spaces from both the start and end.
    • it requires no allocations.
    • it is one fewer lines while still being clear what it is doing.
    • no mutability needed (though input still needs to be mutable here in other cases this can be a benefit).

    These are more nitpicks than anything substantial - would lead to nicer code in more complex situations but negligible at best in this code base (only really pointing out to give you some things to think about):

    Since you break in the win condition the attempts += 1; can be moved out of the other branches at the same level as the input.clear().

    Rand has a gen_range function which can be used like:

    rand::thread_rng().gen_range::<u32>(0..=100);
    

    Though typically you would save the thread_rng() output to a local and reuse that throughout your program instead of creating one each time - here you only need one number so that matters less. The Rng trait has a lot more convenience function on it as well so it is generally worth using over just the random() function. Though in this case it makes very little difference overall here - typically you would want to opt for one of those methods instead so is worth knowing about.

    I dislike the name x as it is very ambiguous. IMO short letters should be used only in smaller scopes or when they represent some sort of mathematical value. Here I would use secret_number or secret_value or something more descriptive. Though in this case there is not a much better domain name here, more often there is.