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

Tell us what’s happening:

I do not pass the 9-11 test. I don’t understand why, I tried to check the example and I think it works the same. Please help

Your code so far

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

<head>
    <meta charset="UTF-8" />
    <title>Tic-Tac-Toe</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.5/babel.min.js"></script>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      src="index.jsx"
    ></script>
    <link rel="stylesheet" href="styles.css" />
</head>

<body>
    <div id="root"></div>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
    >
      import { Board } from './index.jsx';
      ReactDOM.createRoot(document.getElementById('root')).render(<Board />);
    </script>
</body>

</html>
/* file: styles.css */
.square {
  height: 40px;
  width: 40px;
  background-color: white; 
}
.square-container {
  display: grid;
  grid-template-columns: repeat(3, 40px);
  gap: 5px;
  margin: 10px;
}
/* file: index.jsx */
const { useState, useEffect } = React;

export function Board() {
  const initialGrid = Array(9).fill("");
  
  const [grid, setGrid] = useState(initialGrid);
  const [turn, setTurn] = useState("X");
  const [gameOver, setGameOver] = useState(false);
  const [message, setMessage] = useState("Next player: X");
  const [winner, setWinner] = useState("");

  const 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]
  ];

  useEffect(() => {  

    const xPlaces = grid.map((v, i) => (v === "X") ? i : null).filter(v => v !== null);
    const oPlaces = grid.map((v, i) => (v=== "O") ? i : null).filter(v => v !== null);

    for (const combination of winningCombinations) {
        if (combination.every(n => xPlaces.includes(n))) {
          setWinner("X")
        }
        else if (combination.every(n => oPlaces.includes(n))) {
          setWinner("O")
        }
      }

      if (winner) {
        setMessage(`Winner: ${winner}`);
      setGameOver(true);
      } else if (grid.every(v => v !== "")) {
      setMessage("It's a Draw!");
      setGameOver(true);
      } else {
      setMessage(`Next player: ${turn}`);
      }
  
  }, [grid])

  const createGrid = () => grid.map((v, i) => <button className="square" key={i} disabled={gameOver} onClick={() => updateGrid(i)}>{v}</button>);

  const updateGrid = (square) => {
    if (gameOver || grid[square] !== "") return;

  setGrid(prev => prev.map((v,i)=> i===square ? turn : v));
    setTurn(prev => prev==="X" ? "O" : "X");
  
  };

  const reset = () => {
    setGrid(initialGrid);
    setTurn("X");
    setGameOver(false);
    setMessage("Next player: X")
  }


  //renders
  return <>
    <h1>Tic-tac-toe</h1>
    <div className="status">{message}</div>
    <div className="square-container">
       {createGrid()}
    </div>
    <button id="reset" onClick={reset}>Reset</button>
  </>
}

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 OPR/120.0.0.0

Challenge Information:

Build a Tic-Tac-Toe Game - Build a Tic-Tac-Toe Game
https://www.freecodecamp.org/learn/full-stack-developer/lab-tic-tac-toe/build-a-tic-tac-toe-game

What are tests 9-11? Which lines of your code do you believe satisfy those tests?

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

I think the boolean state gameOver (line 32-34) and the if statement to update the grid in line 47 satisfy that statement.

Failed:10. The game should display a message indicating the winner to be X or O.

The message is displayed with the lines 32-34

  1. The game should display a message indicating a draw.
    The draw message is displayed with the line 35-36

Use console.log there to confirm that “gameOver” has been set when you are checking for it.

When you are using state it does not update until the next render so it does not behave the same as setting a variable.

I moved all the game logic from the useEffect hook into the updateGrid function, and now it works perfectly :slight_smile:

1 Like