diff --git a/projects/number-guessing-game/index.html b/projects/number-guessing-game/index.html
index f70b83a..3dcd566 100644
--- a/projects/number-guessing-game/index.html
+++ b/projects/number-guessing-game/index.html
@@ -4,16 +4,20 @@
-
-
-
-
-
+
+
I'm thinking of a number between 1 and 100. Can you guess it?
+
+
+
+
+
+
Attempts: 0
+
diff --git a/projects/number-guessing-game/main.js b/projects/number-guessing-game/main.js
index 64d8fa1..21865d6 100644
--- a/projects/number-guessing-game/main.js
+++ b/projects/number-guessing-game/main.js
@@ -1,15 +1,92 @@
-// TODO: Generate a random number
-// TODO: Handle user guess input
-// TODO: Compare guess to target number
-// TODO: Provide feedback (too high, too low, correct)
-// TODO: Track number of attempts
-// TODO: Restart game functionality
+// Utility to generate a random integer in [min, max]
+function generateRandomInteger(min, max) {
+ const minCeil = Math.ceil(min);
+ const maxFloor = Math.floor(max);
+ return Math.floor(Math.random() * (maxFloor - minCeil + 1)) + minCeil;
+}
function initNumberGuessingGame() {
- // TODO: Generate random number
- // TODO: Handle user input and feedback
- // TODO: Track attempts
- // TODO: Restart game
+ const input = document.getElementById('guess-input');
+ const guessBtn = document.getElementById('guess-btn');
+ const feedback = document.getElementById('feedback');
+ const attemptsText = document.getElementById('attempts');
+ const attemptCount = document.getElementById('attempt-count');
+ const restartBtn = document.getElementById('restart-btn');
+
+ const MIN = 1;
+ const MAX = 100;
+
+ let targetNumber = generateRandomInteger(MIN, MAX);
+ let attempts = 0;
+ let gameOver = false;
+
+ function setFeedback(message, type) {
+ feedback.textContent = message;
+ feedback.dataset.type = type || '';
+ }
+
+ function setGameOver(over) {
+ gameOver = over;
+ input.disabled = over;
+ guessBtn.disabled = over;
+ if (over) {
+ input.blur();
+ }
+ }
+
+ function validateGuess(value) {
+ if (value === '') return { ok: false, msg: 'Please enter a number.' };
+ const num = Number(value);
+ if (!Number.isFinite(num)) return { ok: false, msg: 'That is not a valid number.' };
+ if (!Number.isInteger(num)) return { ok: false, msg: 'Please enter a whole number.' };
+ if (num < MIN || num > MAX) return { ok: false, msg: `Enter a number between ${MIN} and ${MAX}.` };
+ return { ok: true, value: num };
+ }
+
+ function handleGuess() {
+ if (gameOver) return;
+ const { ok, msg, value } = validateGuess(input.value.trim());
+ if (!ok) {
+ setFeedback(msg, 'error');
+ return;
+ }
+ attempts += 1;
+ attemptCount.textContent = String(attempts);
+
+ if (value === targetNumber) {
+ setFeedback(`Correct! The number was ${targetNumber}.`, 'success');
+ setGameOver(true);
+ return;
+ }
+ if (value < targetNumber) {
+ setFeedback('Too low. Try a higher number.', 'low');
+ } else {
+ setFeedback('Too high. Try a lower number.', 'high');
+ }
+ input.select();
+ }
+
+ function restartGame() {
+ targetNumber = generateRandomInteger(MIN, MAX);
+ attempts = 0;
+ attemptCount.textContent = '0';
+ setFeedback('', '');
+ input.value = '';
+ setGameOver(false);
+ input.focus();
+ }
+
+ guessBtn.addEventListener('click', handleGuess);
+ input.addEventListener('keydown', function onKeyDown(event) {
+ if (event.key === 'Enter') {
+ handleGuess();
+ }
+ });
+ restartBtn.addEventListener('click', restartGame);
+
+ // Init state
+ attemptsText.hidden = false;
+ setFeedback('', '');
}
window.addEventListener('DOMContentLoaded', initNumberGuessingGame);
\ No newline at end of file
diff --git a/projects/number-guessing-game/styles.css b/projects/number-guessing-game/styles.css
index 95f3d47..c45c7ef 100644
--- a/projects/number-guessing-game/styles.css
+++ b/projects/number-guessing-game/styles.css
@@ -1 +1,68 @@
-/* TODO: Style game container, input, button, feedback, attempts, restart button */
\ No newline at end of file
+/* Basic reset */
+/* Page-level layout is handled by assets/styles.css; only tweak specifics here */
+html, body { height: 100%; }
+body {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ background: var(--bg);
+ color: var(--text);
+}
+
+h1 { margin: 24px 0 12px; font-size: 24px; font-weight: 700; color: var(--text); }
+
+#game-container {
+ width: 100%;
+ max-width: 420px;
+ background: var(--card);
+ border: 1px solid #262631;
+ border-radius: 12px;
+ padding: 20px;
+ box-shadow: 0 0 0 1px rgba(255,255,255,0.02) inset;
+}
+
+#instructions { margin: 0 0 12px; color: var(--muted); }
+
+#controls {
+ display: flex;
+ gap: 8px;
+}
+
+#guess-input {
+ flex: 1 1 auto;
+ padding: 10px 12px;
+ border: 1px solid #2a2a33;
+ border-radius: 8px;
+ font-size: 14px;
+ outline: none;
+ background: #0e0e13;
+ color: var(--text);
+}
+#guess-input::placeholder { color: var(--muted); }
+#guess-input:focus { border-color: #93c5fd; box-shadow: 0 0 0 3px rgba(147,197,253,0.2); }
+
+button {
+ padding: 10px 14px;
+ border-radius: 8px;
+ border: 1px solid #1e3a8a;
+ background: linear-gradient(135deg, var(--accent), var(--accent-2));
+ color: #0b1020;
+ font-weight: 600;
+ cursor: pointer;
+}
+button:hover { filter: brightness(1.05); }
+button:disabled { background: #1f1f27; border-color: #2a2a33; color: var(--muted); cursor: not-allowed; }
+
+#feedback { min-height: 22px; margin: 12px 0 8px; }
+#feedback[data-type="error"] { color: #f87171; }
+#feedback[data-type="low"], #feedback[data-type="high"] { color: #fbbf24; }
+#feedback[data-type="success"] { color: var(--accent); }
+
+#attempts { margin: 0 0 12px; color: var(--muted); }
+
+#restart-btn {
+ width: 100%;
+ background: linear-gradient(135deg, var(--accent), var(--accent-2));
+ border-color: #1e3a8a;
+}
+#restart-btn:hover { filter: brightness(1.05); }
\ No newline at end of file