-
- Attempts Left:
- 6
-
-
-
Word Length:
-
0
+
+
+
+
Choose your difficulty!
+
+
+
+
-
-
-
-
-
-
-
Guessed Letters:
-
None
+
+
+
+
+
+ Difficulty
+ โ
+
+
+ Attempts Left
+ 6
+
+
+ Word Length
+ 0
+
+
+
+
+
+
+
+
+
+
+
Guessed Letters:
+
None
+
+
+
+
+
โจ๏ธ Type any letter key to guess directly
+
+
+
+
+
+
+
-
-
-
-
โจ๏ธ 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!
-
-