diff --git a/web-app/js/projects/hangman.js b/web-app/js/projects/hangman.js index 052e5a9c..f09d86b8 100644 --- a/web-app/js/projects/hangman.js +++ b/web-app/js/projects/hangman.js @@ -1,38 +1,74 @@ function getHangmanHTML() { return `
-

๐ŸŽฎ Hangman Game

+

Hangman Game

-
-
- Attempts Left: - 6 -
-
- Word Length: - 0 + + +
+

Choose your difficulty!

+
+ + +
- - - -
- -
-

Guessed Letters:

-
None
+ + + - -
- -

โŒจ๏ธ Type any letter key to guess directly

- -
- - +
- + `; } function initHangman() { - const canvas = document.getElementById('hangmanCanvas'); - const ctx = canvas.getContext('2d'); - const wordDisplay = document.getElementById('wordDisplay'); - const guessedList = document.getElementById('guessedList'); - const attemptsLeftEl = document.getElementById('attemptsLeft'); - const wordLengthEl = document.getElementById('wordLength'); - const keyboard = document.getElementById('keyboard'); - const gameMessage = document.getElementById('gameMessage'); - const newGameBtn = document.getElementById('newGameBtn'); - - const words = ['python', 'programming', 'computer', 'algorithm', 'keyboard', - 'monitor', 'software', 'hardware', 'database', 'network', - 'internet', 'developer', 'variable', 'function', 'application']; - - let currentWord = ''; + // โ”€โ”€ Word lists by difficulty + const WORD_LISTS = { + easy: [ + { word: 'cat', hint: 'Small furry pet ๐Ÿฑ' }, + { word: 'dog', hint: 'Man\'s best friend ๐Ÿถ' }, + { word: 'sun', hint: 'Shines in the sky โ˜€๏ธ' }, + { word: 'rain', hint: 'Falls from clouds ๐ŸŒง๏ธ' }, + { word: 'fish', hint: 'Swims in water ๐ŸŸ' }, + { word: 'bird', hint: 'Has wings and can fly ๐Ÿฆ' }, + { word: 'cake', hint: 'Sweet baked treat ๐ŸŽ‚' }, + { word: 'star', hint: 'Twinkles at night โญ' }, + { word: 'tree', hint: 'Has leaves and bark ๐ŸŒณ' }, + { word: 'frog', hint: 'Green and hops around ๐Ÿธ' }, + { word: 'milk', hint: 'White drink from cows ๐Ÿฅ›' }, + { word: 'ball', hint: 'Round toy you throw โšฝ' }, + { word: 'moon', hint: 'Glows at night ๐ŸŒ™' }, + { word: 'lion', hint: 'King of the jungle ๐Ÿฆ' }, + { word: 'rose', hint: 'Fragrant red flower ๐ŸŒน' }, + ], + medium: [ + { word: 'python', hint: 'Programming language ๐Ÿ' }, + { word: 'keyboard', hint: 'Used to type input โŒจ๏ธ' }, + { word: 'monitor', hint: 'Displays output on screen ๐Ÿ–ฅ๏ธ' }, + { word: 'internet', hint: 'Global network ๐ŸŒ' }, + { word: 'database', hint: 'Stores structured data' }, + { word: 'elephant', hint: 'Largest land animal ๐Ÿ˜' }, + { word: 'football', hint: 'Played worldwide โšฝ' }, + { word: 'cricket', hint: 'Popular sport ๐Ÿ' }, + { word: 'teacher', hint: 'Person who teaches' }, + { word: 'library', hint: 'Place full of books ๐Ÿ“š' }, + { word: 'battery', hint: 'Stores electrical power ๐Ÿ”‹' }, + { word: 'engineer', hint: 'Designs and builds things ๐Ÿ”ง' }, + { word: 'hospital', hint: 'Where patients are treated ๐Ÿฅ' }, + { word: 'calendar', hint: 'Tracks days and months ๐Ÿ“…' }, + { word: 'adventure', hint: 'An exciting journey ๐Ÿ—บ๏ธ' }, + ], + hard: [ + { word: 'algorithm', hint: 'Step-by-step problem-solving method' }, + { word: 'cryptography', hint: 'Science of secret codes ๐Ÿ”' }, + { word: 'asynchronous', hint: 'Not happening at the same time' }, + { word: 'polymorphism', hint: 'OOP concept: many forms' }, + { word: 'encapsulation', hint: 'OOP: bundling data with methods' }, + { word: 'microprocessor', hint: 'Brain of a computer chip ๐Ÿ’พ' }, + { word: 'infrastructure', hint: 'Underlying foundation of a system' }, + { word: 'authentication', hint: 'Verifying who you are ๐Ÿ”‘' }, + { word: 'concatenation', hint: 'Joining strings end to end' }, + { word: 'parallelism', hint: 'Running tasks simultaneously' }, + { word: 'semiconductor', hint: 'Material used in electronics' }, + { word: 'extrapolation', hint: 'Estimating beyond known data' }, + { word: 'vulnerability', hint: 'A security weakness ๐Ÿ›ก๏ธ' }, + { word: 'decomposition', hint: 'Breaking a problem into parts' }, + { word: 'initialization', hint: 'Setting up a starting value' }, + ], + }; + + const DIFFICULTIES = { + easy: { label: '๐ŸŸข Easy', maxAttempts: 8 }, + medium: { label: '๐ŸŸก Medium', maxAttempts: 6 }, + hard: { label: '๐Ÿ”ด Hard', maxAttempts: 5 }, + }; + + // โ”€โ”€ DOM refs + const difficultyScreen = document.getElementById('hangmanDifficultyScreen'); + const gameScreen = document.getElementById('hangmanGameScreen'); + const canvas = document.getElementById('hangmanCanvas'); + const ctx = canvas.getContext('2d'); + const wordDisplay = document.getElementById('wordDisplay'); + const guessedList = document.getElementById('guessedList'); + const attemptsLeftEl = document.getElementById('attemptsLeft'); + const wordLengthEl = document.getElementById('wordLength'); + const keyboard = document.getElementById('keyboard'); + const gameMessage = document.getElementById('gameMessage'); + const newGameBtn = document.getElementById('newGameBtn'); + const changeDiffBtn = document.getElementById('hangmanChangeDiff'); + const currentDiffLabel = document.getElementById('currentDiffLabel'); + const hintBox = document.getElementById('hintBox'); + + // โ”€โ”€ State + let currentWord = ''; + let currentHint = ''; let guessedLetters = []; let correctLetters = []; - let wrongAttempts = 0; - const maxAttempts = 6; - let gameOver = false; - - function createKeyboard() { - keyboard.innerHTML = ''; - const letters = 'abcdefghijklmnopqrstuvwxyz'.split(''); - - letters.forEach(letter => { - const btn = document.createElement('button'); - btn.className = 'key-btn'; - btn.textContent = letter.toUpperCase(); - btn.dataset.letter = letter; - btn.addEventListener('click', () => guessLetter(letter)); - keyboard.appendChild(btn); + let wrongAttempts = 0; + let maxAttempts = 6; + let gameOver = false; + let currentDiff = 'medium'; + + // โ”€โ”€ Difficulty selection + document.querySelectorAll('.difficulty-card').forEach(card => { + card.addEventListener('click', () => { + currentDiff = card.dataset.difficulty; + difficultyScreen.style.display = 'none'; + gameScreen.style.display = ''; + initGame(); + drawGallows(); }); - } - - function drawHangman(stage) { - ctx.strokeStyle = '#64748b'; - ctx.lineWidth = 3; - ctx.lineCap = 'round'; - - switch(stage) { - case 1: - ctx.beginPath(); - ctx.moveTo(50, 320); - ctx.lineTo(200, 320); - ctx.stroke(); - break; - case 2: - ctx.beginPath(); - ctx.moveTo(100, 320); - ctx.lineTo(100, 50); - ctx.stroke(); - break; - case 3: - ctx.beginPath(); - ctx.moveTo(100, 50); - ctx.lineTo(200, 50); - ctx.stroke(); - break; - case 4: - ctx.beginPath(); - ctx.moveTo(200, 50); - ctx.lineTo(200, 80); - ctx.stroke(); - break; - case 5: - ctx.beginPath(); - ctx.arc(200, 100, 20, 0, Math.PI * 2); - ctx.stroke(); - ctx.fillStyle = '#64748b'; - ctx.beginPath(); - ctx.arc(195, 95, 2, 0, Math.PI * 2); - ctx.fill(); - ctx.beginPath(); - ctx.arc(205, 95, 2, 0, Math.PI * 2); - ctx.fill(); - ctx.beginPath(); - ctx.arc(200, 105, 8, 0, Math.PI, false); - ctx.stroke(); - break; - case 6: - ctx.beginPath(); - ctx.moveTo(200, 120); - ctx.lineTo(200, 200); - ctx.stroke(); - break; - case 7: - ctx.beginPath(); - ctx.moveTo(200, 140); - ctx.lineTo(170, 170); - ctx.stroke(); - break; - case 8: - ctx.beginPath(); - ctx.moveTo(200, 140); - ctx.lineTo(230, 170); - ctx.stroke(); - break; - case 9: - ctx.beginPath(); - ctx.moveTo(200, 200); - ctx.lineTo(180, 250); - ctx.stroke(); - break; - case 10: - ctx.beginPath(); - ctx.moveTo(200, 200); - ctx.lineTo(220, 250); - ctx.stroke(); - break; - } - } - + }); + + // โ”€โ”€ Game init function initGame() { - currentWord = words[Math.floor(Math.random() * words.length)]; + const config = DIFFICULTIES[currentDiff]; + maxAttempts = config.maxAttempts; + + const list = WORD_LISTS[currentDiff]; + const chosen = list[Math.floor(Math.random() * list.length)]; + currentWord = chosen.word; + currentHint = chosen.hint; + guessedLetters = []; correctLetters = []; - wrongAttempts = 0; - gameOver = false; - + wrongAttempts = 0; + gameOver = false; + ctx.clearRect(0, 0, canvas.width, canvas.height); - - wordLengthEl.textContent = currentWord.length; - attemptsLeftEl.textContent = maxAttempts; - guessedList.textContent = 'None'; - gameMessage.textContent = ''; - gameMessage.className = 'game-message'; - + + currentDiffLabel.textContent = config.label; + wordLengthEl.textContent = currentWord.length; + attemptsLeftEl.textContent = maxAttempts; + guessedList.textContent = 'None'; + gameMessage.textContent = ''; + gameMessage.className = 'game-message'; + hintBox.textContent = `Hint: ${currentHint}`; + createKeyboard(); updateWordDisplay(); } - + + // โ”€โ”€ Keyboard UI + function createKeyboard() { + keyboard.innerHTML = ''; + 'abcdefghijklmnopqrstuvwxyz'.split('').forEach(letter => { + const btn = document.createElement('button'); + btn.className = 'key-btn'; + btn.textContent = letter.toUpperCase(); + btn.dataset.letter = letter; + btn.addEventListener('click', () => guessLetter(letter)); + keyboard.appendChild(btn); + }); + } + + // โ”€โ”€ Word display function updateWordDisplay() { wordDisplay.innerHTML = ''; - for (let letter of currentWord) { - const letterBox = document.createElement('div'); - letterBox.className = 'letter-box'; - letterBox.textContent = correctLetters.includes(letter) ? letter.toUpperCase() : ''; - wordDisplay.appendChild(letterBox); + for (const letter of currentWord) { + const box = document.createElement('div'); + box.className = 'letter-box'; + box.textContent = correctLetters.includes(letter) ? letter.toUpperCase() : ''; + wordDisplay.appendChild(box); } } - + + // โ”€โ”€ Guess logic function guessLetter(letter) { if (gameOver || guessedLetters.includes(letter)) return; - + guessedLetters.push(letter); - + const btn = keyboard.querySelector(`[data-letter="${letter}"]`); if (btn) { btn.disabled = true; - // Flash the button briefly when triggered by keyboard btn.classList.add('key-flash'); setTimeout(() => btn.classList.remove('key-flash'), 150); } - + if (currentWord.includes(letter)) { correctLetters.push(letter); btn && btn.classList.add('correct'); - updateWordDisplay(); - + if (currentWord.split('').every(l => correctLetters.includes(l))) { gameOver = true; - gameMessage.textContent = '๐ŸŽ‰ Congratulations! You won!'; - gameMessage.className = 'game-message win'; + gameMessage.textContent = ' Congratulations! You won!'; + gameMessage.className = 'game-message win'; disableAllKeys(); } } else { wrongAttempts++; btn && btn.classList.add('wrong'); - - const drawStage = wrongAttempts + 4; - drawHangman(drawStage); - + drawHangman(wrongAttempts + 4); attemptsLeftEl.textContent = maxAttempts - wrongAttempts; - + if (wrongAttempts >= maxAttempts) { gameOver = true; - gameMessage.innerHTML = `๐Ÿ˜” Game Over! The word was: ${currentWord.toUpperCase()}`; + gameMessage.innerHTML = ` Game Over! The word was: ${currentWord.toUpperCase()}`; gameMessage.className = 'game-message lose'; disableAllKeys(); + // Reveal word in red wordDisplay.innerHTML = ''; - for (let letter of currentWord) { - const letterBox = document.createElement('div'); - letterBox.className = 'letter-box'; - letterBox.textContent = letter.toUpperCase(); - letterBox.style.color = 'var(--danger-color)'; - wordDisplay.appendChild(letterBox); + for (const letter of currentWord) { + const box = document.createElement('div'); + box.className = 'letter-box'; + box.textContent = letter.toUpperCase(); + box.style.color = 'var(--danger-color)'; + wordDisplay.appendChild(box); } } } - + guessedList.textContent = guessedLetters.join(', ').toUpperCase(); } - + function disableAllKeys() { - keyboard.querySelectorAll('.key-btn').forEach(btn => { - btn.disabled = true; - }); + keyboard.querySelectorAll('.key-btn').forEach(b => { b.disabled = true; }); } - + + // โ”€โ”€ Draw hangman + function drawHangman(stage) { + ctx.strokeStyle = '#64748b'; + ctx.lineWidth = 3; + ctx.lineCap = 'round'; + + switch (stage) { + case 1: ctx.beginPath(); ctx.moveTo(50, 320); ctx.lineTo(200, 320); ctx.stroke(); break; + case 2: ctx.beginPath(); ctx.moveTo(100, 320); ctx.lineTo(100, 50); ctx.stroke(); break; + case 3: ctx.beginPath(); ctx.moveTo(100, 50); ctx.lineTo(200, 50); ctx.stroke(); break; + case 4: ctx.beginPath(); ctx.moveTo(200, 50); ctx.lineTo(200, 80); ctx.stroke(); break; + case 5: + ctx.beginPath(); ctx.arc(200, 100, 20, 0, Math.PI * 2); ctx.stroke(); + ctx.fillStyle = '#64748b'; + ctx.beginPath(); ctx.arc(195, 95, 2, 0, Math.PI * 2); ctx.fill(); + ctx.beginPath(); ctx.arc(205, 95, 2, 0, Math.PI * 2); ctx.fill(); + ctx.beginPath(); ctx.arc(200, 105, 8, 0, Math.PI, false); ctx.stroke(); + break; + case 6: ctx.beginPath(); ctx.moveTo(200, 120); ctx.lineTo(200, 200); ctx.stroke(); break; + case 7: ctx.beginPath(); ctx.moveTo(200, 140); ctx.lineTo(170, 170); ctx.stroke(); break; + case 8: ctx.beginPath(); ctx.moveTo(200, 140); ctx.lineTo(230, 170); ctx.stroke(); break; + case 9: ctx.beginPath(); ctx.moveTo(200, 200); ctx.lineTo(180, 250); ctx.stroke(); break; + case 10: ctx.beginPath(); ctx.moveTo(200, 200); ctx.lineTo(220, 250); ctx.stroke(); break; + } + } + function drawGallows() { - drawHangman(1); - drawHangman(2); - drawHangman(3); - drawHangman(4); + drawHangman(1); drawHangman(2); drawHangman(3); drawHangman(4); } - - newGameBtn.addEventListener('click', () => { - initGame(); - drawGallows(); + + // โ”€โ”€ Buttons + newGameBtn.addEventListener('click', () => { initGame(); drawGallows(); }); + + changeDiffBtn.addEventListener('click', () => { + gameScreen.style.display = 'none'; + difficultyScreen.style.display = ''; }); - // Keyboard handler โ€” using keydown instead of deprecated keypress + // โ”€โ”€ Physical keyboard function handleKeydown(e) { if (gameOver) return; - // Ignore if user is typing in an input field if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; const letter = e.key.toLowerCase(); - if (/^[a-z]$/.test(letter) && !guessedLetters.includes(letter)) { - guessLetter(letter); - } + if (/^[a-z]$/.test(letter) && !guessedLetters.includes(letter)) guessLetter(letter); } document.addEventListener('keydown', handleKeydown); - // Clean up listener when modal closes + // Clean up when modal closes const observer = new MutationObserver(() => { if (!document.getElementById('newGameBtn')) { document.removeEventListener('keydown', handleKeydown); @@ -450,7 +585,4 @@ function initHangman() { } }); observer.observe(document.body, { childList: true, subtree: true }); - - initGame(); - drawGallows(); } \ No newline at end of file diff --git a/web-app/js/projects/number-guessing.js b/web-app/js/projects/number-guessing.js index a8a8f179..9c09faee 100644 --- a/web-app/js/projects/number-guessing.js +++ b/web-app/js/projects/number-guessing.js @@ -1,56 +1,160 @@ function getNumberGuessingHTML() { return `
-

๐ŸŽฏ Number Guessing Game

+

Number Guessing Game

-

I'm thinking of a number between 1 and 100!

- -
- - + + +
+

Choose your difficulty to start!

+
+ + + +
-

โŒจ๏ธ Press Enter to submit your guess

- - - -
-
- Attempts: - 0 + + - + `; } function initNumberGuessing() { - let secretNumber = Math.floor(Math.random() * 100) + 1; - let attempts = 0; - let minRange = 1; - let maxRange = 100; - - const guessInput = document.getElementById('guessInput'); - const submitBtn = document.getElementById('submitGuess'); - const feedback = document.getElementById('feedback'); - const attemptsDisplay = document.getElementById('attempts'); - const rangeDisplay = document.getElementById('range'); - const bestScoreDisplay = document.getElementById('bestScore'); - const resetBtn = document.getElementById('resetGuessing'); + // โ”€โ”€ Difficulty config โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + const DIFFICULTIES = { + easy: { label: '๐ŸŸข Easy', min: 1, max: 100, attempts: 10 }, + medium: { label: '๐ŸŸก Medium', min: 1, max: 100, attempts: 7 }, + hard: { label: '๐Ÿ”ด Hard', min: 1, max: 200, attempts: 5 }, + }; + // โ”€โ”€ Storage โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const storage = window.appStorage || { - saveToStorage(key, value) { - localStorage.setItem(key, JSON.stringify(value)); - }, + saveToStorage(key, value) { localStorage.setItem(key, JSON.stringify(value)); }, loadFromStorage(key, defaultValue = null) { const data = localStorage.getItem(key); if (!data) return defaultValue; - try { - return JSON.parse(data); - } catch { - return defaultValue; - } + try { return JSON.parse(data); } catch { return defaultValue; } }, }; - let bestScore = storage.loadFromStorage('numberGuessBest', null); - updateBestScoreDisplay(); + // โ”€โ”€ DOM refs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + const difficultyScreen = document.getElementById('difficultyScreen'); + const gameScreen = document.getElementById('gameScreen'); + const difficultyBadge = document.getElementById('difficultyBadge'); + const gameInstructions = document.getElementById('gameInstructions'); + const attemptsBar = document.getElementById('attemptsBar'); + const guessInput = document.getElementById('guessInput'); + const submitBtn = document.getElementById('submitGuess'); + const feedback = document.getElementById('feedback'); + const attemptsLeftEl = document.getElementById('attemptsLeft'); + const rangeDisplay = document.getElementById('range'); + const bestScoreDisplay = document.getElementById('bestScore'); + const resetBtn = document.getElementById('resetGuessing'); + const changeDiffBtn = document.getElementById('changeDifficulty'); - // Focus input automatically so Enter works right away - guessInput.focus(); + // โ”€โ”€ State + let secretNumber, attempts, minRange, maxRange, maxAttempts, currentDiff; - submitBtn.addEventListener('click', makeGuess); - guessInput.addEventListener('keydown', (e) => { - if (e.key === 'Enter') makeGuess(); + // โ”€โ”€ Difficulty selection + document.querySelectorAll('.difficulty-card').forEach(card => { + card.addEventListener('click', () => startGame(card.dataset.difficulty)); }); - - resetBtn.addEventListener('click', () => { - secretNumber = Math.floor(Math.random() * 100) + 1; - attempts = 0; - minRange = 1; - maxRange = 100; - attemptsDisplay.textContent = '0'; - rangeDisplay.textContent = '1-100'; - feedback.textContent = ''; + + function startGame(diffKey) { + currentDiff = diffKey; + const config = DIFFICULTIES[diffKey]; + maxAttempts = config.attempts; + minRange = config.min; + maxRange = config.max; + secretNumber = Math.floor(Math.random() * (config.max - config.min + 1)) + config.min; + attempts = 0; + + // Badge + difficultyBadge.textContent = config.label; + difficultyBadge.className = `difficulty-badge ${diffKey}`; + + // Instruction + gameInstructions.textContent = + `I'm thinking of a number between ${config.min} and ${config.max}!`; + + // Input bounds + guessInput.min = config.min; + guessInput.max = config.max; guessInput.value = ''; + + // Stats + attemptsLeftEl.textContent = maxAttempts; + rangeDisplay.textContent = `${config.min}โ€“${config.max}`; + feedback.textContent = ''; + feedback.style.color = ''; + + updateBar(maxAttempts, maxAttempts); + updateBestScore(diffKey); + guessInput.disabled = false; - submitBtn.disabled = false; - guessInput.focus(); - }); + submitBtn.disabled = false; - function updateBestScoreDisplay() { - bestScoreDisplay.textContent = bestScore === null ? 'โ€”' : `${bestScore} attempt${bestScore === 1 ? '' : 's'}`; + difficultyScreen.style.display = 'none'; + gameScreen.style.display = ''; + guessInput.focus(); } - function saveBestScore(newScore) { - bestScore = newScore; - storage.saveToStorage('numberGuessBest', bestScore); - updateBestScoreDisplay(); - } - + // Gameplay + submitBtn.addEventListener('click', makeGuess); + guessInput.addEventListener('keydown', e => { if (e.key === 'Enter') makeGuess(); }); + function makeGuess() { - const guess = parseInt(guessInput.value); - - if (isNaN(guess) || guess < 1 || guess > 100) { - feedback.textContent = 'โš ๏ธ Please enter a number between 1 and 100!'; + const config = DIFFICULTIES[currentDiff]; + const guess = parseInt(guessInput.value); + + if (isNaN(guess) || guess < config.min || guess > config.max) { + feedback.textContent = `โš ๏ธ Please enter a number between ${config.min} and ${config.max}!`; feedback.style.color = 'var(--warning-color)'; return; } - + attempts++; - attemptsDisplay.textContent = attempts; - + const remaining = maxAttempts - attempts; + attemptsLeftEl.textContent = remaining; + updateBar(remaining, maxAttempts); + if (guess === secretNumber) { - feedback.textContent = `๐ŸŽ‰ Congratulations! You found it in ${attempts} attempts!`; + feedback.textContent = `๐ŸŽ‰ Correct! You found it in ${attempts} attempt${attempts === 1 ? '' : 's'}!`; feedback.style.color = 'var(--success-color)'; - guessInput.disabled = true; - submitBtn.disabled = true; - if (bestScore === null || attempts < bestScore) { - saveBestScore(attempts); - } - } else if (guess < secretNumber) { - feedback.textContent = '๐Ÿ“ˆ Too low! Try higher!'; - feedback.style.color = 'var(--primary-color)'; - minRange = Math.max(minRange, guess + 1); + guessInput.disabled = true; + submitBtn.disabled = true; + saveBestScore(currentDiff, attempts); } else { - feedback.textContent = '๐Ÿ“‰ Too high! Try lower!'; - feedback.style.color = 'var(--danger-color)'; - maxRange = Math.min(maxRange, guess - 1); + if (guess < secretNumber) { + feedback.textContent = '๐Ÿ“ˆ Too low! Try higher!'; + feedback.style.color = 'var(--primary-color)'; + minRange = Math.max(minRange, guess + 1); + } else { + feedback.textContent = '๐Ÿ“‰ Too high! Try lower!'; + feedback.style.color = 'var(--danger-color)'; + maxRange = Math.min(maxRange, guess - 1); + } + rangeDisplay.textContent = `${minRange}โ€“${maxRange}`; + + if (remaining <= 0) { + feedback.textContent = `๐Ÿ’€ Out of attempts! The number was ${secretNumber}.`; + feedback.style.color = 'var(--danger-color)'; + guessInput.disabled = true; + submitBtn.disabled = true; + } } - - rangeDisplay.textContent = `${minRange}-${maxRange}`; + guessInput.value = ''; } + + // Progress bar + function updateBar(left, total) { + const pct = (left / total) * 100; + attemptsBar.style.width = pct + '%'; + if (pct > 50) attemptsBar.style.background = 'var(--primary-color)'; + else if (pct > 25) attemptsBar.style.background = '#eab308'; + else attemptsBar.style.background = '#ef4444'; + } + + function getBestScoreKey(diffKey) { return `numberGuessBest_${diffKey}`; } + + function updateBestScore(diffKey) { + const best = storage.loadFromStorage(getBestScoreKey(diffKey), null); + bestScoreDisplay.textContent = best === null ? 'โ€”' : `${best} attempt${best === 1 ? '' : 's'}`; + } + + function saveBestScore(diffKey, score) { + const key = getBestScoreKey(diffKey); + const best = storage.loadFromStorage(key, null); + if (best === null || score < best) { + storage.saveToStorage(key, score); + bestScoreDisplay.textContent = `${score} attempt${score === 1 ? '' : 's'} ๐Ÿ†`; + } + } + + resetBtn.addEventListener('click', () => startGame(currentDiff)); + + changeDiffBtn.addEventListener('click', () => { + gameScreen.style.display = 'none'; + difficultyScreen.style.display = ''; + }); } \ No newline at end of file