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


    在线五子棋人机对弈

    全部使用前端技术,使用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="jump">
                    <button v-on:click="jump()">玩家本地对战button>
                div>
    		 div>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    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()
            };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    落子

    效果如下

    请添加图片描述

    同样使用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";
                }
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

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

    画棋子也是依靠canvas实现

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

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

    判断输赢

    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;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    到此为止,五子棋的人人对弈功能已经完全实现.

    接下来是人机对弈

    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;
                    }
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    横向判断
    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));
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    纵向判断
    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));
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    斜向判断
    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));
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    反斜向判断
    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));
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    根据上面方法得出的连子数调用方法算出得分返回给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;
                    }
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    当玩家落子时,调用回调函数settimeout()调用ai落子
    setTimeout(
                        () => {
                            clear(arrai);
                            aitest();
                            ai();
                        }
                        , 100);
                    flag = "white"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    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);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    总结

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

  • 相关阅读:
    Qt5.15:MinGW64位编译Oracle 19c数据库驱动及代码测试 - 安装时没有选Sources处理办法
    Netty入门--传统IO与NIO详解
    企业在什么情况下需要ERP系统?
    腾讯云轻量数据库是什么?性能如何?费用价格说明
    掌握这几个技巧,才敢称为Jenkins大神!
    lazada、shopee、速卖通、eBay、亚马逊提升排名的关键:掌握自养号测评技巧
    保姆级搭建Mysql 并进行视图可视化操作
    java专项练习(复制数组元素)
    java计算机毕业设计基于安卓Android/微信小程序的产后康复APP
    mongodb学习完整版
  • 原文地址:https://blog.csdn.net/qq_55630615/article/details/138157251