Created
December 25, 2017 19:27
-
-
Save emmanuellyautomated/5a5bff3e712d2abca3f19f9a44f92728 to your computer and use it in GitHub Desktop.
A reactive game of hangman
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en-us"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Hangman</title> | |
</head> | |
<body> | |
<div id="scoreboard"></div> | |
<div id="game"></div> | |
</body> | |
<script> | |
/******* | |
* MODEL | |
* ----- | |
* Constructors of objects that hold data defining the state of the system | |
*/ | |
function HangmanState(words) { | |
this.wins = 0; | |
this.losses = 0; | |
this.score = 0; | |
this.words = words.map(function(word) { return Array(word.length).fill('-'); }); | |
this.render = function() { | |
document.querySelector("#scoreboard").innerHTML = hangmanTemplate(this); | |
}; | |
} | |
function GameState(numWrongGuesses, word) { | |
this.wrongGuessesLeft = numWrongGuesses; | |
this.word = Array(word.length).fill('-'); | |
this.wasWon = !this.word.includes('-'); | |
this.render = function() { | |
document.querySelector("#game").innerHTML = gameTemplate(this); | |
}; | |
} | |
/****** | |
* VIEW | |
* ---- | |
* Templates to display data held in models | |
*/ | |
var hangmanTemplate = function(state) { | |
return "<table>" + | |
"<tr>" + | |
"<th>Wins</th>" + | |
"<th>Losses</th>" + | |
"<th>Score</th>" + | |
"</tr>" + | |
"<tr>" + | |
"<td align='center'>" + state.wins + "</td>" + | |
"<td align='center'>" + state.losses + "</td>" + | |
"<td align='center'>" + state.score + "</td>" + | |
"</tr>" + | |
"</table>"; | |
}; | |
var gameTemplate = function(state) { | |
return "<h1>Hangman</h1>" + | |
"<table>" + | |
"<tr>" + | |
"<th align='right'>Guesses Left</th>" + | |
"<td>" + state.wrongGuessesLeft + "</td>" + | |
"</tr>" + | |
"<tr>" + | |
"<th align='right'>Word</th>" + | |
"<td>" + state.word + "</td>" + | |
"</tr>" + | |
"<tr>" + | |
"<th align='right'>Game Won?!</th>" + | |
"<td>" + state.wasWon + "</td>" + | |
"</tr>" + | |
"</table>"; | |
}; | |
/************ | |
* CONTROLLER | |
* ---------- | |
* Constructors of objects that valdiate user input, modify models accordingly, and | |
* render approprate views of the data | |
*/ | |
function Game(numWrongGuesses, word) { | |
this.state = new GameState(numWrongGuesses, word); | |
this.isPlaying = false; | |
this.wasWon = function() { return this.state.wasWon; }; | |
this.validKeyPressed = function(key) { | |
choices = "abcdefghijklmnopqrstuvwxyz".split(""); | |
return choices.includes(key); | |
}; | |
this.over = function() { | |
noGuessesLeft = this.state.wrongGuessesLeft === 0; | |
guessedAll = !this.state.word.includes('-'); | |
return noGuessesLeft || guessedAll; | |
}; | |
this.play = function() { | |
if (!this.over()) { this.isPlaying = true; } | |
this.state.render(); | |
}; | |
this.pause = function() { | |
if (!this.over()) { this.isPlaying = false; } | |
this.state.render(); | |
}; | |
//-- PRIVATE ------------------------------------>>> | |
var that = this; | |
var answer = word.split(""); | |
var revealLetters = function(userGuess) { | |
for (var i=0; i<answer.length; i++) { | |
if (userGuess == answer[i]) { that.state.word[i] = userGuess; } | |
} | |
}; | |
var revealLettersOrNot = function(userGuess) { | |
if (answer.includes(userGuess)) { | |
revealLetters(userGuess); | |
} else { | |
that.state.wrongGuessesLeft--; | |
} | |
}; | |
// Event Handlers | |
var processInput = function(event) { | |
userGuess = event.key; | |
if (that.validKeyPressed(userGuess) && that.isPlaying && !that.over()) { | |
revealLettersOrNot(userGuess); | |
that.state.render(); | |
} | |
}; | |
//----------------------------------------------->>> | |
document.addEventListener("keyup", processInput); | |
} | |
function Hangman(numWrongGuesses, words) { | |
this.state = new HangmanState(words); | |
this.games = Array.from(new Set(words)).map( | |
function(word) { return new Game(numWrongGuesses, word); } | |
); | |
this.game = this.games[0]; | |
this.selectPreviousGame = function() { | |
this.game.pause(); | |
this.game = this.games[this.games.indexOf(this.game) - 1] || this.games[this.games.length - 1]; | |
this.game.play(); | |
}; | |
this.selectNextGame = function() { | |
this.game.pause(); | |
this.game = this.games[this.games.indexOf(this.game) + 1] || this.games[0]; | |
this.game.play(); | |
}; | |
this.countWins = function() { | |
gamesWonOrNot = this.games.map(function(game) { return game.wasWon && game.over(); }); | |
return gamesWonOrNot.reduce(function(a, b){ return b ? a + 1 : a; }, 0); | |
}; | |
this.countLosses = function() { | |
gamesLostOrNot = this.games.map(function(game) { return !game.wasWon && game.over(); }); | |
return gamesLostOrNot.reduce(function(a, b){ return b ? a + 1 : a; }, 0); | |
}; | |
this.calculateScore = function() { | |
score = 0; | |
this.games.forEach(function(game, index) { | |
guessesLeft = game.state.wrongGuessesLeft; | |
letterCount = game.state.word.reduce(function(tally, char) { return char != "-" ? tally + 1 : tally; }, 0); | |
score += (guessesLeft * letterCount); | |
}); | |
return score; | |
}; | |
//-- PRIVATE ------------------------------------>>> | |
var that = this; | |
var updateScoreboard = function() { | |
that.state.score = that.calculateScore(); | |
if (that.game.over() && that.game.wasWon) { | |
that.state.wins = that.countWins(); | |
} else if (that.game.over() && !that.game.wasWon) { | |
that.state.losses = that.countLosses(); | |
} | |
that.state.render(); | |
}; | |
var allowGameBrowsing = function() { | |
switch (keyPressed) { | |
case "Enter": | |
if (!that.game.isPlaying) { | |
that.game.play(); | |
} else { | |
that.game.pause(); | |
} | |
break; | |
case "ArrowLeft": | |
that.selectPreviousGame(); | |
break; | |
case "ArrowRight": | |
that.selectNextGame(); | |
break; | |
} | |
}; | |
// Event Handlers | |
var processInput = function(event) { | |
keyPressed = event.key; | |
updateScoreboard(); | |
allowGameBrowsing(); | |
}; | |
//----------------------------------------------->>> | |
document.addEventListener("keyup", processInput); | |
document.onload = this.state.render(); this.game.play(); | |
} | |
var words = [ | |
"pineapple", | |
"mango", | |
"papaya", | |
"guava", | |
"lychee", | |
"tamarind", | |
"pitaya", | |
"cherimoya", | |
"soursop", | |
"mangosteen" | |
]; | |
var hangman = new Hangman(6, words); | |
//== LEGACY =====================================>>> | |
var oldGameTemplate = function(state) { | |
return "<h1>Hangman</h1>" + | |
"<p>Guess what word I'm thinking of</p>" + | |
"<p>Guesses Left: " + state.wrongGuessesLeft + "</p>" + | |
"<p>Word: " + state.word + "</p>" + | |
"<p>Game Won?!: " + state.wasWon + "</p>"; | |
}; | |
var oldHangmanTemplate = function(state) { | |
return "<p>Wins: " + state.wins + "</p>" + | |
"<p>Losses: " + state.losses + "</p>"; | |
}; | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment