JavaScript Tutorial
JavaScript Project: Guess the Number
Guess a secret integer. The page says high, low, or correct and counts the attempts.
What you will build
A guessing game. The script picks a secret integer from 1 to 100. The visitor types a guess. The page answers too high, too low, or correct, and counts how many tries it took.
After a correct guess the field locks until a new game starts. A New game button draws a fresh secret and resets the attempt count so you can play again without reloading.
Open an example with Try it in JavaScript. That loads /javascript/try — a live page and a console.
Methods you will use
| Method | Job on this page |
|---|---|
Math.random | Picks a new secret in the range 1 to 100 |
if | Compares the guess to the secret: high, low, or equal |
input / .value | Reads the integer the visitor typed |
Number.isInteger | Rejects blanks, decimals, and text |
textContent | Writes the hint and the attempt count |
Math.floor(Math.random() * 100) + 1 yields 1 through 100, inclusive. Leaving off the+ 1 would include 0 and exclude 100.
Build in slices
The form is a number field, a guess button, a new-game button, a hint line, and an attempt line. Disable nothing yet. That comes after a correct answer.
Example
<label for="guess">Your guess (1–100)</label>
<input id="guess" type="number" min="1" max="100" step="1">
<button id="check" type="button">Guess</button>
<button id="again" type="button">New game</button>
<p id="hint">I picked a number.</p>
<p id="tries">Attempts: 0</p>Pick the secret once. Increment attempts only when the guess is a valid integer in range. Compare with three branches.
Example
let secret = Math.floor(Math.random() * 100) + 1;
let attempts = 0;
function checkGuess(raw) {
const guess = Number(raw);
if (!Number.isInteger(guess) || guess < 1 || guess > 100) {
return "Enter a whole number from 1 to 100.";
}
attempts += 1;
if (guess < secret) return guess + " is too low.";
if (guess > secret) return guess + " is too high.";
return guess + " is correct in " + attempts + " attempts.";
}Hook the function to the button. When the guess matches, disable the field and the guess button so extra clicks do not inflate the count.
Example
<label for="guess">Your guess (1–100)</label>
<input id="guess" type="number" min="1" max="100" step="1">
<button id="check" type="button">Guess</button>
<p id="hint">I picked a number.</p>
<p id="tries">Attempts: 0</p>
<script>
let secret = Math.floor(Math.random() * 100) + 1;
let attempts = 0;
const field = document.getElementById("guess");
const check = document.getElementById("check");
const hint = document.getElementById("hint");
const tries = document.getElementById("tries");
check.addEventListener("click", function () {
const guess = Number(field.value);
if (!Number.isInteger(guess) || guess < 1 || guess > 100) {
hint.textContent = "Enter a whole number from 1 to 100.";
return;
}
attempts += 1;
tries.textContent = "Attempts: " + attempts;
if (guess < secret) hint.textContent = guess + " is too low.";
else if (guess > secret) hint.textContent = guess + " is too high.";
else {
hint.textContent = guess + " is correct in " + attempts + " attempts.";
field.disabled = true;
check.disabled = true;
}
});
</script>While you debug, console.log(secret) in /javascript/try so you can confirm high and low. Remove that log from the finished page. Use Try it in JavaScript.
Complete document
This file is the game you would keep. New game draws a new secret, clears the hint, enables the controls, and focuses the field. The secret is never printed on the page.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Guess the Number</title>
<style>
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background: #fefce8;
font-family: "Segoe UI", system-ui, sans-serif;
color: #1c1917;
}
.card {
width: min(22rem, 92vw);
background: #fffbeb;
border: 1px solid #fde68a;
padding: 1.4rem 1.5rem 1.5rem;
}
h1 { margin: 0 0 0.35rem; font-size: 1.4rem; }
.lead { margin: 0 0 1rem; color: #78716c; }
label { display: block; font-weight: 700; margin-bottom: 0.35rem; }
input {
width: 100%;
box-sizing: border-box;
padding: 0.45rem 0.55rem;
border: 1px solid #d6d3d1;
font: inherit;
margin-bottom: 0.75rem;
}
.row { display: flex; gap: 0.5rem; }
button {
padding: 0.5rem 0.85rem;
border: 0;
background: #854d0e;
color: #fffbeb;
font: inherit;
font-weight: 700;
cursor: pointer;
}
button:disabled { opacity: 0.5; cursor: default; }
#again { background: #a8a29e; color: #1c1917; }
#hint { margin: 1rem 0 0.35rem; min-height: 1.4rem; }
#tries { margin: 0; color: #78716c; }
</style>
</head>
<body>
<article class="card">
<h1>Guess the Number</h1>
<p class="lead">I picked an integer from 1 to 100.</p>
<label for="guess">Your guess</label>
<input id="guess" type="number" min="1" max="100" step="1">
<div class="row">
<button id="check" type="button">Guess</button>
<button id="again" type="button">New game</button>
</div>
<p id="hint">Make a guess.</p>
<p id="tries">Attempts: 0</p>
</article>
<script>
const field = document.getElementById("guess");
const checkBtn = document.getElementById("check");
const againBtn = document.getElementById("again");
const hint = document.getElementById("hint");
const tries = document.getElementById("tries");
let secret = 0;
let attempts = 0;
function newSecret() {
return Math.floor(Math.random() * 100) + 1;
}
function startGame() {
secret = newSecret();
attempts = 0;
field.value = "";
field.disabled = false;
checkBtn.disabled = false;
hint.textContent = "Make a guess.";
tries.textContent = "Attempts: 0";
field.focus();
}
function checkGuess() {
const guess = Number(field.value);
if (!Number.isInteger(guess) || guess < 1 || guess > 100) {
hint.textContent = "Enter a whole number from 1 to 100.";
return;
}
attempts += 1;
tries.textContent = "Attempts: " + attempts;
if (guess < secret) {
hint.textContent = guess + " is too low.";
} else if (guess > secret) {
hint.textContent = guess + " is too high.";
} else {
hint.textContent = guess + " is correct in " + attempts + " attempts.";
field.disabled = true;
checkBtn.disabled = true;
}
}
checkBtn.addEventListener("click", checkGuess);
field.addEventListener("keydown", function (event) {
if (event.key === "Enter" && !checkBtn.disabled) checkGuess();
});
againBtn.addEventListener("click", startGame);
startGame();
</script>
</body>
</html>Fair range and fair counting
Invalid input must not count as an attempt. Typing "hello" is not a guess. The same applies to 0, 101, and 12.5. Only a whole number inside the stated range moves the counter.
Do not print the secret in the heading "for testing" and then forget to remove it. If you need a peek, log it to the console in the editor, then delete the log.
Common mistakes
- Using
Math.round(Math.random() * 100). That distribution is uneven at 0 and 100. - Comparing with
==after reading a string and skippingNumber. It can still work, then fail on blanks. - Incrementing attempts before validating. Empty clicks would pad the score.
- Picking a new secret on every guess. The target would move and "too low" would lie.
- Leaving the field enabled after a win so a second click reports "too high" on the same number.
Practice tasks
- Change the range to 1–50. Update the lead text, the min/max attributes, and the random formula together.
- Track the fewest attempts in a
bestvariable and show it under the current count. - After seven misses, reveal the secret and lock the game. Preview at /javascript/try.