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.