Making a simple game with Rust

Rust is a systems programming language that offers memory safety, concurrency, and performance. In this blog post, we’ll explore some Rust basics while building a simple “guess the number” game. This will give us a hands-on introduction to key Rust concepts and syntax.

Setting Up the Project

Let’s start by creating a new Rust project. Open your terminal and run:

cargo new guess_the_number
cd guess_the_number

This creates a new Rust project named “guess_the_number” and changes into the project directory. Cargo, Rust’s package manager and build system, sets up a basic project structure for us.

Understanding the Project Structure

Before we dive into coding, let’s take a moment to understand the project structure Cargo has created for us:

1. Cargo.toml: This is the manifest file for our Rust package. It contains metadata about the package and its dependencies.
2. src/main.rs: This is the entry point of our program. It contains the main() function, which is where our program starts executing.

Let’s open src/main.rs in your preferred text editor. You’ll see a basic “Hello, world!” program:

fn main() {
    println!("Hello, world!");
}

We’ll be replacing this with our guess the number game shortly.

Basic Rust Concepts

Before we start building our game, let’s cover some basic Rust concepts:

1. Variables: In Rust, variables are immutable by default. To make them mutable, we use the mut keyword.

2. Functions: Functions are defined using the fn keyword, followed by the function name and parameters in parentheses.

3. Macros: Macros in Rust are denoted by an exclamation mark (!). println! is a macro that prints text to the console.

4. Types: Rust is a statically typed language, but it can often infer types. When needed, we declare types using a colon (:) after the variable name.

5. Modules: Rust organizes code into modules. The standard library is available through the std module.

Now, let’s start building our game!

Building the Guess the Number Game

We’ll create a game where the computer generates a random number, and the player tries to guess it. Let’s update our main.rs file:

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
    println!("Welcome to 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(_) => 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;
            }
        }
    }
}

Now, let’s break down this code and explain the Rust concepts it introduces:

Importing Modules

use std::io;
use std::cmp::Ordering;
use rand::Rng;

Here, we’re importing necessary modules. std::io for input/output operations, std::cmp::Ordering for comparing numbers, and rand::Rng for generating random numbers.

Note: To use the rand crate, we need to add it to our Cargo.toml file:

[dependencies]
rand = "0.8.5"

Generating a Random Number

let secret_number = rand::thread_rng().gen_range(1..=100);

This line generates a random number between 1 and 100 (inclusive). We’re using the rand crate’s thread_rng() function to get a random number generator, and gen_range() to generate a number within the specified range.

The Game Loop

loop {
    // Game logic here
}

We use a loop to create an infinite loop, which will continue until we explicitly break out of it (when the player guesses correctly).

Getting User Input

let mut guess = String::new();

io::stdin()
    .read_line(&mut guess)
    .expect("Failed to read line");

We create a mutable String to store the user’s input. Then we use io::stdin().read_line() to read a line of input from the user. The &mut guess argument tells the method to store the input in our guess variable. The expect method is used for error handling – if reading the line fails, it will panic with the given message.

Parsing the Guess

let guess: u32 = match guess.trim().parse() {
    Ok(num) => num,
    Err(_) => continue,
};

This block introduces several important Rust concepts:

1. Shadowing: We’re declaring a new variable named guess, which shadows the previous guess variable. This is often used to convert a value from one type to another.

2. Result handling: The parse() method returns a Result type, which is either Ok or Err. We use a match expression to handle both cases.

3. Type annotation: We specify that guess should be a u32 (unsigned 32-bit integer).

4. Error handling: If parsing fails (i.e., the user didn’t enter a valid number), we continue the loop, asking for another guess.

Comparing the Guess

match guess.cmp(&secret_number) {
    Ordering::Less => println!("Too small!"),
    Ordering::Greater => println!("Too big!"),
    Ordering::Equal => {
        println!("You win!");
        break;
    }
}

Here, we use another match expression to compare the guess with the secret number. The cmp method returns an Ordering, which can be Less, Greater, or Equal. We handle each case, printing an appropriate message. If the guess is correct, we print “You win!” and break out of the loop, ending the game.

Conclusion

This simple game demonstrates several key Rust concepts:

1. Variables and mutability
2. Input and output
3. Random number generation
4. Loops and control flow
5. Match expressions
6. Error handling
7. Type conversion

By building this game, we’ve gotten a taste of Rust’s syntax and some of its core features.
As you keep learning Rust, you’ll come across more advanced concepts like ownership, borrowing, and lifetimes. They are what make Rust unique, but are out of scope for this blog. Hope you had fun reading this!

関連記事

カテゴリー:

ブログ

情シス求人

  1. チームメンバーで作字やってみた#1

ページ上部へ戻る