Skip to content

Commit 04b4a34

Browse files
committed
add hangman game
1 parent 52f7ab9 commit 04b4a34

File tree

5 files changed

+323
-1
lines changed

5 files changed

+323
-1
lines changed

00-boilerplate/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<title>My Project</title>
1414
</head>
1515
<body>
16-
<h1>Project Starter</h1>
16+
<h1>My Project</h1>
1717
<script src="script.js"></script>
1818
</body>
1919
</html>

65-hangman game/index.html

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<link rel="stylesheet" href="style.css" />
7+
<title>Hangman</title>
8+
</head>
9+
<body>
10+
<h1>Hangman</h1>
11+
<p>Find the hidden word - Press a letter</p>
12+
<div class="game-container">
13+
<svg height="250" width="200" class="figure-container">
14+
<!-- rod -->
15+
<line x1="60" y1="20" x2="140" y2="20" />
16+
<line x1="140" y1="20" x2="140" y2="50" />
17+
<line x1="60" y1="20" x2="60" y2="230" />
18+
<line x1="20" y1="230" x2="100" y2="230" />
19+
<!-- head -->
20+
<circle cx="140" cy="70" r="20" class="figure-part" />
21+
<!-- body -->
22+
<line x1="140" y1="90" x2="140" y2="150" class="figure-part" />
23+
<!-- arms -->
24+
<line x1="140" y1="120" x2="120" y2="100" class="figure-part" />
25+
<line x1="140" y1="120" x2="160" y2="100" class="figure-part" />
26+
<!-- legs -->
27+
<line x1="140" y1="150" x2="120" y2="180" class="figure-part" />
28+
<line x1="140" y1="150" x2="160" y2="180" class="figure-part" />
29+
</svg>
30+
<div class="wrong-letters-container">
31+
<div id="wrong-letters"></div>
32+
</div>
33+
<div class="word" id="word"></div>
34+
</div>
35+
<!-- Popup -->
36+
<div class="popup-container" id="popup-container">
37+
<div class="popup">
38+
<h2 id="final-message"></h2>
39+
<h3 id="final-message-reveal-word"></h3>
40+
<button id="play-button">Play Again</button>
41+
</div>
42+
</div>
43+
<!-- Notification -->
44+
<div class="notification-container" id="notification-container">
45+
<p>You have already entered this letter</p>
46+
</div>
47+
<script src="script.js"></script>
48+
</body>
49+
</html>

65-hangman game/script.js

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
const wordElement = document.getElementById("word");
2+
const wrongLettersElement = document.getElementById("wrong-letters");
3+
const playAgainButton = document.getElementById("play-button");
4+
const popup = document.getElementById("popup-container");
5+
const notification = document.getElementById("notification-container");
6+
const finalMessage = document.getElementById("final-message");
7+
const finalMessageRevealWord = document.getElementById(
8+
"final-message-reveal-word"
9+
);
10+
const figureParts = document.querySelectorAll(".figure-part");
11+
12+
const words = [
13+
"application",
14+
"programming",
15+
"interface",
16+
"wizard",
17+
"element",
18+
"prototype",
19+
"callback",
20+
"undefined",
21+
"arguments",
22+
"settings",
23+
"selector",
24+
"container",
25+
"instance",
26+
"response",
27+
"console",
28+
"constructor",
29+
"token",
30+
"function",
31+
"return",
32+
"length",
33+
"type",
34+
"node",
35+
];
36+
let selectedWord = words[Math.floor(Math.random() * words.length)];
37+
38+
let playable = true;
39+
40+
const correctLetters = [];
41+
const wrongLetters = [];
42+
43+
function displayWord() {
44+
wordElement.innerHTML = `
45+
${selectedWord
46+
.split("") // to array
47+
.map(
48+
(letter) => `
49+
<span class="letter">
50+
${correctLetters.includes(letter) ? letter : ""}
51+
</span>
52+
`
53+
)
54+
.join("")}
55+
`; // to string
56+
const innerWord = wordElement.innerText.replace(/\n/g, "");
57+
if (innerWord === selectedWord) {
58+
finalMessage.innerText = "Congratulations! You won! 😃";
59+
finalMessageRevealWord.innerText = "";
60+
popup.style.display = "flex";
61+
playable = false;
62+
}
63+
}
64+
65+
function updateWrongLettersElement() {
66+
wrongLettersElement.innerHTML = `
67+
${wrongLetters.length > 0 ? "<p>Wrong</p>" : ""}
68+
${wrongLetters.map((letter) => `<span>${letter}</span>`)}
69+
`;
70+
figureParts.forEach((part, index) => {
71+
const errors = wrongLetters.length;
72+
index < errors
73+
? (part.style.display = "block")
74+
: (part.style.display = "none");
75+
});
76+
if (wrongLetters.length === figureParts.length) {
77+
finalMessage.innerText = "Unfortunately you lost. 😕";
78+
finalMessageRevealWord.innerText = `...the word was: ${selectedWord}`;
79+
popup.style.display = "flex";
80+
playable = false;
81+
}
82+
}
83+
84+
function showNotification() {
85+
notification.classList.add("show");
86+
setTimeout(() => {
87+
notification.classList.remove("show");
88+
}, 2000);
89+
}
90+
91+
window.addEventListener("keypress", (e) => {
92+
if (playable) {
93+
const letter = e.key.toLowerCase();
94+
if (letter >= "a" && letter <= "z") {
95+
if (selectedWord.includes(letter)) {
96+
if (!correctLetters.includes(letter)) {
97+
correctLetters.push(letter);
98+
displayWord();
99+
} else {
100+
showNotification();
101+
}
102+
} else {
103+
if (!wrongLetters.includes(letter)) {
104+
wrongLetters.push(letter);
105+
updateWrongLettersElement();
106+
} else {
107+
showNotification();
108+
}
109+
}
110+
}
111+
}
112+
});
113+
114+
playAgainButton.addEventListener("click", () => {
115+
playable = true;
116+
correctLetters.splice(0);
117+
wrongLetters.splice(0);
118+
selectedWord = words[Math.floor(Math.random() * words.length)];
119+
displayWord();
120+
updateWrongLettersElement();
121+
popup.style.display = "none";
122+
});
123+
124+
// Init
125+
displayWord();

65-hangman game/style.css

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
@import url("https://fonts.googleapis.com/css2?family=DotGothic16&display=swap");
2+
3+
:root {
4+
--primary-color: #1f2f61;
5+
--secondary-color: #224ca4;
6+
--light-color: #a7c2da;
7+
}
8+
9+
* {
10+
box-sizing: border-box;
11+
}
12+
13+
body {
14+
background-color: var(--primary-color);
15+
color: var(--light-color);
16+
font-family: "DotGothic16", sans-serif;
17+
display: flex;
18+
flex-direction: column;
19+
align-items: center;
20+
justify-content: center;
21+
height: 80vh;
22+
overflow: hidden;
23+
margin: 0;
24+
}
25+
26+
h1 {
27+
margin: 20px 0 0;
28+
letter-spacing: 0.5rem;
29+
text-transform: uppercase;
30+
}
31+
32+
h2,
33+
h3 {
34+
letter-spacing: 0.2rem;
35+
}
36+
37+
.game-container {
38+
padding: 20px 30px;
39+
position: relative;
40+
margin: auto;
41+
height: 350px;
42+
width: 450px;
43+
}
44+
45+
.figure-container {
46+
fill: transparent;
47+
stroke: var(--light-color);
48+
stroke-width: 4px;
49+
stroke-linecap: round;
50+
}
51+
52+
.figure-part {
53+
display: none;
54+
}
55+
56+
.wrong-letters-container {
57+
position: absolute;
58+
top: 20px;
59+
right: 20px;
60+
display: flex;
61+
flex-direction: column;
62+
text-align: right;
63+
}
64+
65+
.wrong-letters-container p {
66+
margin: 0 0 5px;
67+
}
68+
69+
.wrong-letters-container span {
70+
font-size: 24px;
71+
}
72+
73+
.word {
74+
display: flex;
75+
position: absolute;
76+
bottom: 10px;
77+
left: 50%;
78+
transform: translateX(-50%);
79+
}
80+
81+
.letter {
82+
border-bottom: 3px solid var(--secondary-color);
83+
display: inline-flex;
84+
font-size: 30px;
85+
align-items: center;
86+
justify-content: center;
87+
margin: 0 3px;
88+
height: 50px;
89+
width: 20px;
90+
}
91+
92+
.popup-container {
93+
background-color: rgba(0, 0, 0, 0.3);
94+
position: fixed;
95+
top: 0;
96+
bottom: 0;
97+
left: 0;
98+
right: 0;
99+
display: none;
100+
align-items: center;
101+
justify-content: center;
102+
}
103+
104+
.popup {
105+
background-color: var(--secondary-color);
106+
border-radius: 5px;
107+
box-shadow: 0 15px 10px 3px rgba(0, 0, 0, 0.1);
108+
padding: 20px;
109+
text-align: center;
110+
}
111+
112+
.popup button {
113+
cursor: pointer;
114+
background-color: var(--light-color);
115+
color: var(--secondary-color);
116+
border: 0;
117+
margin-top: 20px;
118+
padding: 12px 20px;
119+
font-size: 16px;
120+
font-family: inherit;
121+
border-radius: 5px;
122+
}
123+
124+
.popup button:active {
125+
transform: scale(0.98);
126+
}
127+
128+
.popup button:focus {
129+
outline: none;
130+
}
131+
132+
.notification-container {
133+
background-color: rgba(0, 0, 0, 0.3);
134+
border-radius: 10px 10px 0 0;
135+
padding: 15px 20px;
136+
position: absolute;
137+
bottom: -50px;
138+
transition: transform 0.3s ease-in-out;
139+
}
140+
141+
.notification-container.show {
142+
transform: translateY(-50px);
143+
}
144+
145+
.notification-container p {
146+
margin: 0;
147+
}

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
| 62 | [Exchange Rate Calculator](https://github.com/solygambas/html-css-fifty-projects/tree/master/62-exchange%20rate%20calculator) | [Live Demo](https://codepen.io/solygambas/full/abBPJBG) |
7171
| 63 | [DOM Array Methods](https://github.com/solygambas/html-css-fifty-projects/tree/master/63-DOM%20array%20methods) | [Live Demo](https://codepen.io/solygambas/full/NWbeXYR) |
7272
| 64 | [Menu Slider & Modal](https://github.com/solygambas/html-css-fifty-projects/tree/master/64-menu%20slider%20modal) | [Live Demo](https://codepen.io/solygambas/full/MWbLeKd) |
73+
| 65 | [Hangman Game](https://github.com/solygambas/html-css-fifty-projects/tree/master/65-hangman%20game) | [Live Demo](https://codepen.io/solygambas/full/MWbLEYr) |
7374

7475
Mainly based on 2 courses by Brad Traversy (2020):
7576

0 commit comments

Comments
 (0)