skip to Main Content

I have been following a couple tutorials online for the tic tac toe project but with both times that I have attempted, I have gotten the same error where the X’s and O’s aren’t showing but the other features are. I have my HTML, CSS and JavaScript code below. I apologise if it isn’t the best, I am a beginner.

const playerTurn = document.querySelector('.turn');

let gameActive = true;
let currentPlayer = "X";
let gameArray = ["", "", "", "", "", "", "", "", ""];

const winMessage = () => `Player ${currentPlayer} wins!`;
const drawMessage = () => `It's a Draw!`;
const currentPlayerTurn = () => `Player ${currentPlayer}'s Turn`;

playerTurn.innerHTML = currentPlayerTurn();

function handleCellPlayed() {
  gameArray[clickedCellIndex] = currentPlayer;
  clickedCell.innerHTML = currentPlayer;
}

function handlePlayerChange() {
  currentPlayer = currentPlayer === "X" ? "O" : "X";
  gameArray.innerHTML = currentPlayerTurn();
}
const winningConditions = [
  [0, 1, 2],
  [3, 4, 5],
  [6, 7, 8],
  [0, 3, 6],
  [1, 4, 7],
  [2, 5, 8],
  [0, 4, 8],
  [2, 4, 6]
];

function handleResultValidation() {
  let roundWon = false;
  for (let i = 0; i <= 7; i++) {
    const winCondition = winningConditions[i];
    let a = gameArray[winCondition[0]];
    let b = gameArray[winCondition[1]];
    let c = gameArray[winCondition[2]];
    if (a === '' || b === '' || c === '') {
      continue;
    }
    if (a === b && b === c) {
      roundWon = true;
      break
    }
  }
  if (roundWon) {
    playerTurn.innerHTML = winMessage();
    gameActive = false;
    return;
  }
  let roundDraw = !gameArray.includes("");
  if (roundDraw) {
    playerTurn.innerHTML = drawMessage();
    gameActive = false;
    return;
  }
  handlePlayerChange();
}

function handleCellClick() {
  const clickedCell = clickedCellEvent.target;
  const clickedCellIndex = parseInt(
    clickedCell.getAttribute('data-cell-index')
  );
  if (gameArray[clickedCellIndex] !== "" || !gameActive) {
    return;
  }
  handleCellPlayed(clickedCell, clickedCellIndex);
  handleResultValidation();
}

function handleRestartGame() {
  gameActive = true;
  currentPlayer = "X";
  gameArray = ["", "", "", "", "", "", "", "", ""];
  playerTurn.innerHTML = currentPlayerTurn();
  document.querySelectorAll('.cell')
    .forEach(cell => cell.innerHTML = "");
}

document.querySelectorAll('.cell').forEach(cell => cell.addEventListener('click', handleCellClick));
document.querySelector('.restart').addEventListener('click', handleRestartGame);
body {
  font-family: "Courier", sans-serif;
  text-align: center;
}

.game {
  display: grid;
  grid-template-columns: repeat(3, auto);
  width: 304px;
  margin: 50px auto;
}

.cell {
  font-family: "Permanent Marker", cursive;
  width: 100px;
  height: 100px;
  box-shadow: 0 0 0 1px #333333;
  border: 1px solid #333333;
  cursor: pointer;
  line-height: 100px;
  font-size: 60px;
}
<h1 class="title">Tic Tac Toe</h1>
<div class="game">
  <div data-cell-index="0" class="cell"></div>
  <div data-cell-index="1" class="cell"></div>
  <div data-cell-index="2" class="cell"></div>
  <div data-cell-index="3" class="cell"></div>
  <div data-cell-index="4" class="cell"></div>
  <div data-cell-index="5" class="cell"></div>
  <div data-cell-index="6" class="cell"></div>
  <div data-cell-index="7" class="cell"></div>
  <div data-cell-index="8" class="cell"></div>
</div>
<h2 class="turn"></h2>
<button class="restart">Restart</button>

I have managed to get the restart button to show after a couple of changes to my JavaScript code.

3

Answers


  1. Your function handleCellPlayed does not take any arguments, so it does not get the clickedCell or the clickedCellIndex that you try to pass it.

    Try changing it to

    function handleCellPlayed(clickedCell, clickedCellIndex) {
    
    Login or Signup to reply.
  2. Your parameter had an issue, you need clickedCellEvent to the handCellClick function to fix a bug where the clickedCellIndex was not being set correctly, all the changes I made:
    I made the following changes to the code:

    Created a constant
    gameCells
    to store all the game cells.
    Created a constant
    restartButton
    to store the restart button.
    Moved the
    clickedCellIndex
    variable declaration inside the
    handleCellClick
    function.
    Changed the
    gameArray.innerHTML
    to
    playerTurn.innerHTML
    in the
    handlePlayerChange
    function.
    Added a parameter
    clickedCellEvent
    to the
    handleCellClick
    function to fix a bug where the
    clickedCellIndex
    was not being set correctly.
    Changed the
    document.querySelectorAll(‘.cell’)
    to
    gameCells.forEach()
    to simplify the code.
    Changed the
    document.querySelector(‘.restart’)
    to
    restartButton
    to simplify the code.
    Added comments to explain the purpose of each function and variable.
    Removed unnecessary semicolons.

    Here’s the javascript:

        const playerTurn = document.querySelector('.turn');
        const gameCells = document.querySelectorAll('.cell');
        const restartButton = document.querySelector('.restart');
    
        let gameActive = true;
        let currentPlayer = "X";
        let gameArray = ["", "", "", "", "", "", "", "", ""];
    
        const winMessage = () => `Player ${currentPlayer} wins!`;
        const drawMessage = () => `It's a Draw!`;
        const currentPlayerTurn = () => `Player ${currentPlayer}'s Turn`;
    
        playerTurn.innerHTML = currentPlayerTurn();
    
        function handleCellPlayed(clickedCell, clickedCellIndex) {
        gameArray[clickedCellIndex] = currentPlayer;
        clickedCell.innerHTML = currentPlayer;
        }
    
        function handlePlayerChange() {
        currentPlayer = currentPlayer === "X" ? "O" : "X";
        playerTurn.innerHTML = currentPlayerTurn();
        }
    
        const winningConditions = [
        [0, 1, 2],
        [3, 4, 5],
        [6, 7, 8],
        [0, 3, 6],
        [1, 4, 7],
        [2, 5, 8],
        [0, 4, 8],
        [2, 4, 6]
        ];
    
        function handleResultValidation() {
        let roundWon = false;
        for (let i = 0; i <= 7; i++) {
            const winCondition = winningConditions[i];
            let a = gameArray[winCondition[0]];
            let b = gameArray[winCondition[1]];
            let c = gameArray[winCondition[2]];
            if (a === '' || b === '' || c === '') {
            continue;
            }
            if (a === b && b === c) {
            roundWon = true;
            break
            }
        }
        if (roundWon) {
            playerTurn.innerHTML = winMessage();
            gameActive = false;
            return;
        }
        let roundDraw = !gameArray.includes("");
        if (roundDraw) {
            playerTurn.innerHTML = drawMessage();
            gameActive = false;
            return;
        }
        handlePlayerChange();
        }
    
        function handleCellClick(clickedCellEvent) {
        const clickedCell = clickedCellEvent.target;
        const clickedCellIndex = parseInt(
            clickedCell.getAttribute('data-cell-index')
        );
        if (gameArray[clickedCellIndex] !== "" || !gameActive) {
            return;
        }
        handleCellPlayed(clickedCell, clickedCellIndex);
        handleResultValidation();
        }
    
        function handleRestartGame() {
        gameActive = true;
        currentPlayer = "X";
        gameArray = ["", "", "", "", "", "", "", "", ""];
        playerTurn.innerHTML = currentPlayerTurn();
        gameCells.forEach(cell => cell.innerHTML = "");
        }
    
        gameCells.forEach(cell => cell.addEventListener('click', handleCellClick));
        restartButton.addEventListener('click', handleRestartGame);
    

    Here’s your HTML:
    Heres your html:

    And finally, Here’s your CSS:

            body {
            font-family: "Courier", sans-serif;
            text-align: center;
        }
        
        .game {
            display: grid;
            grid-template-columns: repeat(3, auto);
            width: 304px;
            margin: 50px auto;
        }
        
        .cell {
            font-family: "Permanent Marker", cursive;
            width: 100px;
            height: 100px;
            box-shadow: 0 0 0 1px #333333;
            border: 1px solid #333333;
            cursor: pointer;
            line-height: 100px;
            font-size: 60px;
        } 
    
    Login or Signup to reply.
  3. Just a few details. handleCellPlayed() needs to receive the parameters and
    to get the data from data-yourvalue, you can use dataset.yourvalue.

    Here a working example:

    const playerTurn = document.querySelector('.turn');
    
    let gameActive = true;
    let currentPlayer = "X";
    let gameArray = ["", "", "", "", "", "", "", "", ""];
    
    const winMessage = () => `Player ${currentPlayer} wins!`;
    const drawMessage = () => `It's a Draw!`;
    const currentPlayerTurn = () => `Player ${currentPlayer}'s Turn`;
    
    playerTurn.innerHTML = currentPlayerTurn();
    
    function handleCellPlayed(clickedCell, clickedCellIndex) {
      gameArray[clickedCellIndex] = currentPlayer;
      clickedCell.innerHTML = currentPlayer;
    }
    
    function handlePlayerChange() {
      currentPlayer = currentPlayer === "X" ? "O" : "X";
      gameArray.innerHTML = currentPlayerTurn();
    }
    const winningConditions = [
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8],
      [0, 3, 6],
      [1, 4, 7],
      [2, 5, 8],
      [0, 4, 8],
      [2, 4, 6]
    ];
    
    function handleResultValidation() {
      let roundWon = false;
      for (let i = 0; i <= 7; i++) {
        const winCondition = winningConditions[i];
        let a = gameArray[winCondition[0]];
        let b = gameArray[winCondition[1]];
        let c = gameArray[winCondition[2]];
        if (a === '' || b === '' || c === '') {
          continue;
        }
        if (a === b && b === c) {
          roundWon = true;
          break
        }
      }
      if (roundWon) {
        playerTurn.innerHTML = winMessage();
        gameActive = false;
        return;
      }
      let roundDraw = !gameArray.includes("");
      if (roundDraw) {
        playerTurn.innerHTML = drawMessage();
        gameActive = false;
        return;
      }
      handlePlayerChange();
    }
    
    function handleCellClick(e) {
      const clickedCell = e.target;
      const cellIndex = e.target.dataset.cellIndex;
      const clickedCellIndex = parseInt(cellIndex);
      
      if (gameArray[clickedCellIndex] !== "" || !gameActive) {
        return;
      }
      handleCellPlayed(clickedCell, clickedCellIndex);
      handleResultValidation();
    }
    
    function handleRestartGame() {
      gameActive = true;
      currentPlayer = "X";
      gameArray = ["", "", "", "", "", "", "", "", ""];
      playerTurn.innerHTML = currentPlayerTurn();
      document.querySelectorAll('.cell')
        .forEach(cell => cell.innerHTML = "");
    }
    
    document.querySelectorAll('.cell').forEach(cell => cell.addEventListener('click', handleCellClick));
    document.querySelector('.restart').addEventListener('click', handleRestartGame);
    body {
      font-family: "Courier", sans-serif;
      text-align: center;
    }
    
    .game {
      display: grid;
      grid-template-columns: repeat(3, auto);
      width: 304px;
      margin: 50px auto;
    }
    
    .cell {
      font-family: "Permanent Marker", cursive;
      width: 100px;
      height: 100px;
      box-shadow: 0 0 0 1px #333333;
      border: 1px solid #333333;
      cursor: pointer;
      line-height: 100px;
      font-size: 60px;
    }
    <h1 class="title">Tic Tac Toe</h1>
    <div class="game">
      <div data-cell-index="0" class="cell"></div>
      <div data-cell-index="1" class="cell"></div>
      <div data-cell-index="2" class="cell"></div>
      <div data-cell-index="3" class="cell"></div>
      <div data-cell-index="4" class="cell"></div>
      <div data-cell-index="5" class="cell"></div>
      <div data-cell-index="6" class="cell"></div>
      <div data-cell-index="7" class="cell"></div>
      <div data-cell-index="8" class="cell"></div>
    </div>
    <h2 class="turn"></h2>
    <button class="restart">Restart</button>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search