Guessing Game Part 2: VSCode & Completing the Game

Learning objectives

By the end of class today you should be able to:

  • Use VSCode with rust-analyzer and the integrated terminal for Rust development
  • Start using loops and conditional logic in Rust
  • Use match expressions and Ordering for comparisons
  • Keep your code tidy and readable with clippy, comments, and doc strings

Why VSCode for Rust?

  • Rust Analyzer: Real-time error checking, autocomplete, type hints
  • Integrated terminal: No more switching windows
  • Git integration: Visual diffs, staging, commits

Setting up VSCode for Rust

You'll need to have

  • Installed VSCode
  • Installed Rust
  • Installed the rust-analyzer extension

Opening our project

To make sure we're all at the same starting point, we'll recreate the project.

From MacOS terminal or Windows PowerShell (not git-bash):

# change to your projects folder
cd ~/projects

cargo new guessing_game

cd guessing_game

# check what the default branch name is
git branch

# if default branch is called `master`, rename it to `main`
git branch -m master main

# Add the `rand` crate to the project
cargo add rand

# start VS Code in the current directory
code .

or use File → Open Folder from VSCode and open ~/projects/guessing_game.

VSCode Features Demo

Side Panel

  • Explorer
    • single click and double click filenames
    • split editor views
  • Search,
  • Source Control,
  • Run and Debug,
  • Extensions
    • You should have rust-analyzer, not rust!

Integrated Terminal

  • View → Terminal, Terminal → New
  • You can have multiple terminals
  • Same commands as before: cargo run, cargo check

Rust Analyzer in Action

What you'll see:

  • Red squiggles - Compiler errors
  • Yellow squiggles - Warnings
  • Hover tooltips - Type information
  • Autocomplete - As you type suggestions
  • Format on save - Automatic code formatting

Let's see it in action!

Completing Our Guessing Game

Restore Guessing Game

Replace the content in main.rs with the following:

use std::io;
use rand::Rng;

fn main() {
    let secret_number = rand::rng().random_range(1..=100);
    //println!("The secret number is: {secret_number}");

    println!("Guess the number between 1 and 100!");
    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);

}

Running from VSCode

You have different ways to run the program:

  1. cargo run from terminal
  2. Click the little Run that decorates above fn main() {

VSCode Git Integration

Visual Git Features:

  • Source Control panel - See changed files
  • Diff view - Side-by-side comparisons
  • Stage changes - Click the + button
  • Commit - Write message and commit

Still use terminal for:

  • git status - Quick overview
  • git log --oneline - Commit history
  • git push / git pull - Syncing

Create Git Commit

Let's use the visual interface to make our initi commit.

You can always do this via the integrated terminal instead.

Click the Source Control icon on the left panel.

Click + to stage each file or stage all changes.

Write the commit message: "Initial commit" and click Commit

Now you can see on the left pane that we have one commit.

Making it a real game:

  1. Remove the secret reveal - no cheating!
  2. Add a loop - keep playing until correct
  3. Compare numbers - too high? too low?
  4. Handle invalid input - what if they type "banana"?

But before we proceed, create a topic branch by

  • clicking on main in the bottom left
  • Select Create new branch...
  • Give it a name like compare

Step 1: Comparing Numbers

First, we need to convert the guess to a number and compare:

#![allow(unused)]
fn main() {
// add at top of file after other `use` statements
use std::cmp::Ordering;

// Add this after reading input:
let guess: u32 = guess.trim().parse().expect("Please enter a number!");

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

Now run the program to make sure it works.

If it does, then commit the changes to your topic branch.

Note how you can see the changes in the Source Control panel.

Merge Topic Branch

If you had a remote repo setup like on GitHub, you would then:

  • push your topic branch to the remote git push origin branch_name
  • ask someone to review and possible make changes and push those to the remote

But for now, we are just working locally.

git checkout main
# or use VSCode to switch to main

# merge changes from topic branch into main
git merge compare # replace 'compare' with your branch name

# delete your topic branch
git branch -d compare

Step 2: Adding the Loop

Now, we want to wrap the input/comparison in a loop.

But first create a new topic branch, e.g. loop

#![allow(unused)]
fn main() {
loop {
    println!("Please input your guess.");
    
    // ... input code ...
    
    match guess.cmp(&secret_number) {
        Ordering::Less => println!("Too small!"),
        Ordering::Greater => println!("Too big!"),
        Ordering::Equal => {
            println!("You win!");
            break;  // Exit the loop
        }
    }
}
}

You can indent multiple lines of code by selecting all the lines and then pressing TAB.

Try the code and if it works, commit, checkout main, merge topic branch and then delete topic branch.

Step 3: Handling Invalid Input

Run the program again and then try typing a word instead of a number.

Not great behavior, right?

Replace .expect() with proper error handling, but first create a topic branch.

#![allow(unused)]
fn main() {
let guess: u32 = match guess.trim().parse() {
    Ok(num) => num,
    Err(_) => {
        println!("Please enter a valid number!");
        continue;  // Skip to next loop iteration
    }
};
}

Replace the relevant code, run and debug and do the git steps again.

You should end up on the main branch with all the changes merged and 4 commits.

Final Complete Game

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

fn main() {
    let secret_number = rand::rng().random_range(1..=100);
    //println!("The secret number is: {secret_number}");

    println!("Guess the number between 1 and 100!");

    loop {
        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);

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => {
                println!("Please enter a valid number!");
                continue;  // Skip to next loop iteration
            }
        };

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

}

Comments & Documentation Best Practices

What would happen if you came back to this program in a month?

Inline Comments (//)

  • Explain why, not what the code does
  • Bad: // Create a random number
  • Good: // Generate secret between 1-100 for balanced difficulty
  • If it's not clear what the code does you should edit the code!

Doc Comments (///)

  • Document meaningful chunks of code like functions, structs, modules
  • Show up in cargo doc and IDE tooltips
/// Prompts user for a guess and validates input
/// Returns the parsed number or continues loop on invalid input
fn get_user_guess() -> u32 {
    // implementation...
}

You can try putting a doc comment right before fn main() {

The Better Comments extension

See it on VS Code marketplace

  • Color-codes different types of comments in VSCode - let's paste it into main.rs and see
// TODO: Add input validation here
// ! FIXME: This will panic on negative numbers
// ? Why does this work differently on Windows?
// * Important: This function assumes sorted input

Wrap-up

What we've accomplished so far:

  • Can now use shell, git, and rust all in one place (VSCode)
  • We built a complete, functional game from scratch
  • Started learning key Rust concepts: loops, matching, error handling
  • We've practiced using GitHub Classroom - you'll use it for HW2!