0

I've made a tic tac toe game in HTML, CSS, and Javascript. Clicking on the boxes, displaying messages, and everything else works, except for checking if someone won the game doesn't.

The code doesn't generate errors, it just doesn't work.

Here's the code I used:

var currentPlayer = "X";
var tds = document.querySelectorAll("td");
var playerDisplay = document.querySelector("#playerDisplay")
var warning = document.querySelector("#warning")
var winDisplay = document.querySelector("#win")

function switchPlayers() {
  if(currentPlayer === "X") {
    currentPlayer = "O";
    playerDisplay.innerHTML = "O"
  } else {
    currentPlayer = "X";
    playerDisplay.innerHTML = "X"
  }
}
function checkWin() {
  if (tds[0].textContent === tds[1].textContent === tds[2].textContent) {
        return tds[0].textContent;
  } else if (tds[3].textContent ===   tds[4].textContent ==tds[5].textContent){
        return tds[3].textContent;
  } else if (tds[6].textContent === tds[7].textContent === tds[8].textContent){
        return tds[6].textContent;
  } else if (tds[0].textContent === tds[3].textContent === tds[6].textContent){
        return tds[0].textContent;
  } else if (tds[1].textContent === tds[4].textContent === tds[7].textContent){
        return tds[1].textContent;
  } else if (tds[2].textContent === tds[5].textContent === tds[8].textContent){
        return tds[2].textContent;
  } else if (tds[0].textContent === tds[4].textContent === tds[8].textContent){
        return tds[0].textContent;
  } else if (tds[2].textContent === tds[4].textContent === tds[6].textContent){
        return tds[2].textContent;
  } else if (tds[0].textContent != "-" && tds[1].textContent != "-" && tds[2].textContent != "-" && tds[3].textContent != "-" && tds[4].textContent != "-" && tds[5].textContent != "-" && tds[6].textContent != "-" && tds[7].textContent != "-" && tds[8].textContent != "-"){
        return -1;
  } else {
    return -2;
  }
}

function game() {
  for(var i = 0; i < tds.length; i++) {
      tds[i].addEventListener("click", function(){
        if(this.textContent === "-") {
          this.textContent = currentPlayer;
          if(checkWin() === "X") {
            winDisplay.textContent = "X wins!!!";
            return;

          } else if(checkWin() === "O"){
            winDisplay.textContent = "O wins!!!";
            return;
          } else if (checkWin() === -1) {
            winDisplay.textContent = "Tied!!!"
            return;
          }
          switchPlayers();
        } else {
          warning.textContent = "That block has already been filled, choose and empty one."
          setTimeout(function(){
            warning.textContent = "";
          }, 1000);
        }
      });
  }
}

game();
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>Tic Tac Toe</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
    <link href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto&display=swap" rel="stylesheet">
  </head>
  <body>
    <h1>Tic Tac Toe</h1>
    <table>
      <tr>
        <td id="1">-</td>
        <td id="2" class="top-middle">-</td>
        <td id="3" >-</td>
      </tr>
      <tr>
        <td id="4" class="left">-</td>
        <td id="5" class="middle">-</td>
        <td id="6" class="right">-</td>
      </tr>
      <tr>
        <td id="7" >-</td>
        <td id="8" class="bottom-middle">-</td>
        <td id="9">-</td>
      </tr>
    </table>
    <p id = "win">It's <span id="playerDisplay">X</span>'s turn.</p>
    <p id="warning"></p>
    <script src="script.js"></script>
  </body>
</html>

I just don't understand why it's not working. :)

Yixuan Li
  • 29
  • 1
  • 7
  • 3
    I get an error `Uncaught ReferenceError: currentPlayer is not defined` when running your code. Please provide a [mcve]. – MrUpsidown Mar 20 '20 at 20:53
  • I can't really make a minimal reproducible example, but the error is because I missed a line of code. sry:) I added it. Thank you so much for helping me. – Yixuan Li Mar 20 '20 at 23:02
  • 1
    I would create an array of possible wins and assert if any of those winning configurations exists – Andrew Mar 20 '20 at 23:21

2 Answers2

1

I would create an array of possible wins and assert if any of those winning configurations exists

var currentPlayer = "X";
var tds = document.querySelectorAll("td");
var playerDisplay = document.querySelector("#playerDisplay")
var warning = document.querySelector("#warning")
var winDisplay = document.querySelector("#win")

function switchPlayers() {
  if(currentPlayer === "X") {
    currentPlayer = "O";
    playerDisplay.innerHTML = "O"
  } else {
    currentPlayer = "X";
    playerDisplay.innerHTML = "X"
  }
}

var WINNING_INDEX_CONFIGURATIONS = [
    // horizontal
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],

    // vertical
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],

    // diagonal
    [0, 4, 8],
    [2, 4, 6],
]

function checkPlayerWin(currentPlayer) {
    return WINNING_INDEX_CONFIGURATIONS.some(function (config) {
        return config.every(function (idx) {
            return tds[idx].textContent === currentPlayer
        })
    })
}

function isTie() {
for (let i = 0; i < 9; i++) {
    if (td[i] !== '-') {
        return false
    }
}
return true
}
function game() {
  for(var i = 0; i < tds.length; i++) {
      tds[i].addEventListener("click", function(){
        if(this.textContent === "-") {
          this.textContent = currentPlayer;
          if(checkPlayerWin('X')) {
            winDisplay.textContent = "X wins!!!";
            return;

          } else if(checkPlayerWin('O')){
            winDisplay.textContent = "O wins!!!";
            return;
          } else if (isTie()) {
            winDisplay.textContent = "Tied!!!"
            return;
          }
          switchPlayers();
        } else {
          warning.textContent = "That block has already been filled, choose and empty one."
          setTimeout(function(){
            warning.textContent = "";
          }, 1000);
        }
      });
  }
}

game();
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>Tic Tac Toe</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
    <link href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto&display=swap" rel="stylesheet">
  </head>
  <body>
    <h1>Tic Tac Toe</h1>
    <table>
      <tr>
        <td id="1">-</td>
        <td id="2" class="top-middle">-</td>
        <td id="3" >-</td>
      </tr>
      <tr>
        <td id="4" class="left">-</td>
        <td id="5" class="middle">-</td>
        <td id="6" class="right">-</td>
      </tr>
      <tr>
        <td id="7" >-</td>
        <td id="8" class="bottom-middle">-</td>
        <td id="9">-</td>
      </tr>
    </table>
    <p id = "win">It's <span id="playerDisplay">X</span>'s turn.</p>
    <p id="warning"></p>
    <script src="script.js"></script>
  </body>
</html>
Andrew
  • 7,201
  • 5
  • 25
  • 34
1

Andrew's answer works great, but if you want to understand why your solution specifically doesn't work, it's because of this line (and others like it):

if (tds[0].textContent === tds[1].textContent === tds[2].textContent)

Unfortunately you can't test for three things being equal like this. What you're actually doing is comparing tds[0].textContent, let's say 'X', with the result of tds[1].textContent === tds[2].textContent (which, if they are both 'X', won't be 'X' again but the boolean true).

To make the comparison you could use:

if (tds[0].textContent === tds[1].textContent && tds[0].textContent === tds[2].textContent)

You can read more about this here:

Javascript compare 3 values

I modified your snippet, but used a function to return the comparison for brevity's sake.

Hope that makes sense!

var currentPlayer = "X";
var tds = document.querySelectorAll("td");
var playerDisplay = document.querySelector("#playerDisplay")
var warning = document.querySelector("#warning")
var winDisplay = document.querySelector("#win")

function switchPlayers() {
  if(currentPlayer === "X") {
    currentPlayer = "O";
    playerDisplay.innerHTML = "O"
  } else {
    currentPlayer = "X";
    playerDisplay.innerHTML = "X"
  }
}
function checkWin() {
  if (check3Same(0, 1, 2)) {
        return tds[0].textContent;
  } else if (check3Same(3, 4, 5)){
        return tds[3].textContent;
  } else if (check3Same(6, 7, 8)){
        return tds[6].textContent;
  } else if (check3Same(0, 3, 6)){
        return tds[0].textContent;
  } else if (check3Same(1, 4, 7)){
        return tds[1].textContent;
  } else if (check3Same(2, 5, 8)){
        return tds[2].textContent;
  } else if (check3Same(0, 4, 8)){
        return tds[0].textContent;
  } else if (check3Same(2, 4, 6)){
        return tds[2].textContent;
  } else if (tds[0].textContent != "-" && tds[1].textContent != "-" && tds[2].textContent != "-" && tds[3].textContent != "-" && tds[4].textContent != "-" && tds[5].textContent != "-" && tds[6].textContent != "-" && tds[7].textContent != "-" && tds[8].textContent != "-"){
        return -1;
  } else {
    return -2;
  }
}

function check3Same(a, b, c) {
  return tds[a].textContent === tds[b].textContent && tds[a].textContent === tds[c].textContent;
}

function game() {
  for(var i = 0; i < tds.length; i++) {
      tds[i].addEventListener("click", function(){
        if(this.textContent === "-") {
          this.textContent = currentPlayer;
          if(checkWin() === "X") {
            winDisplay.textContent = "X wins!!!";
            return;

          } else if(checkWin() === "O"){
            winDisplay.textContent = "O wins!!!";
            return;
          } else if (checkWin() === -1) {
            winDisplay.textContent = "Tied!!!"
            return;
          }
          switchPlayers();
        } else {
          warning.textContent = "That block has already been filled, choose and empty one."
          setTimeout(function(){
            warning.textContent = "";
          }, 1000);
        }
      });
  }
}

game();
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>Tic Tac Toe</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
    <link href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto&display=swap" rel="stylesheet">
  </head>
  <body>
    <h1>Tic Tac Toe</h1>
    <table>
      <tr>
        <td id="1">-</td>
        <td id="2" class="top-middle">-</td>
        <td id="3" >-</td>
      </tr>
      <tr>
        <td id="4" class="left">-</td>
        <td id="5" class="middle">-</td>
        <td id="6" class="right">-</td>
      </tr>
      <tr>
        <td id="7" >-</td>
        <td id="8" class="bottom-middle">-</td>
        <td id="9">-</td>
      </tr>
    </table>
    <p id = "win">It's <span id="playerDisplay">X</span>'s turn.</p>
    <p id="warning"></p>
    <script src="script.js"></script>
  </body>
</html>
Michael Beeson
  • 2,840
  • 2
  • 17
  • 25