How to avoid a program to crash when a button is pressed multiple times?

How to avoid a program to crash when a button is pressed multiple times?
0

I did some testing and the problem seems to be related to your check function. In particular, the following line:

intervalId = setInterval(gameTurn, 800);

You need to make sure you are not starting another interval until the current interval has been cleared.

yes absolutely:

The game apparently is playable. You press the power checkbox and start buttons and it will work perfectly. However, if you click in one of the playable buttons repetitively it will start randomly flashing its button many at the same time. I think I have to create a function that should block the game to be pressed more than two times in a period of time to avoid this bug with the gameTurn() function. I

HTML

<div class="container " id="meBaby">

    <!--SETTHINGS BUTTONS-->
    <div class="row section2">
      <div class="scoreName col-sm-4">
        <label for="score" class="labeStyle">Score</label>
        <div class="score" id="turn" value="score">
        </div>
      </div>
      <div class="col-sm-4 strict-style  ">
        <label for="strict" class="labeStyle">Strict</label>
        <input type="checkbox" class="toggle" id="strict" value="strict">
      </div>
      <div class="col-sm-4 power-style">
        <label for="power" class="labeStyle">Power</label>
        <input type="checkbox" id="on" value="power">
      </div>
    </div>


    <div class="row justify-content-center">
      <div class="col-sm-4 offset-sm-2">
        <button id="startButton" class="push_button red">start</button>
      </div>
    </div>
    <!--FOUR GAME BUTTON-->
    <div class="container potrait">
      <div class="row">
        <div class="fourButtons col-sm-4 offset-sm-4">
          <div class="buttonCollor">
            <div class="top-row">
              <div id="btnBlue" class="gamebutton card-1"></div>
            </div>
            <div class="middle-row">
              <div id="btnGreen" class="gamebutton card-1"></div>
              <div id="btnRed" class="gamebutton card-1"></div>
            </div>
            <div class="bottom-row">
              <div id="btnYellow" class="gamebutton card-1"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  </div>

  <!--Script link-->
  <script type="text/javascript" src="assets/scripts/script.js"></script>
  <script type="text/javascript" src="assets/scripts/style.js"></script>
</body>

</html>

script.js

let blueBtnAudio = new Audio('https://s3.amazonaws.com/freecodecamp/simonSound1.mp3');
let redBtnAudio = new Audio('https://s3.amazonaws.com/freecodecamp/simonSound2.mp3');
let yellowBtnAudio = new Audio('https://s3.amazonaws.com/freecodecamp/simonSound3.mp3');
let greenBtnAudio = new Audio('https://s3.amazonaws.com/freecodecamp/simonSound4.mp3');
//======================//
let organization = [];
let playerOrder = [];
let flash;
let turn;
let good;
let compTurn;
let intervalId;
let strict = false;
let noise = true;
let on = false;
let win;
//======================//
// VARIABLES - DOM QUERIES

const btnBlue = document.querySelector("#btnBlue");
const btnGreen = document.querySelector("#btnGreen");
const btnRed = document.querySelector("#btnRed");
const btnYellow = document.querySelector("#btnYellow");

const turnCounter = document.querySelector("#turn");
const startButton = document.querySelector("#startButton");
const gameButton = document.querySelector(".gameButton"); //button start (not used)
const strictButton = document.querySelector("#strict");
const turnOnButton = document.querySelector("#on");

strictButton.addEventListener('click', function(event) {
  if (strictButton.checked == true) {
    strict = true;
  }
  else {
    strict = false;
  }
});

turnOnButton.addEventListener('click', function(event) {
  if (turnOnButton.checked == true) {
    on = true;
    turnCounter.innerHTML = "-";
  }
  else {
    on = false;
    turnCounter.innerHTML = "";
    clearColor();
    clearInterval(intervalId);
  }
});

startButton.addEventListener('click', function(event) {
  if (on || win) {
    play(); //change the name of this function..
  }
});

function play() {
  win = false;
  organization = [];
  playerOrder = [];
  flash = 0;
  intervalId = 0;
  turn = 1;
  turnCounter.innerHTML = 1;
  good = true;
  for (var i = 0; i < 20; i++) {
    organization.push(Math.floor(Math.random() * 4) + 1);
  }
  compTurn = true;

  intervalId = setInterval(gameTurn, 800);
}

function gameTurn() {

  on = false;
  if (flash == turn) {
    clearInterval(intervalId);
    compTurn = false;
    clearColor();
    on = true;
  }
  if (compTurn) {
    clearColor();
    setTimeout(function() {
      if (organization[flash] == 1) first();
      if (organization[flash] == 2) second();
      if (organization[flash] == 3) third();
      if (organization[flash] == 4) fourth();
      flash++;
    }, 200);
  }
}

function first() {
  if (noise) {
    greenBtnAudio.play();
  }
  noise = true;
  btnGreen.style.backgroundColor = "lightgreen";
}

function second() {
  if (noise) {
    redBtnAudio.play();
  }
  noise = true;
  btnRed.style.backgroundColor = "tomato";
}

function third() {
  if (noise) {
    yellowBtnAudio.play();
  }
  noise = true;
  btnYellow.style.backgroundColor = "yellow";
}

function fourth() {
  if (noise) {
    blueBtnAudio.play();
  }
  noise = true;
  btnBlue.style.backgroundColor = "lightskyblue";
}

function clearColor() {
  btnGreen.style.backgroundColor = "darkgreen";
  btnRed.style.backgroundColor = "darkred";
  btnYellow.style.backgroundColor = "goldenrod";
  btnBlue.style.backgroundColor = "darkblue";
}

function btnLightColor() {
  btnGreen.style.backgroundColor = "lightgreen";
  btnRed.style.backgroundColor = "tomato";
  btnYellow.style.backgroundColor = "yellow";
  btnBlue.style.backgroundColor = "lightskyblue";
}

btnGreen.addEventListener('click', function(event) {
  if (on) {
    playerOrder.push(1);
    check();
    first();
    if (!win) {
      setTimeout(function() {
        clearColor();
      }, 300);
    }
  }
})

btnRed.addEventListener('click', function(event) {
  if (on) {
    playerOrder.push(2);
    check();
    second();
    if (!win) {
      setTimeout(function() {
        clearColor();
      }, 300);
    }
  }
})

btnYellow.addEventListener('click', function(event) {
  if (on) {
    playerOrder.push(3);
    check();
    third();
    if (!win) {
      setTimeout(function() {
        clearColor();
      }, 300);
    }
  }
})

btnBlue.addEventListener('click', function(event) {
  if (on) {
    playerOrder.push(4);
    check();
    fourth();
    if (!win) {
      setTimeout(function() {
        clearColor();
      }, 300);
    }
  }
})

function check() {
  if (playerOrder[playerOrder.length - 1] !== organization[playerOrder.length - 1])
    good = false;

  if (playerOrder.length == 20 && good) {
    winGame();
  }

  if (good == false) {
    btnLightColor();
    turnCounter.innerHTML = "NO!";
    setTimeout(() => {
      turnCounter.innerHTML = turn;
      clearColor();

      if (strict) {
        play();
      }
      else {
        compTurn = true;
        flash = 0;
        playerOrder = [];
        good = true;
        intervalId = setInterval(gameTurn, 800);
      }
    }, 800);

    noise = false;
  }

  if (turn == playerOrder.length && good && !win) {
    turn++;
    playerOrder = [];
    compTurn = true;
    flash = 0;
    turnCounter.innerHTML = turn;
    intervalId = setInterval(gameTurn, 800);
  }

}

function winGame() {
  btnLightColor();
  turnCounter.innerHTML = "WIN!";
  on = false;
  win = true;
}

Not all styles is based for this
style.css

body {
    height: 100%;
    text-align: center;
    margin: 0 0;
    font-family: sans-serif;
}

/*---------------------Images*/

.image1 {
    background: /*linear-gradient( rgba(0, 0, 0, 0.6),
    rgba(0, 0, 0, 0.6)),*/
    url("/assets/images/image1.jpg");
    min-height: 100vh;
    margin-top: 0;
    position: relative;
    /*background-attachment: fixed;*/
    background-position: center top;
    background-size: cover;
    background-repeat: no-repeat;
    /*-ms-transform: skewY(-10deg);
     -webkit-transform: skewY(-20deg);
     transform: skewY(-10deg);
     z-index: 2;*/
}

.image1 h2 {
    font-size: 3rem;
    margin: 0;
    padding: 0;
    position: absolute;
    top: 50%;
    width: 100%;
    color: #ffff00;
}

.container#meBaby {
    min-height: 100vh;
    min-width: 100%;
}

/*====================PULSE BUTTON========================*/


/*----------------------Settings*/

.section2 {
    padding-top: 50px;
}

.strict-style {
    text-align: center;
}

.power-style {
    text-align: center;
}

.scoreName {
    text-align: center;
}

.level,
.strict {
    width: 50%;
    float: left;
    text-align: center;
}

.gamebutton {
    width: 90px;
    height: 90px;
    background-color: white;
    border-radius: 50%;
}

.col-sm-4 .offset-sm-2 {
    /*start button*/
    margin-left: 0.666667%;
    margin-left: 0;
}

.row.justify-content-center {
    /*start button*/
    padding-top: 50px;
    height: 100px;
}


/*=============================FONTS FOR THE SETHINGS WORDS*/

label {
    /* fix vertical align issues */
    display: inline-block;
    vertical-align: top;
    margin-top: 10px;
}

#strict.toggle {
    position: relative;
    top: 3px;
}

#on {
    position: relative;
    top: 3px;
}

.level h2 {
    font-family: 'Press Start 2P', cursive;
}

.score#turn {
    font-family: 'Press Start 2P', cursive;
    font-size: 20px;
    padding-left: 60px;
}

.scoreName h2 {
    font-family: 'Press Start 2P', cursive;
}

.labeStyle {
    font-family: 'Press Start 2P', cursive;
    font-size: 40px;
}

/*----------checkbox--------------*/

@supports (zoom:2) {
    input[type=checkbox] {
        zoom: 4;
        /*defines the size of the checkbox*/
    }
}

@supports not (zoom:2) {
    input[type=checkbox] {
        -webkit-transform: scale(2);
        -ms-transform: scale(2);
        transform: scale(2);
        margin: 15px;
    }
}



/*-------------push_button from samwebe.com*/

.push_button {
    position: relative;
    width: 220px;
    height: 40px;
    text-align: center;
    color: #FFF;
    text-decoration: none;
    line-height: 43px;
    font-family: 'Press Start 2P', cursive;
    /*display: block;*/
    /*margin: 30px;*/
}

.push_button:before {
    background: #f0f0f0;
    background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#D0D0D0), to(#f0f0f0));

    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;

    -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .5) inset, 0 1px 0 #FFF;
    -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, .5) inset, 0 1px 0 #FFF;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .5) inset, 0 1px 0 #FFF;


}

.push_button:active {
    -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset, 0 -1px 0 rgba(255, 255, 255, .1) inset;
    top: 5px;
}

.push_button:active:before {
    top: -11px;
    bottom: -5px;
    content: "";
}

.red {
    text-shadow: -1px -1px 0 #A84155;
    background: #D25068;
    border: 1px solid #D25068;

    background-image: -webkit-linear-gradient(top, #F66C7B, #D25068);
    background-image: -moz-linear-gradient(top, #F66C7B, #D25068);
    background-image: -ms-linear-gradient(top, #F66C7B, #D25068);
    background-image: -o-linear-gradient(top, #F66C7B, #D25068);
    background-image: linear-gradient(to bottom, #F66C7B, #D25068);

    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;

    -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset, 0 -1px 0 rgba(255, 255, 255, .1) inset, 0 4px 0 #AD4257, 0 4px 2px rgba(0, 0, 0, .5);
    -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset, 0 -1px 0 rgba(255, 255, 255, .1) inset, 0 4px 0 #AD4257, 0 4px 2px rgba(0, 0, 0, .5);
    box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset, 0 -1px 0 rgba(255, 255, 255, .1) inset, 0 4px 0 #AD4257, 0 4px 2px rgba(0, 0, 0, .5);
}

.red:hover {
    background: #F66C7B;
    background-image: -webkit-linear-gradient(top, #D25068, #F66C7B);
    background-image: -moz-linear-gradient(top, #D25068, #F66C7B);
    background-image: -ms-linear-gradient(top, #D25068, #F66C7B);
    background-image: -o-linear-gradient(top, #D25068, #F66C7B);
    background-image: linear-gradient(top, #D25068, #F66C7B);
}

/*-----------------------button collors*/

#btnBlue {
    background-color: blue;
    padding-bottom: 40px;
}

#btnGreen {
    background-color: green;
    padding-right: 40px;
}

#btnRed {
    background-color: red;
    padding-left: 40px;
}

#btnYellow {
    background-color: #FF9914;
}

/*--Samuel Thornton --BOX-SHADOW DESIGN FOUR BUTTONS*/

.card-1 {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
    transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
}

.card-1:hover {
    box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
}

/*-------------------------Sections*/

.fourButtons {
    height: 500px;
    width: 500px;
    display: flex;
    align-items: center;
    justify-content: center;
}

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

.top-row {
    display: flex;
    justify-content: center;
}

.middle-row {
    display: flex;
    justify-content: space-around;
    align-items: center;
    margin: 15px auto;
    width: 400px;
}

.bottom-row {
    display: flex;
    justify-content: center;
}


/*------------------------------------------------------------media queries*/

@media only screen and (min-width: 320px) and (max-width: 575px) {

    .carousel {
        display: none;
    }

    #turn.score {
        padding-right: 50px;
    }

    .scoreName.col-sm-4 {
        padding-bottom: 20px;
    }

    .col-sm-4.strict-style {
        padding-bottom: 40px;
    }

    .container#meBaby {
        min-height: 100vh;
        min-width: 100%;
    }

    .section2 {
        padding-top: 4px;
    }

    .row.justify-content-center {
        padding-top: 55px;
        height: 100px;
    }

    .labeStyle {
        font-family: 'Press Start 2P', cursive;
        font-size: 29px;
        float: center;
    }
    /*.buttonCollor {}*/
    .potrait {
        padding-top: 38px;
    }

    .col-sm-4.offset-sm-2 {
        position: relative;
        /*padding-left: 95px;*/
    }
    .gamebutton {
        width: 60px;
        height: 60px;
        background-color: white;
        border-radius: 50%;
    }

    .fourButtons {
        height: 275px;
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    .sButton {
        margin-left: 53px;
    }

    .push_button {
        margin: 0;
        border-left: 50px;
    }

    .btnBlue,
    .btnGreen,
    .btnRed,
    .btnYellow {
        width: 95%;
        max-width: 95%;
    }

    .top-row,
    .middle-row,
    bottom-row {
        max-width: 300px;
    }
}


@media only screen and (min-width: 576px) and (max-width: 1024px) {

    .scoreName,
    .labeStyle {
        font-size: 28px;
    }
    .container#meBaby {
        min-height: 100vh;
        min-width: 100%;
        margin: 0 0;
    }
    .carousel {
        display: none;
    }

    .sButton {
        margin-left: 53px;
    }

    .push_button {
        margin: 0;
        border-left: 50px;
    }
    .fourButtons {
        padding: 0;
    }

    .btnBlue,
    .btnGreen,
    .btnRed,
    .btnYellow {
        width: 95%;
        max-width: 95%;
    }

    .gamebutton {
        width: 130px;
        height: 130px;
        background-color: white;
        border-radius: 50%;
    }


    .potrait {
        padding-top: 200px;
    }

    .middle-row {
        display: flex;
        justify-content: space-around;
        align-items: center;
        margin: 15px auto;
        width: 520px;
    }

    .push_button {
        height: 66px;
    }

    .offset-sm-2 {
        margin-left: 1.666667%;
    }

    .row.justify-content-center {
        padding-top: 170px;
        height: 100px;
    }
}


@media only screen and (min-height: 360px) and (max-height: 414px) {

    .section2 {
        padding-top: 0;
    }

    input[type=checkbox] {
        zoom: 2;
        /* padding-top: 20px; */
    }

    #strict.toggle {
        position: relative;
        top: 7px;
    }

    #on {
        position: relative;
        top: 7px;
    }

    .scoreName,
    .labeStyle {
        font-size: 21px;
    }

    .row.justify-content-center {
        padding-top: 10px;
        height: 100%;
    }

    .push_button {
        height: 41px;
        width: 90px;
    }

    .push_button {
        height: 41px;
        width: 90px;
    }

    .potrait {
        padding-top: 15px;
    }

    .gamebutton {
        width: 60px;
        height: 60px;
        background-color: white;
        border-radius: 50%;
    }

    .middle-row {
        display: flex;
        justify-content: space-around;
        align-items: center;
        margin: 15px auto;
        width: 300px;
    }

    .fourButtons {
        padding-bottom: 239px;
    }

    .container.potrait {
        padding-top: 15px;
        max-height: 260px;
        overflow: hidden;
    }
}

See my last reply. That should get you back on track.

Also, I strongly suggest refactoring much of that duplicate code (first, second, third, fourth) and definitely refactor your button click handlers. It is almost the same callback function each time with only a couple differences. I refactored your code and was able to removed about 40 lines of duplicate code. I did that just so I could look at less code to figure out where you problem was.

1 Like

Also, I notice a small bug when the start button is first clicked. I did not research further why, but more than one button flashes at the beginning of the sequence with the last button being flash at the same time the corresponding sound plays. It makes it confusing for a user to know which is the correct button to click.

yes, this is the main issue I am trying to fix right now.

The issue is you are calling clearColor too close to flashing the first color.

You can avoid that buy calling clearColor in the start button click event handler right before calling play().

/walks in

sees globals

/walks out

I didn’t get your point :thinking::smile:!

@Oliver_Olivier

Way too many globals! You should have 0.

Plus some of your variables don’t make sense to me.

When they’re not clearly obvious, I recommend you add comments detailing what they do.

What exactly does “good” mean? Or check()? flash = 0 ? I’m just trying to point out suggestions to make your code more readable.

1 Like

Indeed, I have to do this. Thank you.

I still learning and stuck in this lesson. One month on the same project, may next year I will be able to not have global variables.

Hi everyone.

I would like to know how can I avoid double click a button on my simons game. I posted this question before but I did not understand the approach.

btnBlue.addEventListener("dblclick", avoidBug);

btnGreen.addEventListener("dblclick", avoidBug);

btnRed.addEventListener("dblclick", avoidBug);

btnYellow.addEventListener("dblclick", avoidBug);


function avoidBug(event){
  if (avoidBug){
    event.disabled = true;
  }else{
    event.disabled = false;
  }
}

I did this and many other approaches for hours and I can not find the result.

please, consider that I am new to this and trying to finish this project as soon as possible. This is the last bug I have to fix.

What is the intended behavior? You want to prevent the second click from registering? Or you want only double-clicks to register?

1 Like

I mean, I want to avoid the button being clicked more than twice in a period of milliseconds to avoid the game crashes

An event object doesn’t have a disabled property. I’m guessing you’re trying to event.preventDefault()?

However, unless you’ve specifically added a dblclick handler, you don’t need to prevent any dblclick event from firing. By default, a dblclick event on a button does nothing.

The events triggered by a double click action are:

click
click
dblclick

in that order.

To prevent the second click event from firing, you’ll need to use a variable in the parent scope (let’s call it lastClick), initialized to 0. On every click event, set a local variable now to Date.now(), then check if now >= lastClick + threshold (however many milliseconds you choose). If it is, handle the event how you like and set lastClick to now. If not, do nothing.

ok. I will try your approach. I did understood to settle a var to zero, but not the date.now(). , thank you

@Oliver_Olivier Most people who play simon understand it is just single clicks. They may click fast though. Double clicking is not the issue your code has.

1 Like

Yes, indeed. I’d like to get good grades on my course avoiding this bug. five hours trying until now.

fCC isn’t graded on a scale — you get the certificate for completing the projects to spec. But it’s good to think about this type of UX thing anyway, especially for when you’re building a portfolio of your projects.

Now I can see your live project, I don’t think your problem is click events. It seems like it’s more about lack of audio feedback. If you click red-red in quick succession, you hear the red audio only once.

This is because an Audio object is, weirdly, an HTML element:

const audio = new Audio('https://s3.amazonaws.com/freecodecamp/simonSound1.mp3');

audio instanceof HTMLElement; // true

The audio element’s play method simply checks whether that HTML element (whether or not it’s attached to the DOM) is currently in the playing state. If it isn’t, it plays it; otherwise, it does nothing.

The easiest way around this is to simply clone the element before you play it — then it’s a new node each time, so it starts each time from the beginning.

Compare:

for (let i = 0; i < 3; i++) {
  setTimeout(() => audio.play(), i * 200); // plays 1 time
}

vs.

for (let i = 0; i < 3; i++) {
  setTimeout(() => audio.cloneNode().play(), i * 200); // plays 3 times
}
1 Like