1시간 안에 React에서 AI Tic-Tac-Toe를 만들어 보자

안녕하세요, 오늘 React에서 AI tic-tac-toe를 만들어 봅시다. 시작하기 전에 작은 참고 사항으로 게임을 빌드하는 데 Mini-Max AI 알고리즘을 사용하지 않을 것입니다. 대신 tictactoeAPI 을 사용하겠습니다. 다음은 game 및 Githubrepo에 대한 링크입니다. React에 대한 기본 지식이 있으면 튜토리얼을 따라하기가 더 쉬울 것입니다.

먼저 다음 명령을 사용하여 react-app을 생성해 보겠습니다.npx-create-react-app tictactoe
상용구 코드를 삭제하면 명령을 실행할 때 빈 페이지가 표시되어야 합니다npm start. 폴더 구조는 src 폴더 안에 구성 요소 폴더가 있어 매우 간단합니다. index.js 파일은 다음과 같아야 합니다.

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <>
     <Header />
     <AI/>

  </>
);



이제 우리의 임무는 이 두 구성 요소를 만드는 것입니다. 정말 간단한 헤더 파일부터 시작하겠습니다.

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


AI 구성 요소는 복잡하지만 분해해 보겠습니다.

import React from 'react'
import axios from 'axios'

function AI(){
return(
     <div style={{
        display:'flex',
        flexDirection:'column',        
        alignItems:'center',
        justifyContent:'center'
    }}>

    </div>
)
}


여기에는 모든 내용을 웹 페이지 중앙에 배치하는 외부 div가 있습니다. 그런 다음 재설정 버튼을 만들 것입니다.

   <div style={{
        display:'flex',
        alignItems:'center',
        flexDirection:'row',
        flexWrap:'wrap',
        justifyContent:'center',
        marginTop:'-16px'
    }}>
      {* Reset button *}
      <button 
        style={{
            color:'red'
        }}>Reset</button>

    </div>



그런 다음 일부 상태를 선언해야 합니다.

    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');


우리는 사용자에게 누구의 차례인지, 누가 게임에서 이겼는지 알려줘야 합니다.

    <div>{turn} turn!</div>

    <div>{ winner && winner !== 'No winner' ? (`${winner} won!`):'No one won!'}    
    </div>


몇 가지 스타일을 추가해 보겠습니다.

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


이제 테이블 구성 요소를 만들 차례입니다.

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


스타일을 더 추가해 보겠습니다.

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;
    }
}


우리 웹사이트는 다음과 같아야 합니다.



이제 게임의 논리를 다룰 때입니다. 지금은 모든 td 요소에 onClick 이벤트 핸들러가 있습니다. 그럼 그 함수를 만들어 봅시다.

   function handleEvent(e){
        setundo(e);
        setboard(prevstate => ({...prevstate, [e]: 'O'}))
    }


현재 사용자는 모든 스퀘어에서 O를 플레이할 수 있습니다. 따라서 사용자가 이미 플레이한 동일한 스퀘어에서 O를 플레이하지 않도록 조건을 추가해야 합니다. 따라서 함수를 다음과 같이 다시 작성해 보겠습니다.

   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])


위 부분은 판의 상태가 바뀔 때마다 누가 게임에서 이겼는지 확인하는 부분입니다.
우리가 만든 버튼(초기화 버튼)을 기억하세요. 논리도 추가해 봅시다.

        <button 
        onClick={() =>{
            setwinner('No winner');
            setboard({
                '0': '-',
                '1': '-',
                '2': '-',
                '3': '-',
                '4': '-',
                '5': '-',
                '6': '-',
                '7': '-',
                '8': '-'
            });
            setundo(null);
        }}>Reset</button>


이제 게임의 API 부분이 나옵니다. APIdocumentation를 통해 어떤 일이 일어나고 있는지 더 명확하게 파악하는 것이 좋습니다. 그래서 이번에는 다른 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])


API 문서를 보면 URL에 보드의 현재 상태를 전달해야 한다는 것을 알 수 있습니다.



그리고 그게 다야!! 튜토리얼이 마음에 드셨나요? 의견 섹션에 제안 사항을 작성하십시오.

좋은 웹페이지 즐겨찾기