# SimonSays

Simon says is a game of copycat. The pattern becomes more complex with each round.

This module is a work in progress.

To do:
  • Speed up starting animation
  • Animate colored icons
  • Adjust copy positioning
  • Buttons animate in after game round

# Example

<template>
    <SimonSays
        :boxes="boxes"
        :answerOne="answerOne"
        :answerTwo="answerTwo"
        :answerThree="answerThree"
        :loseOne="loseOne"
        :loseTwo="loseTwo"
        :loseThree="loseThree"
        :simonHeadline="simonHeadline"
        :simonContent="simonContent"
    />
</template>

<script>
    import SimonSays from '~/components/SimonSays.vue';

    export default {
        components: {
            SimonSays,
        },
        data() {
            return {
                simonHeadline: 'Repeat every move',
                simonContent:
                    'Watch the pattern below and see how well you can copy each move. Ready?',
                answerOne:
                    "Nice work. You copied each move just like the little ones around you copy your moves. <br /><span class='test'>Fact:</span> Teens are more likely to smoke cigarettes if their older siblings smoke cigarettes.",
                answerTwo:
                    'You’ve got moves others respect. You copied each move just like the little ones copy what you do. Fact: Teens are more likely to smoke cigarettes if they have friends who smoke cigarettes.',
                answerThree:
                    'You’re on pace to break the cycle. You copied each move just like the little ones copy you. Fact: If smoking continues at this rate, 5.6 million children in the U.S. today will die at a younger age because of smoking.',
                loseOne:
                    'Distractions happen. Next time watch a little closer just like the little ones around you watch your moves closely. Fact: Your younger siblings are more likely to smoke cigarettes if you smoke cigarettes',
                loseTwo:
                    'Nice try. Watch a little closer just like the little ones around you watch your moves closely. Fact: Teens are more likely to smoke cigarettes if they have friends who smoke cigarettes',
                loseThree:
                    'Nice try. Next time follow as closely as little ones do. Fact: If smoking continues at this rate, 5.6 million children in the U.S. today will die at a younger age because of smoking',
                boxes: [
                    {
                        boxNumber: '0',
                        image: '/simonsays/siblings.png',
                        imageAltAttr: 'siblings',
                    },
                    {
                        boxNumber: '1',
                        image: '/simonsays/friends.png',
                        imageAltAttr: 'friends',
                    },
                    {
                        boxNumber: '2',
                        image: '/simonsays/break-the-cycle.png',
                        imageAltAttr: 'break the cycle',
                    },
                ],
            };
        },
    };
</script>

Link to Demo

# props

answerOne (Optional) (String) Copy for the correct answer for round one.

answerTwo (Optional) (String) Copy for the correct answer for round two.

answerThree (Optional) (String) Copy for the correct answer for round three.

loseOne (Optional) (String) Copy for the incorrect answer for round one.

loseTwo (Optional) (String) Copy for the incorrect answer for round two.

loseThree (Optional) (String) Copy for the incorrect answer for round three.

image (Optional) (String) icon image.

imageAltAttr (Optional) (String) alt attribute for images.

simonHeadline (Optional) (String) Game headline text.

simonContent (Optional) (String) paragraph content.

boxes (Optional) (Array) Array of objects for icons and their respective content (boxNumber, image,imageAltAttr).

# Source Code

<template>
  <div class="container">
    <div class="main-simon-wrapper">
      <h1 class="simon-headline">{{simonHeadline}}</h1>
      <div class="simon-rules">{{simonContent}}</div>
      <div class="top-row simon-row">
        <div class="box" :id="'box' + box.boxNumber" v-for="(box, index) in boxes" :key="index">
          <img :src="box.image" :alt="box.imageAltAttr" />
        </div>
      </div>
      <div id="running-score"></div>
      <div id="final-score"></div>
      <div id="score-lose"></div>
      <div id="score-win"></div>
      <div class="button-row">
        <div class="button start">
          <div>START</div>
        </div>
        <div class="next">
          <div>Next</div>
        </div>
        <div class="reset">
          <div>TRY AGAIN?</div>
        </div>
        <div class="spacer"></div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.reset {
  display: none;
}
.next {
  display: none;
}
.shake {
  animation: shake 0.5s;
}
@keyframes shake {
  0% {
    transform: translate(1px, 1px) rotate(0deg);
  }
  10% {
    transform: translate(-1px, -2px) rotate(-1deg);
  }
  20% {
    transform: translate(-3px, 0px) rotate(1deg);
  }
  30% {
    transform: translate(3px, 2px) rotate(0deg);
  }
  40% {
    transform: translate(1px, -1px) rotate(1deg);
  }
  50% {
    transform: translate(-1px, 2px) rotate(-1deg);
  }
  60% {
    transform: translate(-3px, 1px) rotate(0deg);
  }
  70% {
    transform: translate(3px, 1px) rotate(-1deg);
  }
  80% {
    transform: translate(-1px, -1px) rotate(1deg);
  }
  90% {
    transform: translate(1px, 2px) rotate(0deg);
  }
  100% {
    transform: translate(1px, -2px) rotate(-1deg);
  }
}
.main-simon-wrapper {
  width: 100%;
  justify-content: center;
  align-items: center;
  display: flex;
  flex-direction: column;
}

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

.container {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  justify-content: center;
  align-items: center;
}

.simon-row {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: space-around;
  align-items: center;
  width: 100%;
  max-width: 407px;
}

#score-win {
  max-width: 407px;
  width: 100%;
  text-align: center;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}
#score-lose {
  max-width: 407px;
  width: 100%;
  text-align: center;
  display: flex;
  justify-content: center;
  align-items: center;
}

.box {
  border-radius: 20px;
  height: 90%;
  width: 40%;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}

#box0:active {
  animation: shake 0.5s;
}

#box1:active {
  animation: shake 0.5s;
}

#box2:active {
  animation: shake 0.5s;
}

.button:active {
  background: rgba(0, 0, 0, 0.5);
}

.spacer {
  width: 10%;
}

.button {
  display: flex;
  justify-content: center;
  align-items: center;
  background: white;
  border-radius: 12px;
  height: 90%;
  width: 20%;
}
</style>
<script>
export default {
  props: {
    boxNumber: {
      type: String,
      required: false
    },
    answerOne: {
      type: String,
      required: false
    },
    answerTwo: {
      type: String,
      required: false
    },
    answerThree: {
      type: String,
      required: false
    },
    answerThree: {
      type: String,
      required: false
    },
    loseOne: {
      type: String,
      required: false
    },
    loseTwo: {
      type: String,
      required: false
    },
    loseThree: {
      type: String,
      required: false
    },
    image: {
      type: String,
      required: false
    },
    imageAltAttr: {
      type: String,
      required: false
    },
    boxes: {
      type: Array,
      required: false
    },
    simonHeadline: {
      type: String,
      required: false
    },
    simonContent: {
      type: String,
      required: false
    }
  },

  data() {
    return {
      seen: false
    };
  },

  mounted() {
    let $vm = this;
    const boxes = document.querySelectorAll(".box"); //array of all the divs with a class of .box
    const start = document.querySelector(".start"); //selecting the start button
    const reset = document.querySelector(".reset"); //selecting the reset button
    const next = document.querySelector(".next"); //selecting the reset button

    let gameHistory; //initializes game history variable
    let userHistory = []; //User history
    let currentHistory = []; //History for current game
    let currentSteps = 0; //How many buttons have been pressed
    let totalSteps = 1; //How many buttons can be pressed in the current game
    let steps = 0; //steps for the setInterval

    let playingGame = false; //Flag to check if game is running
    let gameSteps = true; //Flag to make sure that colored buttons can only be pressed a # of times
    let gameStarts = false; //Flag to start game
    let gameReset = false; //Resets the game

    //-------------------------------------------------------------------------------------------------------------------------

    function gameCreator() {
      //returns an array of 3 random moves
      //   return [...new Array(3)].map(() => Math.round(Math.random() * 2));
      return [0, 2, 1];
    }

    function resetGame() {
      //resets the values of the game
      reset.style.display = "none";
      start.style.display = "flex";

      var lose = document.getElementById("score-lose");
      var win = document.getElementById("score-win");
      lose.innerHTML = "";
      win.innerHTML = "";

      steps = 0;
      totalSteps = 1;
      currentHistory = [];
      userHistory = [];
      playingGame = false;
      console.log("Game variables reset");
    }

    function jiggleButton(num) {
      let shake = ["shake", "shake", "shake"];
      //array of colors to use for when the buttons are pressed or shown
      let dark = false; //flag for turning a button dark

      var colored = setInterval(function() {
        var element = document.getElementById("box" + num);
        //interval for changing the colors on the buttons
        if (dark) {
          //checks the flag to see if the button should shake
          element.classList.remove("shake");

          clearInterval(colored); // stops the interval
          return;
        }
        element.classList.add("shake");
        dark = !dark; //set flag to true
      }, 600);
      return;
    }

    function gameMove() {
      start.style.display = "none";
      reset.style.display = "none";
      next.style.display = "flex";
      //function that visualizes the moves that the user has to press
      if (!playingGame) {
        //checks to see if the game has already started or is starting
        gameHistory = gameCreator(); //creates an array for the game
        console.log(gameHistory);
        totalSteps = 1;
        currentHistory = [];
        userHistory = [];
        playingGame = true;

        console.log("current history: " + currentHistory);
      }
      let currentMoves = gameHistory.slice(0, totalSteps);
      console.log(currentMoves);

      steps = 0;
      let lightUp = setInterval(function() {
        if (steps >= currentMoves.length) {
          currentSteps = 0;
          gameSteps = true;
          clearInterval(lightUp);
        } else if (steps < currentMoves.length) {
          jiggleButton(currentMoves[steps]);
        }
        steps++;
      }, 1200);
      console.log("steps: " + steps);
      console.log("current Moves: " + steps);
      console.log("game steps: " + gameSteps);
    }

    function onWin(winAnswer, score) {
      var win = document.getElementById("score-win");
      var currentScore = document.getElementById("running-score");

      win.innerHTML += winAnswer;
      currentScore.innerHTML += "Score " + score + "/3";
      next.addEventListener("click", function() {
        gameMove;
        win.innerHTML = "";
        currentScore.innerHTML = "";
      });
    }

    function onLose(loseAnswer, score) {
      var lose = document.getElementById("score-lose");
      var win = document.getElementById("score-win");
      var finalScore = document.getElementById("final-score");
      var runningScore = document.getElementById("running-score");

      finalScore.innerHTML += "Final score: " + score + "/3.";
      runningScore.innerHTML = "";
      playingGame = !playingGame;
      lose.innerHTML += loseAnswer + userHistory.length;
      win.innerHTML = "";
      reset.style.display = "flex";
      next.style.display = "none";

      reset.addEventListener("click", function() {
        finalScore.innerHTML = "";
      });
    }

    function resetLose() {
      reset.style.display = "flex";
      next.style.display = "none";
    }
    function resetLoseThird() {
      reset.style.display = "flex";
      next.style.display = "none";
    }

    function onClick() {
      //function for when the user clicks on one of the colored buttons
      if (playingGame && gameSteps) {
        //Checks the playingGame & gameSteps flag
        for (var i = 0; i < 4; i++) {
          //Checks what colored button was pressed and adds it to the currentHistory
          if (this === boxes[i]) {
            currentHistory.push(i);
            currentSteps++; //adds to the number of moves done
            if (currentSteps === totalSteps) {
              //checks if the player made all the steps
              userHistory.push(currentHistory); //updates the user game history
              currentHistory = [];
              gameSteps = false;
              totalSteps++;

              //round one
              if (userHistory.length === 1) {
                var firstAnswer = $vm.answerOne;
                onWin(firstAnswer, 1);
                //if round one is wrong
                if (i !== 0) {
                  var firstLose = $vm.loseOne;
                  onLose(firstLose, 0);
                }
              }
              //round two
              else if (userHistory.length === 2) {
                var secondAnswer = $vm.answerTwo;
                onWin(secondAnswer, 2);
                //if round two is wrong
                if (i !== 2) {
                  var secondLose = $vm.loseTwo;
                  onLose(secondLose, 1);
                }
              } //round three
              else if (userHistory.length === 3) {
                var win = document.getElementById("score-win");
                var currentScore = document.getElementById("running-score");

                win.innerHTML += $vm.answerThree;
                currentScore.innerHTML += "Score: 3/3. You Win!";

                reset.addEventListener("click", function() {
                  gameMove;
                  win.innerHTML = "";
                  currentScore.innerHTML = "";
                });
                reset.style.display = "flex";
                next.style.display = "none";
                //if round three is wrong
                if (i !== 1) {
                  //if user presses wrong colored button, game over
                  var thirdLose = $vm.loseThree;
                  onLose(thirdLose, 2);
                }
              }
            }
          }
        }
      }
    }
    function rename() {
      let name = document.querySelector(".start");
      name.innerHtml = "Next";
    }
    reset.addEventListener("click", resetGame); //resets the variables for the game
    start.addEventListener("click", gameMove); //sets and event listener to the start button
    next.addEventListener("click", gameMove); //sets and event listener to the start button
    boxes.forEach(box => box.addEventListener("click", onClick)); //sets an event listener to the letters
  }
};
</script>