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

Tell us what’s happening:

Hey everyone. I have been having a lot of trouble passing step 10: “The game should display a message indicating the winner to be X or O.”
I am stumped why this isn’t passing. I have a model message that works perfectly fine and displays the winner. All other logic works. Does the winner also need to be updated in state? I also read of some people passing the tests if they used a different browser… so far I have done it in Chrome and Microsoft Edge.
Thanks in advance for any help!

Your code so far

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

/* file: styles.css */

/* file: index.jsx */

Your browser information:

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

Challenge Information:

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

Hi, and welcome to the community!

Could you please share your code here so we can help you?

Sorry, I thought it shared the code automatically! I just made a separate post with the code attached, as I couldn’t figure out how to edit this one

1 Like

Did you get the issue solved?

I couldn’t find your other post.

Tell us what’s happening:

Hey everyone. I have been having a lot of trouble passing step 10: “The game should display a message indicating the winner to be X or O.”
I am stumped why this isn’t passing. I have a model message that works perfectly fine and displays the winner. All other logic works. Does the winner also need to be updated in state? I also read of some people passing the tests if they used a different browser… so far I have done it in Chrome and Microsoft Edge.
Thanks in advance for any help!

Your code so far

<!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>


body {
  font-family: 'Arial', sans-serif;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh; 
  background-color: #f5f5f5;
}

h2 {
  text-align: center;
  font-family: monospace;
}

.button-container {
  display: flex;
  flex-direction: column; 
  gap: 0.5rem; 
}

/* Each row of buttons (the inner <div> created by map) */
.button-container > div {
  display: flex;
  justify-content: center; 
  gap: 0.5rem; 
}


.square {
  background-color: yellow;
  border: 2px solid #333;
  border-radius: 0.5rem;
  font-size: 2rem; 
  aspect-ratio: 1 / 1; 
  width: 5rem; 
  cursor: pointer;
  transition: background-color 0.2s, transform 0.1s;
}

.square:hover {
  background-color: gold;
  transform: scale(1.05);
}


.reset-button {
  background-color: rgb(187, 228, 246);
  
  border-radius: 0.5rem;
  font-size: 1rem; 
  
  width: 8rem; 
  cursor: pointer;
  transition: background-color 0.2s, transform 0.1s;
}

.reset-button:hover {
  background-color: rgb(127, 210, 246);
  transform: scale(1.05);
}


.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5); 
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 10;
}

.modal {
  background: white;
  border-radius: 1rem;
  padding: 2rem;
  text-align: center;
  box-shadow: 0 4px 10px rgba(0,0,0,0.3);
  animation: fadeIn 0.3s ease;
}


@keyframes fadeIn {
  from { opacity: 0; transform: scale(0.9); }
  to { opacity: 1; transform: scale(1); }
}


const { useState } = React;

export function Board() {
  const Player = { PlayerX: "X", PlayerO: "O" };

  const [playerTurn, setPlayerTurn] = useState(Player.PlayerX);
  const [buttonsText, setButtonsText] = useState(Array(9).fill(""));
  const [showModal, setShowModal] = useState(false);
  const [modalMessage, setModalMessage] = useState("");

  const winningPositions = [
    [0, 1, 2], [3, 4, 5], [6, 7, 8],
    [0, 3, 6], [1, 4, 7], [2, 5, 8],
    [0, 4, 8], [2, 4, 6]
  ];

  const pressButton = (index) => {
    if (buttonsText[index] !== "" || showModal) return;

    const currentPlayer = playerTurn;
    const updated = [...buttonsText];
    updated[index] = currentPlayer;
    setButtonsText(updated);
    setPlayerTurn(currentPlayer === Player.PlayerX ? Player.PlayerO : Player.PlayerX);

    // ✅ only check tie if no winner
    const hasWinner = checkWinner(updated, currentPlayer);
    if (!hasWinner) {
      checkTie(updated);
    }
  };

  const renderButton = (index) => (
    <button
      key={index}
      className="square"
      onClick={() => pressButton(index)}
      disabled={buttonsText[index] !== ""}
    >
      {buttonsText[index]}
    </button>
  );

  const checkWinner = (currentButtons, currentPlayer) => {
    for (const [a, b, c] of winningPositions) {
      if (
        currentButtons[a] === currentPlayer &&
        currentButtons[b] === currentPlayer &&
        currentButtons[c] === currentPlayer
      ) {
        setModalMessage(`${currentPlayer} wins!`);
        setShowModal(true);
        return true;
      }
    }
    return false;
  };

  const checkTie = (currentButtons) => {
    if (currentButtons.every(cell => cell !== "") && !showModal) {
      setModalMessage("Draw!");
      setShowModal(true);
    }
  };

  const resetGame = () => {
    setButtonsText(Array(9).fill(""));
    setPlayerTurn(Player.PlayerX);
    setShowModal(false);
    setModalMessage("");
  };

  return (
    <div>
      <h2>Next Player: {playerTurn}</h2>
      <h2 id="message">{modalMessage}</h2>

      <div className="button-container">
        {[0, 1, 2].map((row) => (
          <div key={row}>
            {renderButton(row * 3)}
            {renderButton(row * 3 + 1)}
            {renderButton(row * 3 + 2)}
          </div>
        ))}
      </div>

      <div className="reset-game">
        <button id="reset" className="reset-button" onClick={resetGame}>
          Reset game
        </button>
      </div>

      {showModal && (
        <div className="modal-overlay">
          <div className="modal">
            <h2>{modalMessage}</h2>
            <button className="reset-button" onClick={resetGame}>
              Play Again
            </button>
          </div>
        </div>
      )}
    </div>
  );

}

Your browser information:

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

Challenge Information:

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

Ok, so everything about your code seems correct. The test is failing because it expects some other kind of message. This should be made clear in the instructions, though. Try changing the message from ${currentPlayer} wins! to something else. You can try:

“Winner: X“ or “Player X wins“. See which ones pass.

Thank you! I finally passed it by using a ternary operator, and wrote the winning message in the format of `Winner: X`

1 Like