From 2bfad8ea09fb0a590321a598f6130ef294fe017e Mon Sep 17 00:00:00 2001 From: Farah <60301461@udst.edu.qa> Date: Sun, 15 Feb 2026 18:37:42 +0300 Subject: [PATCH 1/2] Fix Add Word persistence issue (fixes #2>) --- script.js | 161 ++++++++++++++++++------------------------------------ 1 file changed, 52 insertions(+), 109 deletions(-) diff --git a/script.js b/script.js index 43cfa50..95fb37d 100644 --- a/script.js +++ b/script.js @@ -19,14 +19,22 @@ let gameState = { let wordBank = []; +const savedWords = localStorage.getItem('devopsWords'); + +if (savedWords) { + wordBank = JSON.parse(savedWords); +} else { + wordBank = [...defaultWords]; + localStorage.setItem('devopsWords', JSON.stringify(wordBank)); +} + document.addEventListener('DOMContentLoaded', function() { - loadWordBank(); + displayWordBank(); generateKeyboard(); }); function toggleTheme() { const themeIcon = document.querySelector('.theme-icon'); - if (themeIcon.textContent === '🌙') { themeIcon.textContent = '☀️'; } else { @@ -37,35 +45,16 @@ function toggleTheme() { function switchTab(tabName) { const tabs = document.querySelectorAll('.tab-content'); tabs.forEach(tab => tab.classList.remove('active')); - const tabButtons = document.querySelectorAll('.tab'); tabButtons.forEach(btn => btn.classList.remove('active')); - document.getElementById(tabName).classList.add('active'); event.target.classList.add('active'); } -function loadWordBank() { - const stored = localStorage.getItem('wordBank'); - if (stored) { - wordBank = JSON.parse(stored); - } else { - wordBank = [...defaultWords]; - saveWordBank(); - } - displayWordBank(); -} - -function saveWordBank() { - localStorage.setItem('devopsWords', JSON.stringify(wordBank)); -} - function displayWordBank() { const wordList = document.getElementById('wordList'); const wordCount = document.getElementById('wordCount'); - wordCount.textContent = wordBank.length; - if (wordBank.length === 0) { wordList.innerHTML = `
@@ -75,7 +64,6 @@ function displayWordBank() { `; return; } - wordList.innerHTML = ''; wordBank.forEach((word, index) => { const wordItem = document.createElement('div'); @@ -91,10 +79,14 @@ function displayWordBank() { }); } +function saveWordBank() { + localStorage.setItem('devopsWords', JSON.stringify(wordBank)); +} + function addWord() { const input = document.getElementById('newWord'); const word = input.value.trim().toUpperCase(); - + if (!word || wordBank.includes(word) || /[^A-Z]/.test(word)) return; wordBank.push(word); input.value = ''; saveWordBank(); @@ -103,15 +95,17 @@ function addWord() { function editWord(index) { const newWord = prompt('Edit word:', wordBank[index]); - if (newWord) { - wordBank.splice(index, 1); - saveWordBank(); - displayWordBank(); - } + if (!newWord) return; + const formattedWord = newWord.trim().toUpperCase(); + if (!formattedWord || wordBank.includes(formattedWord) || /[^A-Z]/.test(formattedWord)) return; + wordBank[index] = formattedWord; + saveWordBank(); + displayWordBank(); } function deleteWord(index) { if (confirm('Are you sure you want to delete this word?')) { + wordBank.splice(index, 1); saveWordBank(); displayWordBank(); } @@ -120,7 +114,6 @@ function deleteWord(index) { function generateKeyboard() { const keyboard = document.getElementById('keyboard'); const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - keyboard.innerHTML = ''; for (let letter of letters) { const button = document.createElement('button'); @@ -135,15 +128,12 @@ function generateKeyboard() { function startGame() { const p1Name = document.getElementById('player1Name').value.trim(); const p2Name = document.getElementById('player2Name').value.trim(); - - gameState.player1.name = p1Name || 'Player 1'; - gameState.player2.name = p2Name || 'Player 2'; - + if (!p1Name || !p2Name || p1Name === p2Name) return; + gameState.player1.name = p1Name; + gameState.player2.name = p2Name; document.getElementById('player1Display').textContent = gameState.player1.name; document.getElementById('player2Display').textContent = gameState.player2.name; - document.getElementById('gameArea').style.display = 'block'; - nextRound(); } @@ -152,15 +142,16 @@ function nextRound() { alert('No words in the word bank! Add some words first.'); return; } - gameState.guessedLetters = []; gameState.wrongGuesses = 0; gameState.gameActive = true; - - const randomIndex = Math.floor(Math.random() * wordBank.length); + let randomIndex; + do { + randomIndex = Math.floor(Math.random() * wordBank.length); + } while (gameState.usedWords.includes(randomIndex) && gameState.usedWords.length < wordBank.length); gameState.currentWord = wordBank[randomIndex]; - - document.getElementById('gameStatus').classList.remove('show'); + gameState.usedWords.push(randomIndex); + if (gameState.usedWords.length === wordBank.length) gameState.usedWords = []; document.getElementById('gameStatus').className = 'game-status'; resetHangman(); resetKeyboard(); @@ -172,18 +163,12 @@ function nextRound() { function guessLetter(letter) { if (!gameState.gameActive) return; - - if (gameState.guessedLetters.includes(letter)) { - return; - } - + if (gameState.guessedLetters.includes(letter)) return; gameState.guessedLetters.push(letter); - if (!gameState.currentWord.includes(letter)) { gameState.wrongGuesses++; updateHangman(); } - updateWordDisplay(); updateWrongLetters(); updateLives(); @@ -192,30 +177,13 @@ function guessLetter(letter) { function updateWordDisplay() { const display = document.getElementById('wordDisplay'); - let displayText = ''; - - for (let letter of gameState.currentWord) { - if (gameState.guessedLetters.includes(letter)) { - displayText += letter + ' '; - } else { - displayText += '_ '; - } - } - - display.textContent = displayText.trim(); + display.textContent = [...gameState.currentWord].map(letter => gameState.guessedLetters.includes(letter) ? letter : '_').join(' '); } function updateWrongLetters() { const wrongLettersDiv = document.getElementById('wrongLetters'); - const wrong = gameState.guessedLetters.filter(letter => - !gameState.currentWord.includes(letter) - ); - - if (wrong.length === 0) { - wrongLettersDiv.textContent = 'None yet'; - } else { - wrongLettersDiv.textContent = gameState.guessedLetters.join(', '); - } + const wrong = gameState.guessedLetters.filter(letter => !gameState.currentWord.includes(letter)); + wrongLettersDiv.textContent = wrong.length === 0 ? 'None yet' : wrong.join(', '); } function updateLives() { @@ -224,38 +192,29 @@ function updateLives() { } function updateHangman() { - const parts = ['head', 'body', 'leftArm', 'rightArm', 'leftLeg', 'rightLeg']; - const wrongOrder = ['head', 'leftArm', 'rightArm', 'body', 'leftLeg', 'rightLeg']; const partIndex = gameState.wrongGuesses - 1; - if (partIndex >= 0 && partIndex < wrongOrder.length) { - const partToShow = wrongOrder[partIndex]; - document.getElementById(partToShow).style.display = 'block'; + document.getElementById(wrongOrder[partIndex]).style.display = 'block'; } } function resetHangman() { - const parts = ['head', 'body', 'leftArm', 'rightArm', 'leftLeg', 'rightLeg']; - parts.forEach(part => { + ['head', 'body', 'leftArm', 'rightArm', 'leftLeg', 'rightLeg'].forEach(part => { document.getElementById(part).style.display = 'none'; }); } function resetKeyboard() { - const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - for (let letter of letters) { + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').forEach(letter => { const button = document.getElementById('key-' + letter); - if (button) { - button.disabled = false; - } - } + if (button) button.disabled = false; + }); } function updateCurrentPlayer() { const player1Div = document.getElementById('player1Score'); const player2Div = document.getElementById('player2Score'); - if (gameState.currentPlayer === 1) { player1Div.classList.add('active'); player2Div.classList.remove('active'); @@ -266,15 +225,10 @@ function updateCurrentPlayer() { } function checkGameStatus() { - const allLettersGuessed = [...gameState.currentWord].every(letter => - gameState.guessedLetters.includes(letter) - ); - - if (allLettersGuessed) { + if ([...gameState.currentWord].every(letter => gameState.guessedLetters.includes(letter))) { gameWon(); return; } - if (gameState.wrongGuesses >= gameState.maxWrong) { gameLost(); return; @@ -283,36 +237,25 @@ function checkGameStatus() { function gameWon() { gameState.gameActive = false; - - if (gameState.currentPlayer === 1) { - gameState.player2.score += 10; - document.getElementById('score2').textContent = gameState.player2.score; - } else { + const winner = gameState.currentPlayer === 1 ? 2 : 1; + if (winner === 1) { gameState.player1.score += 10; document.getElementById('score1').textContent = gameState.player1.score; + } else { + gameState.player2.score += 10; + document.getElementById('score2').textContent = gameState.player2.score; } - const statusDiv = document.getElementById('gameStatus'); - const statusMsg = document.getElementById('statusMessage'); - - const winnerName = gameState.currentPlayer === 1 ? - gameState.player2.name : gameState.player1.name; - - statusMsg.textContent = `🎉 ${winnerName} won! The word was: ${gameState.currentWord}`; + const winnerName = winner === 1 ? gameState.player1.name : gameState.player2.name; + document.getElementById('statusMessage').textContent = `🎉 ${winnerName} won! The word was: ${gameState.currentWord}`; statusDiv.classList.add('show', 'winner'); + gameState.currentPlayer = winner; } function gameLost() { gameState.gameActive = false; - - const statusDiv = document.getElementById('gameStatus'); - const statusMsg = document.getElementById('statusMessage'); - - const currentPlayerName = gameState.currentPlayer === 1 ? - gameState.player1.name : gameState.player2.name; - - statusMsg.textContent = `😢 ${currentPlayerName} lost! The word was: ${gameState.currentWord}`; - statusDiv.classList.add('show', 'loser'); - + const currentPlayerName = gameState.currentPlayer === 1 ? gameState.player1.name : gameState.player2.name; + document.getElementById('statusMessage').textContent = `😢 ${currentPlayerName} lost! The word was: ${gameState.currentWord}`; + document.getElementById('gameStatus').classList.add('show', 'loser'); gameState.currentPlayer = gameState.currentPlayer === 1 ? 2 : 1; } From 47b68fc90856cb070aa9f78ccc967da87bac65b9 Mon Sep 17 00:00:00 2001 From: Farah <60301461@udst.edu.qa> Date: Sun, 15 Feb 2026 19:03:28 +0300 Subject: [PATCH 2/2] Fix Add Word duplicate issue (fixes #3) --- script.js | 191 +++++++++++++++++++++++------------------------------- 1 file changed, 82 insertions(+), 109 deletions(-) diff --git a/script.js b/script.js index 43cfa50..3fa11b4 100644 --- a/script.js +++ b/script.js @@ -24,29 +24,8 @@ document.addEventListener('DOMContentLoaded', function() { generateKeyboard(); }); -function toggleTheme() { - const themeIcon = document.querySelector('.theme-icon'); - - if (themeIcon.textContent === '🌙') { - themeIcon.textContent = '☀️'; - } else { - themeIcon.textContent = '🌙'; - } -} - -function switchTab(tabName) { - const tabs = document.querySelectorAll('.tab-content'); - tabs.forEach(tab => tab.classList.remove('active')); - - const tabButtons = document.querySelectorAll('.tab'); - tabButtons.forEach(btn => btn.classList.remove('active')); - - document.getElementById(tabName).classList.add('active'); - event.target.classList.add('active'); -} - function loadWordBank() { - const stored = localStorage.getItem('wordBank'); + const stored = localStorage.getItem('devopsWords'); if (stored) { wordBank = JSON.parse(stored); } else { @@ -91,32 +70,65 @@ function displayWordBank() { }); } +// ADD WORD: validate, reject duplicates, invalid chars function addWord() { const input = document.getElementById('newWord'); const word = input.value.trim().toUpperCase(); - + + if (!word) { + alert('Cannot add empty word!'); + return; + } + if (wordBank.includes(word)) { + alert('Word already exists!'); + return; + } + if (/[^A-Z]/.test(word)) { + alert('Word can only contain letters A-Z!'); + return; + } + wordBank.push(word); input.value = ''; saveWordBank(); displayWordBank(); } +// EDIT WORD: validate, prevent deletion, no duplicates, valid letters only function editWord(index) { const newWord = prompt('Edit word:', wordBank[index]); - if (newWord) { - wordBank.splice(index, 1); - saveWordBank(); - displayWordBank(); + if (!newWord) return; + + const word = newWord.trim().toUpperCase(); + + if (!word) { + alert('Cannot set empty word!'); + return; } + if (wordBank.includes(word) && word !== wordBank[index]) { + alert('Word already exists!'); + return; + } + if (/[^A-Z]/.test(word)) { + alert('Word can only contain letters A-Z!'); + return; + } + + wordBank[index] = word; + saveWordBank(); + displayWordBank(); } +// DELETE WORD: confirm, remove, update count function deleteWord(index) { if (confirm('Are you sure you want to delete this word?')) { + wordBank.splice(index, 1); saveWordBank(); displayWordBank(); } } +// KEYBOARD GENERATION function generateKeyboard() { const keyboard = document.getElementById('keyboard'); const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; @@ -132,6 +144,7 @@ function generateKeyboard() { } } +// START GAME function startGame() { const p1Name = document.getElementById('player1Name').value.trim(); const p2Name = document.getElementById('player2Name').value.trim(); @@ -147,6 +160,7 @@ function startGame() { nextRound(); } +// NEXT ROUND: alternates players, random word, resets counters function nextRound() { if (wordBank.length === 0) { alert('No words in the word bank! Add some words first.'); @@ -157,25 +171,30 @@ function nextRound() { gameState.wrongGuesses = 0; gameState.gameActive = true; - const randomIndex = Math.floor(Math.random() * wordBank.length); + let randomIndex; + do { + randomIndex = Math.floor(Math.random() * wordBank.length); + } while (wordBank[randomIndex] === gameState.currentWord && wordBank.length > 1); + gameState.currentWord = wordBank[randomIndex]; - document.getElementById('gameStatus').classList.remove('show'); document.getElementById('gameStatus').className = 'game-status'; resetHangman(); resetKeyboard(); updateWordDisplay(); updateWrongLetters(); updateLives(); + + // Alternate player after round + gameState.currentPlayer = gameState.currentPlayer === 1 ? 2 : 1; updateCurrentPlayer(); } +// GUESS LETTER function guessLetter(letter) { if (!gameState.gameActive) return; - if (gameState.guessedLetters.includes(letter)) { - return; - } + if (gameState.guessedLetters.includes(letter)) return; gameState.guessedLetters.push(letter); @@ -190,129 +209,83 @@ function guessLetter(letter) { checkGameStatus(); } +// DISPLAY FUNCTIONS function updateWordDisplay() { const display = document.getElementById('wordDisplay'); - let displayText = ''; - - for (let letter of gameState.currentWord) { - if (gameState.guessedLetters.includes(letter)) { - displayText += letter + ' '; - } else { - displayText += '_ '; - } - } - - display.textContent = displayText.trim(); + display.textContent = [...gameState.currentWord].map(l => gameState.guessedLetters.includes(l) ? l : '_').join(' '); } function updateWrongLetters() { const wrongLettersDiv = document.getElementById('wrongLetters'); - const wrong = gameState.guessedLetters.filter(letter => - !gameState.currentWord.includes(letter) - ); - - if (wrong.length === 0) { - wrongLettersDiv.textContent = 'None yet'; - } else { - wrongLettersDiv.textContent = gameState.guessedLetters.join(', '); - } + const wrong = gameState.guessedLetters.filter(l => !gameState.currentWord.includes(l)); + wrongLettersDiv.textContent = wrong.length ? wrong.join(', ') : 'None yet'; } function updateLives() { - const livesLeft = gameState.maxWrong - gameState.wrongGuesses + 1; + const livesLeft = gameState.maxWrong - gameState.wrongGuesses; document.getElementById('livesLeft').textContent = livesLeft; } function updateHangman() { - const parts = ['head', 'body', 'leftArm', 'rightArm', 'leftLeg', 'rightLeg']; - const wrongOrder = ['head', 'leftArm', 'rightArm', 'body', 'leftLeg', 'rightLeg']; const partIndex = gameState.wrongGuesses - 1; - if (partIndex >= 0 && partIndex < wrongOrder.length) { - const partToShow = wrongOrder[partIndex]; - document.getElementById(partToShow).style.display = 'block'; + document.getElementById(wrongOrder[partIndex]).style.display = 'block'; } } function resetHangman() { - const parts = ['head', 'body', 'leftArm', 'rightArm', 'leftLeg', 'rightLeg']; - parts.forEach(part => { - document.getElementById(part).style.display = 'none'; + ['head','body','leftArm','rightArm','leftLeg','rightLeg'].forEach(id => { + document.getElementById(id).style.display = 'none'; }); } function resetKeyboard() { - const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - for (let letter of letters) { - const button = document.getElementById('key-' + letter); - if (button) { - button.disabled = false; - } - } + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').forEach(letter => { + const btn = document.getElementById('key-' + letter); + if (btn) btn.disabled = false; + }); } +// PLAYER DISPLAY function updateCurrentPlayer() { - const player1Div = document.getElementById('player1Score'); - const player2Div = document.getElementById('player2Score'); + const p1Div = document.getElementById('player1Score'); + const p2Div = document.getElementById('player2Score'); - if (gameState.currentPlayer === 1) { - player1Div.classList.add('active'); - player2Div.classList.remove('active'); - } else { - player1Div.classList.remove('active'); - player2Div.classList.add('active'); - } + p1Div.classList.toggle('active', gameState.currentPlayer === 1); + p2Div.classList.toggle('active', gameState.currentPlayer === 2); } +// GAME STATUS function checkGameStatus() { - const allLettersGuessed = [...gameState.currentWord].every(letter => - gameState.guessedLetters.includes(letter) - ); - - if (allLettersGuessed) { - gameWon(); - return; - } + const allGuessed = [...gameState.currentWord].every(l => gameState.guessedLetters.includes(l)); - if (gameState.wrongGuesses >= gameState.maxWrong) { - gameLost(); - return; - } + if (allGuessed) gameWon(); + else if (gameState.wrongGuesses >= gameState.maxWrong) gameLost(); } function gameWon() { gameState.gameActive = false; + const winner = gameState.currentPlayer === 1 ? gameState.player2 : gameState.player1; + winner.score += 10; + document.getElementById('score1').textContent = gameState.player1.score; + document.getElementById('score2').textContent = gameState.player2.score; - if (gameState.currentPlayer === 1) { - gameState.player2.score += 10; - document.getElementById('score2').textContent = gameState.player2.score; - } else { - gameState.player1.score += 10; - document.getElementById('score1').textContent = gameState.player1.score; - } - + const winnerName = winner.name; const statusDiv = document.getElementById('gameStatus'); - const statusMsg = document.getElementById('statusMessage'); - - const winnerName = gameState.currentPlayer === 1 ? - gameState.player2.name : gameState.player1.name; - - statusMsg.textContent = `🎉 ${winnerName} won! The word was: ${gameState.currentWord}`; + document.getElementById('statusMessage').textContent = `🎉 ${winnerName} won! The word was: ${gameState.currentWord}`; statusDiv.classList.add('show', 'winner'); } function gameLost() { gameState.gameActive = false; + const currentPlayerName = gameState.currentPlayer === 1 ? gameState.player1.name : gameState.player2.name; const statusDiv = document.getElementById('gameStatus'); - const statusMsg = document.getElementById('statusMessage'); - - const currentPlayerName = gameState.currentPlayer === 1 ? - gameState.player1.name : gameState.player2.name; - - statusMsg.textContent = `😢 ${currentPlayerName} lost! The word was: ${gameState.currentWord}`; + document.getElementById('statusMessage').textContent = `😢 ${currentPlayerName} lost! The word was: ${gameState.currentWord}`; statusDiv.classList.add('show', 'loser'); + // Switch player for next round gameState.currentPlayer = gameState.currentPlayer === 1 ? 2 : 1; + updateCurrentPlayer(); }