0

I am fairly new to JavaScript and am making a simple Rock, Paper, Scissors game. I am using addEventListener to wait for either the Rock button, paper button, or scissors button to be pressed, then it will execute the game. The problem is when I press the restart game button and start a new game, the button click function from the addEventListener is executed twice. So it plays the round 2 times on 1 button click. If I restart the game again, the addEventListener function is executed 3 times and so on. The restart function resets scores to 0 and calls the main() game function. I think this issue has to deal with executing addEventListener again when main() is recursively run in the restart() function. How do I fix this?

const myScoreLabel = document.querySelector('.myScore');
            const compScoreLabel = document.querySelector('.compScore');
            const resultLabel = document.querySelector('.result');
            const winnerLabel = document.querySelector('.winner');
            let myscore = 0;
            let computerscore = 0;
            
            function computerPlay() {
                let choices = ["Rock", "Paper", "Scissors"];
                let index = Math.floor(Math.random() * 3);
                let move = choices[index];
                return move;
            }

            function playRound(playerSelection, computerSelection) {
                let player = playerSelection.toLowerCase();
                let computer = computerSelection.toLowerCase();
                switch(player) {
                    case "rock":
                        switch(computer){
                            case "rock":
                               return "Draw! Try again..."; 
                               break;
                            case "paper":
                                return "You lose! Try again...";
                                break;
                            case "scissors": 
                                return "You win!";
                                break;
                        }
                        break;

                    case "paper":
                        switch(computer){
                            case "rock":
                                return "You win!";
                                break;
                            case "paper":
                                return "Draw! Try again...";
                                break;
                            case "scissors": 
                                return "You lose! Try again...";
                                break;
                        }
                        break;

                    case "scissors":
                        switch(computer){
                            case "rock":
                                return "You lose! Try again...";
                                break;
                            case "paper":
                                return "You win!";
                                break;
                            case "scissors": 
                                return "Draw! Try again...";
                                break;
                        }
                        break;
                }
            }

            function main() {
                myScoreLabel.textContent = myscore;
                compScoreLabel.textContent = computerscore;
                resultLabel.textContent = "";
                winnerLabel.textContent = "";
                
                const buttons = document.querySelectorAll('button');
                buttons.forEach((button) => {
                    button.addEventListener('click', function() {
                        let playerSelection = this.value;
                        let computerSelection = computerPlay();
                        let result = playRound(playerSelection, computerSelection);
                        const resultLabel = document.querySelector('.result');
                        resultLabel.textContent = result;
                        console.log(result);

                        if(result == "You win!") {  //Win
                            myscore++;
                            myScoreLabel.textContent = myscore.toString();
                            console.log("Your score: " + myscore);
                            console.log("Computer's score: " + computerscore);
                            console.log("");
                            if(myscore == 5){
                                winnerLabel.textContent = "You won the game!";
                                alert("Click Restart to play a new game");
                            }
                        }
                        else if(result == "You lose! Try again..."){    //Lose
                            computerscore++;
                            compScoreLabel.textContent = computerscore.toString();
                            console.log("Your score: " + myscore);
                            console.log("Computer's score: " + computerscore);
                            console.log("");
                            if(computerscore == 5) {
                                winnerLabel.textContent = "You lost the game!";
                                alert("Click Restart to play a new game");
                            }
                        }
                        else{   //Draw 
                            console.log("Your score: " + myscore);
                            console.log("Computer's score: " + computerscore);
                            console.log("");
                        }
                    });
                });
            }  

            function restart() {
                myscore = 0;
                computerscore = 0;
                main();
            }
            
            main();
<div class="score">
            <h2 class="myScore"></h2>
            <span>:</span>
            <h2 class="compScore"></h2>

        </div>
        <div class="choice">
            <button class="rock" value="rock">
                Rock
            </button>
            <button class="paper" value="paper">
                Paper
            </button>
            <button class="scissors" value="scissors">
                Scissors
            </button>
            <input id="restartSettings" type="button" value="Restart" onclick="restart()" />
        </div>
        <h2 class="result"></h2>
        <h1 class="winner"></h1>
        

Edit: If you run the code snippet, you can see that after you click Restart, the code inside the button addEventListener is executed twice.

Mschreider
  • 13
  • 4

2 Answers2

1

Every time you call main(), it adds the event listeners again, which means that clicking the buttons will cause the event to fire multiple times.

Either remove the event listeners before you add them, or simply add them only once, outside your main().

kmoser
  • 8,780
  • 3
  • 24
  • 40
  • Thank you! I'm still wrapping my head around how JavaScript code is essentially a continuous while loop so I do not even need main(). – Mschreider May 08 '20 at 15:49
  • For reference, see [How to remove an event listener in javascript?](https://stackoverflow.com/questions/15100576/how-to-remove-an-event-listener-in-javascript). – showdev Oct 17 '21 at 05:19
0

The addEventListener function was added to the DOM API specifically to address the limitations of on.. type event handlers. It is designed to add rather than replace event handlers so each time you call it it keeps the old event listeners and add the new one so that the element will now trigger multiple event listeners just like what you observe.

One very simple, cross-browser and robust way to solve this if your intention is for the button to only ever have a single event handler (which is 90% of what I personally do) is to not use addEventListener and use the much more older and widely supported on.. event handler:

button.onclick = function() { ...
slebetman
  • 109,858
  • 19
  • 140
  • 171
  • Don't worry about opinions that this API is old-fashioned. Engineering is not about following trends but creating something that works – slebetman May 08 '20 at 05:24