In my ongoing effort in learning advanced JavaScript I tried to develop the traditional rock paper scissors game by using the famous revealing module pattern. I'm not comfortable yet with what has to be Private/Public. In my solution, I decided to have a single public function: Game
. It uses a lot of private stuff and organizes the global game behavior. Everything else is private and not available to the caller. I'm not sure if it's a correct use of that pattern ?
Anyway I commented my code a lot I hope it will explain my intent correctly. I'm looking for any advices I can get, even if not directly related to the pattern I used.
var roshambo = (function() {
// We will add +1 for each human victory
var privateGameDB = 0;
// We will add +1 for each human or robot victory
var privateGameCount = 0;
// Get human input with validation, returns a number between 1 and 3
function privateGetInput() {
var choice = prompt('Rock: 1, Paper: 2, Scissors: 3');
// Input validation
while (parseInt(choice) <= 0 || parseInt(choice) >= 4 || isNaN(parseInt(choice))) {
choice = prompt('Rock: 1, Paper: 2, Scissors:3 (your choice vas not valid)');
}
return parseInt(choice);
}
// Generate robot's play, randomize a number between 1 and 3
// Also includes a display box alerting the robot's play
function privateGetRobotPlay() {
var play = Math.floor(Math.random() * 3) + 1;
switch (play) {
case 1:
alert('Robot played Rock');
break;
case 2:
alert('Robot played Paper');
break;
case 3:
alert('Robot played Scissors');
break;
}
return play;
}
// Check who wins the round, by comparing the two numbers.
// Returns 0 on draw, 1 on loss and 2 on win
function privateComparePlays(human, robot) {
var humanPlay = human;
var robotPlay = robot;
// Tie
if (robotPlay == humanPlay) {
return 0;
}
// Robot wins
if (robotPlay == 1 && humanPlay == 3 || robotPlay == 2 && humanPlay == 1 || robotPlay == 3 && humanPlay == 2) {
return 1;
}
// Defaults to player's victory
return 2;
}
// Update game database and game counter, do nothing if the round is a tie
function privateUpdateDB(check) {
switch (check) {
case 1:
privateGameCount++;
break;
case 2:
privateGameDB++;
privateGameCount++;
break;
}
}
// Display a message depending on round result
function privateAlertRoundResults(results) {
switch (results) {
case 0:
alert('Draw !');
break;
case 1:
alert('You lose !');
break;
case 2:
alert('You win !');
break;
}
}
// Display a message with total winrate from 0 to 100% (rounded)
function privateAlertTotalResults() {
var results = Math.floor((privateGameDB / privateGameCount) * 100);
alert('You won ' + results + '% of total games !');
}
// Check if the player wants to play again
function privatePlayAgain() {
var choice = confirm('Play again ?');
return choice;
}
// Manage the whole game
function publicGame() {
// First we check who wins the round
var humanPlay = privateGetInput();
var robotPlay = privateGetRobotPlay();
var roundResults = privateComparePlays(humanPlay, robotPlay);
// Then display result to the user
privateAlertRoundResults(roundResults);
// If it's a tie, we do nothing.
// If it's not : update database, display total winrate
if (roundResults != 0) {
privateUpdateDB(roundResults)
privateAlertTotalResults();
}
// We end by asking the user if he wants to play again
// If he does, we use a recursion to start the game again
if (privatePlayAgain() == true) {
publicGame();
}
}
// The only function available to the user is the whole game
return {
play: publicGame
};
})();
// Init a game
roshambo.play();