Search code examples
javascripthtmlcsstic-tac-toe

Tic Tac Toe: Infinite winning after resetting game


I'm recreating the classic Tic Tac Toe using HTML, CSS, and JS.

I've got the game to run successfully for a single match but functionality seems to have some errors after creating a New Game option. After clicking new game, the winner message will pop up every time a player marks a square.

The game-checking algorithm is inside of the gameBoard variable and named checkWin. It's called inside of displayController after updating the view.

Pictures showing issue:

) Working normally aside from winning message popping up before showing final X placement (bottom-left)

enter image description here ISSUE: After clicking new-game, I click a single square and the winning message pops up.

let counter = 0;
let gameBoard = (function() {
  // 'use strict';

  let Board = ["", "", "", "", "", "", "", "", ""];

  let winningCombinations = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
  ]

  // has array 
  return {
    Board: Board,
    clickSquare: function(player) {
      document.querySelectorAll('td').forEach(item => {
        item.addEventListener('click', event => {
          // console.log(item.id.replace('_',''));
          player.markSquare(item.id.replace('_', ''));
        })
      });
    },
    checkWin: function() {
      return winningCombinations.some(combination => {
        return combination.every(index => {
          return Board[index] === "X"
        }) || combination.every(index => {
          return Board[index] === "O"
        })
      })
    }
  }
})();



let displayController = (function() {
  'use strict';

  function updateView(square) {
    console.log(square);
    document.querySelector("#_" + square).textContent = gameBoard.Board[square];
    if (gameBoard.checkWin() && counter % 2 === 0) {
      alert("Player One Wins!");
    } else if (gameBoard.checkWin() && counter % 2 !== 0) {
      alert("Player Two Wins!");
    } else if (counter == 8) {
      alert("TIE!");
    }
    counter++;
  }
  return {
    updateView: updateView
  }
})();

function createPlayer(name) {
  return {
    name: name,
    markSquare(square) {
      if (gameBoard.Board[square] === "") {
        if (counter % 2 === 0) {
          gameBoard.Board[square] = "X";
        } else {
          gameBoard.Board[square] = "O";
        }

        displayController.updateView(square);
      }
    }
  }
}

function gameFlow() {
  let player1 = createPlayer("Phil");
  gameBoard.clickSquare(player1);

  let resetGame = document.querySelector("button");
  resetGame.addEventListener('click', function() {
    for (let i = 0; i <= 8; i++) {
      document.querySelector("#_" + i).textContent = "";
    }
    gameBoard.Board = ["", "", "", "", "", "", "", "", ""];
    counter = 0;
  });

}
gameFlow();
body {
  margin: 0;
  font-family: 'Nunito', sans-serif;
}

h1 {
  text-align: center;
}

#playerNames {
  margin: auto;
  align-items: center;
  justify-content: center;
  display: flex;
}

input {
  width: 170px;
  height: 40px;
  font-size: 30px;
  margin: 0 30px 0 30px;
}

button {
  width: 100px;
  height: 100px;
  font-size: 30px;
  border-radius: 50%;
  background-color: yellow;
}

table {
  margin: auto;
}

td {
  width: 190px;
  height: 190px;
  text-align: center;
  font-size: 100px;
}

tr td:nth-of-type(2) {
  border-left: 2px solid black;
  border-right: 2px solid black;
}

tr:nth-of-type(2) td {
  border-top: 2px solid black;
  border-bottom: 2px solid black;
}
<!DOCTYPE html>
<html>

<head>
  <title></title>
  <link rel="stylesheet" type="text/css" href="TicTac.css">
  <link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
</head>

<body>
  <h1><b>Tic Tac Toe</b></h1>
  <div id="playerNames">
    <input id="pOne" placeholder="Player One" type="text">
    <button>New Game</button>
    <input id="pTwo" placeholder="Player Two" type="text">
  </div>

  <div>
    <table>
      <tr>
        <td id="_0"></td>
        <td id="_1"></td>
        <td id="_2"></td>
      </tr>
      <tr>
        <td id="_3"></td>
        <td id="_4"></td>
        <td id="_5"></td>
      </tr>
      <tr>
        <td id="_6"></td>
        <td id="_7"></td>
        <td id="_8"></td>
      </tr>

    </table>
  </div>

  <script src="TicTac.js"></script>
</body>

</html>


Solution

  • You are very close, but you had two problems.

    One is that your weren't adding the click event correctly to the "New Game" button. I made a quick edit to make it work, but there's other ways to do it.

    The second was that you were assigning a new array to gameBoard.Board.Board. I'm not sure why that didn't work, but resetting the current values in the loop you already had does work.

    Making those two minor changes seems to get things working. I used console.logs to make sure that not only were things running correctly, but also to see the values in the variables. It helped me quickly determine the "Reset" method wasn't being called on the button click as well as confirming that the data wasn't being updated as expected. I've left in those logs so you can see them as examples of how to use them. I also left in the code I commented out to show the few differences, so don't forget to clean all this up.

    BTW, there's a few things that could be done a little better, but good job so far. This is really fairly clean and concise while working.

    let counter = 0;
    let gameBoard = (function() {
        // 'use strict';
    
        let Board = ["", "", "", "", "","","","",""];
    
        let winningCombinations = [
            [0,1,2],
            [3,4,5],
            [6,7,8],
            [0,3,6],
            [1,4,7],
            [2,5,8],
            [0,4,8],
            [2,4,6]
        ]
    
        // has array 
        return {
            Board: Board,
            clickSquare: function(player) {
                document.querySelectorAll('td').forEach(item => {
                    item.addEventListener('click', event => {
                        // console.log(item.id.replace('_',''));
                        player.markSquare(item.id.replace('_',''));
                    })
                });       
            },
            checkWin: function() {
            console.log(Board);
                return winningCombinations.some(combination => {
                    return combination.every(index => {
                        return Board[index] === "X"
                    }) || combination.every(index => {
                        return Board[index] === "O"
                })
            })
            }
        }
    })();
    
    
    
    let displayController = (function() {
        'use strict';
    
        function updateView(square) {
                console.log(square);
                document.querySelector("#_"+square).textContent = gameBoard.Board[square];
                if (gameBoard.checkWin() && counter %2 === 0) {
                    alert("Player One Wins!");
                }
                else if (gameBoard.checkWin() && counter %2 !== 0) {
                    alert("Player Two Wins!");
                }
                else if (counter == 8) {
                    alert("TIE!");
                }
                counter++;
        }
        return {
            updateView: updateView
        }
    })();
    
    function createPlayer(name) {
        return {
            name: name,
            markSquare(square) {
                if (gameBoard.Board[square] === "") {
                    if (counter %2 === 0) {
                        gameBoard.Board[square] = "X";
                    }
                    else {
                        gameBoard.Board[square] = "O";
                    }
                    
                    displayController.updateView(square);
                }
            }
        }
    }
    
    function gameFlow() {
        let player1 = createPlayer("Phil");
        gameBoard.clickSquare(player1);
    
        let resetGame = document.getElementById("resetbutton");
        resetGame.addEventListener('click', function() {
            console.log("reset");
            for (let i =0; i<=8; i++) {
                document.querySelector("#_"+i).textContent="";
                gameBoard.Board[i] = "";
            }
            //gameBoard.Board = ["", "", "", "", "","","","",""];
            counter = 0;
        });
            
    }
    gameFlow();
    body {
        margin: 0;
        font-family: 'Nunito', sans-serif;
    
    }
    h1 {
        text-align: center;
    }
    #playerNames {
        margin: auto;
        align-items: center;
        justify-content: center;
        display: flex;
    }
    input {
        width:170px;
        height: 40px;
        font-size: 30px;
        margin: 0 30px 0 30px;
    }
    button {
        width:100px;
        height: 100px;
        font-size: 30px;
        border-radius: 50%;
        background-color: yellow;
    }
    table {
        margin: auto;
    }
    td {
        width: 190px;
        height: 190px;
        text-align: center;
        font-size: 100px;
    }
    tr td:nth-of-type(2) {
        border-left: 2px solid black;
        border-right:2px solid black;
    }
    tr:nth-of-type(2) td {
        border-top: 2px solid black;
        border-bottom: 2px solid black;
    }
    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
        <link rel="stylesheet" type="text/css" href="TicTac.css">
        <link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
    </head>
    <body>
        <h1><b>Tic Tac Toe</b></h1>
        <div id="playerNames">
            <input id="pOne" placeholder="Player One" type="text">
            <button id="resetbutton">New Game</button>
            <input id="pTwo" placeholder="Player Two" type="text">
        </div>
        
        <div>
        <table>
            <tr>
                <td id="_0"></td>
                <td id="_1"></td>
                <td id="_2"></td>
            </tr>
            <tr>
                <td id="_3"></td>
                <td id="_4"></td>
                <td id="_5"></td>
            </tr>
            <tr>
                <td id="_6"></td>
                <td id="_7"></td>
                <td id="_8"></td>
            </tr>
    
        </table>
    </div>
    
    <script src="TicTac.js"></script>
    </body>
    </html>