Chapter - 2
Guessing Game
Functionality of the game :
Program generates random no between 1 and 100.
It will then prompt the player to enter a guess.
After a guess is entered, the program will indicate whether the guess is too low or too high.
If the guess is correct, the game will print a congratulatory message and exit.
Setting up the project
$ cargo new guessing_game
$ cd guessing_game
use std::io; // Library to obtain user input
Prelude - Collection of commonly used items that are automatically available in the every rust program. Main purpose is to save you from repeatedly importing these items manually and make code cleaner and more concise
Create a variable in Rust
let apple = 5;
By default Rust make the variable immutable (i.e, we cannot change them)
To make the variable mutable:
let mut banana = 10;
fn main() {
println!("Guess the number!");
println!("Please input your guess.");
let mut guess = String::new(); // It return a new instance of a string.
// The :: syntax in the ::new line indicates that new is an associated function of the String type.
io::stdin() .read_line(&mut guess) .expect("Failed to read line");
// read_line will take the input from the user and append it to the variable (will not overwrite it)
// If the code fill fail then the code inside "except" will run.
// It also gives us the Result which have multiple possible states, which are known as variants.
// Result variants -> Ok (Operation was successful), err (Operation was failed)
println!("You guessed: {}", guess);
}
Creating random number
To generate random no in Rust, we have to download and import rand library
To download rand :
$ cargo add rand
Import rand library :
use rand::Rng;
This line imports the Rng trait from the rand crate, which provides functionality for generating random numbers.
Crates in Rust
A crate is a collection of Rust source code files.. Think of it like a box that contains everything needed to compile a peice of software.
Binary crate : These create executable programs
Library crate : Provide reusable that we can be used by other crates. It does not produce executable
The program we are making is a binary crate and "rand" is the library crate.
Semantic Versioning
Ex : The "rand" which we have added is the version of "0.8.5"
0 -> MAJOR : Big changes that might break things 8 -> MINOR : New features that don't break anything 5 -> PATCH : Smal fixes or updates
In Rust, the Cargo.lock file is used to ensure that your project builds the same way every time, even if the dependencies change. Here’s how it works:
Dependencies: When you build your Rust project, Cargo (Rust’s package manager) pulls in libraries (dependencies) from the internet.
Cargo.toml: This file lists the dependencies and their versions, but it might allow some flexibility (e.g., "any version 1.x").
Cargo.lock: When you first build your project, Cargo creates a Cargo.lock file that records the exact versions of all dependencies used.
To update a crate to get a new version:
$ cargo update
It will update only PATCH version.
If you want to update the MAJOR or MINOR version, then you have to explicitely create changes in the Cargo.toml file
To generate a random no :
let secret_number = rand::thread_rng().gen_range(1..=100);
This line generates a random number between 1 and 100 (inclusive) using the rand crate.
The thread_rng() function returns a random number generator, and
The gen_range() method generates a random number within the specified range.
Compiled code till now :
use std::io; use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1..=100);
println!("The secret number is: {secret_number}");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin() .read_line(&mut guess) .expect("Failed to read line");
println!("You guessed: {guess}");
}
If you want to build the doc provided by all your dependencies locally:
$ cargo doc --open
Comparing the Guess to the Secret Number
use rand::Rng;
use std::cmp::Ordering; // Imports Orderning which is used to compare the numbersuse std::io;
fn main() {
// --snip--
println!("You guessed: {guess}");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"), }
}
match is like switch that we used in other programming languages. But in case of match we have to provide all of the conditions.
When we will run the above code we will get error that secret_number and guess variable is of not same type. secret_number is u32 but the guess is string.
To parse the guess into a u32 :
let guess: u32 = guess.trim().parse().expect("Please type a number!");
This code attempts to parse the input string guess into a u32 (unsigned 32-bit integer) value.
The trim() method removes any whitespace from the input string because when we enter the guess we also press the Enter key which stores in the form of "\n", and
The parse() method attempts to convert the resulting string into a u32 value.
This method also returns a Result read_line so we also have to use the expect()
It will shadow the previous guess variable
If the user entered the wrong input, the program will crash with an error message. To handle this situation, we can use the match statement to handle the error
// --snip--
io::stdin() .read_line(&mut guess) .expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => println!("Please enter valid input");
};
println!("You guessed: {guess}");
// --snip--
If the user entered the correct input, the input will be stored in the num variable otherwise it will show throw error message.
We can also use the loop to keep asking the user for input until they guess the number correctly.
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1..=100);
loop {
println!("Please input your guess.");
let mut guess = String::new();
io::stdin() .read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("Please enter valid input");
continue;
}
};
println!("You guessed: {guess}");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => { println!("You win!");
break; }
}
}
}
And that's it !!!
Enjoy !!!
Subscribe to my newsletter
Read articles from Kartik Sangal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by