<!--  Simon Game challenge for FreeCodeCamp
		author: Sergio Gaspar
		date: 2017.01
-->

<div class="options steps"></div>
<div class="options status"></div>
<button class="options start">Start</button>
<button class="options strict">dificulty: easy</button>
    
<div class="container"></div>
<button class="simon" id="red">Red</button>
<button class="simon" id="blue">Blue</button>
<button class="simon" id="yellow">Yellow</button>
<button class="simon" id="green">Green</button>

<footer class="footer">
<script src="https://use.fontawesome.com/c51cc08ec6.js"></script>
<div class="container-fluid text-center">
<div class="footer-text text-muted row">
<Created>by Sérgio Gaspar for freeCodeCamp Challenge:</Created><a href="https://www.freecodecamp.com/challenges/build-a-simon-game" target="_blank">Build Simon game</a>.
</div>
<div class="social-icons">
<a href="https://github.com/sergiomgaspar" target="_blank"><i id="github" class="fa fa-github" aria-hidden="true"></i></a>
<a href="https://codepen.io/sergiomgaspar/" target="_blank"><i id="codepen" class="fa fa-codepen" aria-hidden="true"></i></a>
<a href="https://www.freecodecamp.com/sergiomgaspar" target="_blank"><i id="freecodecamp" class="fa fa-free-code-camp" aria-hidden="true"></i></a>
<a href="https://www.linkedin.com/in/sergiomgaspar" target="_blank"><i id="linkedin" class="fa fa-linkedin-square" aria-hidden="true"></i></a>
<a href="https://twitter.com/sergiomgaspar" target="_blank"><i id="twitter" class="fa fa-twitter" aria-hidden="true"></i></a>
</div>
</div>
</footer>
@import url(https://fonts.googleapis.com/css?family=Oswald:400,300);
@import url("https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css");
body {
  background: #1E1E24;
}

.container{
 // @include center;
  height:550px;
  width:400px;
  border-radius:50%;
}
.simon {
  height: 175px;
  width: 175px;
  cursor: pointer;
  background: none;
  padding: none;
  border: none;
  margin: none;
  box-shadow: none;
  outline: none;
  border-radius: 50%;
  font-family: 'Oswald';
  font-size: 50px;
  -webkit-transition: background 0.2s ease-in;
  transition: background 0.2s ease-in;
  -webkit-transition: border 0.1s linear;
  transition: border 0.1s linear;
}

#yellow, #blue, #green, #red {
  position: absolute;
  top: 50%;
  -webkit-transform: translateY(-50%);
          transform: translateY(-50%);
}

#yellow {
  left: 20%;
}

#blue {
  left: 35%;
}

#red {
  left: 50%;
}

#green {
  left: 65%;
}

#yellow {
  border: #EFBD26 solid 15px;
  color: #EFBD26;
}
#yellow:hover {
  background: #EFBD26;
  color: #1E1E24;
}
#yellow:hover:active {
  -webkit-transform: translateY(-50%) scale(1.1);
          transform: translateY(-50%) scale(1.1);
}

.clicked-yellow:before {
  display: block;
  content: '';
  opacity: 0;
  background: #EFBD26;
  height: 100%;
  width: 100%;
  position: absolute;
  border-radius: 50%;
  left: 0;
  top: 0;
  -webkit-animation: click 0.4s ease-in 1;
          animation: click 0.4s ease-in 1;
}

#red {
  border: #D63B29 solid 15px;
  color: #D63B29;
}
#red:hover {
  background: #D63B29;
  color: #1E1E24;
}
#red:hover:active {
  -webkit-transform: translateY(-50%) scale(1.1);
          transform: translateY(-50%) scale(1.1);
}

.clicked-red:before {
  display: block;
  content: '';
  opacity: 0;
  background: #D63B29;
  height: 100%;
  width: 100%;
  position: absolute;
  border-radius: 50%;
  left: 0;
  top: 0;
  -webkit-animation: click 0.4s ease-in 1;
          animation: click 0.4s ease-in 1;
}

#blue {
  border: #006992 solid 15px;
  color: #006992;
}
#blue:hover {
  background: #006992;
  color: #1E1E24;
}
#blue:hover:active {
  -webkit-transform: translateY(-50%) scale(1.1);
          transform: translateY(-50%) scale(1.1);
}

.clicked-blue:before {
  display: block;
  content: '';
  opacity: 0;
  background: #006992;
  height: 100%;
  width: 100%;
  position: absolute;
  border-radius: 50%;
  left: 0;
  top: 0;
  -webkit-animation: click 0.4s ease-in 1;
          animation: click 0.4s ease-in 1;
}

#green {
  border: #00CC66 solid 15px;
  color: #00CC66;
}
#green:hover {
  background: #00CC66;
  color: #1E1E24;
}
#green:hover:active {
  -webkit-transform: translateY(-50%) scale(1.1);
          transform: translateY(-50%) scale(1.1);
}

.clicked-green:before {
  display: block;
  content: '';
  opacity: 0;
  background: #00CC66;
  height: 100%;
  width: 100%;
  position: absolute;
  border-radius: 50%;
  left: 0;
  top: 0;
  -webkit-animation: click 0.4s ease-in 1;
          animation: click 0.4s ease-in 1;
}

.options {
  display: block;
  position: absolute;
  left: 50%;
  top: 20%;
  -webkit-transform: translate(-50%, -50%);
          transform: translate(-50%, -50%);
  display: block;
  height: 100px;
  width: 100%;
}

.start {
  position: absolute;
  background: none;
  border: none;
  outline-color: #FF8D2A;
  box-shadow: none;
  cursor: pointer;
  left: 50%;
  font-size: 30px;
  font-family: 'Oswald';
  width: 150px;
  height: 100px;
  border-radius: 25%;
  border: #FF8D2A solid 10px;
  color: #FF7700;
}
.start i {
  font-size: 40px;
}
.start:active {
  color: #D63B29;
}
.start:hover {
  background: #FF8D2A;
  color: #1E1E24;
}

.strict {
  position: absolute;
  left: 30%;
  cursor: pointer;
  background: none;
  border: none;
  outline: none;
  color: #09925C;
  height: 40px;
  width: 150px;
  font-size: 20px;
  font-family: 'Oswald';
}

.steps {
  position: absolute;
  left: 50%;
  padding-left: 25px;
  color: #21618C;
  font-family: 'Oswald';
  font-size: 25px;
}

.status {
  position: absolute;
  -webkit-transform: translateX(-50%);
          transform: translateX(-50%);
  font-size: 25px;
  font-family: 'Oswald';
  color: #F1E4F3;
  left: 50%;
  padding-left: 25px;
  height: 40px;
}

.clicked:before {
  display: block;
  content: '';
  opacity: 0;
  background: black;
  height: 100%;
  width: 100%;
  position: absolute;
  border-radius: 50%;
  left: 0;
  top: 0;
  -webkit-animation: click 0.4s linear 1;
          animation: click 0.4s linear 1;
}

.disabled {
  pointer-events: none;
  cursor: wait;
}

@-webkit-keyframes click {
  0% {
    opacity: 0;
  }
  30% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

@keyframes click {
  0% {
    opacity: 0;
  }
  30% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
.footer {
  background-color: #222;
  border-top: 1px outset #444;
  font-size: 12px;
  font-weight: normal;
  margin-top: 3em;
  min-width: 320px;
  padding: 1em 1em 0 1em;
  width: 100%;
  position: fixed;
  bottom: 0;
}
.footer .social-icons {
  margin-top: 3px;
}
.footer .social-icons a {
  font-size: 30px;
  color: #0431B4;
  margin: 5px;
}
.footer .social-icons a i:hover {
  color: #7ba9d6;
}
.footer .social-icons .footer .container-fluid {
  max-width: 768px;
}
View Compiled
/**
	Simon Game challenge for FreeCodeCamp
	
	This is the code for the Simon Game challenge. Feel free to use but keep in mind its a WIP :)
	Any comments feel free to reach-out @sergiomgaspar.
	
    Note: This JS is a bit different than the other since i adopted a JS "approach" and included all simon-related objects/functions inside their specific object (based on online examples). Looks a lot "cleaner" this way!
    
	author: Sergio Gaspar
	date: 2017.01
*/
var colors = ['#yellow', '#red', '#green', '#blue'];
var maxSeq = 20; // Max sequences necessary to win
var sounds = { // Sound provided by FCC
	red_sound: new Audio('https://s3.amazonaws.com/freecodecamp/simonSound1.mp3'),
	green_sound: new Audio('https://s3.amazonaws.com/freecodecamp/simonSound2.mp3'),
	yellow_sound: new Audio('https://s3.amazonaws.com/freecodecamp/simonSound3.mp3'),
	blue_sound: new Audio('https://s3.amazonaws.com/freecodecamp/simonSound4.mp3')
};
// Debug variable, true = turn on console logging
var debug = false;

/* This function animates and plays the sound of specific button */
function animateClick(id) {
	var cs = id.slice(1, id.length);
	console.log(cs);
	$(id).addClass('clicked-' + cs);
	var s = id.slice(1, 2);
	switch (s) {
		case 'r':
			sounds.red_sound.play();
			break;
		case 'g':
			sounds.green_sound.play();
			break;
		case 'y':
			sounds.yellow_sound.play();
			break;
		case 'b':
			sounds.blue_sound.play();
			break;
	}
	var time = setTimeout(function() {
		$(id).removeClass('clicked-' + cs);
	}, 400);
}

/* This function animates without sound (used when finished) */
function animateWithoutSound(id) {
	var cs = id.slice(1, id.length);
	$(id).addClass('clicked-' + cs);
	var timenosound = setTimeout(function() {
		$(id).removeClass('clicked-' + cs);
	}, 400);
}

/* Simple log wrapper */
function log(text) {
	if (debug)
		console.log(text);
}

/* question object - includes question functions */
var question = {
	name: 'question',

	/* use Math.random() to add new random button to question */
	newQuestion: function() {
		game.values.push(colors[Math.floor(4 * Math.random())]);
		game.steps++;
		$('.steps').html("Current Nb steps: " + game.steps);
		log("Game Steps: " + game.steps);
		log("logging game values:");
		log(game.values);
	},

	playQuestion:

		function() {
			var i = 0;
			var t = setInterval(function() {
				animateClick(game.values[i]);
				if (i >= game.values.length - 1) {
					clearInterval(t);
					game.change_state(question);
				} else {
					i++;
				}
			}, 800);
		}
};

/* Answer object - includes answer functions */
var answers = {
	name: 'answers',
	index_so_far: 0,
	total_correct: 0,

	/* resets answers */
	init_answers: function() {
		$(".simon").removeClass('disabled');

		answers.index_so_far = 0;
		answers.total_correct = game.values.length;
		log("init answers.index_so_far:" + answers.index_so_far);
		log("init answers.total_correct" + answers.total_correct);
	},

	/* Checks answers[index] with button pressed */
	check_answers: function(id) {
		log("check_answers ID:" + id);
		log("check_answers game.values:" + game.values);
		if (id == game.values[answers.index_so_far]) {
			answers.index_so_far++;
			log("check_answers answers.index_so_far:" + answers.index_so_far);
			log("check_answers answers.total_correct:" + answers.total_correct);

			if (answers.index_so_far >= answers.total_correct) {
				log("check_answers EXECUTAR O CHANGE STATE:");
				game.change_state(answers);
			}
		} else {
			game.lose();
		}
	}
};

/* Game object */
var game = {
	state: question,
	values: [],
	mode: 'dificulty: easy',
	steps: 0,
	reset: function() {
		game.steps = 0;
		game.state = question;
		game.values = [];
		$('.steps').html("Current Nb steps: " + game.steps);
	},

	start: function() {
		game.reset();
		$('.status').html('game running');
		$('.simon').addClass('disabled');
		question.newQuestion();
		question.playQuestion();
	},

	change_state: function(state) {
		log("change_state state.name:" + state.name);
		if (state.name == 'question') {
			game.state = answers;
			answers.init_answers();
		} else {
			game.state = question;
			$('.simon').addClass('disabled');
			if (game.steps >= maxSeq) {
				game.stop();
			} else {
				question.newQuestion();
				setTimeout(question.playQuestion, 1000);
			}
		}
	},

	/* Hanldes the player loss of the game */
	lose: function() {
		$('.status').html('game loss :(');
		log("GAME OVER");
		if (game.mode == 'dificulty: strict') {
			game.celebrate(700, 2);
			setTimeout(game.start, 1200);
		} else {
			game.state = question;
			$('.simon').addClass('disabled');
			game.celebrate(700, 2);
			setTimeout(function() {
				$('.status').html('game running');
				question.playQuestion();
			}, 1200);
		}
	},

	/* Stops the game when the player wins */
	stop: function() {
		$('.status').html('game WON!!!');
		game.celebrate(700, 3);
		game.reset();
	},

	/* Do a quick flash of the y,b,r,g buttons */
	celebrate: function(interval, number) {
		for (var j = 0; j < number; j++) {
			setTimeout(function() {
				for (var i in colors) {
					animateWithoutSound(colors[i]);
				}
				sounds.green_sound.play();
			}, j * interval);
		}
	}
};

$(document).ready(function() {
	sounds.red_sound.load();
	sounds.green_sound.load();
	sounds.yellow_sound.load();
	sounds.blue_sound.load();
	$('.simon').on('click', function(e) {
		var id = '#' + e.target.id;
		var s = id.slice(1, 2);
		log("ID:" + id);
		log("S:" + s);
		switch (s) {
			case 'r':
				sounds.red_sound.play();
				break;
			case 'g':
				sounds.green_sound.play();
				break;
			case 'y':
				sounds.yellow_sound.play();
				break;
			case 'b':
				sounds.blue_sound.play();
				break;
		}
		if (game.state.name == 'answers') {
			answers.check_answers(id);
		}
	});

	$('.start').on('click', function() {
		log("Game starting...");
		game.start();
	});

	$('.strict').on('click', function() {
		log("Changing dificulty");
		if (game.mode == 'dificulty: easy') {
			game.mode = 'dificulty: strict';
			$(this).html('dificulty: strict');
		} else {
			game.mode = 'dificulty: easy';
			$(this).html('dificulty: easy');
		}
	});

});

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js