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="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的理解等等都比较欠缺,以现在的知识储备应该是改不明白了,再多学点把这个做成线上人人对战.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/569843.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

男生一般穿什么裤子好看?五大爆款男装精选测评!

男生裤子要怎么选才能找到适合自己的裤子呢&#xff1f;这肯定是大家选裤子时经常出现的一个疑问了&#xff0c;现在的市面上虽然款式风格非常多&#xff0c;但是由于品牌鱼龙混杂的原因&#xff0c;不同的裤子质量也参差不齐。为了帮助各位男同胞能选到适合自己的裤子&#xf…

centos7使用源码安装方式redis

安装编译源码的工具gcc yum install -y gcc下载源码 源码下载地址 https://download.redis.io/releases/ 注意事项 不建议安装最新版本redis&#xff0c;所以我这里选择6.2.6版本 下载 wget https://download.redis.io/releases/redis-6.2.6.tar.gz解压 tar -zxvf redis-…

工业相机和镜头参数和选型

工业相机和镜头参数和选型 文章目录 工业相机和镜头参数和选型前言一、相机参数解释和选型1.相机参数1.1快门-shutter1.2曝光-exposure1.3增益-gain1.4 感光芯片类型&#xff08;CCD/CMOS&#xff09;1.5 感光芯片&#xff08;靶面&#xff09;尺寸1.6 分辨率1.7 像元尺寸1.8 帧…

【点量云流】国内首家适配国产信创的实时云渲染解决方案,助力国产化信创新体验!

一、背景 随着信息技术的广泛应用&#xff0c;信息安全与自主可控成为国家发展的重要保障。近年来&#xff0c;国产化信创的发展&#xff0c;为推动信息技术产业自主创新&#xff0c;实现关键技术和产品的自主可控&#xff0c;对于保障国家信息安全、促进产业发展有着重要意义。…

程序员英语之Spring篇

spring.io/quickstart 本期课程讲解Spring官网的快速上手页面 官网地址 https://spring.io/quickstart Spring Quickstart Guide Spring 快速开始指南 Guide 指南 What you’ll build 接下来你将要构建的是什么&#xff1f; build 构建 You will build a classic “H…

Laravel 6 - 第十二章 控制器

​ 文章目录 Laravel 6 - 第一章 简介 Laravel 6 - 第二章 项目搭建 Laravel 6 - 第三章 文件夹结构 Laravel 6 - 第四章 生命周期 Laravel 6 - 第五章 控制反转和依赖注入 Laravel 6 - 第六章 服务容器 Laravel 6 - 第七章 服务提供者 Laravel 6 - 第八章 门面 Laravel 6 - …

计算机网络4——网络层1

文章目录 一、网络层1、概念2、网络层的两个层面1&#xff09;介绍2&#xff09;问题3&#xff09;解决 二、网际协议IP1、介绍2、虚拟互联网络1&#xff09;介绍2&#xff09;案例 3、IP地址1&#xff09;IP 地址及其表示方法2&#xff09;分类的IP地址3&#xff09;无分类编址…

FineVis助力智慧水务:水务可视化智能决策与管理

一、智慧水务是什么 智慧水务是利用数采仪、无线网络、水质水压表等在线监测设备实时感知城市供排水系统的运行状态&#xff0c;以及采用可视化方式整合水务管理部门与供排水设施&#xff0c;形成“城市水务物联网”的创新管理模式。通过这一系统&#xff0c;海量水务信息可以…

慧明咨询:成绩公式,发现未知,助力进步

在当今社会,数以万计的学子面临着激烈的教育竞争。2000万的中考生、1000万的高考生、300万的考研生以及500万的国考备考者,都在为了通过这“独木桥”而战。 面对有限的优质学区、师资力量的不足、以及巨大的心理压力,学生及其家长们焦虑不已。为此,深圳市慧明咨询顾问有限公司…

CentOS-7安装clickhouse并允许其他主机登录

一、通用设置 1、配置主机名 hostnamectl set-hostname --static 主机名2、修改hosts文件 vim /etc/hosts 输入&#xff1a; 192.168.15.129 master 192.168.15.133 node1 192.168.15.134 node2 192.168.15.136 node33、 保持服务器之间时间同步 yum install -y ntpdate &…

【性能测试】ChaosTesting(混沌测试)ChaosBlade(混沌实验工具)(五)-jvm混沌实验

6. chaosblade-jvm实验场景 6.1 挂载 java agent blade prepare jvm 6.1.1 介绍 挂载 java agent&#xff0c;执行 java 实验场景必要步骤 6.1.2 参数 -j, --javaHome string&#xff1a; 指定 JAVA_HOME 路径&#xff0c;用于指定 java bin 和 tools.jar&#xff0c;如果…

《HCIP-openEuler实验指导手册》1.1Apache安装与测试

一、安装httpd 查看软件仓库中apache版本列表 dnf provides http 安装apache dnf install -y httpd 二、启动http并测试 查看apache版本号 httpd -v 检查配置文件是否正确 httpd -t 将如下97行取消注释消除报错 重新测试配置文件 httpd -t 启动并设置为开机启动 syste…

QT中对于QPushButton样式的调整

文章目录 前言1.QPushButton1.1 新建项目导入资源1.2 添加Push Button并定义样式1.3 调整样式1.4 实际需求情况1.5 背景色和边框 2. 一些概念理解2.1 图片2.2 边距 总结 前言 前段时间在调软件的样式&#xff0c;学到了些新的东西&#xff0c;也碰到了些问题&#xff0c;这里做…

光纤、以太网电缆和 DSL 的比较:技术指南

了解光纤、以太网电缆和 DSL 之间的差异对于做出有关互联网连接的明智决策至关重要。本技术指南对这些技术进行了全面比较&#xff0c;讨论了它们的独特功能、性能指标和应用。它旨在为您提供必要的知识&#xff0c;以选择最适合您的特定需求的选项。 光纤、以太网电缆和 DSL …

汇编期末复习知识点

参考文献1 第一章 概述 组成 计算机系统由硬件子系统和软件子系统组成。硬件子系统&#xff1a;组成计算机系统的所有电子的&#xff0c;机械的&#xff0c;光学的和磁性的元部件。 计算机中常用进制数表示 十进制(Decimal):数据尾部加一后缀D&#xff0c;如2355D二进制&a…

FANUC机器人socket通讯硬件配置

一、添加机器人选配包 Fanuc机器人要进行socket通讯&#xff0c;需要有机器人通讯的选配包&#xff0c;1A05B-2600-R648 User Socket Msg&#xff0c;1A05B-2600-R632 KAREL&#xff0c;1A05B-2600-R566 KAREL Diagnostic&#xff0c;1A05B-2600-J971 KAREL Use Sprt FCTN。 二…

初学python,怎样入门?

答案&#xff1a;乌龟绘图。 "乌龟绘图"通常指的是使用Logo语言的变种——Python中的turtle模块来进行图形绘制。在turtle模块中&#xff0c;一只名为“海龟”&#xff08;Turtle&#xff09;的小动物会在屏幕上移动&#xff0c;根据其行进路径来绘制图形。以下是一段…

音视频直播原理解析

直播原理就是一个推流和拉取流的过程&#xff1b; 直播端将直播流推送至服务器&#xff0c;用户端发起请求从服务器拉取直播流然后解码播放 第一部分就是视频直播端的操作&#xff1a;视频采集处理后推流到流媒体服务器。 首先从前端采集设备中获得原始的音频、视频数据&…

Vue页面生成导出PDF文件

第一种&#xff1a; 使用浏览器自带打印方法window.print(); 也可使用print-js插件&#xff08;原理相同&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>printDemo</title> </…

助力24五一杯数学建模比赛

完成助力美赛建模&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 完成助力妈妈杯建模&#xff01;&#xff01;&#xff01;&#xff01; 完成助力华中杯建模&#xff01;&#xff01;&#xff01;&#xff01; 这边将在开赛后24小时内发布资料和初步思路 需…