欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用React实现井字棋小游戏

程序员文章站 2024-03-18 23:51:04
...

使用React实现井字棋小游戏

  • 按照React官方教程来实现一个井字棋小游戏并完善其他功能,这里主要讲怎么完善这些功能
    1. 在游戏历史记录列表显示每一步棋的坐标,格式为 (列号, 行号)。
    2. 在历史记录列表中加粗显示当前选择的项目。
    3. 使用两个循环来渲染出棋盘的格子,而不是在代码里写死(hardcode)。
    4. 添加一个可以升序或降序显示历史记录的按钮。
    5. 每当有人获胜时,高亮显示连成一线的 3 颗棋子。
    6. 当无人获胜时,显示一个平局的消息。
  • 点击此处获取React官方井字棋小游戏源码———官方代码.
  • 点击此处获取已完善的井字棋的源码———已完善代码.

1.添加坐标功能

  1. 在state的history中添加coordinate
    this.state = {
        // square: Array(9).fill(null),
        xIsNext: true,
        history: [
            {
                square: Array(9).fill(null),
                coordinate: 0
            }
        ],
        stepNumber: 0,
        order: false
    }
  1. 点击时根据index添加坐标信息
    handleClick(i) {
        let history = this.state.history.slice(0, this.state.stepNumber + 1);
        let current = history[history.length - 1]
        let square = current.square.slice();
        //如果存在获胜者或此棋格已有值,则返回
        if (calculateWinner(square) || square[i]) {
            return;
        }
        //根据xIsNext判断值为X或0
        square[i] = this.state.xIsNext ? "X" : "O";
        //计算此步的x坐标
        let x = Math.floor(i / 3) + 1
        //计算此步的y坐标
        let y = i % 3 + 1
        //生成坐标信息
        let coordinate = square[i] + '(' + x + ',' + y + ')'
        this.setState({
            history: history.concat([
                {
                    square: square,
                    coordinate: coordinate
                }
            ]),
            stepNumber: history.length,
            xIsNext: !this.state.xIsNext
        });
    }
  1. 渲染时渲染坐标
    const moves = history.map((step, index) => {
        const desc = index ?
            'Go to move : ' + step.coordinate :
            'Go to game start';
        return (
            <li key={index}>
                <button onClick={() => this.jumpTo(index)} className='btn' {desc}</button>
            </li>
        );
    });

效果图:使用React实现井字棋小游戏

2.加粗显示当前选择的项目

  1. 根据stepNumber判断按钮是否对应当前项目,对应的话加入相应的样式
    const moves = history.map((step, index) => {
        const desc = index ?
            'Go to move : ' + step.coordinate :
            'Go to game start';
        let light = {
            color: 'rgb(158, 147, 147)'
        };
        if(index === this.state.stepNumber){
            if(winner){
                light={
                    color: 'red'
                }
            }else{
                light={
                    color: '#000'
                }
            }
                        
        }
        return (
            <li key={index}>
                <button onClick={() => this.jumpTo(index)} className='btn' style={light}>{desc}</button>
            </li>
        );
    });

效果图:使用React实现井字棋小游戏

3.使用两个循环来渲染出棋盘的格子

  1. 通过两个for循环来生成3X3表格
    const SquareRow = []
    for (let i = 0; i < 3; i++) {
        let str = [];
        //两重循环遍历出棋盘
        for (let j = 0; j < 3; j++) {
            let light = false;
            if (this.props.winnnerStep.indexOf(i * 3 + j) != -1) {
                light = true;
            } else {
                light = false;
            }
            str.push(
                <Square
                    value={this.props.square[i * 3 + j]}
                    key={i * 3 + j}
                    onClick={() => this.props.handleClick(i * 3 + j)}
                    light={light}
                />
            )

        }
        let square = <div className="board-row">{str}</div>
        SquareRow.push(square)
    }
    let showSquare = SquareRow.map((item, index) => {
        return <div key={index}>{item}</div>
    })
    return (
        <div>
            <div>
                {showSquare}
            </div>
            <div>
                <button onClick={() => this.props.reSetClick()} className='reset_btn'>重置</button>
            </div>
        </div>
    );

4.添加一个可以升序或降序显示历史记录的按钮

  1. 添加一个state:order,(order为false时为正序,true时为倒序)
    this.state = {
        xIsNext: true,
        history: [
            {
                square: Array(9).fill(null),
                coordinate: 0
            }
        ],
        stepNumber: 0,
        order: false
    }
  1. 渲染按钮列表时判断order的值,并根据值渲染按钮列表和标题箭头
    let order = this.state.order ? '▲' : '▼'
    const moves = history.map((step, index) => {
        const desc = index ?
            'Go to move : ' + step.coordinate :
            'Go to game start';
        return (
            <li key={index}>
                <button onClick={() => this.jumpTo(index)} className='btn'>{desc}</button>
            </li>
        );
    });
    if (this.state.order) {
        moves.reverse()
    }
    return (
        <div className="game">
            <div className="game-board">
                <Board
                    square={current.square}
                    handleClick={this.handleClick.bind(this)}
                    winnnerStep={winnerStep} 
                    reSetClick={this.reSetClick.bind(this)}
                />
            </div>
            <div className="game-info">
                <div onClick={this.changeOrder.bind(this)}>
                    <div className='status'>
                        {status}
                    </div>
                    <div className='order'>
                        {order}
                    </div>
                </div>
                <ul>{moves}</ul>
            </div>
        </div>
    );

效果图:使用React实现井字棋小游戏
使用React实现井字棋小游戏

5.每当有人获胜时,高亮显示连成一线的 3 颗棋子

  1. 获胜时获取3连棋子的位置(step)
    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]) {
                //返回获胜的value和三连棋子的位置
                return { user: squares[a], step: [a, b, c] };
            }
        }
        return null;
    }
  1. 将step传给子组件
    let history = this.state.history;
    let current = history[this.state.stepNumber];
    let winner = calculateWinner(current.square);
    //初始化获胜者获胜步的位置数组
    let winnerStep = [] 
    if (winner) {
        status = '获胜者:' + winner.user;
        //将连成一线的 3 颗棋子的位置放入数组
        winnerStep = winner.step
    }
    <Board
        square={current.square}
        handleClick={this.handleClick.bind(this)}
        winnnerStep={winnerStep} 
        reSetClick={this.reSetClick.bind(this)}
    />
  1. 在循环渲染棋盘时判断当前棋子是否在3连棋子数组内
    if (this.props.winnnerStep.indexOf(i * 3 + j) != -1) {
        light = true;
    } else {
        light = false;
    }
    str.push(
        <Square
            value={this.props.square[i * 3 + j]}
            key={i * 3 + j}
            onClick={() => this.props.handleClick(i * 3 + j)}
            light={light}
        />
    )

效果图:使用React实现井字棋小游戏

6.当无人获胜时,显示一个平局的消息

  1. 渲染时判断棋盘是否已满,如果已满则将status改为平局
    //设置标量标记棋盘是否已满
    let flag = true;
    //遍历判断棋盘是否已满
    for (let i = 0; i < current.square.length; i++) {
        if (current.square[i] === null) {
            flag = false;
        }
    }
    //初始化状态信息(显示对局情况)
    let status;
    if (winner) {
        status = '获胜者:' + winner.user;
        //将连成一线的 3 颗棋子的位置放入数组
        winnerStep = winner.step
    } else {
        if(flag){
            status = '平局'
        }else{
            status = "下一位选手: " + (this.state.xIsNext ? "X" : "O");
        }         
    }

效果图:使用React实现井字棋小游戏

相关标签: react js 游戏