개발노트

07 틱택토 본문

React/webgame

07 틱택토

aloha2jh 2024. 4. 16. 00:30

 

import React, { useReducer, useCallback, useEffect, useMemo } from 'react';
import Table from './Table.jsx';
/*
#강좌
컴포넌트별로 쪼개기

#바뀌는 부분
테이블(9칸) , 턴(user1,user2), 결과-승리자

*/

const initalState = {
    turn: 'user1',
    winner: '',
    tableData: [['', '', ''], ['', '', ''], ['', '', '']],
    recentCell: [-1, -1],
};

export const SET_WINNER = 'SET_WINNER';
export const CLICK_CELL = 'CLICK_CELL';
export const CHANGE_TURN = 'CHANGE_TURN';
export const RESET = 'RESET';

function checkWinner(recentCell, tableData) {
    const [tr, td] = recentCell;
    const turn = tableData[tr][td];
    let win = false;
    if (tableData[tr][0] === turn && tableData[tr][1] === turn && tableData[tr][2] === turn) {
        win = turn;
    }
    if (tableData[0][td] === turn && tableData[1][td] === turn && tableData[2][td] === turn) {
        win = turn;
    }
    if (tableData[0][0] === turn && tableData[1][1] === turn && tableData[2][2] === turn) {
        win = turn;
    }
    if (tableData[0][2] === turn && tableData[1][1] === turn && tableData[2][0] === turn) {
        win = turn;
    }
    return win;
}
function checkTie(tableData) {
    return tableData.every((tr) => (tr.every((td) => (td !== ''))));
}
const reducer = (state, action) => {
    switch (action.type) {
        case SET_WINNER:
            return {
                ...state,
                winner: action.winner,
            }
        case CLICK_CELL: {
            const tableData = [...state.tableData];
            tableData[action.tr] = [...tableData[action.tr]];
            tableData[action.tr][action.td] = state.turn;
            return {
                ...state,
                tableData,
                recentCell: [action.tr, action.td]
            }
        }
        case CHANGE_TURN: {
            return {
                ...state,
                turn: state.turn === 'user1' ? 'user2' : 'user1'
            }
        }
        case RESET: {
            return {
                ...initalState
            }
        }
        default:
            return state;
    }
};


const Tictactoe = () => {
    const [state, dispatch] = useReducer(reducer, initalState);

    const onClickReset = () => {
        dispatch({ type: RESET });
    }
    useEffect(() => {
        const [tr, td] = state.recentCell;
        if (tr == -1 || td == -1) {
            return;
        }
        dispatch({ type: CHANGE_TURN });
        const result = checkWinner(state.recentCell, state.tableData, state.turn);
        if (result) { //누군가 이김
            dispatch({ type: 'SET_WINNER', winner: result });
            const tds = document.querySelectorAll(`.${result}`);
            tds.forEach((v) => { v.classList.add('win'); });
        } else { //무승부인지검사
            if (checkTie(state.tableData)) {
                dispatch({ type: 'SET_WINNER', winner: 'tie' });
            }
        }
    }, [state.recentCell]);

    return (
        <>
            <div className="tictactoe-wrap">
                <h3>틱택토</h3>
                <Table tableData={state.tableData}
                    dispatch={dispatch} />
                <ul>
                    <li>턴: 사용자 {state.turn.slice(4)}</li>
                </ul>
                <h3>{(state.winner !== 'tie' && state.winner !== '')
                    ? `사용자 ${state.winner.slice(4)}의 승리` : null}
                    {state.winner == 'tie' && `무승부`}</h3>
                <button onClick={onClickReset}>다시하기</button>
                <ul>
                    <li>최근클릭:{state.recentCell}</li>
                </ul>
            </div>
        </>
    )
}

export default Tictactoe;

 

 

import React from 'react';

import Tr from './Tr';

const Table = ({ onClick, tableData, dispatch }) => {
    return (
        <table onClick={onClick}>
            <tbody>
                {tableData.map((v, i) => {
                    return <Tr rowData={v} rowIndex={i}
                        dispatch={dispatch}
                        key={`tr-${i}`} />;
                })}
            </tbody>

        </table>
    )
}

export default Table;

 

import React, { memo } from 'react';
import Td from './Td';

const Tr = memo(({ rowData, rowIndex, dispatch }) => {
    return (
        <>
            <tr>
                {rowData.map((v, i) => (
                    <Td cellData={v} tr={rowIndex} td={i}
                        dispatch={dispatch}
                        key={`td-${i}`} />
                ))}
            </tr>
        </>
    )
});

export default Tr;

 

import React, { useCallback, memo } from 'react';
import { CLICK_CELL, } from './Tictactoe';

const Td = memo(({ cellData, tr, td, dispatch }) => {

    const onClickTd = useCallback(() => {
        if (cellData) {
            return false;
        }
        dispatch({ type: CLICK_CELL, tr: tr, td: td });
    }, [cellData]);
    return (
        <>
            <td onClick={onClickTd} className={`tr${tr}-td${td} ${cellData}`}
                key={`${tr}-${td}`}>
                {/* {`${tr}-${td}`} */}
            </td >
        </>
    )
});

export default Td;

'React > webgame' 카테고리의 다른 글

slot machine  (0) 2024.10.17
08 지뢰찾기  (0) 2024.04.20
06 로또번호뽑기  (0) 2024.04.13
05 가위바위보  (0) 2024.04.11
04 반응속도체크 코드  (0) 2024.04.09