After reviewing this approach: Rock-Paper-Scissors with the revealing module pattern
I decided to write an alternative where the Revealing Module Pattern is used for the UI, model, and controller.
I am open to all feedback from style to design.
// noprotect
var roshambo = (function() {
var UI = ( function containedUI(){
var output = document.getElementById( 'output' );
function log( message ){
output.innerHTML = message + '<br>' + output.innerHTML;
}
return {
log : log
};
})();
var model = ( function containedModel(){
//'Rock: 1, Paper: 2, Scissors: 3'
var gamesCount = 0,
winsCount = 0,
robotMove,
DRAW = 0,
LOSE = 1,
WIN = 2,
ROCK = 1,
PAPER = 2,
SCISSORS = 3,
moves = [ '', 'Rock', 'Paper', 'Scissors' ],
results = [ 'Draw !', 'You lose !', 'You win !' ];
function registerResult( result ){
if ( result == WIN ){
winsCount++;
}
gamesCount++;
}
function getStats(){
return {
gamesCount : gamesCount , winsCount : winsCount
};
}
function generateRobotMove(){
return Math.floor(Math.random() * 3) + 1;
}
function getMoveDescription( move ){
return moves[move];
}
function getResultDescription( result ){
return results[result];
}
function compareMoves(human, robot) {
// Tie
if (human == robot) {
return DRAW;
}
// Robot wins
if (robot == ROCK && human == SCISSORS ||
robot == PAPER && human == ROCK ||
robot == SCISSORS && human == PAPER) {
return LOSE;
}
//In all other cases, the player wins
return WIN;
}
return {
registerResult : registerResult,
generateRobotMove : generateRobotMove,
getMoveDescription : getMoveDescription,
getResultDescription : getResultDescription,
getStats : getStats,
compareMoves : compareMoves,
ROCK: ROCK,
PAPER: PAPER,
SCISSORS: SCISSORS
};
})();
var controller = ( function containedController(doc){
function play(){
UI.log( 'Click on of the move buttons to play' );
}
function newGame( humanMove ){
var robotMove = model.generateRobotMove();
UI.log( 'You chose ' + model.getMoveDescription( humanMove ) );
UI.log( 'The robot played ' + model.getMoveDescription( robotMove ) );
var result = model.compareMoves(humanMove, robotMove);
UI.log( model.getResultDescription( result ) );
model.registerResult( result );
var stats = model.getStats();
var winStats = Math.round( stats.winsCount / stats.gamesCount * 100 , 2);
UI.log( 'You won ' + winStats + '% of total games !' );
}
doc.getElementById('Rock').addEventListener("click" , function clickRock(){
newGame( model.ROCK );
});
doc.getElementById('Paper').addEventListener("click" , function clickRock(){
newGame( model.PAPER );
});
doc.getElementById('Scissors').addEventListener("click" , function clickRock(){
newGame( model.SCISSORS );
});
return {
play : play
};
})(document);
// Display a message with total winrate from 0 to 100% (rounded)
function privateAlertTotalResults() {
var results = Math.floor((privateGameDB / privateGameCount) * 100);
UI.log('You won ' + results + '% of total games !');
}
// The only function available to the caller is the play function
return {
play: controller.play
};
})();
// Init a game
roshambo.play();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<button id="Rock">Rock</button>
<button id="Paper">Paper</button>
<button id="Scissors">Scissors</button>
<div id="output">
</div>
</body>
</html>