Skip to content

Instantly share code, notes, and snippets.

@semlak
Created November 23, 2017 20:39
Show Gist options
  • Save semlak/830d86153b0e16e3b1e490db301e9a6d to your computer and use it in GitHub Desktop.
Save semlak/830d86153b0e16e3b1e490db301e9a6d to your computer and use it in GitHub Desktop.
FreeCodeCamp Zipline: Simon Game
<div class="container">
<div class="row verticle-center-row">
<div class="col-md-12">
<div id='app-container'>
<div class='border' id='outer-circle'>
<div class='quarter-circle' id='quarter-circle-0'></div>
<div class='quarter-circle' id='quarter-circle-1'></div>
<div class='quarter-circle' id='quarter-circle-2'></div>
<div class='quarter-circle' id='quarter-circle-3'></div>
<div class='border' id='horizontal-rectangle'></div>
<div class='border' id='vertical-rectangle'></div>
<div id='inner-circle'>
<div class='inner-circle-contents' id=game-name-div>simon<div class="glyphicon glyphicon-registration-mark
"></div>
</div>
<div class='inline inner-circle-contents' id='counter-div'>
<div id='counter'>--</div>
<div class='game-label'>COUNT</div>
</div>
<div class='inline inner-circle-contents' id='start-button-div'>
<div class='game-control-button' id='start-button'></div>
<div class='game-label' id='start-game-button-label'>START</div>
</div>
<div class='inline inner-circle-contents' id='strict-button-div'>
<div class='game-control-button' id='strict-button'></div>
<div class='game-label'>STRICT</div>
<div class='game-label' id='strict-status-indicator'></div>
</div>
<div class='inner-circle-contents' id=on-off-switch-div>
<div class='inline on-off-switch-label'>OFF</div>
<div class='inline' id='on-off-switch'>
<div class='inline on-off-controls active-on-off-control' id='turn-off'></div>
<div class='inline on-off-controls' id='turn-on'></div>
</div>
<div class='inline on-off-switch-label'> ON</div>
</div>
</div>
</div>
<!--end of .col-md-4 div -->
</div>
<!-- end of .row div -->
</div>
<!-- end of .container div -->
var currentGame ;
var windowTimeouts = [];
var printVar = function(x, varName) {
var name = varName || '';
console.log("printing variable " + name + ":", x);
};
var getRandomHexColor = function(min, max) {
//return ('#'+Math.floor(Math.random()*16777215).toString(16));
return ('#'+(Math.floor(Math.random()*(max - min + 1)) + min).toString(16));
};
var getRandomInt = function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
var SimonGame = function(difficulty, gameTimingLength) {
this.difficulty = difficulty || 0; //levels could be 0 (easy), or 1 (hard). Default is 0
this.playerTurnInProgress = false;
this.playSequence = [];
this.initialGameTimingLength = gameTimingLength || 1000;
this.gameTimingLength = this.initialGameTimingLength;
this.audioElements = []; //globalVariable
this.playerTurnCurrentInput = [];
this.gameOnStatus = false; //this refers to whether the gaming device is switched on or off
this.gameStartedStatus = false; // this refers to whether there is currently a game in progress. The device must be on for this to be true (gameOnStatus === true)
this.strictModeOn = false;
};
SimonGame.prototype.prepareAudioElements = function() {
var game = this;
for (var i = 0; i < 4; i++) {
var array = [];
var audioElement0 = document.createElement('audio');
audioElement0.setAttribute('src', 'https://s3.amazonaws.com/freecodecamp/simonSound' + (i + 1) + '.mp3');
var audioElement1 = document.createElement('audio');
audioElement1.setAttribute('src', 'https://s3.amazonaws.com/freecodecamp/simonSound' + (i + 1) + '.mp3');
array.push(audioElement0);
array.push(audioElement1);
game.audioElements.push(array);
}
};
SimonGame.prototype.cycleThroughLights = function() {
//this is just for testing colors;
for (var i = 0; i < 12; i++) {
window.setTimeout(function(i) {
$('#quarter-circle-' + (i%4)).addClass('lit');
window.setTimeout(function(i) {
console.log(i%4);
$('#quarter-circle-' + (i%4)).removeClass('lit');
}, 500, i);
}, (1000 * i), i);
}
}
SimonGame.prototype.resetGame = function() {
var game = this;
$('.quarter-circle').removeClass('lit');
$('#start-game-button-label').text('RESTART');
game.gameStartStatus = true;
$('#counter').text('--');
while (windowTimeouts.length > 0) {
var timeoutID = windowTimeouts.shift();
window.clearTimeout(timeoutID);
};
game.gameTimingLength = game.initialGameTimingLength;
game.playSequence = [];
game.addToPlaySequence();
game.playerTurnInProgress = false;
game.playCurrentPlaySequenceForUser();
};
SimonGame.prototype.addToPlaySequence = function() {
this.playSequence.push(getRandomInt(0,3));
$('#counter').text(this.playSequence.length);
};
SimonGame.prototype.playAudioElement = function(i) {
var game = this;
var audioElement = game.audioElements[i].shift();
audioElement.pause();
audioElement.currentTime = 0;
audioElement.play();
game.audioElements[i].push(audioElement);
};
SimonGame.prototype.playCurrentPlaySequenceForUser = function() {
var game = this;
game.playSequence.forEach(function(gameQuarter, index) {
windowTimeouts.push(window.setTimeout(function() {
var piece = '#quarter-circle-' + gameQuarter;
$(piece).addClass('lit');
game.playAudioElement(gameQuarter);
windowTimeouts.push(window.setTimeout(function() {
$(piece).removeClass('lit')
}, game.gameTimingLength));
}, game.gameTimingLength*1.5* (index+1)));
});
windowTimeouts.push(window.setTimeout(function() {
game.beginUserResponseSession();
}, (game.playSequence.length + 0) * game.gameTimingLength*1.5 + game.gameTimingLength));
};
SimonGame.prototype.handleOnOffClick = function(e) {
var game = this;
if (game.gameOnStatus) {
//game.turnOffGame();
console.log("turning off game");
$('.quarter-circle').removeClass('lit');
$('#start-game-button-label').text('START');
$('.inner-circle-contents').children().addClass('inactive');
game.gameStartStatus = false;
game.gameOnStatus = false;
//window.clearTimeout(ids)
$('#turn-on').removeClass('active-on-off-control');
$('#turn-off').addClass('active-on-off-control');
$('#counter').text('--');
while (windowTimeouts.length > 0) {
var timeoutID = windowTimeouts.shift();
window.clearTimeout(timeoutID);
};
}
else {
//game.turnOnGame();
console.log("turning on game");
game.gameOnStatus = true;
$('#turn-off').removeClass('active-on-off-control');
$('#turn-on').addClass('active-on-off-control');
$('.inner-circle-contents').children().removeClass('inactive');
}
};
SimonGame.prototype.handleGameWin = function() {
$('#counter').text("**");
var game = this;
game.gameStartStatus = false;
for (var i = 0; i < 24; i++) {
//$('#quarter-circle-' + i).css('background', getRandomHexColor(7829367, 16777215));
window.setTimeout(function(i) {
//$('#quarter-circle-' + (i%4)).css('background', getRandomHexColor(1911, 4095));
$('#quarter-circle-' + (i%4)).toggleClass('lit');
}, (100 * i), i);
//console.log(500*i);
}
}
SimonGame.prototype.handleUserSuccess = function() {
//console.log("handlingUserSuccess");
var game = this;
game.playerTurnInProgress = false;
$('.quarter-circle').removeClass('lit');
var currentGameLength = game.playerTurnCurrentInput.length;
//currentGameLength is number of turns already completed.
if (currentGameLength === 4) {
//speed up game
game.gameTimingLength = game.gameTimingLength * .5;
}
else if (currentGameLength === 8) {
//speed up game
game.gameTimingLength = game.gameTimingLength * .5;
}
else if (currentGameLength === 12) {
//speed up game
game.gameTimingLength = game.gameTimingLength * .5;
}
if (currentGameLength === 20) {
//end game
game.handleGameWin();
}
else {
game.addToPlaySequence();
game.playCurrentPlaySequenceForUser();
}
}
SimonGame.prototype.handleUserError = function() {
var game = this;
game.playerTurnInProgress = false;
$('.quarter-circle').removeClass('lit');
[0,1,2,3].forEach(function(gameQuarter, index) {
window.setTimeout(function() {
var piece = '#quarter-circle-' + gameQuarter;
$(piece).addClass('lit');
game.playAudioElement(gameQuarter);
window.setTimeout(function() {
$(piece).removeClass('lit')
}, 100);
}, 100* (index+1));
});
window.setTimeout(function() {
if (game.strictStatusOn) {
game.resetGame();
}
else {
game.playCurrentPlaySequenceForUser();
}
}, (4) * 100);
};
SimonGame.prototype.handleQuarterCircleMousedown = function(e) {
var game = this;
if (game.playerTurnInProgress) {
var quarterNum = e.currentTarget.id.slice(-1);
//printVar(quarterNum, "quarterNum");
$('#quarter-circle-' + quarterNum).addClass('lit');
game.playAudioElement(quarterNum);
game.playerTurnCurrentInput.push(Number.parseInt(quarterNum));
if (game.playerTurnCurrentInput[game.playerTurnCurrentInput.length - 1] !== game.playSequence[game.playerTurnCurrentInput.length - 1]) {
window.setTimeout(function() {
game.handleUserError();
} , 500);
//do something to alert of an error
}
else if (game.playerTurnCurrentInput.length === game.playSequence.length) {
window.setTimeout(function() {
game.handleUserSuccess();
} , 500);
}
}
};
SimonGame.prototype.handleQuarterCircleMouseup = function(e) {
var game = this;
if (game.playerTurnInProgress) {
var quarterNum = e.currentTarget.id.slice(-1);
$('#quarter-circle-' + quarterNum).removeClass('lit');
//game.audioElements[quarterNum].pause();
}
};
SimonGame.prototype.beginUserResponseSession = function() {
var game = this;
game.playerTurnInProgress = true;
game.playerTurnCurrentInput = [];
//now, the mousedown listening function will listen for user clicks, add the response to the playerTurnCurrentInput array, and see if it was the correct response by comparing to the game.playSequence array
};
SimonGame.prototype.handleGameStartButtonMousedown = function() {
var game = this;
//basically start or restart game
game.resetGame();
}
SimonGame.prototype.handleGameControlButtonMousedown = function(e) {
var game = this;
$('#' + e.target.id).addClass('button-press');
if (game.gameOnStatus) {
if (e.target.id === 'start-button') {
game.handleGameStartButtonMousedown();
}
else if (e.target.id === 'strict-button') {
game.strictStatusOn = (game.strictStatusOn === true ? false : true);
$('#strict-status-indicator').toggleClass('enabled');
printVar(game.strictStatusOn, "strictStatusOn");
}
}
};
SimonGame.prototype.handleGameControlButtonMouseup = function(e) {
//var target = "#" + e.target.id;
$('.game-control-button').removeClass('button-press');
};
$(document).ready(function(){
currentGame = new SimonGame(1);
currentGame.prepareAudioElements();
$(".quarter-circle").on('mousedown', function(e) {
currentGame.handleQuarterCircleMousedown(e);
});
$(".quarter-circle").on('mouseup', function(e) {
currentGame.handleQuarterCircleMouseup(e);
});
$(".on-off-controls").on('click', function(e) {
currentGame.handleOnOffClick(e);
});
$('.game-control-button').on('mousedown', function(e) {
currentGame.handleGameControlButtonMousedown(e)
});
$('.game-control-button').on('mouseup', function(e) {
currentGame.handleGameControlButtonMouseup(e)
});
$('.inner-circle-contents').children().addClass('inactive');
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
body {
background-image: url('http://www.psdgraphics.com/file/oak-wood-background.jpg');
}
#app-container {
margin: 20px 0 20px 0;
}
.border {
background: #000;
position: relative;
}
#outer-circle {
height: 400px;
width: 400px;
border-radius: 50%;
z-index: 0;
margin: auto;
}
.quarter-circle {
height: 170px;
width: 170px;
z-index: 20;
position: relative;
border-radius: 100% 0 0 0;
}
#quarter-circle-0 {
background: #007700;
/* top and left offsets are just the width of the outer border*/
top: 30px;
left: 30px;
}
#quarter-circle-0.lit {
background: #00ff00;
}
#quarter-circle-1 {
background: #770000;
/* top offset is the difference outer-radius - 2* outer border width, negated
left offset is the outer radius*/
top: -140px;
left: 200px;
transform: rotate(90deg)
}
#quarter-circle-1.lit {
background: #ff0000;
}
#quarter-circle-2 {
background: #000077;
/*same as quarter-circle1 */
top: -140px;
left: 200px;
transform: rotate(180deg)
}
#quarter-circle-2.lit {
background: #0000ff;
}
#quarter-circle-3 {
background: #777700;
/* top offset is the previous quarter offset (140) - the outer-radius + outer-border
left offset is just width of outer border*/
top: -310px;
left: 30px;
transform: rotate(270deg)
}
#quarter-circle-3.lit {
background: #ffff00;
}
#horizontal-rectangle {
height: 30px;
width: 400px;
border-radius: 15px;
/*top offset is just the quarter-circle-3 offset - the outer-circle-radius plus half of the outer radius border (same as height of rectangle) */
top: -495px;
z-index: 30
}
#vertical-rectangle {
height: 400px;
width: 30px;
border-radius: 15px;
/*top offset is offset of horizonal rectangle - outer-circle-radius - half of outer-circle border (height of rectangle)
left offset is the outer-circle radius minus half the outer-circle border (same as width of rectangle) */
top: -710px;
left: 185px;
z-index: 30
}
#inner-circle {
height: 200px;
width: 200px;
border-radius: 50%;
background: #fff;
border: 15px solid #000;
position: relative;
/*top offset is vertical-rectangle offset - 3/4 of outer-circle-radius
left offset is 1/4 of outer-circle-radius*/
top: -1010px;
left: 100px;
z-index: 50;
padding: 15px 5px 0px 10px;
}
#game-name-div {
font-size: 20px;
}
.glyphicon-registration-mark {
font-size: 10px;
vertical-align: top;
}
#intro {
/*margin-top: 40px;*/
color: #000;
background: #fff;
border: 2px solid #000;
width: 350px;
padding-bottom: 20px;
margin: auto;
margin-top: 10px;
text-align: center;
}
#counter {
height: 25px;
width: 40px;
border-radius: 10px;
border: 3px solid #222;
font-family: "Bank Gothic", "Futura", "Arial";
background: #311;
color: #ff0000;
box-shadow: 1px 1px 3px #000;
}
#counter.inactive {
color: #700;
font-color: #000;
}
#start-button-div {
margin-right: 10px;
margin-left: 8px;
width: 47px;
}
#start-button {
background: #00ff00;
}
#strict-button {
background: #ffff00;
}
#strict-status-indicator {
position: relative;
top : -60px;
left: 14px;
height: 10px;
width: 10px;
border-radius: 50%;
background: #777 !important;
border: 2px solid #222 ;
}
#strict-status-indicator.inactive {
border-color: #444 ;
}
#strict-status-indicator.enabled {
background: #f00 !important;
}
.game-control-button {
height: 25px;
width: 25px;
border-radius: 50%;
border: 3px solid #222;
margin: auto;
box-shadow: 2px 2px 6px;
}
.game-control-button.inactive {
background: #777 !important;
box-shadow: none;
border-color: #444;
}
.button-press {
box-shadow: none;
}
.game-label {
font-size: 10px;
margin-top: 3px;
}
.game-label.inactive {
color: #777;
}
#on-off-switch-div {
margin-top: 10px;
}
.on-off-switch-label {
vertical-align: middle;
height: 20px;
font-size: 10px;
padding-left: 0px;
padding-right: 0px;
}
.on-off-controls {
width: 30px;
height:20px;
background: #111;
}
#on-off-switch {
border: 2px solid #000;
background: #111;
border-radius: 2px;
height: 24px;
box-shadow: 1px 1px 3px;
}
.active-on-off-control {
border: 1px solid #000;
border-radius: 2px;
background: #00688B; /*deepskyblue4 */
box-shadow: 1px 1px 4px #000;
}
#game-options {
/*margin-top: 40px;*/
color: #000;
background: #fff;
border: 2px solid #000;
width: 350px;
padding-bottom: 20px;
margin: auto;
margin-top: 10px;
text-align: center;
}
.inner-circle-contents {
text-align: center;
margin: auto;
margin-top: 8px;
}
.inline {
display: inline-block;
}
#message-container {
/*
color: #000;
background: #fff;
border: 2px solid #000;
*/
width: 350px;
height: 30px;
margin: auto;
margin-top: 10px;
margin-bottom: 20px;
color: #fff;
text-align: center;
}
#message {
color: #fff;
text-align: center;
margin: auto;
margin: 0px;
padding: 0px;
}
#game-board {
background: #000;
width: 350px;
height: 350px;
padding: 25px;
margin: auto;
margin-top: 20px;
text-align: center;
}
#game-board-table {
margin: auto;
color: #fff;
}
.square {
height: 100px;
width: 100px;
margin: auto;
font-size: 50px;
padding: 0px;
}
.h-borders {
border-top: 1px solid #fff;
border-bottom: 1px solid #fff;
}
.v-borders {
border-left: 1px solid #fff;
border-right: 1px solid #fff;
}
.v-h-borders {
border: 1px solid #fff;
}
.falling-diagonal {
margin: 0px;
padding: 0px;
width: 422px; /*roughly 300 * sqrt(2) */
height: 1px;
border-bottom: 1px dashed #fff;
-webkit-transform:
translateY(-70px)
translateX(50px)
rotate(45deg);
position: relative;
top: -81px;
left: -111px;
z-index: 10;
/* top: -20px; */
}
.rising-diagonal {
margin: 0px;
padding: 0px;
width: 422px; /*roughly 300 * sqrt(2) */
height: 1px;
border-bottom: 1px dashed #fff;
-webkit-transform:
translateY(-70px)
translateX(50px)
rotate(-45deg);
position: relative;
top: -81px;
left: -111px;
z-index: 10;
/* top: -20px; */
}
.horizontal-line {
margin: 0px;
padding: 0px;
width: 300px;
height: 1px;
border-bottom: 1px dashed #fff;
position: relative;
top: -250px;
left: 0px;
z-index: 10;
/* top: -20px; */
}
.vertical-line {
margin: 0px;
padding: 0px;
width: 50px;
height: 300px;
border-left: 1px dashed #fff;
position: relative;
top: -300px;
left: 50px;
z-index: 10;
/* top: -20px; */
}
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment