利用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 相关文章推荐
同一个表单 根据要求递交到不同页面的实现方法小结
Aug 05 Javascript
Jquery Ajax学习实例4 向WebService发出请求,返回实体对象的异步调用
Mar 16 Javascript
javascript返回顶部效果(自写代码)
Jan 06 Javascript
防止xss和sql注入:JS特殊字符过滤正则
Apr 18 Javascript
动态加载JS文件的三种方法
Nov 08 Javascript
jQuery插件StickUp实现网页导航置顶
Apr 12 Javascript
jQuery Ajax中的事件详细介绍
Apr 16 Javascript
分享一个插件实现水珠自动下落效果
Jun 01 Javascript
Bootstrap源码解读导航(6)
Dec 23 Javascript
jQuery实现表格冻结顶栏效果
Aug 20 jQuery
在vue-cli的组件模板里使用font-awesome的两种方法
Sep 28 Javascript
解决nuxt 自定义全局方法,全局属性,全局变量的问题
Nov 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 reset() 函数指针指向数组中的第一个元素并输出实例代码
2016/11/21 PHP
php如何利用pecl安装mongodb扩展详解
2019/01/09 PHP
js 多种变量定义(对象直接量,数组直接量和函数直接量)
2010/05/24 Javascript
js绑定事件this指向发生改变的问题解决方法
2013/04/23 Javascript
用js提交表单解决一个页面有多个提交按钮的问题
2014/09/01 Javascript
Bootstrap选项卡与Masonry插件的完美结合
2016/07/06 Javascript
用原生JS对AJAX做简单封装的实例代码
2016/07/13 Javascript
AngularJS模块详解及示例代码
2016/08/17 Javascript
JavaScript实现瀑布流以及加载效果
2017/02/11 Javascript
jQuery插件HighCharts实现的2D条状图效果示例【附demo源码下载】
2017/03/15 Javascript
jQuery animate()实现背景色渐变效果的处理方法【使用jQuery.color.js插件】
2017/03/15 Javascript
vue.js 左侧二级菜单显示与隐藏切换的实例代码
2017/05/23 Javascript
nodejs基于mssql模块连接sqlserver数据库的简单封装操作示例
2018/01/05 NodeJs
vue-cli脚手架搭建的项目去除eslint验证的方法
2018/09/29 Javascript
JS运算符优先级与表达式示例详解
2020/09/04 Javascript
在win和Linux系统中python命令行运行的不同
2016/07/03 Python
详解Python的collections模块中的deque双端队列结构
2016/07/07 Python
对Tensorflow中权值和feature map的可视化详解
2018/06/14 Python
python实现Flappy Bird源码
2018/12/24 Python
为什么从Python 3.6开始字典有序并效率更高
2019/07/15 Python
Pycharm及python安装详细教程(图解)
2020/07/31 Python
python中pyplot基础图标函数整理
2020/11/10 Python
使用Html5实现异步上传文件,支持跨域,带有上传进度条
2016/09/17 HTML / CSS
canvas简易绘图的实现(海绵宝宝篇)
2018/07/04 HTML / CSS
英国口碑最好的的维他命胶囊品牌:Myvitamins(有中文站)
2016/12/03 全球购物
海量信息软件测试笔试题
2015/08/08 面试题
初级Java程序员面试题
2016/03/03 面试题
医药大学生求职简历的自我评价
2013/10/17 职场文书
汽车运用工程毕业生自荐信
2013/10/29 职场文书
新郎新娘婚礼答谢词
2014/01/11 职场文书
乡领导班子四风问题对照检查材料
2014/09/25 职场文书
司机岗位职责
2015/02/04 职场文书
2019生态环境保护倡议书!
2019/07/03 职场文书
详解Js模块化的作用原理和方案
2021/04/29 Javascript
Python 解决空列表.append() 输出为None的问题
2021/05/23 Python
Python内置数据结构列表与元组示例详解
2021/08/04 Python