JavaScript:js实现在线五子棋人机(人人)对弈

本文详细描述了如何使用HTML、CSS和JavaScript实现一个简单的在线五子棋游戏,包括棋盘绘制、用户落子交互、以及基本的AI对弈逻辑。尽管存在一些逻辑漏洞,但展示了前端开发在棋类游戏中的应用。
摘要由CSDN通过智能技术生成

在线五子棋人机对弈

全部使用前端技术,使用HTML,CSS以及JS进行实现.

棋盘在后端就是一个15*15的二维数组

页面设计

请添加图片描述

页面设计的比较粗糙

主要使用js自带的canvas画布进行绘画

HTML代码如下:

<div class="outer">
        <canvas id="canvas" height="900" width="900"></canvas>
        <div class="button">
            <div id="reset">
                <button v-on:click="reset()">重试</button>
            </div>
            <!-- <div id="check">
                <button v-on:click="check()">开始</button>
            </div> -->
            <div id="jump">
                <button v-on:click="jump()">玩家本地对战</button>
            </div>
		 </div>
</div>

CSS样式设计如下:

给canvas加了个居中和看上去像棋盘的颜色

按钮使用fixed布局跟随视口移动

#canvas {
    margin: 0 auto;
    display: block;
    margin: auto;
    background:burlywood ;
    border: 5px solid black;
    border-radius: 5px;
}

.outer {
    background: grey;
    padding: 20px;
}

.button{
    position: fixed;
    top: 100px;
    left: 100px;
}

.button button{
    color: black;
    font-size: 20px;
    background-color:powderblue
}

#reset{
    float: left;
}

#check{
    float: left;
    margin-left: 10px;
}

JS代码如下:

简而言之:就是画了一堆横线和竖线

var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        for (let index = 0; index <= 15; index += 1) {
            ctx.moveTo(0, 60 * index);
            ctx.lineTo(900, 60 * index);
            ctx.stroke()
            ctx.moveTo(60 * index, 0);
            ctx.lineTo(60 * index, 900);
            ctx.stroke()
        };

落子

效果如下

请添加图片描述

同样使用canvas进行绘画,代码如下

 canvas.addEventListener('click', e => {
            //获取坐标距离父级的偏移量
            var { offsetX, offsetY } = e;
            //边界判断 不能点击格子外面的范围
            if (offsetX < 30 || offsetY < 30 || offsetX > 870 || offsetY > 870) {
                return;
            } else if (flag === "black") {
                let x = Math.round(e.offsetX / 60) * 60;
                let y = Math.round(e.offsetY / 60) * 60;
                if (arr[y / 60][x / 60] != 0) {
                    alert("此处已有棋子")
                    return;
                }
                arr[y / 60][x / 60] = "black";
                ctx.fillStyle = '#000';
                ctx.beginPath();
                ctx.arc(x, y, 20, 0, 2 * Math.PI)
                ctx.fill();
                ctx.closePath();
                if (test()) {
                    return;
                }
                // setTimeout(
                //     () => {
                //         clear(arrai);
                //         aitest();
                //         ai();
                //     }
                //     , 100);
                flag = "white"
            } else {
                    let x = Math.round(e.offsetX / 60) * 60;
                    let y = Math.round(e.offsetY / 60) * 60;
                    if (arr[y / 60][x / 60] != 0) {
                        alert("此处已有棋子")
                        return;
                    }
                    arr[y / 60][x / 60] = "white";
                    ctx.fillStyle = '#fff';
                    ctx.beginPath();
                    ctx.arc(x, y, 20, 0, 2 * Math.PI)
                    ctx.fill();
                    ctx.closePath();
                    test();
                flag = "black";
            }
        });

给页面的鼠标点击绑了个监听事件.

画棋子也是依靠canvas实现

就是相当于先画一个圆,再往里面填颜色.

 ctx.fillStyle = '#000';
                ctx.beginPath();
                ctx.arc(x, y, 20, 0, 2 * Math.PI)
                ctx.fill();
                ctx.closePath();

判断输赢

js逻辑判断,代码如下

就是遍历棋盘,然后判断横向纵向以及斜向是否连成五子

 function test() {
            let countx = 1;
            for (let i = 0; i <= 14; i++) {
                for (let j = 0; j <= 14; j++) {
                    if (arr[i][j] !== 0 && arr[i][j] === arr[i][j + 1]) {
                        countx++;
                        if (countx == 5) {
                            alert(flag == "black" ? "黑棋获胜" : "白棋获胜");
                            setTimeout(() => location.reload(), 1000);
                            return true;
                        }
                    } else {
                        countx = 1;
                    }
                }
            }
            let county = 1;
            for (let j = 0; j <= 14; j++) {
                for (let i = 0; i <= 14; i++) {
                    if (arr[i][j] !== 0 && arr[i][j] === arr[i + 1][j]) {
                        county++;
                        if (county == 5) {
                            alert(flag == "black" ? "黑棋获胜" : "白棋获胜");
                            setTimeout(() => location.reload(), 1000);
                            return true;
                        }
                    } else {
                        county = 1;
                    }
                }
            }
            let countob = 1;
            let orii = 0;
            let orij = 0;
            for (let i = 0; i <= 14; i++) {
                for (let j = 0; j <= 14; j++) {
                    if (arr[i][j] === arr[i + 1][j + 1]) {
                        orii = i;
                        orij = j;
                        while (1 <= i <= 14 && j <= 14) {
                            if (arr[i][j] === arr[i + 1][j + 1] && arr[i][j] !== 0) {
                                countob++;
                                // console.log(countob);
                                i++;
                                j++;
                                if (countob == 5) {
                                    alert(flag == "black" ? "黑棋获胜" : "白棋获胜");
                                    setTimeout(() => location.reload(), 1000);
                                    return true;
                                }
                            } else {
                                break;
                            }
                        }
                        i = orii;
                        j = orij;
                        countob = 1;
                    }
                }
            }
            let countob1 = 1;
            let orii1 = 0;
            let orij1 = 0;
            for (let i = 1; i <= 14; i++) {
                for (let j = 0; j <= 14; j++) {
                    if (arr[i][j] === arr[i + 1][j - 1]) {
                        orii = i;
                        orij = j;
                        while (i <= 14 && 1 <= j <= 14) {
                            if (arr[i][j] === arr[i + 1][j - 1] && arr[i][j] !== 0) {
                                countob1++;
                                // console.log(countob);
                                i++;
                                j--;
                                if (countob1 == 5) {
                                    alert(flag == "black" ? "黑棋获胜" : "白棋获胜");
                                    setTimeout(() => location.reload(), 1000);
                                    return true;
                                }
                            } else {
                                break;
                            }
                        }
                        i = orii;
                        j = orij;
                        countob1 = 1;
                    }
                }
            }
            return false;
        }
到此为止,五子棋的人人对弈功能已经完全实现.

接下来是人机对弈

ai判断

逻辑就是算出棋盘上己方的最高分位置和对方的最高分位置,进行分数相加,最终的最高分位置就是最优位置.

js逻辑,代码如下:

遍历棋盘对所有位置的所有方向进行判断,得出得分

 function aitest() {
            let sum1 = 0;
            let sum2 = 0;
            for (let i = 0; i <= 14; i++) {
                for (let j = 0; j <= 14; j++) {
                    sum1 += aitestx(i, j);
                    sum1 += aitesty(i, j);
                    sum1 += aitestobl(i, j);
                    sum1 += aitestobr(i, j);
                    flag = (flag == "black") ? "white" : "black";
                    sum2 += aitestx(i, j);
                    sum2 += aitesty(i, j);
                    sum2 += aitestobl(i, j);
                    sum2 += aitestobr(i, j);
                    flag = (flag == "black") ? "white" : "black";
                    arrai[i][j] = sum1 + sum2;
                    console.log(arrai[i][j]);
                    sum1 = 0;
                    sum2 = 0;
                }
            }
        }
横向判断
function aitestx(x, y) {
            let temp = arr[x][y];
            let deadr = false;
            let deadl = false;
            let count = 1;
            for (let i = 1; i <= 5; i++) {
                if (y + i > 14) {
                    deadr = true;
                    break;
                }
                if (arr[x][y + i] != flag) {
                    if (arr[x][y + i] != 0) {
                        deadr = true;
                    }
                    break;
                } else {
                    count++;
                }
            }
            for (let i = 1; i <= 5; i++) {
                if (y - i < 0) {
                    deadl = true;
                    break;
                }
                if (arr[x][y - i] != flag) {
                    if (arr[x][y - i] != 0) {
                        deadl = true;
                    }
                    break;
                } else {
                    count++;
                }
            }
            if (deadl == true && deadr == true) {
                return 0;
            } else {
                if (count > 5) {
                    count = 5;
                    count = 5;
                }
                return (score(count, deadl == deadr ? false : true));
            }
        }
纵向判断
function aitesty(x, y) {
            let temp = arr[x][y];
            let deadr = false;
            let deadl = false;
            let count = 1;
            for (let i = 1; i <= 5; i++) {
                if (x + i > 14) {
                    deadr = true;
                    break;
                }
                if (arr[x + i][y] != flag) {
                    if (arr[x + i][y] != 0) {
                        deadr = true;
                    }
                    break;
                } else {
                    count++;
                }
            }
            for (let i = 1; i <= 5; i++) {
                if (x - i < 0) {
                    deadl = true;
                    break;
                }
                if (arr[x - i][y] != flag) {
                    if (arr[x - i][y] != 0) {
                        deadl = true;
                    }
                    break;
                } else {
                    count++;
                }
            }
            if (deadl == true && deadr == true) {
                return 0;
            } else {
                return (score(count, deadl == deadr ? false : true));
            }
        }
斜向判断
function aitestobl(x, y) {
            let temp = arr[x][y];
            let deadr = false;
            let deadl = false;
            let count = 1;
            for (let i = 1; i <= 5; i++) {
                if (x + i > 14 || y + i > 14) {
                    deadr = true;
                    break;
                }
                if (arr[x + i][y + i] != flag) {
                    if (arr[x + i][y + i] != 0) {
                        deadr = true;
                    }
                    break;
                } else {
                    count++;
                }
            }
            for (let i = 1; i <= 5; i++) {
                if (x - i < 0 || y - i < 0) {
                    deadl = true;
                    break;
                }
                if (arr[x - i][y - i] != flag) {
                    if (arr[x - i][y - i] != 0) {
                        deadl = true;
                    }
                    break;
                } else {
                    count++;
                }
            }
            if (deadl == true && deadr == true) {
                return 0;
            } else {
                return (score(count, deadl == deadr ? false : true));
            }
        }
反斜向判断
function aitestobr(x, y) {
            let temp = arr[x][y];
            let deadr = false;
            let deadl = false;
            let count = 1;
            for (let i = 1; i <= 5; i++) {
                if (x - i < 0 || y + i > 14) {
                    deadr = true;
                    break;
                }
                if (arr[x - i][y + i] != flag) {
                    if (arr[x - i][y + i] != 0) {
                        deadr = true;
                    }
                    break;
                } else {
                    count++;
                }
            }
            for (let i = 1; i <= 5; i++) {
                if (x + i > 14 || y - i < 0) {
                    deadl = true;
                    break;
                }
                if (arr[x + i][y - i] != flag) {
                    if (arr[x + i][y - i] != 0) {
                        deadl = true;
                    }
                    break;
                } else {
                    count++;
                }
            }
            if (deadl == true && deadr == true) {
                return 0;
            } else {
                return (score(count, deadl == deadr ? false : true));
            }
        }
根据上面方法得出的连子数调用方法算出得分返回给aitest()
function score(num, dead) {
            if (dead) {
                switch (num) {
                    case 1:
                        return 1;
                    case 2:
                        return 10;
                    case 3:
                        return 50;
                    case 4:
                        return 400;
                    case 5:
                        return 500000;
                }
            } else {
                switch (num) {
                    case 1:
                        return 5;
                    case 2:
                        return 30;
                    case 3:
                        return 250;
                    case 4:
                        return 10000;
                    case 5:
                        return 500000;
                }
            }
        }
当玩家落子时,调用回调函数settimeout()调用ai落子
setTimeout(
                    () => {
                        clear(arrai);
                        aitest();
                        ai();
                    }
                    , 100);
                flag = "white"
ai()落子函数

遍历棋盘,将分数和映射到另一个二维数组

如果发现此处已有棋子则递归调用本方法.

最后在相应位置完成落子

大功告成
 function ai() {
            let max = -1;
            let maxarr = new Array(-1, -1);
            for (let i = 1; i <= 14; i++) {
                for (let j = 1; j <= 14; j++) {
                    if (max < arrai[i][j] && arr[i][j] == 0) {
                        max = arrai[i][j];
                        maxarr[0] = i;
                        maxarr[1] = j;
                    }
                }
            }
            console.log(maxarr);
            console.log(arr);
            if (arr[maxarr[0]][maxarr[1]] != 0) {
                arrai[maxarr[0]][maxarr[1]] = -1;
                ai();
                console.log("重新来过");
                return;
            }
            console.log("max:" + max);
            console.log("max数组:" + maxarr[0] + "  " + maxarr[1]);
            x = 60 * maxarr[1];
            y = 60 * maxarr[0];
            arr[maxarr[0]][maxarr[1]] = "white";
            ctx.fillStyle = '#fff';
            ctx.beginPath();
            ctx.arc(x, y, 20, 0, 2 * Math.PI)
            ctx.fill();
            ctx.closePath();
            test();
            flag = "black";
            clear(arrai);
        }

总结

一个不难的小游戏,逻辑存在一定漏洞,主要是对js也不熟悉,包括对var和let的理解等等都比较欠缺,以现在的知识储备应该是改不明白了,再多学点把这个做成线上人人对战.

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值