美文网首页
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