Simon game

In this example below you will see how to do a Simon game with some HTML / CSS and Javascript

a freecodecamp activity

Thumbnail
This awesome code was written by roblegaspi, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright roblegaspi ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Simon game</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">

  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  
<div id="app" v-cloak>
    <audio id="audio" src="" type="audio/mpeg"></audio>

    <div class="configuration">
        <div class="title">
            <h1>Simon</h1>
            <h2 v-text="status" :class="{'has-winner' : win}"></h2>
        </div>
        <div class="bottom-half-circle">

            <div class="mode">
                <div class="button-set">
                    <label class="screen"><span :class="{'on' : enabledGame}" v-text="level"></span></label>
                    <h6>COUNT</h6>
                </div>

                <div class="start">
                    <div class="button-set">
                        <button id="start" @click="start"></button>
                        <h6>START</h6>
                    </div>


                    <div class="button-set">
                        <button :class="{'strict-mode' : strictMode}" id="strict" @click="toggleStrictMode"></button>
                        <h6>STRICT</h6>
                    </div>
                </div>
            </div>

            <div class="power">
                <h4>OFF</h4>
                <label class="switch">
                    <input type="checkbox" v-model="enabledGame" @click="toggleSwitch">
                    <div class="slider"></div>
                </label>
                <h4>ON</h4>
            </div>
        </div>
    </div>

    <div class="buttons">
        <div style="display:flex;">
            <div class="btn" @click="play(0)" id="audio0"></div>
            <div class="btn" @click="play(1)" id="audio1"></div>
        </div>
        <div style="display:flex;">
            <div class="btn" @click="play(2)" id="audio2"></div>
            <div class="btn" @click="play(3)" id="audio3"></div>
        </div>
    </div>



</div>
  <script src='https://unpkg.com/vue/dist/vue.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/roblegaspi/simon-game-qqLeKx */
  body {
      width: 100vw;
      height: 100vh;
      overflow: hidden;
  }

  .configuration {
      position: absolute;
      left: 50%;
      top: 50%;
      z-index: 999;
      -webkit-transform:translate(-50%,-50%);
              transform:translate(-50%,-50%);
      width: 450px;
      height: 450px;
      background: #f5f5f5;
      border: 10px solid firebrick;
      border-radius: 100%;
  }

  .title {
      display: flex;
      align-items: center;
      justify-content: space-around;
      flex-direction: column;
      height: 50%;
      background: #222;
      color: #f5f5f5;
      text-transform: uppercase;
      border-top-left-radius: 225px;
      border-top-right-radius: 225px;
  }

  .buttons{
      position: absolute;
      left: 50%;
      top: 50%;
      -webkit-transform:translate(-50%,-50%);
              transform:translate(-50%,-50%);
  }

  .btn {
      cursor: pointer;
      transition: .2s ease-in-out;
      margin: 0;
      border: 0;
      color: #fff;
      margin: 0;
      padding: 0;
      border-radius: 0px;
      width: 300px;
      height: 300px;
  }

  #audio0 {
      background: darkgreen;
      border-top: 10px solid #222;
      border-left:  10px solid #222;
      border-top-left-radius: 100%;
  }

  #audio1 {
      background: darkblue;
      border-top: 10px solid #222;
      border-right:  10px solid #222;
      border-top-right-radius: 100%;
  }
  #audio2 {
      background: darkcyan;
      border-bottom: 10px solid #222;
      border-left:  10px solid #222;
      border-bottom-left-radius: 100%;
  }
  #audio3 {
      background: darkgoldenrod;
      border-bottom: 10px solid #222;
      border-right:  10px solid #222;
      border-bottom-right-radius: 100%;
  }

  .beep {
      -webkit-animation: zoom 500ms ease forwards;
              animation: zoom 500ms ease forwards;
  }

  @-webkit-keyframes  zoom {
      0% {
        -webkit-transform: scale(1);
                transform: scale(1);
      }
      50% {
          -webkit-transform: scale(1.1);
                  transform: scale(1.1);
      }
      100% {
          -webkit-transform: scale(1);
                  transform: scale(1);
      }
  }

  @keyframes  zoom {
      0% {
        -webkit-transform: scale(1);
                transform: scale(1);
      }
      50% {
          -webkit-transform: scale(1.1);
                  transform: scale(1.1);
      }
      100% {
          -webkit-transform: scale(1);
                  transform: scale(1);
      }
  }

  .bottom-half-circle {
      display: flex;
      align-items: center;
      justify-content: space-around;
      height: 225px;
      flex-direction: column;
      border-bottom-left-radius: 225px;
      border-bottom-right-radius: 225px;
  }


  .switch {
      position: relative;
      display: inline-block;
      width: 60px;
      height: 34px;
  }

  .switch input {display:none;}

  .slider {
      position: absolute;
      cursor: pointer;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: #aaa;
      transition: .4s;
  }

  .slider:before {
      position: absolute;
      content: "";
      height: 26px;
      width: 26px;
      left: 4px;
      bottom: 4px;
      background-color: white;
      transition: .4s;
  }

  input:checked + .slider {
      background-color: darkgreen;
  }

  input:focus + .slider {
      box-shadow: 0 0 1px darkgreen;
  }

  input:checked + .slider:before {
      -webkit-transform: translateX(26px);
      transform: translateX(26px);
  }

  /* Rounded sliders */
  .slider.round {
      border-radius: 34px;
  }

  .slider.round:before {
      border-radius: 50%;
  }

  .mode {
      width: 450px;
      display: flex;
      align-items: center;
      justify-content: space-around;
  }

  .mode button {
      border-radius: 100%;
      width: 25px;
      height: 25px;
  }

  .button-set {
      display: flex;
      flex-direction:column;
      justify-content: center;
      align-items:center;
  }

  .button-set > h6 {
      margin: 0px;
  }

  .start {
      display: flex;
      width: 225px;
      justify-content: space-around;
  }

  .screen {
      background: #222;
      color: red;
      font-weight: bolder;
      padding: 5px 10px;
      border-radius: 5px;
      border: 1px solid red;
      width: 40px;
      height: 20px;
      text-align: center;
  }

  button {
      border: 3px solid #222;
      cursor: pointer;
  }

  #reset {
      background: darkgoldenrod;
  }

  #strict {
      background: firebrick;
  }

  #start {
      background: darkgreen;
  }

  .strict-mode {
      border: 3px solid darkgreen;
  }

  .power {
      display: flex;
      justify-content: center;
      align-items:center;
  }

  .screen span {
      display: flex;
      justify-content: center;
      align-items:center;
  }

  .on {
      transition: .2s ease-in-out;
      -webkit-transform: scale(2);
              transform: scale(2);
      opacity: 1;
  }

  .has-winner {
      -webkit-animation: blink .2s ease-in-out infinite;
              animation: blink .2s ease-in-out infinite;
  }

  @-webkit-keyframes blink {
      0% {
        opacity: 0;
      }
      70% {
          opacity: 0.7;
      }
      100% {
          opacity: 1;
      }
  }

  @keyframes blink {
      0% {
        opacity: 0;
      }
      70% {
          opacity: 0.7;
      }
      100% {
          opacity: 1;
      }
  }

/*Downloaded from https://www.codeseek.co/roblegaspi/simon-game-qqLeKx */
new Vue({
    el: '#app',
    data: {
        musicForWrongAnswer: "http://www.orangefreesounds.com/wp-content/uploads/2014/08/Wrong-answer-sound-effect.mp3",
        musicForCorrectAnswer: "http://www.orangefreesounds.com/wp-content/uploads/2014/10/Correct-answer.mp3",
        audioList: ["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"],
        audio: document.getElementById('audio'),
        level: "--",
        status: "",
        simonSet: [],
        enabledGame: false,
        playerPick: [],
        moves: 0,
        strictMode: false,
        allowToMove: false,
        win: false
    },

    watch: {
        enabledGame: function enabledGame() {
            if (!this.enabledGame) this.off();
        },
        simonSet: function simonSet() {
            this.level = this.simonSet.length > 0 ? this.simonSet.length : "--";
        }
    },

    methods: {
        toggleSwitch: function toggleSwitch() {
            this.enabledGame = !this.enabledGame;
            this.setStatus('let play');
            this.win = false;
        },

        toggleStrictMode: _.debounce(function () {
            if (this.enabledGame) {
                if (!this.isSimonSetEmpty()) return;
                this.strictMode = !this.strictMode;
            }
        }, 500),

        onStrictMode: function onStrictMode() {
            return this.strictMode;
        },
        on: function on() {
            this.enabledGame = true;
        },
        off: function off() {
            this.simonSet = [];
            this.enabledGame = false;
            this.playerPick = [];
            this.moves = 0;
            this.strictMode = false;
            this.allowToMove = false;
            this.setStatus("");
        },
        resetGame: function resetGame() {
            this.off();
            this.enabledGame = true;
        },


        start: _.debounce(function () {
            if (!this.enabledGame || !this.isSimonSetEmpty()) return;

            this.win = false;
            this.addSimonSet();
            this.playNextLevel();
        }, 500),

        setNumberOfMoves: function setNumberOfMoves(count) {
            this.moves = count;
        },
        subOneMoves: function subOneMoves() {
            this.moves = this.moves - 1;
        },
        movesLeft: function movesLeft() {
            return this.moves;
        },
        isNoMovesLeft: function isNoMovesLeft() {
            return this.movesLeft() < 1;
        },
        setStatus: function setStatus(status) {
            this.status = status;
        },
        playNextLevel: function playNextLevel() {
            var self = this;
            var index = 0;

            self.setStatus("listen first!!");
            self.allowNextMoves(false);
            self.audio.src = self.getSource(index);
            self.audio.play();
            var btn = document.getElementById('audio' + this.simonSet[index]).classList;

            self.audio.onplay = function () {
                btn.add('beep');
            };

            self.audio.onended = function () {
                btn.remove('beep');
                index++;
                if (index < _.size(self.simonSet)) {
                    self.audio.src = self.getSource(index);

                    _.delay(function () {
                        btn = document.getElementById('audio' + self.simonSet[index]).classList;
                        btn.add('beep');
                        self.audio.play();
                    }, 500);
                } else {
                    self.allowNextMoves(true);
                    self.setStatus("Go!!");
                }
            };
        },
        allowNextMoves: function allowNextMoves(bool) {
            this.allowToMove = bool;
        },
        getSource: function getSource(index) {
            return this.audioList[this.simonSet[index]];
        },
        addSimonSet: function addSimonSet() {
            this.resetPlayersPick();
            this.simonSet.push(this.randomizeAudioList());
            this.setNumberOfMoves(_.size(this.simonSet));
        },
        isSimonSetEmpty: function isSimonSetEmpty() {
            return _.size(this.simonSet) < 1;
        },
        resetPlayersPick: function resetPlayersPick() {
            this.playerPick = [];
        },
        resetSimonSet: function resetSimonSet() {
            this.simonSet = [];
        },
        play: function play(index) {
            var self = this;
            var btn = document.getElementById('audio' + index).classList;

            self.audio.onplay = function () {
                btn.add('beep');
            };

            self.audio.onended = function () {
                btn.remove('beep');
            };

            if (!self.enabledGame || self.isSimonSetEmpty() || self.isNoMovesLeft() || !this.allowToMove) return;
            self.playerPick.push(index);

            var current_index = _.size(self.simonSet) - self.movesLeft();

            self.subOneMoves();
            if (self.simonSet[current_index] !== index) {
                if (self.onStrictMode()) {
                    self.resetSimonSet();
                    self.addSimonSet();
                } else {
                    self.resetPlayersPick();
                    self.setNumberOfMoves(_.size(self.simonSet));
                }

                self.audio.src = self.musicForWrongAnswer;
                self.audio.play();

                _.delay(function () {
                    self.playNextLevel();
                }, 2000);
            } else {
                self.audio.src = self.audioList[index];
                self.audio.play();
            }

            if (self.isNoMovesLeft() && self.isCombinationCorrect()) {
                if (self.hasWinner()) return;
                self.hasCorrectAnswer();

                _.delay(function () {
                    self.addSimonSet();
                    self.playNextLevel();
                }, 4000);
            }
        },
        isCombinationCorrect: function isCombinationCorrect() {
            return _.isEqual(self.simonSet, self.playerPick);
        },
        randomizeAudioList: function randomizeAudioList() {
            if (!this.enabledGame) return;

            var len = this.audioList.length;
            var randNumber = Math.floor(Math.random() * len);

            return randNumber;
        },
        hasCorrectAnswer: function hasCorrectAnswer() {
            var self = this;
            _.delay(function () {
                self.audio.onplay = function () {
                    return;
                };
                self.audio.src = self.musicForCorrectAnswer;
                self.audio.play();
            }, 1000);
        },
        hasWinner: function hasWinner() {
            var self = this;
            if (self.playerPick.length > 19) {
                _.delay(function () {
                    self.audio.onplay = function () {
                        return;
                    };
                    self.audio.src = self.musicForCorrectAnswer;
                    self.audio.play();
                    self.setStatus("YOU WIN CONGRATULATION");
                    self.win = true;
                }, 1000);
                self.resetGame();
                return true;
            }
            return false;
        }
    }
});

Comments