Skip to content
aviral gupta

// B1.5 · ~35 min · Beginner

Build: a number-guessing game

After this build you can write a game that compares guesses with a secret number, counts the attempts and prints Too low, Too high or Correct, and debug it.

Lesson 5 of 5 in B1 Getting started

End of the module

You will be able to

  • Compare a guess with the secret and print Too low, Too high or Correct, with a first look at if and else
  • Keep the secret, the guess and the attempts in const and let
  • Debug the game with its error messages and logged values
  1. Warm-up · Activity 1 of 7

    Warm-up: the secret number stays the same for the whole game; the guess changes every round. Which declarations fit best?

  2. Predict · Activity 2 of 7

    Predict before you read on: what does this print?

    const secret = 7;
    let guess = 4;
    if (guess < secret) {
      console.log("Too low");
    } else if (guess > secret) {
      console.log("Too high");
    } else {
      console.log("Correct");
    }
  3. Practice · Activity 3 of 7

    Fill in the comparison so that the program prints Too high for this guess.

    const secret = 7;
    let guess = 9;
    if (guess ____ secret) {
      console.log("Too high");
    }
    if (guess secret) {
  4. Practice · Activity 4 of 7

    Which whole numbers can this expression give? (A preview: modules B2 and B3 come back to Math.)

    Math.floor(Math.random() * 10) + 1
  5. Practice · Activity 5 of 7

    Three rounds each count one attempt. What does the last line print?

    let attempts = 0;
    attempts = attempts + 1;
    attempts = attempts + 1;
    attempts = attempts + 1;
    console.log("Attempts:", attempts);
  6. Brain teaser · Activity 6 of 7

    Brain teaser. This program stops with an error. What does it print before that?

    const secret = 42;
    const guess = 30;
    console.log("Guess:", guess);
    guess = 50;
    console.log("Guess:", guess);
  7. Apply · Activity 7 of 7

    Mini-task. Write the whole game for the secret 42 and the guesses 25, 75 and 42. Each round sets guess, adds one to attempts, and prints the guess with Too low, Too high or Correct. At the end print Found 42 in 3 attempts, with both numbers taken from the variables. Then change a guess and run it again.

    Check your work against this list

Build it yourself

Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.

Worked example

Three rounds of the game

The secret is fixed at 42 and the three guesses are written into the program, because the editor has no keyboard input. Each round gives guess a new value, counts the attempt and prints one of three messages. Run it, then change a guess, or the secret, and predict the output before you run it again.

main.js

// Number guessing, with the guesses written into the program.
const secret = 42;
let attempts = 0;

let guess = 30;
attempts = attempts + 1;
if (guess < secret) {
  console.log(guess, "Too low");
} else if (guess > secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}

guess = 50;
attempts = attempts + 1;
if (guess < secret) {
  console.log(guess, "Too low");
} else if (guess > secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}

guess = 42;
attempts = attempts + 1;
if (guess < secret) {
  console.log(guess, "Too low");
} else if (guess > secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}

console.log("Attempts:", attempts);

Run it with

node main.js

Output

30 Too low
50 Too high
42 Correct
Attempts: 3
  • secret is a const: it never changes. guess and attempts are let: each round changes them.
  • In each round exactly one of the three messages is printed.
  • guess = 50; has no let in front: the variable exists already, it only gets a new value.
  • The same round is written three times. Loops (B3) and functions (B4) will make that one block.
Change it and run it

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Exercises

Exercise 1 of 3

Step 1: judge three guesses

The secret is 42 and the guesses are 30, 50 and 42. After each guess, print the guess and Too low, Too high or Correct, as in 30 Too low. Use if, else if and else to choose the message, and let JavaScript compare: do not type the answers.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Hints
  1. Hint 1

    Start with the first guess only: if (guess < secret) { console.log(guess, "Too low"); }.

  2. Hint 2

    Add else if (guess > secret) { … } and else { … } for the other two messages.

  3. Hint 3

    Copy the whole if … else block after each new guess = line.

Show a solution

One way to solve it. Yours can look different and still pass the checks.

const secret = 42;
let guess = 30;
if (guess < secret) {
  console.log(guess, "Too low");
} else if (guess > secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}

guess = 50;
if (guess < secret) {
  console.log(guess, "Too low");
} else if (guess > secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}

guess = 42;
if (guess < secret) {
  console.log(guess, "Too low");
} else if (guess > secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}
Run it on your computer

Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.js

const secret = 42;
let guess = 30;
// Print the guess and "Too low", "Too high" or "Correct".

guess = 50;
// The same check again.

guess = 42;
// And once more.

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';

const lines = async () => (await runMain()).trimEnd().split('\n');

test('says Too low for 30', async () => {
  const got = await lines();
  assert.equal(got[0], '30 Too low', `the first line is ${JSON.stringify(got[0])}, expected "30 Too low"`);
});

test('says Too high for 50', async () => {
  const got = await lines();
  assert.equal(got[1], '50 Too high', `the second line is ${JSON.stringify(got[1])}, expected "50 Too high"`);
});

test('says Correct for 42', async () => {
  const got = await lines();
  assert.equal(got[2], '42 Correct', `the third line is ${JSON.stringify(got[2])}, expected "42 Correct"`);
});

test('prints exactly one line per guess', async () => {
  const got = await lines();
  assert.equal(got.length, 3, `the program printed ${got.length} line(s), expected 3`);
});

package.json

{
  "type": "module"
}

package.json tells Node.js that the .js files are modules; keep it in the folder.

Run the program:

node main.js

Run the checks (needs learnrun.js in the same folder):

node --test
Download learnrun.js

Exercise 2 of 3

Step 2: fix the broken game

This game should print 30 Too low, then 42 Correct, then Attempts: 2. It has two bugs. Run it, read the error message and fix that line. Then compare the output with what it should be: the second bug gives no error at all, only wrong feedback.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Hints
  1. Hint 1

    The first error is TypeError: Assignment to constant variable. Which variable gets a new value, and how is it declared?

  2. Hint 2

    After that fix, 30 is reported as Too high. Log guess and secret, or read each condition aloud: is 30 > 42?

  3. Hint 3

    Swap the two comparisons: guess < secret goes with Too low, guess > secret with Too high.

Show a solution

One way to solve it. Yours can look different and still pass the checks.

const secret = 42;
let attempts = 0;

let guess = 30;
attempts = attempts + 1;
if (guess < secret) {
  console.log(guess, "Too low");
} else if (guess > secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}

guess = 42;
attempts = attempts + 1;
if (guess < secret) {
  console.log(guess, "Too low");
} else if (guess > secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}

console.log("Attempts:", attempts);
Run it on your computer

Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.js

const secret = 42;
const attempts = 0;

let guess = 30;
attempts = attempts + 1;
if (guess > secret) {
  console.log(guess, "Too low");
} else if (guess < secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}

guess = 42;
attempts = attempts + 1;
if (guess > secret) {
  console.log(guess, "Too low");
} else if (guess < secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}

console.log("Attempts:", attempts);

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';

test('runs without an error', async () => {
  await runMain();
});

test('says Too low for 30', async () => {
  const got = (await runMain()).trimEnd().split('\n');
  assert.equal(got[0], '30 Too low', `the first line is ${JSON.stringify(got[0])}, expected "30 Too low"`);
});

test('prints the whole game', async () => {
  const got = (await runMain()).trimEnd().split('\n');
  assert.deepEqual(got, ['30 Too low', '42 Correct', 'Attempts: 2'], `the program printed ${JSON.stringify(got)}`);
});

package.json

{
  "type": "module"
}

package.json tells Node.js that the .js files are modules; keep it in the folder.

Run the program:

node main.js

Run the checks (needs learnrun.js in the same folder):

node --test
Download learnrun.js

Exercise 3 of 3

Step 3: a random secret

Now let the program pick the secret: a whole number from 1 to 10, with Math.floor(Math.random() * 10) + 1. The guess is 5. Print the feedback line as before, then The secret was and the secret, such as The secret was 8. The tests run your program many times: the secret must always be a whole number from 1 to 10, the feedback must fit it, and it must not always be the same.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Hints
  1. Hint 1

    Run the starter a few times: the secret has decimals, such as 7.3918…, which a player could never guess.

  2. Hint 2

    Math.floor(…) rounds down to a whole number, and Math.random() * 10 is below 10, so you get 0 to 9.

  3. Hint 3

    Add 1 after rounding: Math.floor(Math.random() * 10) + 1.

Show a solution

One way to solve it. Yours can look different and still pass the checks.

const secret = Math.floor(Math.random() * 10) + 1;
const guess = 5;
if (guess < secret) {
  console.log(guess, "Too low");
} else if (guess > secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}
console.log("The secret was", secret);
Run it on your computer

Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.js

// Pick a whole number from 1 to 10.
const secret = Math.random() * 10;
const guess = 5;
if (guess < secret) {
  console.log(guess, "Too low");
} else if (guess > secret) {
  console.log(guess, "Too high");
} else {
  console.log(guess, "Correct");
}
console.log("The secret was", secret);

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';

const RUNS = 6;

const play = async () => {
  const [feedback, reveal] = (await runMain()).trimEnd().split('\n');
  const found = /^The secret was (\d+)$/.exec(reveal ?? '');
  return {feedback, reveal, secret: found ? Number(found[1]) : null};
};

test('the secret is a whole number from 1 to 10', async () => {
  for (let run = 0; run < RUNS; run++) {
    const {reveal, secret} = await play();
    assert.ok(secret !== null && secret >= 1 && secret <= 10, `the last line is ${JSON.stringify(reveal)}, expected The secret was followed by a whole number from 1 to 10`);
  }
});

test('the feedback fits the secret', async () => {
  for (let run = 0; run < RUNS; run++) {
    const {feedback, secret} = await play();
    const expected = secret > 5 ? '5 Too low' : secret < 5 ? '5 Too high' : '5 Correct';
    assert.equal(feedback, expected, `with the secret ${secret}, the first line is ${JSON.stringify(feedback)}, expected ${JSON.stringify(expected)}`);
  }
});

test('the secret changes between runs', async () => {
  const seen = new Set();
  for (let run = 0; run < 10 && seen.size < 2; run++) seen.add((await play()).secret);
  assert.ok(seen.size > 1, `10 runs all gave the secret ${[...seen][0]}`);
});

package.json

{
  "type": "module"
}

package.json tells Node.js that the .js files are modules; keep it in the folder.

Run the program:

node main.js

Run the checks (needs learnrun.js in the same folder):

node --test
Download learnrun.js

Common mistakes

A guess declared with const

const secret = 42;
const guess = 30;
guess = 50;

What Node.js prints

TypeError: Assignment to constant variable.

Why, and the fix

A const cannot be given a new value, and the program stops at the line that tries. The guess changes every round, so declare it with let guess = 30; and keep const for the secret. The same happens with a const attempts counter.

A capital F in Math.floor

const secret = Math.Floor(Math.random() * 100) + 1;

What Node.js prints

TypeError: Math.Floor is not a function

Why, and the fix

Math exists, but it has no Floor with a capital F, so there is nothing to call. Names are case-sensitive: Math starts with a capital M, and its methods, floor and random, are in lower case.

A missing closing brace

const secret = 42;
const guess = 30;
if (guess < secret) {
  console.log(guess, "Too low");
} else {
  console.log(guess, "Too high or correct");

What Node.js prints

SyntaxError: Unexpected end of input

Why, and the fix

Every { needs its }. Here the else block is never closed, so JavaScript reaches the end of the file still waiting for it. As with every SyntaxError, no line runs. Match each { with its } and indent the code inside, so a missing one stands out.

JavaScript in the browser: your browser’s own engine, in a sandboxed worker. Syntax errors are located with acorn 8.18.0, MIT. Licence and source

Exit ticket

5 questions, no hints. Score 80% or more to complete the lesson.

Finish every activity above to unlock the exit ticket.

Report a problem

Spotted something wrong or unclear? Say what, and it will be checked and fixed.

#

At least 20 characters.

Only if you want a reply.

Key ideas

A first look at if and else

A game must choose what to print, and if…else does that. if (guess < secret) { … } runs its block in curly braces only when the condition in round brackets is true. else if (guess > secret) { … } is tried next, and else { … } runs when nothing before it was true: here, when the guess equals the secret. Exactly one of the three blocks runs. < means less than and > greater than; the comparison itself gives true or false. This is a preview: module B3 covers conditions in full.

const for what stays, let for what changes

The secret stays the same for the whole game, so it is a const. The guess changes every round and the attempts go up, so they are let. guess = 50; gives the variable a new value, and attempts = attempts + 1; adds one to the count. Try that on a const and the program stops with TypeError: Assignment to constant variable. The editor has no keyboard input, so the guesses are written into the program, one round after another. The repeated round is what loops (B3) and functions (B4) will make short.

A random secret, and a game you can debug

MDN’s version picks the secret with Math.floor(Math.random() * 100) + 1. Math.random() gives a decimal number from 0 up to, but not including, 1; times 100, it is below 100; Math.floor rounds it down to a whole number, 0 to 99; + 1 makes it 1 to 100. A random secret makes every run different, so print it while you test the game. When the feedback is wrong but no error appears, log guess and secret next to it: a < where a > belongs shows up at once.

Sources

Last reviewed September 30, 2026