My game runs smoothly until I reach the stage of determining the winner. It only recognizes the winner when the X player wins, but not when the O player wins. I believe it's a bug related to the useState delays, but I can't seem to figure it out!

This is my code js:

const checkOfWinner= (state) => {
  const win = [
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8],
      [0, 3, 6],
      [1, 4, 7],
      [2, 5, 8],
      [0, 4, 8],
      [2, 4, 6],
    ];

  for (let i = 0; i < win.length; i++) {
      //deconstruction
      const [a, b, c] = win[i];
      if (state[a] && state[a] === state[b] && state[a] === state[c]) {
        return state[a];
      }
    }
    return null;
};


const Square = ({id, newState}) => {
  const [color,setColor] = React.useState("red")
  const [status, setStatus] = React.useState(null);
  const XorO = ["O", "X"];

  const colors = ['#ffb147', "#ffb192", "red", "#5eb192"];
  const getRandomColor = () => colors[Math.floor(Math.random()*4)];
  
  
  React.useEffect (() => {
    console.log(`Render square ${id}`);
    return () => console.log(`unmounted square ${id}`);

  });
// bug -delay of displayin a random color at setcolor  no calling the setcolor but instead a differet var col(instead color)
return (
<button  style={{color:"#ffffff"}} onClick={(e) => {
  let col = getRandomColor();
  setColor(col);
  let nextPlayer = newState(id);
  setStatus(nextPlayer);  
  e.target.style.border= `10px solid ${col}`;
  e.target.style.borderRadius= "10px";
  
}}
>
  {XorO[status]}
</button>
);
};

const Board = () => {
  const [isMounted, setIsMounted] = React.useState(true);
  const [state, setState] = React.useState(Array(9).fill(null));
  const [player, setPlayer] = React.useState(1);
  

  let status = `Player ${player}`;
  let winner = checkOfWinner(state);
  if(winner != null) status = `Player ${winner} wins`;

  const newState = idOfSquare => {
    //is this the player from the begining ? const [player, setPlayer] = React.useState(1);
    let presentPlayer = player;
    state[idOfSquare] = player; //present player
    setState(state); //state is an arrayof o or x or null

    let nextPlayer = (player + 1) % 2; //module of any number with 2will ether be 1 or 0
    setPlayer(nextPlayer);
  
    //i guess i return a variable if i want to no lose it wht the scope finishes , on the otherside for set state variable you dont need to reetunr becasue they keep updated automaticly?
    return presentPlayer;
    };
    
 
  const reRender = () =>{ 
      return setRender(true)};

  const toggle = () => {
     setIsMounted(!isMounted);
  };

 
  function renderSquare(i) {
    return  <Square id={i}  newState={newState}></Square>  };

  return (
    <div style={{whiteSpace: "pre-line"}} className="game-board">
          <div className="grid-row">
          {renderSquare(0)}
          {renderSquare(1)}
          {renderSquare(2)}
          </div>
          <div className="grid-row">
          {renderSquare(3)}
          {renderSquare(4)}
          {renderSquare(5)}
          </div>
          <div className="grid-row">
          {renderSquare(6)}
          {renderSquare(7)}
          {renderSquare(8)}
          </div>
          <div  id="info" >
          <h1 style={{color:"#ffffff"}}>{status}</h1>
          <button className="button-3" role="button" style={{color:"#ffffff"}} onClick={toggle}> <h4> Show/Hide </h4> </button>
          </div>
    </div>
     
     
  );
};

// ========================================

ReactDOM.render(<Board />, document.getElementById("root"));

Here it is my html doc:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>React Tik Tak Toe</title>
    <style>
      body {
        font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
        color: rgb(17, 17, 17);
      }
      button {
        background-color: #0b0b0b;
        border: 6px solid #bdcfc4;
        border-radius: 10px;
      }
   
      /* CSS */
      .button-3 {
        appearance: none;
        background-color: #2ea44f;
        border: 1px solid rgba(27, 31, 35, .15);
        border-radius: 6px;
        box-shadow: rgba(27, 31, 35, .1) 0 1px 0;
        box-sizing: border-box;
        color: #fff;
        cursor: pointer;
        display: inline-block;
        font-family: -apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
        font-size: 14px;
        font-weight: 600;
        line-height: 20px;
        padding: 6px 16px;
        position: relative;
        text-align: center;
        text-decoration: none;
        user-select: none;
        -webkit-user-select: none;
        touch-action: manipulation;
        vertical-align: middle;
        white-space: nowrap;
      }

      .button-3:focus:not(:focus-visible):not(.focus-visible) {
        box-shadow: none;
        outline: none;
      }

      .button-3:hover {
        background-color: #2c974b;
      }

      .button-3:focus {
        box-shadow: rgba(46, 164, 79, .4) 0 0 0 3px;
        outline: none;
      }

      .button-3:disabled {
        background-color: #94d3a2;
        border-color: rgba(27, 31, 35, .1);
        color: rgba(255, 255, 255, .8);
        cursor: default;
      }

      .button-3:active {
        background-color: #298e46;
        box-shadow: rgba(20, 70, 32, .2) 0 1px 0 inset;
      }

      .game-board {
        width: 600px;
        height: 600px;
        margin: 0 auto;
        background-color: #34495e;
        color: rgb(8, 8, 8);
        border: 6px  #0b0d0f;
        border-radius: 10px;
        display: grid;
        grid-template-rows: 1fr 1fr 1fr ;
        grid-template-columns: 1fr;
      }

      .grid-row {
        border: 6px  #739dc7;
        border-radius: 10px;
        font-family: Helvetica;
        font-weight: bold;
        font-size: 4em;
        display: grid;
        grid-template-rows: 1fr;
        grid-template-columns: 1fr 1fr 1fr;
        background-color: rgb(6, 6, 6);
        
      }
      .block {
        background-color: rgb(219, 28, 28);
        border: 6px  green;
        border-radius: 6px;
        font-family: Helvetica;
        font-weight: bold;
        font-size: 20em;
      }
    </style>
    <!-- load stylesheets bootstrap -->
    <link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
    integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
    crossorigin="anonymous"
  />
    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  </head>
  <body>
    <h1>React Tik Tak Toe</h1>

    <!-- We will put our React component inside this div. -->
    <div id="root"></div>

    <!-- Load React. -->
    <script
      src="https://unpkg.com/react/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://unpkg.com/react-dom/umd/react-dom.development.js"
      crossorigin
    ></script>
    <!-- load scripts bootstrap -->
    <script src="https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js" crossorigin></script>

    <script
      src="https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js"
      crossorigin></script>

    <script
      src="https://cdn.jsdelivr.net/npm/react-bootstrap@next/dist/react-bootstrap.min.js"
      crossorigin></script>

    <script>var Alert = ReactBootstrap.Alert;</script>

    <!-- Load our React component. -->
    <script src="colorGame0002.js" defer type="text/babel"></script>
  </body>
</html>

I switched the setState value at the beginning if the status to 0 instead of 1, to see if then the winner would be selected only when the O player wins, but it didn't work. X is still the only one recognized as the winner, not O. The issue I'm facing is that the winner doesn't print correctly. The winner is only detected on the X player. It seems like there's a mistake in getting the winner state?. I don't know where to look to get fix that mistake.

0

There are 0 best solutions below