From 2cca42ce07ce58d88c4ab23a9d1197c6078c9ad0 Mon Sep 17 00:00:00 2001 From: Atharv Nikam Date: Sun, 26 Oct 2025 16:02:37 +0530 Subject: [PATCH] feat(ui): enhance number guessing game UI for elegance --- projects/number-guessing-game/index.html | 38 +++-- projects/number-guessing-game/main.js | 148 ++++++++--------- projects/number-guessing-game/style.css | 200 +++++++++++++++++++++++ projects/number-guessing-game/styles.css | 68 -------- 4 files changed, 294 insertions(+), 160 deletions(-) create mode 100644 projects/number-guessing-game/style.css delete mode 100644 projects/number-guessing-game/styles.css diff --git a/projects/number-guessing-game/index.html b/projects/number-guessing-game/index.html index 3dcd566..9279c98 100644 --- a/projects/number-guessing-game/index.html +++ b/projects/number-guessing-game/index.html @@ -1,24 +1,30 @@ - - - Number Guessing Game - - + + + Number Guessing Game + + + -

Number Guessing Game

-
-

I'm thinking of a number between 1 and 100. Can you guess it?

-
- - +
+
+

Number Guessing Game

+

I'm thinking of a number between 1 and 100. Can you guess it?

+ +
+ + +
+ +

+

Attempts: 0

+ + +
-

-

Attempts: 0

- -
- + \ No newline at end of file diff --git a/projects/number-guessing-game/main.js b/projects/number-guessing-game/main.js index 21865d6..ece2ffc 100644 --- a/projects/number-guessing-game/main.js +++ b/projects/number-guessing-game/main.js @@ -1,92 +1,88 @@ -// 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; -} +// Get references to the HTML elements +const guessInput = document.getElementById('guessInput'); +const guessButton = document.getElementById('guessButton'); +const resetButton = document.getElementById('resetButton'); +const message = document.getElementById('message'); +const attemptsDisplay = document.getElementById('attempts'); -function initNumberGuessingGame() { - 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'); +// Game variables +let randomNumber; +let attempts; +const MIN_NUM = 1; +const MAX_NUM = 100; - const MIN = 1; - const MAX = 100; +// Function to start a new game or reset the current one +function newGame() { + // 1. Generate a new random number + randomNumber = Math.floor(Math.random() * (MAX_NUM - MIN_NUM + 1)) + MIN_NUM; + console.log(`The secret number is: ${randomNumber}`); // For testing purposes - let targetNumber = generateRandomInteger(MIN, MAX); - let attempts = 0; - let gameOver = false; + // 2. Reset the number of attempts + attempts = 0; + attemptsDisplay.textContent = `Attempts: ${attempts}`; - function setFeedback(message, type) { - feedback.textContent = message; - feedback.dataset.type = type || ''; - } + // 3. Clear messages and input field + message.textContent = ''; + guessInput.value = ''; - function setGameOver(over) { - gameOver = over; - input.disabled = over; - guessBtn.disabled = over; - if (over) { - input.blur(); - } - } + // 4. Re-enable input and guess button, hide reset button + guessInput.disabled = false; + guessButton.disabled = false; + resetButton.style.display = 'none'; // Hide the reset button + message.style.color = '#333'; // Default text color +} - 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 to handle the user's guess +function checkGuess() { + const userGuess = parseInt(guessInput.value); - function handleGuess() { - if (gameOver) return; - const { ok, msg, value } = validateGuess(input.value.trim()); - if (!ok) { - setFeedback(msg, 'error'); - return; + // Validate the input + if (isNaN(userGuess) || userGuess < MIN_NUM || userGuess > MAX_NUM) { + message.textContent = `Please enter a valid number between ${MIN_NUM} and ${MAX_NUM}.`; + message.style.color = 'orange'; // Will be mapped to var(--warning-color) by CSS + 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'); + // Increment attempts + attempts++; + attemptsDisplay.textContent = `Attempts: ${attempts}`; + + // Compare the guess and provide feedback + if (userGuess < randomNumber) { + message.textContent = 'Too Low! Try again.'; + message.style.color = '#3498db'; // Will be mapped by CSS + } else if (userGuess > randomNumber) { + message.textContent = 'Too High! Try again.'; + message.style.color = '#e74c3c'; // Will be mapped to var(--error-color) by CSS } else { - setFeedback('Too high. Try a lower number.', 'high'); + message.textContent = `Correct! You guessed the number ${randomNumber} in ${attempts} attempts! 🎉`; + message.style.color = '#2ecc71'; // Will be mapped to var(--success-color) by CSS + endGame(); } - input.select(); - } - function restartGame() { - targetNumber = generateRandomInteger(MIN, MAX); - attempts = 0; - attemptCount.textContent = '0'; - setFeedback('', ''); - input.value = ''; - setGameOver(false); - input.focus(); - } + // Clear the input for the next guess + guessInput.value = ''; + guessInput.focus(); +} + +// Function to end the game when the number is guessed correctly +function endGame() { + guessInput.disabled = true; + guessButton.disabled = true; + resetButton.style.display = 'inline-block'; // Show the reset button +} + +// Event Listeners +guessButton.addEventListener('click', checkGuess); +resetButton.addEventListener('click', newGame); - guessBtn.addEventListener('click', handleGuess); - input.addEventListener('keydown', function onKeyDown(event) { - if (event.key === 'Enter') { - handleGuess(); +// Allow pressing "Enter" to submit a guess +guessInput.addEventListener('keydown', (event) => { + if (event.key === 'Enter' && !guessButton.disabled) { // Ensure button is not disabled + checkGuess(); } - }); - restartBtn.addEventListener('click', restartGame); +}); - // Init state - attemptsText.hidden = false; - setFeedback('', ''); -} -window.addEventListener('DOMContentLoaded', initNumberGuessingGame); \ No newline at end of file +// Initialize the game when the page loads +newGame(); \ No newline at end of file diff --git a/projects/number-guessing-game/style.css b/projects/number-guessing-game/style.css new file mode 100644 index 0000000..bd0ef51 --- /dev/null +++ b/projects/number-guessing-game/style.css @@ -0,0 +1,200 @@ +/* Custom properties for easy theme management */ +:root { + --primary-color: #6a0572; /* Deep purple */ + --secondary-color: #8e2de2; /* Lighter purple */ + --accent-color: #e0b4ff; /* Light purple for highlights */ + --text-dark: #333333; + --text-light: #f4f4f4; + --background-light: #f0f2f5; /* Light grey for body background */ + --card-background: #ffffff; + --success-color: #28a745; + --error-color: #dc3545; + --warning-color: #ffc107; + --border-color: #dddddd; + --box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1); + --border-radius-card: 15px; + --border-radius-elements: 8px; +} + +body { + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + margin: 0; + background: linear-gradient(135deg, var(--background-light) 0%, var(--accent-color) 100%); /* Subtle gradient */ + font-family: 'Poppins', sans-serif; /* Use Poppins for a modern look */ + color: var(--text-dark); + line-height: 1.6; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.card { + background: var(--card-background); + padding: 2.5rem 2rem; /* Increased padding */ + border-radius: var(--border-radius-card); + box-shadow: var(--box-shadow); + text-align: center; + max-width: 450px; /* Slightly wider card */ + width: 90%; + position: relative; + overflow: hidden; /* For potential background elements */ + animation: fadeIn 0.8s ease-out; /* Add a subtle fade-in animation */ +} + +/* Header */ +h1 { + font-family: 'Poppins', sans-serif; + font-weight: 700; + color: var(--primary-color); + margin-bottom: 0.8rem; + font-size: 2.2rem; /* Larger heading */ + letter-spacing: -0.5px; +} + +.description { + font-family: 'Roboto', sans-serif; + font-size: 1.05rem; + color: #555; + margin-bottom: 2rem; /* More space below description */ +} + +/* Input Group */ +.input-group { + display: flex; + gap: 12px; /* Slightly increased gap */ + margin: 2rem 0; +} + +#guessInput { + flex-grow: 1; + padding: 0.9rem 1.2rem; /* More padding */ + border: 2px solid var(--border-color); /* Thicker border */ + border-radius: var(--border-radius-elements); + font-size: 1.1rem; /* Larger font size */ + font-family: 'Roboto', sans-serif; + color: var(--text-dark); + transition: border-color 0.3s ease, box-shadow 0.3s ease; /* Smooth transitions */ + -webkit-appearance: none; /* Remove default number input styling */ + -moz-appearance: textfield; /* Firefox number input styling */ +} + +#guessInput:focus { + outline: none; + border-color: var(--primary-color); /* Highlight on focus */ + box-shadow: 0 0 0 3px rgba(106, 5, 114, 0.2); /* Subtle glow */ +} + +/* Buttons */ +.btn { + padding: 0.9rem 1.5rem; + border: none; + border-radius: var(--border-radius-elements); + font-size: 1.05rem; + font-weight: 600; + cursor: pointer; + transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.primary-btn { + background-color: var(--primary-color); + color: var(--text-light); + box-shadow: 0 4px 15px rgba(106, 5, 114, 0.3); +} + +.primary-btn:hover { + background-color: var(--secondary-color); + transform: translateY(-2px); /* Lift effect */ + box-shadow: 0 6px 20px rgba(142, 45, 226, 0.4); +} + +.primary-btn:active { + transform: translateY(0); + box-shadow: 0 2px 10px rgba(106, 5, 114, 0.2); +} + +.secondary-btn { + background-color: #e9e9e9; + color: var(--primary-color); + border: 1px solid var(--primary-color); +} + +.secondary-btn:hover { + background-color: var(--accent-color); + transform: translateY(-2px); + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); +} + +.secondary-btn:active { + transform: translateY(0); + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); +} + +.btn:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none; + box-shadow: none; +} + +/* Messages and Attempts */ +.message { + min-height: 28px; /* Ensure consistent height */ + font-weight: 600; + font-size: 1.15rem; /* Slightly larger message */ + margin-bottom: 1.5rem; + transition: color 0.3s ease; +} + +.message[style*="color: rgb(46, 204, 113)"] { /* Correct! - Green */ + color: var(--success-color) !important; +} +.message[style*="color: rgb(52, 152, 219)"] { /* Too Low! - Blue */ + color: #3498db !important; /* Keeping original for "too low" as a different shade */ +} +.message[style*="color: rgb(231, 76, 60)"] { /* Too High! - Red */ + color: var(--error-color) !important; +} +.message[style*="color: orange"] { /* Validation error - Orange */ + color: var(--warning-color) !important; +} + + +.attempts { + font-family: 'Roboto', sans-serif; + color: #777; + margin-bottom: 2rem; /* More space below attempts */ + font-size: 1rem; +} + +.reset-btn { + display: none; /* Initially hidden */ + margin-top: 1rem; +} + +/* Animations */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Ensure number input arrows are hidden for a cleaner look */ +/* For Chrome, Safari, Edge, Opera */ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} +/* For Firefox */ +input[type=number] { + -moz-appearance: textfield; +} \ No newline at end of file diff --git a/projects/number-guessing-game/styles.css b/projects/number-guessing-game/styles.css deleted file mode 100644 index c45c7ef..0000000 --- a/projects/number-guessing-game/styles.css +++ /dev/null @@ -1,68 +0,0 @@ -/* 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