hangman / index.html
sqibhe's picture
Add 3 files
94ed895 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hangman Game</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.hangman-container {
position: relative;
width: 300px;
height: 350px;
margin: 0 auto;
}
.hangman-part {
position: absolute;
display: none;
}
/* Gallows */
#gallows-base {
width: 150px;
height: 15px;
bottom: 0;
left: 75px;
background-color: #8B4513;
display: block;
border-radius: 3px;
}
#gallows-pole {
width: 15px;
height: 250px;
bottom: 15px;
left: 75px;
background-color: #8B4513;
display: block;
border-radius: 3px;
}
#gallows-top {
width: 120px;
height: 15px;
top: 0;
left: 90px;
background-color: #8B4513;
display: block;
border-radius: 3px;
}
#gallows-rope {
width: 8px;
height: 40px;
top: 15px;
left: 210px;
background-color: #654321;
display: block;
border-radius: 3px;
}
/* Hangman parts */
#head {
width: 50px;
height: 50px;
border-radius: 50%;
top: 55px;
left: 185px;
background-color: #FFD700;
border: 3px solid #DAA520;
box-sizing: border-box;
}
#face {
width: 50px;
height: 50px;
border-radius: 50%;
top: 55px;
left: 185px;
display: none;
}
#eye-left {
width: 8px;
height: 8px;
background-color: #333;
border-radius: 50%;
top: 70px;
left: 195px;
}
#eye-right {
width: 8px;
height: 8px;
background-color: #333;
border-radius: 50%;
top: 70px;
left: 217px;
}
#mouth {
width: 20px;
height: 5px;
background-color: #333;
border-radius: 5px;
top: 85px;
left: 195px;
}
#body {
width: 15px;
height: 100px;
top: 105px;
left: 202px;
background-color: #FFD700;
border: 3px solid #DAA520;
box-sizing: border-box;
}
#left-arm {
width: 60px;
height: 15px;
top: 130px;
left: 142px;
background-color: #FFD700;
border: 3px solid #DAA520;
box-sizing: border-box;
transform: rotate(30deg);
transform-origin: right;
}
#right-arm {
width: 60px;
height: 15px;
top: 130px;
left: 217px;
background-color: #FFD700;
border: 3px solid #DAA520;
box-sizing: border-box;
transform: rotate(-30deg);
transform-origin: left;
}
#left-leg {
width: 60px;
height: 15px;
top: 205px;
left: 152px;
background-color: #FFD700;
border: 3px solid #DAA520;
box-sizing: border-box;
transform: rotate(20deg);
transform-origin: right;
}
#right-leg {
width: 60px;
height: 15px;
top: 205px;
left: 202px;
background-color: #FFD700;
border: 3px solid #DAA520;
box-sizing: border-box;
transform: rotate(-20deg);
transform-origin: left;
}
.letter-tile {
width: 40px;
height: 50px;
border-bottom: 3px solid #333;
font-size: 24px;
font-weight: bold;
display: flex;
align-items: flex-end;
justify-content: center;
margin: 0 5px;
}
.keyboard-key {
width: 40px;
height: 40px;
font-size: 18px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
}
.keyboard-key:hover {
transform: scale(1.1);
}
.keyboard-key.used {
opacity: 0.5;
cursor: not-allowed;
}
.keyboard-key.correct {
background-color: #4CAF50;
color: white;
}
.keyboard-key.wrong {
background-color: #F44336;
color: white;
}
.modal {
transition: opacity 0.3s ease;
}
.word-input-container {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.word-input-container input {
flex-grow: 1;
margin-right: 10px;
}
/* Walking animation */
@keyframes walk {
0% { transform: translateX(0) rotate(0deg); }
25% { transform: translateX(20px) rotate(5deg); }
50% { transform: translateX(40px) rotate(0deg); }
75% { transform: translateX(60px) rotate(-5deg); }
100% { transform: translateX(80px) rotate(0deg); }
}
.walking {
animation: walk 2s infinite linear;
}
/* Speech bubble */
.speech-bubble {
position: absolute;
background: #fff;
border-radius: 10px;
padding: 10px;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
max-width: 200px;
font-size: 14px;
z-index: 10;
}
.speech-bubble:after {
content: '';
position: absolute;
bottom: -10px;
left: 20px;
border-width: 10px 10px 0;
border-style: solid;
border-color: #fff transparent;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex flex-col items-center justify-center p-4">
<div class="bg-white rounded-lg shadow-xl p-8 w-full max-w-4xl">
<h1 class="text-4xl font-bold text-center mb-8 text-indigo-700">
<i class="fas fa-ghost mr-2"></i> Hangman Game <i class="fas fa-ghost ml-2"></i>
</h1>
<!-- Initial setup section -->
<div id="initial-setup" class="mb-8">
<h2 class="text-2xl font-semibold mb-4 text-gray-800">Game Setup</h2>
<div class="flex flex-col space-y-4">
<div>
<label for="word-count" class="block text-sm font-medium text-gray-700 mb-1">How many words do you want to play with?</label>
<input type="number" id="word-count" min="1" max="10" value="1" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
</div>
<button id="proceed-to-words" class="bg-indigo-600 text-white px-6 py-3 rounded-md font-medium hover:bg-indigo-700 transition duration-200">
Proceed to Add Words <i class="fas fa-arrow-right ml-2"></i>
</button>
</div>
</div>
<!-- Word input section (hidden initially) -->
<div id="word-input-section" class="mb-8 hidden">
<h2 class="text-2xl font-semibold mb-4 text-gray-800">Enter Your Words</h2>
<div id="word-inputs" class="mb-4">
<!-- Word inputs will be added here -->
</div>
<div>
<label for="hint" class="block text-sm font-medium text-gray-700 mb-1">Optional hint (category):</label>
<input type="text" id="hint" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="e.g. Animals, Countries, etc.">
</div>
<button id="start-game" class="mt-4 bg-indigo-600 text-white px-6 py-3 rounded-md font-medium hover:bg-indigo-700 transition duration-200">
Start Game <i class="fas fa-play ml-2"></i>
</button>
</div>
<!-- Game section (hidden initially) -->
<div id="game-section" class="hidden">
<div class="flex flex-col md:flex-row gap-8">
<!-- Left side - Hangman display -->
<div class="w-full md:w-1/2">
<div class="bg-gray-50 p-6 rounded-lg shadow-inner relative">
<h2 class="text-xl font-semibold mb-4 text-center">Hangman</h2>
<div class="hangman-container">
<!-- Gallows structure -->
<div id="gallows-base" class="hangman-part"></div>
<div id="gallows-pole" class="hangman-part"></div>
<div id="gallows-top" class="hangman-part"></div>
<div id="gallows-rope" class="hangman-part"></div>
<!-- Hangman parts -->
<div id="head" class="hangman-part"></div>
<div id="face" class="hangman-part">
<div id="eye-left" class="hangman-part"></div>
<div id="eye-right" class="hangman-part"></div>
<div id="mouth" class="hangman-part"></div>
</div>
<div id="body" class="hangman-part"></div>
<div id="left-arm" class="hangman-part"></div>
<div id="right-arm" class="hangman-part"></div>
<div id="left-leg" class="hangman-part"></div>
<div id="right-leg" class="hangman-part"></div>
</div>
<div id="hangman-speech" class="speech-bubble hidden" style="bottom: -60px; left: 50px;"></div>
<div class="mt-6 text-center">
<p id="hint-display" class="text-gray-600 italic"></p>
<p id="remaining-guesses" class="text-lg font-medium mt-2">Remaining wrong guesses: <span class="text-indigo-600">5</span></p>
<p id="current-word" class="text-sm text-gray-500 mt-1">Word 1 of 1</p>
</div>
</div>
</div>
<!-- Right side - Word and keyboard -->
<div class="w-full md:w-1/2">
<div class="bg-gray-50 p-6 rounded-lg shadow-inner">
<h2 class="text-xl font-semibold mb-4 text-center">Guess the Word</h2>
<!-- Word display -->
<div id="word-display" class="flex justify-center gap-2 mb-8 flex-wrap"></div>
<!-- Keyboard -->
<div id="keyboard" class="grid grid-cols-7 gap-2">
<!-- Keyboard will be generated by JavaScript -->
</div>
<div class="mt-6 flex justify-center gap-4">
<button id="new-game" class="bg-gray-600 text-white px-4 py-2 rounded-md font-medium hover:bg-gray-700 transition duration-200">
<i class="fas fa-redo mr-2"></i> New Game
</button>
<button id="next-word" class="bg-indigo-600 text-white px-4 py-2 rounded-md font-medium hover:bg-indigo-700 transition duration-200 hidden">
Next Word <i class="fas fa-arrow-right ml-2"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Game over modal -->
<div id="game-over-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden modal">
<div class="bg-white rounded-lg shadow-xl p-8 w-full max-w-md">
<h2 id="game-result-title" class="text-3xl font-bold mb-4 text-center"></h2>
<p id="game-result-message" class="text-lg mb-6 text-center"></p>
<div class="flex justify-center">
<button id="play-again" class="bg-indigo-600 text-white px-6 py-2 rounded-md font-medium hover:bg-indigo-700 transition duration-200">
<i class="fas fa-play mr-2"></i> Play Again
</button>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Game variables
let words = [];
let hint = '';
let currentWordIndex = 0;
let secretWord = '';
let guessedLetters = [];
let wrongGuesses = 0;
const maxWrongGuesses = 5;
const hangmanParts = ['head', 'face', 'body', 'left-arm', 'right-arm', 'left-leg', 'right-leg'];
// DOM elements
const initialSetup = document.getElementById('initial-setup');
const wordInputSection = document.getElementById('word-input-section');
const wordInputsContainer = document.getElementById('word-inputs');
const gameSection = document.getElementById('game-section');
const wordCountInput = document.getElementById('word-count');
const proceedToWordsBtn = document.getElementById('proceed-to-words');
const startGameBtn = document.getElementById('start-game');
const newGameBtn = document.getElementById('new-game');
const nextWordBtn = document.getElementById('next-word');
const playAgainBtn = document.getElementById('play-again');
const wordDisplay = document.getElementById('word-display');
const keyboard = document.getElementById('keyboard');
const hintDisplay = document.getElementById('hint-display');
const remainingGuesses = document.getElementById('remaining-guesses');
const currentWordDisplay = document.getElementById('current-word');
const gameOverModal = document.getElementById('game-over-modal');
const gameResultTitle = document.getElementById('game-result-title');
const gameResultMessage = document.getElementById('game-result-message');
const hangmanSpeech = document.getElementById('hangman-speech');
// Initialize the keyboard
function initKeyboard() {
keyboard.innerHTML = '';
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
alphabet.forEach(letter => {
const key = document.createElement('div');
key.className = 'keyboard-key flex items-center justify-center bg-gray-200 rounded-md';
key.textContent = letter;
key.dataset.letter = letter;
key.addEventListener('click', () => handleGuess(letter));
keyboard.appendChild(key);
});
}
// Create word inputs based on word count
function createWordInputs() {
const wordCount = parseInt(wordCountInput.value);
wordInputsContainer.innerHTML = '';
for (let i = 0; i < wordCount; i++) {
const container = document.createElement('div');
container.className = 'word-input-container';
const input = document.createElement('input');
input.type = 'text';
input.className = 'w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500';
input.placeholder = `Word ${i + 1}`;
input.dataset.index = i;
container.appendChild(input);
wordInputsContainer.appendChild(container);
}
initialSetup.classList.add('hidden');
wordInputSection.classList.remove('hidden');
document.querySelector('.word-input-container input').focus();
}
// Start a new game
function startGame() {
// Collect all words
words = [];
const inputs = wordInputsContainer.querySelectorAll('input');
inputs.forEach(input => {
if (input.value.trim()) {
words.push(input.value.trim().toUpperCase());
}
});
if (words.length === 0) {
alert('Please enter at least one word to start the game!');
return;
}
hint = document.getElementById('hint').value.trim();
// Start with first word
currentWordIndex = 0;
setupWord();
// Hide setup, show game
wordInputSection.classList.add('hidden');
gameSection.classList.remove('hidden');
// Initialize keyboard
initKeyboard();
// Hide all hangman parts
hangmanParts.forEach(part => {
document.getElementById(part).style.display = 'none';
});
// Show gallows
document.getElementById('gallows-base').style.display = 'block';
document.getElementById('gallows-pole').style.display = 'block';
document.getElementById('gallows-top').style.display = 'block';
document.getElementById('gallows-rope').style.display = 'block';
// Update UI
hintDisplay.textContent = hint ? `Hint: ${hint}` : 'No hint provided';
currentWordDisplay.textContent = `Word ${currentWordIndex + 1} of ${words.length}`;
// Hide next word button if only one word
if (words.length === 1) {
nextWordBtn.classList.add('hidden');
} else {
nextWordBtn.classList.remove('hidden');
}
}
// Setup the current word
function setupWord() {
secretWord = words[currentWordIndex];
guessedLetters = [];
wrongGuesses = 0;
// Update UI
remainingGuesses.innerHTML = `Remaining wrong guesses: <span class="text-indigo-600">${maxWrongGuesses - wrongGuesses}</span>`;
currentWordDisplay.textContent = `Word ${currentWordIndex + 1} of ${words.length}`;
// Display word with blanks
updateWordDisplay();
// Reset keyboard
initKeyboard();
// Reset hangman
hangmanParts.forEach(part => {
document.getElementById(part).style.display = 'none';
});
// Show face
document.getElementById('face').style.display = 'block';
document.getElementById('eye-left').style.display = 'block';
document.getElementById('eye-right').style.display = 'block';
document.getElementById('mouth').style.display = 'block';
// Show speech bubble
showSpeech("Help me! Guess the word to save me!");
}
// Update the word display with guessed letters
function updateWordDisplay() {
wordDisplay.innerHTML = '';
secretWord.split('').forEach(letter => {
const tile = document.createElement('div');
tile.className = 'letter-tile';
if (guessedLetters.includes(letter) || letter === ' ') {
tile.textContent = letter;
} else if (letter === '-') {
tile.textContent = '-';
} else {
tile.textContent = '';
}
wordDisplay.appendChild(tile);
});
// Check if player has won
if (isWordGuessed()) {
wordCompleted();
}
}
// Handle a letter guess
function handleGuess(letter) {
const keyElement = document.querySelector(`.keyboard-key[data-letter="${letter}"]`);
// If letter was already guessed, do nothing
if (keyElement.classList.contains('used')) {
return;
}
// Mark letter as used
keyElement.classList.add('used');
// Check if letter is in the word
if (secretWord.includes(letter)) {
keyElement.classList.add('correct');
guessedLetters.push(letter);
updateWordDisplay();
// Show positive feedback
const correctCount = secretWord.split('').filter(l => l === letter).length;
showSpeech(`Thank you! ${correctCount} ${letter}'s found! You're one step closer to saving me!`);
} else {
keyElement.classList.add('wrong');
wrongGuesses++;
updateHangman();
remainingGuesses.innerHTML = `Remaining wrong guesses: <span class="text-indigo-600">${maxWrongGuesses - wrongGuesses}</span>`;
// Show negative feedback
showSpeech("Ouch! That's wrong! I'm dying here!");
// Check if player has lost
if (wrongGuesses >= maxWrongGuesses) {
endGame(false);
}
}
}
// Update the hangman display based on wrong guesses
function updateHangman() {
if (wrongGuesses > 0 && wrongGuesses <= hangmanParts.length) {
const partToShow = hangmanParts[wrongGuesses - 1];
document.getElementById(partToShow).style.display = 'block';
// Update face expression based on wrong guesses
if (wrongGuesses >= 3) {
document.getElementById('mouth').style.borderRadius = '0';
document.getElementById('mouth').style.height = '3px';
document.getElementById('mouth').style.width = '15px';
document.getElementById('mouth').style.top = '88px';
}
}
}
// Show speech bubble
function showSpeech(text) {
hangmanSpeech.textContent = text;
hangmanSpeech.classList.remove('hidden');
// Hide after 3 seconds
setTimeout(() => {
hangmanSpeech.classList.add('hidden');
}, 3000);
}
// Check if the entire word has been guessed
function isWordGuessed() {
return secretWord.split('').every(letter =>
guessedLetters.includes(letter) || letter === ' ' || letter === '-'
);
}
// Handle when a word is completed
function wordCompleted() {
// Free the hangman from the rope
document.getElementById('gallows-rope').style.display = 'none';
// Make the hangman walk
const hangman = document.querySelector('.hangman-container');
hangman.classList.add('walking');
// Show success message
showSpeech("You saved me! Thank you!");
// Check if there are more words
if (currentWordIndex < words.length - 1) {
// Show next word button
nextWordBtn.classList.remove('hidden');
} else {
// All words completed
endGame(true);
}
}
// Move to next word
function nextWord() {
// Stop walking animation
const hangman = document.querySelector('.hangman-container');
hangman.classList.remove('walking');
// Show rope again
document.getElementById('gallows-rope').style.display = 'block';
// Move to next word
currentWordIndex++;
setupWord();
// Hide next word button if last word
if (currentWordIndex === words.length - 1) {
nextWordBtn.classList.add('hidden');
}
}
// End the game (win or lose)
function endGame(isWin) {
// Stop walking animation if any
const hangman = document.querySelector('.hangman-container');
hangman.classList.remove('walking');
if (isWin) {
gameResultTitle.textContent = 'You Win!';
gameResultTitle.className = 'text-3xl font-bold mb-4 text-center text-green-600';
gameResultMessage.textContent = `Congratulations! You guessed all ${words.length} words!`;
} else {
gameResultTitle.textContent = 'Game Over';
gameResultTitle.className = 'text-3xl font-bold mb-4 text-center text-red-600';
gameResultMessage.textContent = `The word was "${secretWord}". Better luck next time!`;
// Reveal all letters in the word
secretWord.split('').forEach(letter => {
if (!guessed
</html>