Simon game software implementation. User is presented a random series of button presses. Each time user inputs a series of button presses correctly, user sees the same series of button presses but with an additional step. User hears a sound that corresponds each button both when the series of button presses plays, and when user personally presses a button. If user presses a wrong button, user is notified that he has done so, and that series of button presses starts again to remind the pattern so user can try again. User can see how many steps are in the current series of button presses. User can hit restart button during gameplay, and the game will return to a single step. User can play in strict mode where if user gets a button press wrong, notification is presented that user has done so, and the game restarts at a new random series of button presses. The tempo of the game speeds up incrementally on the 5th, 9th and 13th step. User can win the game by getting a series of 20 steps correct. User is notified of the victory, then the game can be started over by hitting start button.
Last active
November 25, 2017 19:29
-
-
Save rfprod/1832b0048a5303f6ab23 to your computer and use it in GitHub Desktop.
Simon Game
This file contains hidden or 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
<script type="text/javascript" async src="https://platform.twitter.com/widgets.js"></script> | |
<link href='https://fonts.googleapis.com/css?family=Play&effect=neon|emboss|3d-float' rel='stylesheet' type='text/css'> | |
<div class="container-fluid nopadding unselectable"> | |
<nav class="navbar navbar-inverse navbar-fixed-top topnav" role="navigation"> | |
<div class="navbar-header"> | |
<button class="navbar-toggle collapsed" data-toggle="collapse" data-target="#toggle-nav" aria-expanded="false"> | |
<span class="sr-only">Toggle navigation</span> | |
<span class="icon-bar"></span> | |
<span class="icon-bar"></span> | |
<span class="icon-bar"></span> | |
</button> | |
<a class="navbar-brand font-effect-neon" target=_blank href="https://codepen.io/rfprod"><span class="glyphicon glyphicon-wrench"></span> RFProd</a> | |
</div> | |
<div class="collapse navbar-collapse" id="toggle-nav"> | |
<div class="container-fluid"> | |
<ul class="nav navbar-nav navbar-right font-effect-emboss"> | |
<li class="nav-tabs"><a href="#simon"><span class="glyphicon glyphicon-th-large"></span> SIMON GAME</a></li> | |
<li class="nav-tabs"><a href="https://gist.github.com/rfprod/1832b0048a5303f6ab23" target=_blank><span class="glyphicon glyphicon-download-alt" ></span> GIST</a></li> | |
</ul> | |
</div> | |
</div> | |
</nav> | |
<a name="simon"></a> | |
<div class="home"> | |
<div class="flex-item"> | |
<div class="col-md-12"> | |
<span id="output" class="font-effect-emboss"> | |
<div id="simon-body"> | |
<audio id="speaker"></audio> | |
<div id="green-button" class="simon-button" name="1"></div> | |
<div id="red-button" class="simon-button" name="2"></div> | |
<div id="yellow-button" class="simon-button" name="3"></div> | |
<div id="blue-button" class="simon-button" name="4"></div> | |
</div> | |
<div id="simon-settings"> | |
<div id="cntnr"> | |
<span class="badge" id="steps-counter">Simon</span> | |
</div> | |
<div id="cntnr"> | |
<div class="btn-group"> | |
<button class="btn btn-xs btn-default btn-responsive" id="start" title="Start game">START</button> | |
<button class="btn btn-xs btn-default btn-responsive" id="strict" title="Toggle strict mode on/off">STRICT</button> | |
</div> | |
</div> | |
<div id="cntnr"> | |
<div class="btn-group btn-toggle" title="Toggle Simon game on/off"> | |
<button class="btn btn-xs btn-default btn-responsive" id="on">ON</button> | |
<button class="btn btn-xs btn-primary btn-responsive active" id="off">OFF</button> | |
</div> | |
</div> | |
</div> | |
</span> | |
<span class="credits font-effect-emboss">licence <a href="http://www.gnu.org/licenses/gpl-3.0.en.html" target=_blank>GPL 3.0</a></span> | |
</div> | |
</div> | |
</div> | |
</div> |
This file contains hidden or 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
var turn; | |
var rnd = []; | |
var userAnswers = []; | |
var timeouts = []; | |
var userTurnTimeout; | |
var aiTurnTimeout; | |
var simonSounds = ["https://s3.amazonaws.com/freecodecamp/simonSound1.mp3", "https://s3.amazonaws.com/freecodecamp/simonSound2.mp3", "https://s3.amazonaws.com/freecodecamp/simonSound3.mp3", "https://s3.amazonaws.com/freecodecamp/simonSound4.mp3"]; | |
var audioElement; | |
$(document).ready(function(){ | |
centerGame(); | |
// initialize simon on-off switch (and all other buttons inside) | |
$('.btn-toggle').click(function(){ | |
$(this).find('.btn').toggleClass('active'); | |
if ($(this).find('.btn-primary').size()>0) {$(this).find('.btn').toggleClass('btn-primary');} | |
if ($(this).find('.btn-danger').size()>0) {$(this).find('.btn').toggleClass('btn-danger');} | |
if ($(this).find('.btn-success').size()>0) {$(this).find('.btn').toggleClass('btn-success');} | |
if ($(this).find('.btn-info').size()>0) {$(this).find('.btn').toggleClass('btn-info');} | |
$(this).find('.btn').toggleClass('btn-default'); | |
// check toggler state (set or rmove click listeners) | |
if ($('.btn-toggle').find("#on").hasClass("active")){ | |
$("#strict").click(function(){ | |
$(this).toggleClass("active"); | |
$(this).toggleClass("btn-danger"); | |
}); | |
$("#start").click(function(){ | |
if ($(this).html() == "START"){ | |
$(this).toggleClass("active"); | |
$(this).toggleClass("btn-success"); | |
$(this).html("RESTART"); | |
$("#green-button").mousedown(function(){ | |
playSound(0); | |
clearTimeouts(); | |
checkResult($(this).attr("name")); | |
}); | |
$("#red-button").mousedown(function(){ | |
playSound(1); | |
clearTimeouts(); | |
checkResult($(this).attr("name")); | |
}); | |
$("#yellow-button").mousedown(function(){ | |
playSound(2); | |
clearTimeouts(); | |
checkResult($(this).attr("name")); | |
}); | |
$("#blue-button").mousedown(function(){ | |
playSound(3); | |
clearTimeouts(); | |
checkResult($(this).attr("name")); | |
}); | |
} | |
startGame(); | |
$("#steps-counter").html("--"); | |
}); | |
}else if ($('.btn-toggle').find("#off").hasClass("active")){ | |
$("#strict").off(); | |
$("#start").off(); | |
$("#green-button").off(); | |
$("#red-button").off(); | |
$("#blue-button").off(); | |
$("#yellow-button").off(); | |
$("#steps-counter").html("Simon"); | |
if ($("#strict").hasClass("active")){ | |
$("#strict").removeClass("active btn-danger"); | |
$("#strict").addClass("btn-default"); | |
} | |
if ($("#start").hasClass("active")){ | |
$("#start").removeClass("active btn-success"); | |
$("#start").addClass("btn-default"); | |
if ($("#start").html() == "RESTART"){ | |
$("#start").html("START"); | |
} | |
} | |
clearTimeouts(); | |
rnd = []; | |
stopSound(); | |
} | |
}); | |
audioElement = document.getElementById('speaker'); | |
}); | |
function startGame(){ | |
turn = 1; | |
rnd = []; | |
userAnswers = []; | |
//alert("rnd[0]: "+rnd[0]); | |
clearTimeouts(); | |
userTurnTimeout = 0; | |
aiTurnTimeout = 0; | |
aiTurn(); | |
} | |
function aiTurn(){ | |
rnd.push(generateRandom()); | |
//alert("ai moves: "+rnd); | |
(function pressButtonsSequentially(i){ | |
timeouts.push(setTimeout(function(){ | |
//alert("index: "+(rnd.length - i)); | |
pressButton(rnd[rnd.length - i]); | |
if (rnd.length < 10){ | |
$("#steps-counter").html("-"+rnd.length); | |
}else{ | |
$("#steps-counter").html(rnd.length); | |
} | |
if (--i) pressButtonsSequentially(i); | |
},aiTurnTimeout * 0.85)); | |
})(rnd.length); | |
} | |
function aiTurnOnWrongSequenceOrTimeout(){ | |
(function pressButtonsSequentially(i){ | |
timeouts.push(setTimeout(function(){ | |
pressButton(rnd[rnd.length-i]); | |
if (--i) pressButtonsSequentially(i); | |
},aiTurnTimeout*0.85)); | |
})(rnd.length); | |
} | |
function userTurn(rndVal){ | |
userTurnTimeout = aiTurnTimeout * turn * 2; | |
timeouts.push(setTimeout(function(){pressButton(rndVal,turn);},userTurnTimeout)); | |
userAnswers = []; | |
} | |
function clearTimeouts(){ | |
for (var i=0; i<timeouts.length; i++) { | |
clearTimeout(timeouts[i]); | |
} | |
if ($("#green-button").hasClass("hovered")){ | |
$("#green-button").toggleClass("hovered"); | |
} | |
if ($("#red-button").hasClass("hovered")){ | |
$("#red-button").toggleClass("hovered"); | |
} | |
if ($("#blue-button").hasClass("hovered")){ | |
$("#blue-button").toggleClass("hovered"); | |
} | |
if ($("#yellow-button").hasClass("hovered")){ | |
$("#yellow-button").toggleClass("hovered"); | |
} | |
} | |
function checkResult(thisName){ | |
userAnswers.push(thisName); | |
// this for loop checks validity of every click, which is excessice imo | |
// if next loop is commented, game checks validity of user input sequence once it is complete | |
for (var c = 0; c < userAnswers.length; c++){ | |
if (userAnswers[c] != rnd[c]){ | |
alert("wrong sequence, try again"); | |
if ($("#strict").hasClass("active")){ | |
alert("STRICT mode activated, new control sequence for turn "+turn+" generated"); | |
rnd = []; | |
for (var k=0;k<turn;k++){ | |
rnd.push(generateRandom()); | |
} | |
//alert("new control sequence: "+rnd); | |
} | |
clearTimeouts(); | |
aiTurnOnWrongSequenceOrTimeout(); | |
} | |
} | |
//alert("check result, thisName: "+thisName); | |
var success = false; | |
if (userAnswers.length == rnd.length){ | |
var checkCounter = 0; | |
for (var e = 0; e < rnd.length; e++){ | |
if (userAnswers[e] == rnd[e]){checkCounter++;} | |
} | |
if (checkCounter == rnd.length){success = true;} | |
if (success){ | |
turn++; | |
if (turn >= 21){ | |
alert(turn+" memory challenges passed: user wins "); | |
$("#green-button").toggleClass("hovered"); | |
$("#red-button").toggleClass("hovered"); | |
$("#yellow-button").toggleClass("hovered"); | |
$("#blue-button").toggleClass("hovered"); | |
$("#start").toggleClass("active"); | |
$("#start").toggleClass("btn-success"); | |
$("#steps-counter").html("WIN"); | |
if ($("#start").html() == "RESTART"){ | |
$("#start").html("START"); | |
} | |
}else{ | |
alert("correct, next turn: "+turn); | |
clearTimeouts(); | |
aiTurn(); | |
} | |
}else{ | |
alert("wrong sequence, try again"); | |
if ($("#strict").hasClass("active")){ | |
alert("STRICT mode activated, new control sequence for turn "+turn+" generated"); | |
rnd = []; | |
for (var k=0;k<turn;k++){ | |
rnd.push(generateRandom()); | |
} | |
//alert("new control sequence: "+rnd); | |
} | |
clearTimeouts(); | |
aiTurnOnWrongSequenceOrTimeout(); | |
} | |
}else{ | |
timeouts.push(setTimeout(function(){ | |
alert("timeout, repeating control sequence..."); | |
clearTimeouts(); | |
aiTurnOnWrongSequenceOrTimeout(); | |
},userTurnTimeout)); | |
} | |
} | |
function pressButton(rndVal){ | |
if (turn <10){ | |
// decreases by 45ms / turn | |
aiTurnTimeout = 2000 - turn * 45; | |
}else{ | |
// decreases by 15ms / turn | |
aiTurnTimeout = 2000 - 10*45 - (turn - 10) * 15; | |
} | |
if (rndVal == 1){ | |
$("#green-button").toggleClass("hovered"); | |
playSound(0); | |
timeouts.push(setTimeout(function(){$("#green-button").toggleClass("hovered");},aiTurnTimeout*0.75)); | |
} | |
if (rndVal == 2){ | |
$("#red-button").toggleClass("hovered"); | |
playSound(1); | |
timeouts.push(setTimeout(function(){$("#red-button").toggleClass("hovered");},aiTurnTimeout*0.75)); | |
} | |
if (rndVal == 3){ | |
$("#yellow-button").toggleClass("hovered"); | |
playSound(2); | |
timeouts.push(setTimeout(function(){$("#yellow-button").toggleClass("hovered");},aiTurnTimeout*0.75)); | |
} | |
if (rndVal == 4){ | |
$("#blue-button").toggleClass("hovered"); | |
playSound(3); | |
timeouts.push(setTimeout(function(){$("#blue-button").toggleClass("hovered");},aiTurnTimeout*0.75)); | |
} | |
userTurn(rndVal); | |
} | |
function generateRandom(){ | |
var randomNumber = Math.floor(Math.random()*(4-1+1) + 1); | |
return randomNumber; | |
} | |
function playSound(index){ | |
audioElement.setAttribute('src', simonSounds[index]); | |
audioElement.setAttribute('autoplay', 'autoplay'); | |
audioElement.addEventListener("load", function() { | |
audioElement.play(); | |
}, true); | |
return audioElement; | |
} | |
function stopSound(){ | |
audioElement.pause(); | |
} | |
// center game on window resize | |
$(window).resize(function(){ | |
centerGame(); | |
}); | |
function centerGame(){ | |
var windowWidth = $(window).width(); | |
var simonBodyHeightAndWidth = $("#simon-body").height(); | |
var simonButtonHeightAndWidth = (simonBodyHeightAndWidth / 2) - 6; // -5 due objects' borders | |
$(".simon-button").each(function(){ | |
$(this).height(simonButtonHeightAndWidth+"px"); | |
$(this).width(simonButtonHeightAndWidth+"px"); | |
}); | |
// fit simon settings in simon body | |
var simonSettingsHeightAndWidth = $("#simon-settings").height(); | |
// center game | |
var paddingH = (windowWidth - simonBodyHeightAndWidth) / 2; | |
var paddingV = (simonBodyHeightAndWidth - simonSettingsHeightAndWidth) / 2; | |
$("#output").css('padding-left',paddingH-5+'px'); | |
if (windowWidth < 972){ | |
windowWidth = $(window).width(); | |
paddingV = (simonBodyHeightAndWidth - simonSettingsHeightAndWidth) / 2; | |
$("#simon-settings").css('height',simonBodyHeightAndWidth/2.5+'px'); | |
$("#simon-settings").css('width',simonBodyHeightAndWidth/2.5+'px'); | |
$("#simon-settings").css('top',paddingV+'px'); | |
$("#simon-settings").css('left',paddingH+simonBodyHeightAndWidth/3+3+'px'); | |
}else{ | |
windowWidth = $(window).width(); | |
paddingV = (simonBodyHeightAndWidth - simonSettingsHeightAndWidth) / 2; | |
$("#simon-settings").css('height',simonBodyHeightAndWidth/2.5+'px'); | |
$("#simon-settings").css('width',simonBodyHeightAndWidth/2.5+'px'); | |
$("#simon-settings").css('top',paddingV*1.2+'px'); | |
$("#simon-settings").css('left',paddingH+simonBodyHeightAndWidth/3+'px'); | |
} | |
} |
This file contains hidden or 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
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> | |
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> |
This file contains hidden or 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
.unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;} | |
.home {background: transparent url('https://image.freepik.com/free-vector/running-man-vector-free-color-splash_23-2147492712.jpg') fixed center top / cover;min-height: calc(100vh - 0.95em);height: auto !important;margin-top: 0.95em; display: flex; padding-top: 1em;} | |
.flex-item { | |
flex: 1 1 auto; | |
} | |
.nopadding {padding: 0;} | |
body {font-family: 'Play', sans-serif;font-size: 2.4em;} | |
.navbar-brand {font-size: 1em;} | |
.credits{display:block;text-align:center;font-size:0.75em;} | |
.credits a:hover{text-decoration:none;} | |
h2{text-align:center;margin-top:21.5vh;margin-bottom:1em;} | |
.img-fit{width:100%;} | |
#output{display:block;text-align:center;margin-top:1em;} | |
/* simon body */ | |
#simon-body{display:block; position: relative; border:1px solid #000000;border-radius:50%;height:50vh;width:50vh;min-height:256px;min-width:256px;z-index:0;background-color:#000000;overflow:hidden;box-shadow: 0px 0px 7px #000000;} | |
.simon-button{display:inline-block;border:1px solid #000000;height:48.9%;width:48.9%;z-index:0;} | |
.simon-button:hover{cursor:pointer;} | |
#green-button{background-color:#007f00;} | |
#green-button:hover, #green-button.hovered{background-color:#00ff00;} | |
#red-button{background-color:#7f0000;} | |
#red-button:hover, #red-button.hovered{background-color:#ff0000;} | |
#blue-button{background-color:#00007f;} | |
#blue-button:hover, #blue-button.hovered{background-color:#0000ff;} | |
#yellow-button{background-color:#7f7f00;} | |
#yellow-button:hover, #yellow-button.hovered{background-color:#ffff00;} | |
#simon-settings{text-align:center;position:absolute;border:1px solid #000000;border-radius:50%;height:21vh;width:21vh;z-index:100;background-color:#000000;overflow:hidden;padding-top:0.5%;} | |
#cntnr{display:block;} | |
#steps-counter:hover{cursor:default;} | |
.btn-responsive {padding:2px 4px;font-size:45%;line-height:1;} |
This file contains hidden or 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
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" /> | |
<link href="//cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.3/animate.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment