美文网首页
React 文档 井字格小游戏 实现

React 文档 井字格小游戏 实现

作者: 普通市民王二狗 | 来源:发表于2022-07-13 10:15 被阅读0次
    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import './index.css';
    
    // 获胜判定
    function calculateWinner(squares) {
      const lines = [
        [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 < lines.length; i++) {
        const [a, b, c] = lines[i];
        if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
          return {winner: squares[a],coordinate:[a,b,c]};
        }
      }
      return null;
    }
    // 渲染格子
    function Square(props) {
      const {value,style} = props;
      return (
        <button 
          style={style}
          className="square"
          onClick={props.onClick}
        >
          {value}
        </button>
      );
    }
    // 渲染大棋盘,格子父组件,承担props
    class Board extends React.Component {
      renderSquare(i) {
        const { squares, winnerList } = this.props;
        const style = winnerList.includes(i) ? {backgroundColor: 'beige'} : {};
        return <Square 
                  key={i}
                  style={style}
                  value = {squares[i]}
                  onClick={() => {this.props.onClick(i)}}
                />;
      }
      renderBoard(row = 3,column = 3) {
        return (
          <div>{
            Array(row).fill(null).map((itemM,m) => {
              return (
               <div className="board-row" key={m}>
                {
                  Array(column).fill(null).map((itemN,n) => {
                    return this.renderSquare(m * 3 + n)
                  })
                }
               </div>
              )
            })
          }</div>
        )
      }
    
      render() {
        return this.renderBoard();
      }
    }
    
    class Game extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          squares: [],// 当前棋局布局
          squaresList: [],// 记录每一步棋局布局
          squareList: [],// 记录点击顺序,用于显示每一步坐标
          winnerList: [],
          xIsNext: true,
          isAsc: true //是否升序
        }
        this.renderLi = this.renderLi.bind(this);
        this.onClickButton = this.onClickButton.bind(this);
        this.clickSquare = this.clickSquare.bind(this);
        this.restartGame = this.restartGame.bind(this);
        this.desc = this.desc.bind(this);
      }
      //desc
      desc() {
        const { isAsc } = this.state;
        this.setState({
          isAsc: !isAsc
        })
      }
      // 重启游戏
      restartGame() {
        this.setState({
          squares: [],
          squareList: [],// 记录点击顺序
          squaresList: [],
          winnerList: [],
          xIsNext:true
        })
      }
      // 判断行列坐标
      checkCoordinate(index) {
        const x = Math.floor(index % 3);
        const y = Math.floor(index / 3);
        return {x,y}
      }
      // 点击列表按钮,跳转某一步
      onClickButton(index) {
        // 最后一步点击不再跳转
        if(index + 1 == this.state.squaresList.length) return;
    
        const squaresList = this.state.squaresList.slice(0, index + 1);
        const length = squaresList.length;
    
        this.setState({
          squares: squaresList[index],
          squaresList,
          winnerList: [],
          xIsNext: length % 2 === 0 // 奇数为true
        })
      }
      // 渲染右侧li列表
      renderLi() {
        const { squaresList, squareList, isAsc } = this.state;
        const length = squaresList.length - 1;
        return (
          squaresList.map((currentSquare,index) => {
            const {x,y} = this.checkCoordinate(squareList[index]);
            const status = `第${index+1}步`
            const coordinate = `坐标:(x: ${x+1} y: ${y+1})`
            const style = length === index ? {fontWeight: 'bold'} : {};
    
            return (
              <li key={index}>
                <button 
                  style = {style}
                  onClick={() => {this.onClickButton(index)}}
                >
                  {status} {coordinate}
                </button>
              </li>
            )
          })
        )
      }
      // 点击格子
      clickSquare(index) {
        const { xIsNext, squaresList, squareList } = this.state;
        const squares = this.state.squares.slice();
        const winner = calculateWinner(squares);
        // 若获胜/格子存在 return
        if (winner || squares[index]) return;
        
        // 否则 1 更新squares 2 把squares加入squaresList 
        squares[index] = xIsNext ? 'X' : 'O';
    
        this.setState({
          squaresList: squaresList.concat([squares]),
          squareList: squareList.concat([index]),
          squares,
          xIsNext: !xIsNext
        },() => {
          // 在回调中判断是否获胜,并添加获胜样式
          const winner = calculateWinner(this.state.squares);
          if (winner) {
            this.setState({
              winnerList: [...winner.coordinate] 
            })
          }
        });
      }
    
    
    
      render() {
        const { squares, isAsc, winnerList, squaresList, xIsNext } = this.state;
        const winner = calculateWinner(squares);
    
        let status;
        if (winner) {
          status = `winner is ${winner.winner}`
        } else if(squaresList.length == 9) {
          status = `no winner`
        } else{
          status = `Next player: ${xIsNext ? 'X' : 'O'}`;
        }
    
        const ascButton = isAsc ? '降序' : '升序';
        let liList = this.renderLi();
        liList = isAsc ? liList : liList.reverse();
        
        return (
          <div className="game">
            <div className="game-board">
              <Board 
                squares={squares}
                onClick={this.clickSquare}
                winnerList={winnerList}
              />
            </div>
            <div className="game-info">
              <button onClick={this.desc}>{ascButton}</button>
              <div>{ status }</div>
              <button onClick={this.restartGame}>go to start</button>
              <ol>{liList}</ol>
            </div>
          </div>
        );
      }
    }
    
    // ========================================
    
    const root = ReactDOM.createRoot(document.getElementById("root"));
    root.render(<Game />);
    
    

    相关文章

      网友评论

          本文标题:React 文档 井字格小游戏 实现

          本文链接:https://www.haomeiwen.com/subject/zcizbrtx.html