利用JavaScript在网页实现八数码启发式A*算法动画效果


Posted in Javascript onApril 16, 2017

最近人工智能课老师布置了一个八数码实验,网上看到很多八数码的启发式A*算法,但是大多数都是利用C或者C++在控制台实现的,于是我用js在网页中做了一个类似的。

首先八数码就是一个九宫格,其中有一个空格,其他八个对应数字1-8,

利用JavaScript在网页实现八数码启发式A*算法动画效果

移动空格,使得最后状态为有序,如下图

利用JavaScript在网页实现八数码启发式A*算法动画效果

启发式算法是指在求解时,利用启发函数将不符合规则的解节点去掉,从而缩小问题的解空间。

A*算法是利用评价函数的启发式算法,在本例中,利用当前节点状态与最终节点状态所不同的格子数来评估节点的优劣,将优越节点储存并在之后展开,将劣质节点抛弃。

利用web实现这一点首先在html中添加九个如图所示input文本框,背景图片为数码格

利用JavaScript在网页实现八数码启发式A*算法动画效果

页面代码为

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>八数码</title>
 <style type="text/css">
 #result input{
  display: inline-block;
  font-family:"微软雅黑";
  font-size: 60px;
  font-weight: 900;
  text-align: center;
  width:100px;
  height:100px;
  background:url(images/0.png);
  background-size:cover;
 }
</style>
</head>
<body>
 <div id="result">
  <input type="text" id="r1">
  <input type="text" id="r2">
  <input type="text" id="r3"><br>
  <input type="text" id="r4">
  <input type="text" id="r5">
  <input type="text" id="r6"><br>
  <input type="text" id="r7">
  <input type="text" id="r8">
  <input type="text" id="r9"><br>
 </div>
 <button onclick="run()">求解</button>
</body>
</html>

然后利用javascript获取输入的值,并保存在二维数组中

var startArray=[[8,1,3],[0,2,4],[7,6,5]];//初始化八数码数组
   //获取输入的初始状态
   var cpic=1;
   for(var i=0;i<N;i++){
    for(var j=0;j<N;j++){
     var rid='r'+cpic++;
     var inputValue=getId(rid).value;
     if(inputValue==""){inputValue=0;}
     startArray[i][j]=parseInt(inputValue);
     getId(rid).value="";
    }
   }
var startGraph=new Graph(startArray);
var endArray=[[ 1,2,3],[ 8,0,4 ],[ 7,6,5 ]];
var endGraph=new Graph(endArray);//目标节点
evaluateGraph(startGraph,endGraph);
showGraph(startGraph);

其中Graph类是用来来保存一个状态节点相关数据:

//节点类
  var Graph = function(formData){
   this.form=formData;
   this.evalue=0;
   this.udirect=0;
   this.parent=null;
  };

实现一个showGraph()函数来显示八数码状态:

function showGraph(graph) {
   var c=1;
   for(var i=0;i<N;i++){
    for(var j=0;j<N;j++){
     var s='r'+c++;
     getId(s).style.backgroundImage="url(images/"+graph.form[i][j]+".png)";
    }
   }
  }

利用评估函数evaluateGraph()评估当前节点与目标节点的差距值

//评估函数
  function evaluateGraph(theGraph, endGraph){
   var differ = 0;//差距数
   for (var i = 0; i<N; i++)
   {
    for (var j = 0; j<N; j++)
    {
     if (theGraph.form[i][j] != endGraph.form[i][j]){differ++;}
    }
   }
   theGraph.evalue = differ;
   return differ;
  }

利用moveGraph()函数来移动并返回一个新节点:

//移动数码组
  function moveGraph(theGraph, direct){
   var HasGetBlank = 0;//是否找到空格位置
   var AbleMove = 1;//是否可移动
   var i, j, t_i, t_j;
   //查找空格坐标i,j
   for (i = 0; i<N; i++)
   {
    for (j = 0; j<N; j++)
    {
     if (theGraph.form[i][j] == 0)
     {
      HasGetBlank = 1;
      break;
     }
    }
    if (HasGetBlank == 1)
     break;
   }
   t_i = i;
   t_j = j;
   //移动空格
   switch (direct)
   {
    case 1://上
     t_i--;
     if (t_i<0)
      AbleMove = 0;//移动超过边界
     break;
    case 2://下
     t_i++;
     if (t_i >= N)
      AbleMove = 0;
     break;
    case 3://左
     t_j--;
     if (t_j<0)
      AbleMove = 0;
     break;
    case 4://右
     t_j++;
     if (t_j >= N)
      AbleMove = 0;
     break;
   }
   //Direct方向不能移动,返回原节点
   if (AbleMove == 0)
   {
    return theGraph;
   }
   //向Direct方向移动,生成新节点
   var ta=[[0,0,0],[0,0,0],[0,0,0]];
   var New_graph = new Graph(ta);
   for (var x = 0; x<N; x++)//复制数码组
   {
    for (var y = 0; y<N; y++)
    {
     New_graph.form[x][y] = theGraph.form[x][y];
    }
   }
   //交换
   New_graph.form[i][j] = New_graph.form[t_i][t_j];//交换空格和移动方向上的数字
   New_graph.form[t_i][t_j] = 0;
   return New_graph;
  }

最后是搜索函数,通过从初始节点开始一层层向下搜索,直到抵达目标节点,返回子节点,从子节点一层层向上回溯父节点,便可找到解路径:

//搜索路径
  function Search(beginGraph, endGraph){
   var g1, g2, g;
   var Step = 0;//深度
   var Direct = 0;//方向
   var i;
   var front=-1,rear=-1;
   g1=beginGraph;//初始八数码节点
   while (g1)//队列不空,从close队列中拿出一个节点
   {
    for (i = 1; i <= 4; i++){//分别从四个方向推导出新子节点
     Direct = i;
     if (Direct == g1.udirect)
      continue;//跳过屏蔽方向
     g2=moveGraph(g1,Direct);
     if (evaluateGraph(g2,g1)!=0){//数码组是否可以移动
      evaluateGraph(g1,endGraph);
      evaluateGraph(g2,endGraph);//评价新的节点
      if (g2.evalue <= g1.evalue + 1)//利用评估值判断是否为优越节点
      { //若为优,将g2的父节点指向g1
       g2.parent = g1;
       //设置屏蔽方向,防止往回推
       switch (Direct){
        case 1://上
         g2.udirect = 2;
         break;
        case 2://下
         g2.udirect = 1;
         break;
        case 3://左
         g2.udirect = 4;
         break;
        case 4://右
         g2.udirect = 3;
         break;
       }
       Qu[++rear]=g2;//把优越节点放到close队列
       if (g2.evalue == 0)//为0则搜索完成
       {
        g = g2;
        break;
       }
      }
      else{g2 = null;}//抛弃劣质节点
     }
    }
    //搜索完成,继续退出
    if (typeof g !== 'undefined')
    {
     if (g.evalue == 0)
     {
      break;
     }
    }
    Step++;//统计深度
    if (Step>Max_Step){
     alert("超过搜索深度!");
     break;}
    g1=Qu[++front];//从close队列中拿出一个节点继续下一轮展开
   }
   return g;
  }

最后将解路径节点按顺序压入堆栈,每秒弹出一个节点,显示,形成动画:

var top=-1;
   var G;
   G = Search(startGraph, endGraph);
   //解序列存入堆栈
   var P=G;
   while (P != null)
   {
    top++;
    St[top] = P;
    P = P.parent;
   }
   //动画执行
   var si=setInterval(function () {
    if (top>-1)
    {
     showGraph(St[top]);
     top--;
    }else {
     clearInterval(si);
    }
   },1000);
  }

以上所述是小编给大家介绍的利用JavaScript在网页实现八数码启发式A*算法动画效果,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的,在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JavaScript中伪协议 javascript:使用探讨
Jul 18 Javascript
JavaScript中操作字符串小结
May 04 Javascript
详解用原生JavaScript实现jQuery的某些简单功能
Dec 19 Javascript
详解angular2采用自定义指令(Directive)方式加载jquery插件
Feb 09 Javascript
MUI 解决动态列表页图片懒加载再次加载不成功的bug问题
Apr 13 Javascript
基于pako.js实现gzip的压缩和解压功能示例
Jun 13 Javascript
vue component组件使用方法详解
Jul 14 Javascript
angularjs2 ng2 密码隐藏显示的实例代码
Aug 01 Javascript
JavaScript自执行函数和jQuery扩展方法详解
Oct 27 jQuery
使用webpack打包koa2 框架app
Feb 02 Javascript
JS/CSS实现字符串单词首字母大写功能
Sep 03 Javascript
Vant+postcss-pxtorem 实现浏览器适配功能
Feb 05 Javascript
JavaScript 函数的定义-调用、注意事项
Apr 16 #Javascript
AngularJS双向绑定和依赖反转实例详解
Apr 15 #Javascript
JavaScript简单计算人的年龄示例
Apr 15 #Javascript
微信小程序 ES6Promise.all批量上传文件实现代码
Apr 14 #Javascript
微信小程序动态的加载数据实例代码
Apr 14 #Javascript
JAVA中截取字符串substring用法详解
Apr 14 #Javascript
jQuery插件FusionCharts绘制2D双折线图效果示例【附demo源码】
Apr 14 #jQuery
You might like
浅析php插件 Simple HTML DOM 用DOM方式处理HTML
2013/07/01 PHP
如何修改和添加Apache的默认站点目录
2013/07/05 PHP
php使用qr生成二维码的示例分享
2014/01/20 PHP
详解WordPress中用于更新和获取用户选项数据的PHP函数
2016/03/08 PHP
Yii实现显示静态页的方法
2016/04/25 PHP
phpStorm2020 注册码
2020/09/17 PHP
Javascript对象属性方法汇总
2013/11/21 Javascript
javascript字符串与数组转换汇总
2015/05/26 Javascript
ExtJs动态生成treepanel的Json格式
2015/07/19 Javascript
JQuery操作textarea,input,select,checkbox方法
2015/09/02 Javascript
关于 jQuery Easyui异步加载tree的问题解析
2016/12/06 Javascript
基于NodeJS+MongoDB+AngularJS+Bootstrap开发书店案例分析
2017/01/12 NodeJs
vue轮播图插件vue-awesome-swiper的使用代码实例
2017/07/10 Javascript
React Native如何消除启动时白屏的方法
2017/08/08 Javascript
Vue2.0父组件与子组件之间的事件发射与接收实例代码
2017/09/19 Javascript
Javascript 之封装(Package)
2018/09/14 Javascript
vscode 开发Vue项目的方法步骤
2018/11/25 Javascript
JS阻止事件冒泡的方法详解
2019/08/26 Javascript
JavaScript相等运算符的九条规则示例详解
2019/10/20 Javascript
node.js中 redis 的安装和基本操作示例
2020/02/10 Javascript
ES6中Promise的使用方法实例总结
2020/02/18 Javascript
vue 子组件watch监听不到prop的解决
2020/08/09 Javascript
Vue按时间段查询数据组件使用详解
2020/08/21 Javascript
vue路由切换时取消之前的所有请求操作
2020/09/01 Javascript
vue从后台渲染文章列表以及根据id跳转文章详情详解
2020/12/14 Vue.js
Python使用add_subplot与subplot画子图操作示例
2018/06/01 Python
TensorFlow的权值更新方法
2018/06/14 Python
python使用opencv实现马赛克效果示例
2019/09/28 Python
DataFrame.groupby()所见的各种用法详解
2020/06/14 Python
Homestay中文官网:全球寄宿家庭
2018/10/18 全球购物
2014初中数学教研组工作总结
2014/12/19 职场文书
2019大学生预备党员转正思想汇报
2019/06/21 职场文书
原生Js 实现的简单无缝滚动轮播图的示例代码
2021/05/10 Javascript
MySQL 8.0 之不可见列的基本操作
2021/05/20 MySQL
Python使用永中文档转换服务
2022/05/06 Python
正则表达式基础与常用验证表达式
2022/06/16 Javascript