Simon Game

HTML
<main> <div class="container"> <div id="lives-wrap"> <div id="lives"></div> <p class="text-center">Lives</p> </div> <div id="level-wrap"> <div id="level"></div> <p class="text-center">Level</p> </div> <div id="game"> <div id="buttons"> <audio id="green-audio" src="https://s3.amazonaws.com/freecodecamp/simonSound1.mp3"></audio> <audio id="red-audio" src="https://s3.amazonaws.com/freecodecamp/simonSound2.mp3"></audio> <audio id="yellow-audio" src="https://s3.amazonaws.com/freecodecamp/simonSound3.mp3"></audio> <audio id="blue-audio" src="https://s3.amazonaws.com/freecodecamp/simonSound4.mp3"></audio> <div class="quarter-circle top-left"></div> <div class="quarter-circle top-right"></div> <div class="quarter-circle bottom-left"></div> <div class="quarter-circle bottom-right"></div> </div> <div id="center" class="text-center"> <button type="button" id="start-btn"></button> <p>Start</p> <button id="reset-btn">Reset</button> </div> </div> </div> </main>
SCSS
$size : 500px; $green : rgba(38, 166, 91, 1); $red : rgba(166, 38, 43, 1); $yellow: rgba(244, 208, 63, 1); $blue : rgba(65, 131, 215, 1); @mixin border-radius-bottom-right($radius) { -webkit-border-radius: 0 0 $radius 0; -moz-border-radius: 0 0 $radius 0; -ms-border-radius: 0 0 $radius 0; border-radius: 0 0 $radius 0; } @mixin border-radius-bottom-left($radius) { -webkit-border-radius: 0 0 0 $radius; -moz-border-radius: 0 0 0 $radius; -ms-border-radius: 0 0 0 $radius; border-radius: 0 0 0 $radius; } @mixin border-radius-top-right($radius) { -webkit-border-radius: 0 $radius 0 0; -moz-border-radius: 0 $radius 0 0; -ms-border-radius: 0 $radius 0 0; border-radius: 0 $radius 0 0; } @mixin border-radius-top-left($radius) { -webkit-border-radius: $radius 0 0 0; -moz-border-radius: $radius 0 0 0; -ms-border-radius: $radius 0 0 0; border-radius: $radius 0 0 0; } @mixin lighten-button($color) { background-color: $color; &.highlighted { background-color: lighten($color, 20%); } &.transparent { background-color: transparent; } &.lose { background-color: $red; } &.win { background-color: $green; } } body { background: #ddd; font-family: 'Roboto'; } #game { position: absolute; width: $size; height: $size; top: 50%; left: 50%; background: #444; border-radius: 50%; transform: translate(-50%, -50%); box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4); z-index: 1; } .quarter-circle { position: absolute; width: $size / 2.5; height: $size / 2.5; cursor: pointer; z-index: 2; } .top-left { top: 8%; left: 8%; @include lighten-button($green); @include border-radius-top-left($size); } .top-right { top: 8%; right: 8%; @include lighten-button($red); @include border-radius-top-right($size); } .bottom-left { bottom: 8%; left: 8%; @include lighten-button($yellow); @include border-radius-bottom-left($size); } .bottom-right { bottom: 8%; right: 8%; @include lighten-button($blue); @include border-radius-bottom-right($size); } #center { position: relative; top: 50%; width: 45%; height: 45%; margin: 0 auto; background: #ddd; color: #444; font-weight: bold; border-radius: 50%; border: 20px solid #444; transform: translateY(-50%); z-index: 3; } #start-btn { width: 40px; height: 40px; margin-top: 40px; background-color: #D24D57; border-radius: 50%; border: 3px solid #444; box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.4); } #reset-btn { position: absolute; right: 36%; bottom: 20%; } #lives-wrap, #level-wrap { position: fixed; font-weight: bold; } #lives-wrap { top: 10%; right: 10%; } #level-wrap { top: 10%; left: 10%; } #lives, #level { width: 80px; height: 60px; padding: 5px; background-color: #444; text-align: center; line-height: 1.75em; font-size: 2em; border-radius: 10%; box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4); } #lives { color: #D24D57; } #level { color: #36D7B7; } #lives + p, #level + p { margin-top: 5px; } #start-btn:focus { outline: 0; } #center h1 { position: relative; top: 5%; transform: translateY(-50%); }
JAVASCRIPT
(function() { var buttons = $(".quarter-circle"), lives = $("#lives"), level = $("#level"); /* [Game] *********************************************************/ function Game(config) { this.lives = config.lives; this.level = config.level; this.sequence = []; this.attempt = []; this.time = 0; this.step = config.step; this.flashTime = config.flashTime; this.status = 'off'; this.config = config; $this = this; } Game.prototype = { constructor: Game, start: function() { this.status = 'on'; lives.text(this.lives); level.text(this.level); setTimeout(function() { $this.playSequence(); }, 1500); }, addStep: function() { this.sequence.push(Math.floor(Math.random() * 4)); }, playSequence: function() { this.status = 'teach'; if (this.sequence.length === 0) { for (var i = 0; i < this.level; i++) { this.addStep(); } } if (this.level === 5) this.speedUp(20); if (this.level === 9) this.speedUp(25); if (this.level === 13) this.speedUp(33); /* Play the sequence */ for (var i = 0; i < this.sequence.length; i++) { (function(button) { setTimeout(function() { $this.pressButton(button); }, $this.time); })($(buttons[this.sequence[i]])); this.time += this.step; /* Disable user clicks until sequence is finished. */ setTimeout(function() { $this.status = 'play'; }, this.level * this.step); } }, sendClick: function(button) { this.attempt.push(buttons.index(button)); this.verify(); }, verify: function() { /* If last button pressed does not match corresponding button in the sequence */ if (this.attempt[this.attempt.length - 1] !== this.sequence[this.attempt.length - 1]) { this.status = 'check'; this.lives -= 1; this.updateLives(); if (this.lives === 0) this.status = 'lose'; setTimeout(function() { $this.fail(); }, 2000); /* Otherwise it's the correct sequence */ } else if (this.attempt.length === this.sequence.length) { this.status = 'check'; this.level += 1; this.updateLevel(); if (this.level > 20) this.status = 'win'; setTimeout(function() { $this.success(); }, 3000); } }, success: function() { this.time = 0; this.attempt = []; if (this.status === 'win') { this.animate(); this.reset(); } else { this.addStep(); this.playSequence(); } }, fail: function() { this.time = 0; this.attempt = []; if (this.status === 'lose') { this.animate(); this.reset(); } else { this.playSequence(); } }, pressButton: function(button) { this.highlight(button); this.playSound(button); }, highlight: function(button, highlight) { var classes = ['highlighted', highlight].join(' '); button.addClass(classes); setTimeout(function() { button.removeClass(classes); }, this.flashTime); }, playSound: function(button) { var index = buttons.index(button); document.getElementsByTagName('audio')[index].play(); }, updateLives: function() { lives.text(this.lives); lives.addClass("animated shake"); setTimeout(function() { lives.removeClass("animated shake"); }, 1500); }, updateLevel: function() { level.text(this.level); level.addClass("animated tada"); setTimeout(function() { level.removeClass("animated tada"); }, 1500); }, speedUp: function(percent) { this.step -= this.step / (100 / percent); this.flashTime -= this.flashTime / (100 / percent); }, reset: function() { this.lives = this.config.lives; this.level = this.config.level; this.step = this.config.step; this.flashTime = this.config.flashTime; this.sequence = []; this.attempt = []; this.time = 0; this.status = 'on'; lives.text(this.lives); level.text(this.level); }, animate: function() { var i = 0, rounds = 0, order = [0, 1, 3, 2], step = 200, status = this.status; buttons.addClass('transparent'); var spin = function() { if (rounds === 2) { clearTimeout(timer); } /* Color each button depending on whether the user won or lost the game */ while (i < 4) { (function(button) { setTimeout(function() { $this.highlight(button, status); }, $this.time); })($(buttons[order[i]])); $this.time += step; i++; } i = 0; rounds++; } /* Color the 4 buttons 3 times */ var timer = setInterval(spin, 0); /* Reset the button colours after 3 spins have occurred */ setTimeout(function() { buttons.removeClass('transparent'); }, step * 13); } }; /* [Event Handlers] **************************************/ buttons .on("click", function() { if (game.status !== 'play') return; game.pressButton($(buttons[buttons.index($(this))])); game.sendClick($(this)); }); $("#start-btn") .mousedown(function() { $(this).css('transform', 'translateY(1px)'); game.start(); }) .mouseup(function() { $(this).css('transform', 'translateY(-1px)'); }); $("#reset-btn") .on("click", function() { game.reset(); }) /* [Main] **********************************************/ /* Pass in a config to the game so that the game can reset to those values */ var cfg = { lives: 3, level: 1, step: 1000, flashTime: 300 } var game = new Game(cfg); })();
Expand for more options Login