Skip to content

Instantly share code, notes, and snippets.

@chemok78
Created July 22, 2016 06:23
Show Gist options
  • Save chemok78/a7a93de1a7395e461682a7349c4b4817 to your computer and use it in GitHub Desktop.
Save chemok78/a7a93de1a7395e461682a7349c4b4817 to your computer and use it in GitHub Desktop.
Simon Game
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--Make sure latest rendering mode in IE-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap2/bootstrap-switch.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/js/bootstrap-switch.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Ubuntu" rel="stylesheet">
<!--to ensure proper rendering and touch zooming-->
<title>Simon Game</title>
</head>
<body>
<div class="wrapper">
<div id="green"></div>
<div id="red"></div>
<div id="yellow"></div>
<div id="blue"></div>
</div><!--wrapper-->
<div class="innerCircle text-center">
<h1 id="innerTitle">Simon Game</h1>
<div class="gameControls">
<div id="counter" class="control">--</div>
<button type="button" class="btn btn-primary btn-md control" id="startButton">Start</button>
<button type="button" class="btn btn-primary btn-md control" id="strictButton" data-toggle="button">Strict</button>
</div><!--gameControls-->
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary" id="on">
<input type="radio" name="switch"> On
</label>
<label class="btn btn-primary active" id="off">
<input type="radio" name="switch" checked>Off
</label>
</div>
</div><!--innerCircle-->
</body>
</html>
$(document).ready(function() {
var resize = function() {
$('.wrapper').css({
position: 'absolute',
left: ($(window).width() - $('.wrapper').outerWidth()) / 2,
//outerWidth is a jQuery for wdith including padding and behavior
//difference between window width and wrapper width divided by 2
top: ($(window).height() - $('.wrapper').outerHeight()) / 2
});
} //resize
var resizeCircle = function() {
$('.innerCircle').css({
position: 'absolute',
left: ($(window).width() - $('.innerCircle').outerWidth()) / 2,
//outerWidth is a jQuery for wdith including padding and behavior
//difference between window width and wrapper width divided by 2
top: ($(window).height() - $('.innerCircle').outerHeight()) / 2
});
}
resize();
//call resize function once when the page is loaded
resizeCircle();
$(window).resize(function() {
//call resize every time the window resizes
resize();
resizeCircle();
})
//global variables
var board = ["green", "red", "blue", "yellow"];
//global array for gameplay buttons with different colors
var clickCount = 0;
//global variable to hold the click sequence by the human player to compare with the computer sequence
var currentGame = null;
//global variable to hold the current game, toggled by on/off button
var currentState = null;
//global variable to hold the current state of the game
var animateAudio = function(button, speed) {
//public function to create button sound and bind to colored button
//used both in click by user and animate sequence by computer
//input: string for button color: "red", "blue", "yellow", "green"
var audio = document.createElement('audio');
//create audio element
audio.defaultPlaybackRate = speed;
//set the playbackrate to the speed parameter
switch (button) {
//bind sounds to the different color buttons
case "red":
audio.setAttribute('src', 'https://s3.amazonaws.com/freecodecamp/simonSound1.mp3');
break;
case "blue":
audio.setAttribute('src', 'https://s3.amazonaws.com/freecodecamp/simonSound2.mp3');
break;
case "yellow":
audio.setAttribute('src', 'https://s3.amazonaws.com/freecodecamp/simonSound3.mp3');
break;
case "green":
audio.setAttribute('src', 'https://s3.amazonaws.com/freecodecamp/simonSound1.mp3');
};
audio.play();
//play the audio
}
var animateButton = function(buttonID, time) {
//public function for animate button highlight using jQuery UI
//Used in both in click by user and animate sequence by computer
//input: button ID and animation time
$(buttonID).effect("highlight", {}, time);
}
var State = function() {
//State class to represent state of the current game
this.sequence = [];
//sequence of button presses currently playing
this.makeSequence = function() {
//generate a first sequence (called from currentGame.startSequence())
//adds a new button to the sequence
var number = Math.floor(Math.random() * 4);
//generate random index number between 0-3
var color = board[number];
//get the color from the board belonging to random index
currentState.sequence.push(color);
//add the color to the end of the sequence array in currentState
$('#counter').html(currentState.sequence.length);
//display the length of the sequence as the counter in the display
} //makeSequence
this.animateSequence = function() {
//public: animate the sequence in array with button highlights and sounds
currentGame.status = "animating";
//game is not clickable when computer is animating sequence
var sequence = currentState.sequence;
//save copy of sequence array in local variable
var animate = function(i) {
//private function that calls the public animate function with an index parameter
animateAudio(sequence[i], 0.5);
animateButton("#" + sequence[i], 1000);
}
var i = 0;
//local counter to use in recursive loop
function loop() {
//recursive function that calls itself from a setTimeout function, that calls animate from within
//setTimeout returns right away. So increment counter and call next loop within, when each setTimeout finishes
setTimeout(function() {
$('#counter').html(currentState.sequence.length).css("font-size", "24px");
animate(i);
i++
//increment counter from within function
if (i < sequence.length) {
loop();
//recursive call if the sequence has not been completely iterated yet
} else {
currentGame.status = "running";
//set status back to running again in last loop, so board is clickable again
};
}, 1000);
}
loop();
//call the recursive animate loop
currentState.changeTurn("computer");
} //animate sequence
} //class State
var Game = function() {
//class to represent the current Game
this.on = false;
//public: is the game turned on or not
//nothing runs or is clickable when game is turned off.
///When turning on from off, the game resets
this.status = "off";
//off, beginning (still needs to press start for sequence), running
this.strict = false;
//public: game being played in strict mode or not
//if true: game restarts when one time press wrong button in sequence
this.setState = function() {
//public: to reset and start a new State
//when turned on from off
//when 1 wrong button press if strict mode
//when press start while game is running
currentState = new State();
//create a new state (reset state)
$('#counter').html("Press Start!").css("font-size", "15px");
//display the length of the current sequence in display
$('#startButton').effect("highlight");
}
this.startSequence = function() {
//public: to start the game:
//when the game is turned on and player presses start (called from click start)
if (currentGame.status !== "off") {
//start button only clickable if game is turned on;
currentState.sequence = [];
//when click start, the sequence starts from beginning: reset the array.
currentState.makeSequence();
//make sequence for the first time = make the first button press
$('#counter').html(currentState.sequence.length).css("font-size", "24px");
//set counter to display the current sequence length = 1;
currentState.animateSequence();
//animate the sequence
} // if status is not off
} //startSequence
this.checkSequence = function(button) {
//public: use in UI button clicks to check if the clicks match the current sequence
//if match complete sequence: change turn back to computer who generates a new sequence
//if one button does not match sequence: animate again. If strict mode: reset state
//called from button clicks with the button name as input
var sequence = currentState.sequence;
//make a copy of current sequence in local variable
if (sequence[clickCount] === button) {
//if button is same as current position in sequence, press is correct
clickCount = clickCount + 1;
//increase the clickcount by 1 for the next click
if (sequence.length === clickCount) {
//if the clickcount reaches the sequence length: whole sequence was correctly pressed and in right order
if (sequence.length === 20) {
//first check if we have reached 20 correct presses
$('#counter').html("Win!").css("font-size", "24px");
//display win
setTimeout(function() {
//restart state after a few seconds
currentGame.startSequence();
}, 3000);
} else {
//correctly pressed sequence but not 20 buttons yet
clickCount = 0;
//reset clickCount for the computer for a new check after computer has generated new button for sequence
$('#counter').html("Great!").css("font-size", "24px");
currentState.makeSequence();
//add a new button to currentState.sequence
currentState.animateSequence();
//animate the sequence
} //check if end game, length = 21
} //if end of matching sequence
} else {
//wrong button press: does not match current element of sequence
if (currentGame.strict === false) {
//not strictmode: animate the sequence again and set clickCount
$('#counter').html("Wrong!").css("font-size", "24px");
clickCount = 0;
currentState.animateSequence();
} else {
//strict mode: restart the game
$('#counter').html("Wrong!").css("font-size", "24px");
setTimeout(function(){
//Restart after 1 second, show Wrong message first
currentGame.startSequence();
}, 1000);
}
} //click count = current button
} //checkSequence
}; // var Game
//Board control UI for human player to match sequence;
$('#yellow').on('click', function() {
if(currentGame.status === "running" && currentGame.status !== "animating"){
animateAudio("yellow", 1);
animateButton("#yellow", 500);
currentGame.checkSequence("yellow");
//check sequence match with button
}
});
$('#green').on('click', function() {
if(currentGame.status === "running" && currentGame.status !== "animating"){
animateAudio("green", 1);
animateButton("#green", 500);
currentGame.checkSequence("green");
}
});
$('#blue').on('click', function() {
if(currentGame.status === "running" && currentGame.status !== "animating"){
animateAudio("blue", 1);
animateButton("#blue", 500);
currentGame.checkSequence("blue");
}
});
$('#red').on('click', function() {
if(currentGame.status === "running" && currentGame.status !== "animating"){
animateAudio("red", 1);
animateButton("#red", 500);
currentGame.checkSequence("red");
}
});
//Game Control UI:
$('#on').on('click', function() {
currentGame = new Game();
//intiliaze a new currentGame object
currentGame.on = true;
//set game on to true
currentGame.status = "beginning";
//set game status to beginning (when click start will be running)
currentGame.setState();
//call setState method to initialize a new currentState object
//also sets the display to show "--"
$('#off').on('click', function() {
currentGame.on = false;
//set game on to false
currentGame.status = "off";
//set game status to off
$('#counter').html("--");
//set display to show "--" again because it's turned off
});
}); //on button
$('#startButton').on('click', function() {
//start sequence when
currentState.status = "running";
currentGame.startSequence();
});
$('#strictButton').on('click', function() {
//toggle strict mode
if (currentGame.strict === false) {
currentGame.strict = true;
$('#strictButton').addClass('ui-state-focus');
$('#strictButton').css('color', '#e74c3c');
} else {
currentGame.strict = false;
$('#strictButton').removeClass('ui-state-focus');
$('#strictButton').css('color', 'white');
}
});
}); //document.ready
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
body {
background-color: #bdc3c7;
font-family:ubuntu;
}
.wrapper {
width: 600px;
height: 600px;
background-color:black;
border-radius: 50%;
}
#green {
width:300px;
height: 300px;
background-color: #27ae60;
float:left;
border-top-left-radius:100%;
border-left: 8px solid black;
border-top: 8px solid black;
border-bottom: 4px solid black;
border-right: 4px solid black;
}
#red{
width:300px;
height:300px;
background-color:#c0392b;
float:left;
border-top-right-radius:100%;
border-left: 4px solid black;
border-top: 8px solid black;
border-bottom: 4px solid black;
border-right: 8px solid black;
}
#yellow {
width:300px;
height:300px;
background-color:#f1c40f;
float:left;
border-bottom-left-radius: 100%;
border-left: 8px solid black;
border-top: 4px solid black;
border-bottom: 8px solid black;
border-right: 4px solid black;
}
#red{
width:300px;
height:300px;
background-color:#c0392b;
float:left;
border-top-right-radius:100%;
border-left: 4px solid black;
border-top: 8px solid black;
border-bottom: 4px solid black;
border-right: 8px solid black;
}
#blue{
width:300px;
height:300px;
background-color:#2980b9;
float:left;
border-bottom-right-radius:100%;
border-left: 4px solid black;
border-top: 4px solid black;
border-bottom: 8px solid black;
border-right: 8px solid black;
}
.innerCircle {
width:300px;
height:300px;
background-color:white;
border-radius:50%;
border: 8px solid black;
}
#innerTitle{
/*text-align:center;*/
padding-top:50px;
}
.gameControls {
background-color:transparant;
height:100px;
width:250px;
margin:auto;
}
#counter{
background-color:black;
border-radius: 15%;
width:100px;
height:50px;
color:white;
font-size:24px;
text-align:center;
padding-top:3%;
}
.control {
float:left;
margin-right:10px;
margin-top:10px;
}
#startButton {
background-color: #e74c3c;
border-color: #e74c3c;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment