○×React Hooks로 게임을 구현합니다.

38669 단어 Reacttech

개시하다


React 튜토리얼에서×게임을 소재로 설명했지만 변함없는 학급 기반 게임이었다.그래서 React Hooks를 사용해서 그 내용을 소개해 봤어요.
이쪽으로 했어요.교과서와는 조금 다르다.
  • 히스토리 제거 및 복원만 가능
  • 송어를 클릭할 때 커서 아이콘으로 사용할 수 있음
  • 몇 개의 라이브러리도 사용했다.
  • lodash
  • classnames
  • prop-types
  • 또한 아래에 설명된 내용은 JavaScript의 출처일 뿐입니다. CSS에 관해서는 JSFiddle에 기재된 내용을 참조하십시오.

    이루어지다


    디스크 어셈블리(Board) 제작


    먼저 접시 부분을 만든다.테이블 변수에 다음 2차원 그룹 데이터가 포함되어 있으면 그림과 같은 표를 표시합니다.
    // null, '×', '○'のどれかが入る
    const table = [
      [null, null, null],
      [null, '×', '○'],
      [null, null, null],
    ];
    

    자세한 조정은 격자가 disabled과 내용이 null일 때만 커서를 표시하고 클릭할 수 있습니다.
    Board.js
    const Board = (props) => {
      return (
        <div className="board">
          {props.table.map((row, i) => (
          	<div key={i} className="board__line">
          	  {row.map((col, j) => (
                <div
                  key={j}
                  className={classNames('board-item', {
                  	'-clickable': !props.disabled && col == null,
                  })}
                  onClick={() => {
                  	if (!props.disabled && col == null) {
                      props.onSelectItem(i, j);
                    }
                  }}
                >
                  <div className="board-item__content">{col}</div>
                </div>
              ))}
          	</div>
          ))}
        </div>
      );
    };
    Board.propTypes = {
      table: PropTypes.array.isRequired,
      disabled: PropTypes.bool.isRequired,
      onSelectItem: PropTypes.func.isRequired,
    };
    

    ○×논리적 구현 구성


    Board 구성 요소 사용하십시오.○×채우기
  • 디스크 데이터의 초기화
  • 리셋 기능도 고려하여 초기화하는 방법으로 초기화
  • 단계에 따라 번호 지정
  • 유저 리스트를 정의하고 현재 몇 단계인지 기록함으로써 다음 단계가 누구의 라운드화인지 계산할 수 있다
  • 디스크 데이터 업데이트
  • Board 구성 요소에서 선택한 칸 정보를 받은 후 수치를 입력하고 ImmutablecloneDeep이 되기 위해 변경된 내용으로 업데이트
  • App.js
    const SIZE = 3;
    const PLAYERS = ['X', '◯'];
    
    /**
     * 最初の盤面データを生成する
     * @param size - 縦横それぞれの方向の個数
     * @return 盤面データ
     */
    const createInitialBoardData = (size) => {
      return Array(size).fill().map(() => Array(size).fill(null));
    };
    
    const App = () => {
      const [step, setStep] = useState(0);
      const [boardData, setBoardData] = useState(createInitialBoardData(SIZE));
      const player = PLAYERS[step % PLAYERS.length];
      
      return (
        <div className="game">
          <div className="game__item">
            <Board
              table={boardData}
              onSelectItem={(i, j) => {
                if (boardData[i][j] != null) {
                  return;
                }
                const newBoardData = _.cloneDeep(boardData);
                newBoardData[i][j] = player;
                setBoardData(newBoardData);
                setStep(step + 1);
              }}
            />        
          </div>
        </div>
      );
    };
    

    승자를 판정하다


    판면 데이터를 전달하여 승자를 판정하다.수직선, 가로선, 사선에 같은 요소가 있는지 확인하세요.
    승자를 판정하다
    /**
     * 勝者の判定をする
     * @param boardData - 盤面データ
     * @return 勝者(nullの場合はまだ未決定)
     */
    const judgeWinner = (boardData) => {
      // 横ラインの勝者判定
      for (let i = 0; i < boardData.length; i++) {
        const putPlayer = boardData[i][0];
        // 始めが誰も置いていない場合は調べても無駄なのでスキップ
        if (putPlayer == null) {
          continue;
        }
        const isThePlayerWon = boardData[i]
          .every((player) => player === putPlayer);
        if (isThePlayerWon) {
          return putPlayer;
        }
      }
      
      // 縦ラインの勝者判定
      for (let j = 0; j < boardData[0].length; j++) {
        const putPlayer = boardData[0][j];
        // 始めが誰も置いていない場合は調べても無駄なのでスキップ
        if (putPlayer == null) {
          continue;
        }
        const isThePlayerWon = _.times(boardData[0].length)
          .map((i) => boardData[i][j])
          .every((player) => player === putPlayer);
        if (isThePlayerWon) {
          return putPlayer;
        }
      }
      
      // 右下ラインの勝者判定
      {
        const putPlayer = boardData[0][0];
        if (putPlayer != null) {
          const isThePlayerWon = _.times(boardData.length)
            .map((i) => boardData[i][i])
            .every((player) => player === putPlayer);
          if (isThePlayerWon) {
            return putPlayer;
          }
        }
      }
      
      // 右上ラインの勝者判定
      {
        const putPlayer = boardData[boardData.length - 1][0];
        if (putPlayer != null) {
          const isThePlayerWon = _.times(boardData.length)
            .map((i) => boardData[boardData.length - 1 - i][i])
            .every((player) => player === putPlayer);
          if (isThePlayerWon) {
            return putPlayer;
          }
        }
      }
      
      // 誰も見つけられなかったらnullを返す
      return null;
    }
    

    상태 표시 및 재설정 기능 추가


    마지막으로 승자 등의 상태 표시와 리셋 기능을 더하면 완성된다.
    App.js
    const App = () => {
      const [step, setStep] = useState(0);
      const [boardData, setBoardData] = useState(createInitialBoardData(SIZE));
      const player = PLAYERS[step % PLAYERS.length];
    + const winner = judgeWinner(boardData);
      
    + const statusLabel = (() => {
    +   if (winner != null) {
    +     return `winner: ${winner}`;
    +   }
    +   
    +   if (step >= SIZE * SIZE) {
    +     return 'draw';
    +   }
    +   
    +   return `next player: ${player}`;
    + })();
      
      return (
        <div className="game">
          <div className="game__item">
            <Board
    	  table={boardData}
    +         disabled={winner != null}
              onSelectItem={(i, j) => {
                if (boardData[i][j] != null) {
                	return;
                }
                const newBoardData = _.cloneDeep(boardData);
                newBoardData[i][j] = player;
                setBoardData(newBoardData);
                setStep(step + 1);
              }}
            />        
          </div>
    +     <div className="game__item">
    +       <div>{statusLabel}</div>
    +       <button
    +         onClick={() => {
    +           setBoardData(createInitialBoardData(SIZE));
    +           setStep(0);
    +         }}
    +       >
    +         reset
    +       </button>
    +     </div>
        </div>
      );
    };
    

    끝맺다


    지금까지 React Hooks를 사용했습니다.×게임의 실현.상당히 간단한 설치라 리액트 훅스의 장점은 별로 없는데 뭔가 도움이 된다면 좋겠네요.

    좋은 웹페이지 즐겨찾기