Hangman game
The hangman game is a classical paper and pencil guessing game for two or more players. One player thinks of a word, phrase or sentence and the other(s) tries to guess it by suggesting letters within a certain number of guesses. In this tutorial we will explan how to create a basic JavaScript version of the game using about 130 lines of code.
A working example
Source code
var Hangman = function() {
// Initializing self.
var self = {
// Propertie to store the number of user fails.
fails: 0,
// Propertie to store the last user input.
userInput: '',
// Propertie to be the a clue of the word.
clue: 'FRUITS',
// Propertie to store a random word from values.
currentWord: '',
// Propertie to be used to apply some changes in the selected current word.
auxWord: '',
// Propertie to store all the possibilities of words.
values: ['apple', 'banana', 'orange', 'pear', 'papaya', 'kiwi', 'lemon', 'mandarine', 'peach', 'raspberry', 'mango', 'fig', 'plum'],
// Propertie to store the element where the letters in.
lettersElement: null,
}
/**
* Generate a random word from self.values.
* Using Math.floor(Math.random()*self.values.length) calculate some random number.
* @param {number} Math.random()*self.values.length - calculate some random number between 0 to 1 using Math.random()
* and multiply by the length of self.values to what word will be chosen.
* */
self.setWord = function() {
self.currentWord = self.auxWord = self.values[Math.floor(Math.random() * self.values.length)];
}
/**
* Renders the elements that will be the slots for each letter.
* @param {event} o - used to manipulate the element dom.
* */
self.renderLetters = function(o) {
// Clear up the element
o.innerHTML = '';
// Setting a random word in the array of fruits.
self.setWord();
// Using a for loop to create each letter in the element.
for (var i = 0; i < self.currentWord.length; i++) {
var letterElement = document.createElement('span');
o.appendChild(letterElement);
}
}
/**
* Used to display a letter when the user hits the right word.
* @param {string} letter - Pass the letter typed by the user.
* */
self.showLetter = function(letter) {
for (var i = 0; i < self.currentWord.length; i++) {
if (self.currentWord[i] == letter) {
self.lettersElement.children[i].textContent = letter;
}
}
}
/**
* Shows a body part of the stickman on the gallows based on its body part id.
* @param {string} body_id - Id from the body part to show.
* */
self.showStickman = function(body_id) {
document.getElementById('stickman-' + body_id).style.visibility = 'visible';
}
/**
* Checks if the user input is a valid input.
* @param {element} o - The input that will be checked.
* */
self.check = function(o) {
self.userInput = o.value;
// Checking if the user input is in the current word.
var findedLetterIndex = self.auxWord.indexOf(self.userInput);
// Check if the user input exists in the current game word.
if (findedLetterIndex >= 0) {
self.auxWord = self.auxWord.replaceAll(self.userInput, "");
self.showLetter(self.userInput);
// When the auxWord no longer has letters, it means that the user has finished the game.
if (! self.auxWord.length) {
self.endGame(o, 0);
}
}
else {
// Handles user fails
self.fails++;
self.showStickman(self.fails)
if (self.fails > 5) {
self.endGame(o, 1);
}
}
// Reset the input value
o.value = "";
}
/**
* Specifies the endgame type and displays a message to the user.
* @param {Object} o - The input object that will be disabled.
* @param {Object} m - The message object to display.
* */
self.endGame = function(o, m) {
o.setAttribute('disabled', '');
var message = !m ? "You finished the game successfully, congratulations" : "You failed! Try again?"
alert(message);
}
/**
* Function responsable to restart the game.
* */
self.resetGame = function() {
// Restarting the main properties.
self.fails = 0;
self.userInput = '';
self.currentWord = '';
self.auxWord = '';
self.lettersElement = null;
// Cleans the entire container.
document.getElementById('root').innerHTML = '';
// Call lemonade.blender again to assign the self to the template again and re-render the result in the container.
lemonade.blender(template, self, document.getElementById('root'));
}
// Game template
var template = `
<div class='p20' style='max-width: 460px;'>
<div style='border-left:2px solid black; border-top:2px solid black; height: 160px;width:100px;padding-top:20px;'>
<div style='position: absolute; margin-left:40px;'>
<svg class="stickman" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns1="http://sozi.baierouge.fr" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 168.38 357.72" width='60'>
<g transform="translate(-165.46 -71.804)">
<g transform="translate(15.143 -322.57)">
<path id="stickman-1" d="m275 450.36c0 22.644-18.356 41-41 41s-41-18.356-41-41 18.356-41 41-41 41 18.356 41 41z" style=" visibility: hidden; stroke:#000000;stroke-width:10;fill:none" />
<path id="stickman-2" d="m234 511.91v138.91z" style=" visibility: hidden; stroke:#000000;stroke-width:8.4187;" />
<path id="stickman-5" d="m244 667.36 47 72z" style=" visibility: hidden; stroke:#000000;stroke-width:10;" />
<path id="stickman-6" d="m222.5 666.36-47 72z" style=" visibility: hidden; stroke:#000000;stroke-linecap:round;stroke-width:10;" />
<path id="stickman-3" d="m211.5 520.36-47 72z" style=" visibility: hidden; stroke:#000000;stroke-width:10;" />
<path id="stickman-4" d="m257.5 514.36 47 72z" style=" visibility: hidden; stroke:#000000;stroke-width:10;" />
</g>
</g>
</svg>
</div>
</div>
<div @ready="self.renderLetters(this)" @ref="self.lettersElement" class="word" style='text-align: center'></div>
<div style="display: flex; justify-content: space-between; align-items: center; padding: 10px;">
<div>
<label for="user-input">Input:</label>
<input type="text" name="user-input" placeholder="Enter a letter" onkeyup="self.check(this)"/>
</div>
<input type="button" onclick="self.resetGame(this)" value="Restart Game" class="jbutton dark" /> <span class="clue">Clue: {{self.clue}}</span>
</div>
</div>`;
return lemonade.element(template, self);
}