FizzBuzz

Combine modulo arithmetic, conditionals, functions, and a mutable loop counter.

1

Core concepts

%, while, if, else, function composition

2

How the learner should approach this project

Do not paste the complete program immediately. Create the file, type the first step, run vpp check, and then run the program when a complete entry point exists. Read the explanation before looking at the snippet. After each step, predict what the new code should do. This turns the page into a lesson rather than a code dump.

3

Step 1: Encode FizzBuzz rules

The order of checks matters. A number divisible by both 3 and 5 must be recognized as FizzBuzz before the individual Fizz or Buzz cases. The modulo operator returns the remainder, so a remainder of zero means exact divisibility.

After typing the snippet, identify the new names introduced by the step. Ask what each name represents, what type the compiler should infer or check, and what value should exist after the code runs.

main.vpp
fn fizzbuzz(n: int) -> string {
    if n % 15 == 0 {
        return "FizzBuzz"
    }
    if n % 3 == 0 {
        return "Fizz"
    }
    if n % 5 == 0 {
        return "Buzz"
    }
    return "num"
}
4

Step 2: Run the rule through a loop

The loop owns the sequence of inputs while fizzbuzz owns the decision logic. Separating those responsibilities keeps the function easy to test and the loop easy to read.

Before moving forward, explain how this step connects to the previous one. In particular, identify which values cross a function boundary, which values change, and which values are guaranteed by the type system.

main.vpp
fn main() -> int {
    let mut i = 1
    while i <= 20 {
        let label = fizzbuzz(i)
        if label == "num" {
            print(i)
        } else {
            print(label)
        }
        i = i + 1
    }
    return 0
}
5

Complete source

main.vpp
fn fizzbuzz(n: int) -> string {
    if n % 15 == 0 {
        return "FizzBuzz"
    }
    if n % 3 == 0 {
        return "Fizz"
    }
    if n % 5 == 0 {
        return "Buzz"
    }
    return "num"
}
fn main() -> int {
    let mut i = 1
    while i <= 20 {
        let label = fizzbuzz(i)
        if label == "num" {
            print(i)
        } else {
            print(label)
        }
        i = i + 1
    }
    return 0
}
6

Expected behavior

The complete program should produce the following output when run with the command shown below. Exact formatting should follow the current V++ runtime.

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
7

Run the project

terminal
vpp run projects/10-fizzbuzz/main.vpp
8

What the learner should understand after this project

Good small programs separate decision logic from iteration. The fizzbuzz function owns the rule while main owns the sequence.

9

Common mistakes to teach

  1. Checking 3 and 5 before 15
  2. Forgetting to increment the loop counter
  3. Returning a string that the caller does not interpret correctly
10

Practice extension

Extend the loop to 50. Then change the labels and add another divisibility rule.

A strong learner should be able to explain the program without looking at the code, rebuild the core idea from memory, and make the practice change without copying a solution.

11

Full program

main.vpp
fn fizzbuzz(n: int) -> string {
    if n % 15 == 0 {
        return "FizzBuzz"
    }
    if n % 3 == 0 {
        return "Fizz"
    }
    if n % 5 == 0 {
        return "Buzz"
    }
    return "num"
}
fn main() -> int {
    let mut i = 1
    while i <= 20 {
        let label = fizzbuzz(i)
        if label == "num" {
            print(i)
        } else {
            print(label)
        }
        i = i + 1
    }
    return 0
}
vpp
$ ready. Click Test program.