Hello, Let's build an AI tic-tac-toe today in React. Just a small note before we start, we'll not be using any Mini-Max AI algorithms to build the game. Instead, we are going to use the tictactoeAPI. Here is the link to the game and the Github repo. It will be easier for you to follow the tutorial if you have some basic knowledge of React.
First of all, let's create the react-app with the command
npx-create-react-app tictactoe
Delete the boilerplate code and you should see a blank page when you run the command npm start
. Our folder structure will be quite straightforward with a components folder inside the src folder. Our index.js file should look like this:
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<>
<Header />
<AI/>
</>
);
Now our task is to create these two components. Let's start with the Header file which is really simple.
import React from 'react'
function Header() {
return (
<div style={{
display:'flex',
alignItems:'cemter',
justifyContent:'center',
padding:'10px',
marginTop:'1.4em',
fontWeight:'650',
fontSize:'1.4rem'
}}>Let's Play Tac-Tac-Toe 👍</div>
)
}
export default Header
The AI component is the complicated one, but let's break it down.
import React from 'react'
import axios from 'axios'
function AI(){
return(
<div style={{
display:'flex',
flexDirection:'column',
alignItems:'center',
justifyContent:'center'
}}>
</div>
)
}
Here we have an outer div to place all its contents in the center of the webpage. Then, we are going to build a reset button.
<div style={{
display:'flex',
alignItems:'center',
flexDirection:'row',
flexWrap:'wrap',
justifyContent:'center',
marginTop:'-16px'
}}>
{* Reset button *}
<button
style={{
color:'red'
}}>Reset</button>
</div>
Then, we need to declare some states
const [winner, setwinner] = React.useState('No winner');
const [undo, setundo] = React.useState(null);
const [board, setboard] = React.useState({
'0': '-',
'1': '-',
'2': '-',
'3': '-',
'4': '-',
'5': '-',
'6': '-',
'7': '-',
'8': '-'
})
const [turn, setturn] = React.useState('X');
We need to tell the user whose turn is and who won the game, so:
<div>{turn} turn!</div>
<div>{ winner && winner !== 'No winner' ? (`${winner} won!`):'No one won!'}
</div>
Let's add some styling:
<div style={{
fontSize:'25px',
padding:'3px',
fontWeight:'650'
}}>{turn} turn!</div>
<div style={{
display:'flex',
alignItems:'center',
justifyContent:'center',
fontSize:'25px',
color:'green'
}}>{ winner && winner !== 'No winner' ? (`${winner} won!`):'No one won!'}
</div>
It's time to create the table component
<table>
<tbody>
<tr>
<td onClick={() =>{
handleEvent(0);
}}> {board['0']} </td>
<td onClick={() =>{
handleEvent(1)
}}> { board['1']} </td>
<td onClick={() =>{
handleEvent(2)
}}> {board['2']} </td>
</tr>
<tr>
<td onClick={() =>{
handleEvent(3)
}}> {board['3']} </td>
<td onClick={() =>{
handleEvent(4)
}}> {board['4']} </td>
<td onClick={() =>{
handleEvent(5)
}}> {board['5']} </td>
</tr>
<tr>
<td onClick={() =>{
handleEvent(6)
}}> {board['6']} </td>
<td onClick={() =>{
handleEvent(7)
}}> {board['7']} </td>
<td onClick={() =>{
handleEvent(8)
}}> {board['8']} </td>
</tr>
</tbody>
</table>
Let's add some more styling:
table{
background-color: white;
border: 2px solid #1b1b32;
}
td{
border: 2px solid #1b1b32;
padding: 40px;
align-items: center;
}
td:hover{
background-color: azure;
}
@media (max-width:485px){
td{
padding: 25px;
}
}
Our website should look like this:
Now, it's time to handle the logic of the game. Right now, we have an onClick event handler on every td element. So let's create that function.
function handleEvent(e){
setundo(e);
setboard(prevstate => ({...prevstate, [e]: 'O'}))
}
Right now the user could play O on every square. So we need to add a condition to make sure that the user does not play O on the same square already played. So let's rewrite the function as:
function handleEvent(e){
if (board[e] === '-' && winner === 'No winner'){
setundo(e);
setboard(prevstate => ({...prevstate, [e]: 'O'}))
}
}
// Check for winners
React.useEffect(() =>{
if (board['0'] === board['1'] && board['1'] === board['2'] && board['2'] !== '-'){
setwinner(board['0'])
}
else if(board['3'] === board['4'] && board['4'] === board['5'] && board['5'] !== '-'){
setwinner(board['3'])
}
else if(board['6'] === board['7'] && board['7'] === board['8'] && board['8'] !== '-'){
setwinner(board['6'])
}
else if(board['0'] === board['3'] && board['3'] === board['6'] && board['6'] !== '-'){
setwinner(board['0'])
}
else if(board['1'] === board['4'] && board['4'] === board['7'] && board['7'] !== '-'){
setwinner(board['1'])
}
else if(board['2'] === board['5'] && board['5'] === board['8'] && board['8'] !== '-'){
setwinner(board['2'])
}
else if(board['0'] === board['4'] && board['4'] === board['8'] && board['8'] !== '-'){
setwinner(board['0'])
}
else if(board['2'] === board['4'] && board['4'] === board['6'] && board['6'] !== '-'){
setwinner(board['2'])
}
}, [board])
The above part is to check whether anyone has won the game whenever the state of the board changes.
Remember the button we made(Reset button). Let's add logic to that as well.
<button
onClick={() =>{
setwinner('No winner');
setboard({
'0': '-',
'1': '-',
'2': '-',
'3': '-',
'4': '-',
'5': '-',
'6': '-',
'7': '-',
'8': '-'
});
setundo(null);
}}>Reset</button>
Now comes the API part of the game. I recommend you to go through the API documentation to get a more clear idea of what's happening. So, this time, we are going to create another useEffect.
React.useEffect(() =>{
var game = [board[0], board[1], board[2], board[3], board[4], board[5], board[6], board[7], board[8]];
game = game.join('');
const options = {
method: 'GET',
url: `https://stujo-tic-tac-toe-stujo-v1.p.rapidapi.com/${game}/X`,
headers: {
'X-RapidAPI-Key': #your api key,
'X-RapidAPI-Host': #rapidapi host
}
};
axios.request(options).then(function (response) {
if (winner === 'No winner'){
setboard(prevstate => ({...prevstate, [response.data.recommendation]: 'X'}))
}
}).catch(function (error) {
console.error(error);
});
}, [undo])
If you look at the API documentation, you could see that we need to pass in the current state of the board in the URL.
And that's it!! Did you enjoy the tutorial? Write your suggestions in the comment section.
Top comments (0)