Build a Tic-Tac-Toe Game - Build a Tic-Tac-Toe Game - Test 9

Tell us what’s happening:

I cannot pass test 9, I’ve tried different ways to disable the buttons but all of them make me fail test 8, 9, 10 and 11.

Test 9 says:
9. Clicking on a button.square element after the game has ended should result in no change.

I tried the following solutions:

  • inside handleClick I added an if statement to check if winOrDraw is true, if it is return;
  • Making the if statement in handleClick be if (!squares[row][col] && !winOrDraw) so the buttons would only work if the button’s textContent is empty AND there was no win/draw;
  • Adding the disabled attribute in each of the nine buttons and setting it to {winOrDraw} so whenever there was a win or a draw all buttons would be disabled.

In each of these tries the same thing happened, it went from only test no. 9 failing to tests 8 to 11 failing even though the preview window looked fine.

I don’t know which other approaches I could use to make the buttons not do anything after the game is ended except maybe setting up a condition in the onClick attribute of each button, but that would likely have the same result, what am I missing here?

I should add that looking in the console there is an Error object with the following properties, not sure what they mean:

actual: "O"​

expected: undefined​

message: "expected 'O' to not include 'O'"​

operator: "notStrictEqual"​

showDiff: false​

stack: "@https://www.freecodecamp.org/js/test-runner/9.0.0/dom-test-evaluator.js line 2 > eval:16:16\n"

Your code so far

<!-- file: index.html -->

/* file: styles.css */
#container {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.square {
  width: 50px;
  height: 50px;
}

/* file: index.jsx */
const { useState } = React;

export function Board() {

  const [squares, setSquares] = useState([['', '', ''], ['', '', ''], ['', '', '']])
  const [currPlayer, setCurrPlayer] = useState('X');
  const [winOrDraw, setWinOrDraw] = useState(false);
  const [msg, setMsg] = useState('');
  
  function handleClick(row, col) {
    //if (winOrDraw) return;
    if (!squares[row][col]) {
      const copyArr = squares.map(r => [...r]);
      copyArr[row][col] = currPlayer;
      setSquares(copyArr);
      setCurrPlayer(() => currPlayer === 'X' ? 'O' : 'X');
      handleWinnerOrTie(copyArr)
    }
  }
  
  function handleReset() {
    setSquares([['', '', ''], ['', '', ''], ['', '', '']]);
    setCurrPlayer('X');
  }
  
  function handleWinnerOrTie(board = squares) {
    let winner = '';
    for (let i = 0; i <= 2; i++) {
      const xRowCheck = board[i].every(col => col === 'X');
      const xColCheck = [board[0][i], board[1][i], board[2][i]].every(col => col === 'X');
      const oRowCheck = board[i].every(col => col === 'O');
      const oColCheck = [board[0][i], board[1][i], board[2][i]].every(col => col === 'O');
      if (xRowCheck || xColCheck) {
        winner = 'X';
      }
      else if (oRowCheck || oColCheck) {
        winner = 'O';
      }
    }
    if (!winner.length) {
      const xDiagCheck1 = [board[0][0], board[1][1], board[2][2]].every(col => col === 'X');
      const xDiagCheck2 = [board[2][0], board[1][1], board[0][2]].every(col => col === 'X');
      const oDiagCheck1 = [board[0][0], board[1][1], board[2][2]].every(col => col === 'O');
      const oDiagCheck2 = [board[2][0], board[1][1], board[0][2]].every(col => col === 'O');
      if (xDiagCheck1 || xDiagCheck2) {
        winner = 'X';
      }
      else if (oDiagCheck1 || oDiagCheck2) {
        winner = 'O';
      }
    }
    
    if (winner) {
      setWinOrDraw(true);
      setMsg(`Winner: ${winner}!`);
    }
    else {
      let allChecked = board[0].every(c => c) && board[1].every(c => c) && board[2].every(c => c);
      if (allChecked) {
        setWinOrDraw(true);
        setMsg('It was a Tie!');
      }
    }
  }

  return (
    <div id="container">
    <h1>Tic-Tac-Toe</h1>
    <h3>{!winOrDraw ? `Next Player: ${currPlayer}` : msg}</h3>
      <div className="row">
        <button onClick={() => handleClick(0, 0)} className="square">{squares[0][0]}</button>
        <button onClick={() => handleClick(0, 1)} className="square">{squares[0][1]}</button>
        <button onClick={() => handleClick(0, 2)} className="square">{squares[0][2]}</button>
      </div>
      <div className="row">
        <button onClick={() => handleClick(1, 0)} className="square">{squares[1][0]}</button>
        <button onClick={() => handleClick(1, 1)} className="square">{squares[1][1]}</button>
        <button onClick={() => handleClick(1, 2)} className="square">{squares[1][2]}</button>
      </div>
      <div className="row">
        <button onClick={() => handleClick(2, 0)} className="square">{squares[2][0]}</button>
        <button onClick={() => handleClick(2, 1)} className="square">{squares[2][1]}</button>
        <button onClick={() => handleClick(2, 2)} className="square">{squares[2][2]}</button>
      </div>
      <button id="reset" onClick={handleReset}>RESET</button>
    </div>
  )
}

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:143.0) Gecko/20100101 Firefox/143.0

Challenge Information:

Build a Tic-Tac-Toe Game - Build a Tic-Tac-Toe Game

Update:

I tried updating each button’s onClick to be nothing if winOrDraw is true and the normal arrow function otherwise. Functionally it seemed to work on the preview, but again it went from only failing test 9 to failing tests 8, 9, 10, 11.

have you tested though?

When I try your game it lets me click on squares (keep playing) even after someone wins.

. Once a player has won the game, clicking on any button.square should not cause any further changes.

The above should not be possible

Yeah my problem was that when I tried any of these ways of making the game stop after detecting a win it would fail other tests, but I just found out it was due to not dealing with winOrDraw when handling the reset button, it’s all good now!