在昨天的基础上,对五子棋进行了调整

1、增加了背景颜色

2、增加了修改棋盘大小功能

3、增加了重新开始功能

仍未进行代码优化,同时对vue的data内的数据修改、读取,未发现好的方式,既可以直接读取带来的方便,但感觉也会带来随意修改数据产生的意外,会影响健壮性。

完整代码Game.vue

<script>
export default {
    data() {
        return {
            board: [],
            player: 1,//1--白棋;2--黑棋
            winner: null,
            restart: false,
            boardDetail: {
                width: 0,//棋盘大小
                lineNumber: 0,//棋盘线数
                space: 0,//间隙
            }
        };
    },
    // 实例刚创建,但未挂载dom
    created() {
        document.title = "五子棋";
    },
    // 实例创建完成,仅在首次加载时完成
    mounted() {
        this.boardDetail = {
            width: document.getElementById("board").clientWidth,
            lineNumber: 20,//棋盘线数
            space: 30,//间隙
        }
        this.drawBoard(this.boardDetail.width,
            this.boardDetail.lineNumber,
            this.boardDetail.space);

    },
    methods: {
        /**
         * 画整体棋盘
         * @param width 所需棋盘整体大小,上下左右预留一半space空间
         * @param lineNumber 线条数,线条数*间距=width
         * @param space 间距
         */
        drawBoard(width, lineNumber, space) {
            const halfSpace = space / 2;

            const canvas = document.getElementById("board");
            const ctx = canvas.getContext("2d");
            // 设置线条颜色
            ctx.strokeStyle = "black";

            for (let i = 0; i < lineNumber; i++) {
                // 绘制横线
                ctx.beginPath();
                ctx.moveTo(halfSpace, i * space + halfSpace);
                ctx.lineTo(width - halfSpace, i * space + halfSpace);
                ctx.stroke();
                // 绘制竖线
                ctx.beginPath();
                ctx.moveTo(i * space + halfSpace, halfSpace);
                ctx.lineTo(i * space + halfSpace, width - halfSpace);
                ctx.stroke();
                //填充数组,重置为0
                this.board.push(new Array(lineNumber).fill(0))
            }
        },
        /**
         * 监听每步棋子,需要传入棋盘信息
         * @param event
         * @param detail 棋盘信息
         */
        handleClickAndDraw(event, detail) {
            //存在输赢以后,不允许在落子
            if (this.winner != null) {
                return;
            }
            const lineNumber = detail.lineNumber
            const space = detail.space
            const halfSpace = space / 2;

            // let x = event.offsetX;
            // let y = event.offsetY;
            // console.log(x + '   ' + y)
            // 计算棋子落在哪个方格中
            const cellX = Math.floor((event.offsetX) / space);
            const cellY = Math.floor((event.offsetY) / space);
            // console.log(cellX, cellY)
            // 判断该位置是否有棋子
            if (this.board[cellX][cellY] !== 0) {
                alert("该位置已有棋子")
                return;
            }
            const canvas = document.getElementById("board");
            const ctx = canvas.getContext("2d");
            //画带渐变色的棋子,同心圆形式
            //考虑起点为2,因半径为space一半,避免太大,截止1/3大小
            let grd = ctx.createRadialGradient(
                cellX * space + halfSpace,
                cellY * space + halfSpace,
                2,
                cellX * space + halfSpace,
                cellY * space + halfSpace,
                space / 3
            )
            grd.addColorStop(0, this.player === 1 ? '#FFFFFF' : '#4C4C4C')
            grd.addColorStop(1, this.player === 1 ? '#DADADA' : '#000000')
            ctx.beginPath()
            ctx.fillStyle = grd
            //画圆,半径设置为space/3,同上r1参数一致
            ctx.arc(
                cellX * space + halfSpace,
                cellY * space + halfSpace,
                space / 3,
                0,
                2 * Math.PI,
                false
            );
            ctx.fill();
            ctx.closePath();
            this.board[cellX][cellY] = this.player; //将黑白棋信息存储

            this.winner = this.checkWinner(this.board, lineNumber) //判断输赢
            if (this.winner != null) {
                alert(this.winner)
            }

            this.player = this.player === 1 ? 2 : 1//交换
        },
        /**
         * 胜负检查
         * @param board X*X 二维数组
         * @param lineNumber 线条数
         * @returns {number|null}
         */
        checkWinner(board, lineNumber) {
            // 检查横向是否有五子连线
            for (let i = 0; i < lineNumber; i++) {
                let count = 0;
                for (let j = 0; j < lineNumber; j++) {
                    if (board[i][j] === this.player) {
                        count++;
                    } else {
                        count = 0;
                    }

                    if (count >= 5) return this.player;
                }
            }

            // 检查纵向是否有五子连线
            for (let j = 0; j < lineNumber; j++) {
                let count = 0;
                for (let i = 0; i < lineNumber; i++) {
                    if (board[i][j] === this.player) {
                        count++;
                    } else {
                        count = 0;
                    }

                    if (count >= 5) return this.player;

                }
            }

            // 检查右斜线是否有五子连线
            for (let i = 0; i < lineNumber - 5; i++) {
                for (let j = 0; j < lineNumber - 5; j++) {
                    let count = 0;
                    for (let k = 0; k < 5; k++) {
                        if (board[i + k][j + k] === this.player) {
                            count++;
                        } else {
                            count = 0;
                        }

                        if (count >= 5) return this.player;

                    }
                }
            }

            // 检查左斜线是否有五子连线
            for (let i = 0; i < lineNumber - 5; i++) {
                for (let j = 4; j < lineNumber; j++) {
                    let count = 0;
                    for (let k = 0; k < 5; k++) {
                        if (board[i + k][j - k] === this.player) {
                            count++;
                        } else {
                            count = 0;
                        }

                        if (count >= 5) return this.player;
                    }
                }
            }

            // 如果没有五子连线,则游戏继续
            return null;
        },
        /**
         * 重置游戏
         */
        restartGame() {
            //清空基础数据
            this.board = []
            this.player = 1
            this.winner = null
            this.restart = false
            //清空画布
            const canvas = document.getElementById("board");
            const ctx = canvas.getContext("2d");
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            //重新绘制
            this.drawBoard(this.boardDetail.width,
                this.boardDetail.lineNumber,
                this.boardDetail.space);
        },
        updateDetail(square, lineNumber) {
            //重新设置board大小
            let canvas = document.getElementById("board")
            canvas.width = square
            canvas.height = square
            //重新设置棋盘大小
            this.boardDetail = {
                width: square,
                lineNumber: lineNumber,
                space: square / lineNumber
            }
            //重新绘制游戏
            this.restartGame()
        }
    }
};
</script>

<template>
    <div class="board">
        <canvas id="board" width="600" height="600" class="board-chess"
                @click="handleClickAndDraw($event,this.boardDetail)"></canvas>
        <div class="board-detail">
            <div>
                <span>棋盘信息:</span><br>
                <span>棋盘长宽:<input v-model="this.boardDetail.width"/></span><br>
                <span>棋盘线条数:<input v-model="this.boardDetail.lineNumber"/></span><br>
                <span>棋盘间距:<input v-model="this.boardDetail.space" disabled/></span><br>
                <button @click="updateDetail(this.boardDetail.width,this.boardDetail.lineNumber)">修改</button>
            </div>
            <button @click="restartGame">重新开始</button>
            <div>当前落子:{{ this.player === 1 ? "白" : "黑" }}</div>
            <div>胜利方:{{ this.winner === 1 ? "白棋" : this.winner === 2 ? "黑棋" : "" }}</div>
        </div>
    </div>
</template>

<style scoped>
.board {
    padding: 0 0;
    margin: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.board-chess {
    border: 3px solid black;
    padding: 0 0;
    margin: 0 0;
}

.board-detail {
    margin: 0 20px;

}

.board-detail > div input {
    width: 50px;
}
</style>

效果图,测试中发现了一个bug,斜线的胜负检验逻辑有问题

最后修改:2024 年 11 月 29 日
如果觉得我的文章对你有用,请随意赞赏