JS连连看源码完美注释版(推荐)


Posted in Javascript onDecember 09, 2013

闲来无事,也写一个javascript连连看,注释比较完整,想学的朋友可要看了。

连连看最难的部分应该是路径搜索,即鼠标点的两点之间看有无可通的路径。 看过有人写的递归写法,心里痒痒,就捉摸了一下,发现不用递归的情况下难度也不大。

路径搜索由简到难分析,先分析一条直线上是否可直线连通,再分析一条直线上的两点通过拐两个弯是否可通,最后分析不在一条直线上的情况.

在IE6, IE8, firefox3.0.3下测试过.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JS连连看源码完美注释版</title>
</head>
<style>
 table{
  border-collapse: collapse;
 }
 td{
  border: solid #ccc 1px;
  height: 36px;
  width: 36px;
  cursor: pointer;
 }
 td img{
   height: 30px;
   width: 30px;
   border: solid #fff 3px;
   /*
   filter: alpha(opacity=80);
   -moz-opacity: 0.8;
   opacity: 0.8;
   */
 }</style>
<script>
//以下部分为路径搜索算法部分,与表现层无关

//全局变量
var X = 16;//总行数
var Y = 14;//总列数
var types = 15;//图形种类
//布局矩阵
//为了算法方便,矩阵的第一行,第一列,最后一行,最后一列都标注为0,天然通路。
var arr = new Array(Y);
var tbl;//显示布局的table元素
var p1 = null;//搜索路径用的第1个点的坐标
var p2 = null;//搜索路径用的第2个点的坐标
var e1 = null;//第1个点对应的元素
var e2 = null;//第2个点对应的元素
//路径搜索,给出两个点,搜索出通路
//通路用可连通的点表示
function getPath(p1, p2){
 //开始搜索前对p1,p2排序,使p2尽可能的在p1的右下方。
 //这样做可以简化算法
 if(p1.x>p2.x){
  var t = p1; 
  p1 = p2;
  p2 = t; 
 }
 else if(p1.x==p2.x){
  if(p1.y>p2.y){
   var t = p1; 
   p1 = p2;
   p2 = t; 
  }
 }
 //通过分析连连看中两点之间的位置关系,逐步由简到难分析每一种类型
 //第一种类型, 两点是否在一条直线上,而且两点之间可直线连通
 if((onlineY(p1, p2)||onlineX(p1, p2)) && hasLine(p1, p2)){
  status = 'type 1';
  return [p1,p2];
 }
 //第二种类型, 如果两点中任何一个点被全包围,则不通。
 if( !isEmpty({x:p1.x, y:p1.y+1}) && !isEmpty({x:p1.x, y:p1.y-1}) && !isEmpty({x:p1.x-1, y:p1.y}) && !isEmpty({x:p1.x+1, y:p1.y}) ){
  status = 'type 2';
  return null;
 }
 if( !isEmpty({x:p2.x, y:p2.y+1}) && !isEmpty({x:p2.x, y:p2.y-1}) && !isEmpty({x:p2.x-1, y:p2.y}) && !isEmpty({x:p2.x+1, y:p2.y}) ){
  status = 'type 2';
  return null;
 }
 //第三种类型, 两点在一条直线上,但是不能直线连接
 var pt0, pt1, pt2, pt3;
 //如果都在x轴,则自左至右扫描可能的路径,
 //每次构造4个顶点pt0, pt1, pt2, pt3,然后看他们两两之间是否连通
 if(onlineX(p1, p2)){
  for(var i=0; i<Y; i++){
   if(i==p1.y){
    continue;
   }
   pt0 = p1;
   pt1 = {x: p1.x, y: i};
   pt2 = {x: p2.x, y: i};
   pt3 = p2;
   //如果顶点不为空,则该路不通。
   if(!isEmpty(pt1) || !isEmpty(pt2)){
    continue;
   }
   if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
    status = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')';
    return [pt0, pt1, pt2, pt3];
   }
  }
 }
 //如果都在y轴,则自上至下扫描可能的路径,
 //每次构造4个顶点pt0, pt1, pt2, pt3,然后看他们两两之间是否连通
 if(onlineY(p1, p2)){
  for(var j=0; j<X; j++){
   if(j==p1.x){
    continue; 
   }
   pt0 = p1;
   pt1 = {x:j, y:p1.y};
   pt2 = {x:j, y:p2.y};
   pt3 = p2;
   //如果顶点不为空,则该路不通。
   if(!isEmpty(pt1) || !isEmpty(pt2)){
    continue;
   }
   if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
    status = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')';
    return [pt0, pt1, pt2, pt3];
   }
  }
 }
 //第四种类型, 两点不在一条直线上。
 //先纵向扫描可能的路径
 //同样,每次构造4个顶点,看是否可通
 for(var k=0; k<Y; k++){
   pt0 = p1;
   pt1 = {x:p1.x, y:k};
   pt2 = {x:p2.x, y:k};
   pt3 = p2;
   status = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')';
   //特殊情况,如果pt0和pt1重合
   if(equal(pt0,pt1)){
    //如果pt2不为空,则此路不通
    if(!isEmpty(pt2)){
     continue;
    }
    if( hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
     return [pt1, pt2, pt3];
    }
    else{
     continue;
    }
   }
   //特殊情况,如果pt2和pt3重合
   else if(equal(pt2,pt3)){
    //如果pt1不为空,则此路不通
    if(!isEmpty(pt1)){
     continue;
    }
    if( hasLine(pt0, pt1) && hasLine(pt1, pt2) ){
     return [pt0, pt1, pt2];
    }
    else{
     continue;
    }
   }
   //如果pt1, pt2都不为空,则不通
   if(!isEmpty(pt1) || !isEmpty(pt2)){
    continue;
   }
   if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
    return [pt0, pt1, pt2, pt3];
   }
 }
 //横向扫描可能的路径
 for(var k=0; k<X; k++){
   pt0 = p1;
   pt1 = {x:k, y:p1.y};
   pt2 = {x:k, y:p2.y};
   pt3 = p2;
   status = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')';
   if(equal(pt0,pt1)){
    if(!isEmpty(pt2)){
     continue;
    }
    if( hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
     return [pt1, pt2, pt3];
    }
   }
   if(equal(pt2,pt3)){
    if(!isEmpty(pt1)){
     continue;
    }
    if( hasLine(pt0, pt1) && hasLine(pt1, pt2) ){
     return [pt0, pt1, pt2];
    }
   }
   if(!isEmpty(pt1) || !isEmpty(pt2)){
    continue;
   }
   if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
    return [pt0, pt1, pt2, pt3];
   }
 }
 //status='type4';
 return null;
 /********** end type 4 **************/
}
function equal(p1, p2){
 return ((p1.x==p2.x)&&(p1.y==p2.y));
}
function onlineX(p1, p2){
 return p1.y==p2.y;
}
function onlineY(p1, p2){
 return p1.x==p2.x; 
}
function isEmpty(p){
 return (arr[p.y][p.x]==0); 
}
function hasLine(p1, p2){
 if(p1.x==p2.x&&p1.y==p2.y){
  return true; 
 }
 if(onlineY(p1, p2)){
  var i = p1.y>p2.y?p2.y:p1.y;
  i = i+1;
  var max = p1.y>p2.y?p1.y:p2.y;
  for(; i<max; i++){
   var p = {x: p1.x, y: i};
   if(!isEmpty(p)){
    break
   }
  }
  if(i==max){
   return true;
  }
  return false;
 }
 else if(onlineX(p1, p2)){
  var j = p1.x>p2.x?p2.x:p1.x;
  j = j+1;
  var max = p1.x>p2.x?p1.x:p2.x;
  for(; j<max; j++){
   var p = {x: j, y: p1.y};
   if(!isEmpty(p)){
    break
   }
  }
  if(j==max){
   return true;
  }
  return false;
 }
}
//以下部分为表现层部分,包括绘图, 初始化矩阵, 绑定鼠标事件...
function $(id){return document.getElementById(id)}
var t1, t2;//测试用
//图片基路径
var IMG_PATH = 'https://3water.com';
//初始化
function init(){
 //构造图片库
 var imgs = new Array(30);
 for(var i=1; i<=30; i++){
  imgs[i] = 'r_' + i + '.gif';
 }
 tbl = $('tbl');
 //构造table
 for(var row=0;row<Y-2;row++){
  var tr=tbl.insertRow(-1);
  for(var col=0;col<X-2;col++) {
   var td=tr.insertCell(-1);
  }
 }
 //构造矩阵
 for(var i=0; i<Y; i++){
  arr[i] = new Array(X);
  for(var j=0; j<X; j++){
   arr[i][j] = 0;
  }
 }
 var total = (X-2)*(Y-2);
 var tmp = new Array(total);//产生随机位置用
 for(var i=0; i<total; i++){
  tmp[i] = 0;
 }
 for(var i=0; i<total; i++){
  if(tmp[i]==0){
   var t = Math.floor(Math.random()*types) + 1;
   tmp[i] = t;
   while(true){
    var c = Math.floor(Math.random()*(total-i)) + i;
    if(tmp[c]==0){
     tmp[c] = t;
     break;
    }
   }
  }
 }
 var c = 0;
 for(var i=1; i<Y-1; i++){
  for(var j=1; j<X-1; j++){
   arr[i][j] = tmp[c++];
   tbl.rows[i-1].cells[j-1].innerHTML = '<img src="' + IMG_PATH + imgs[arr[i][j]] + '" />';
  } 
 }
 //绑定鼠标事件
  var img1, img2;
 document.body.onclick = function(e){
  var el = document.all?event.srcElement:e.target;
  if(el.parentNode.tagName!='TD'){
   return;
  }
  if(!img1){
   img1 = el;
  }
  else{
   img2 = el;
  }
  el.style.border = 'solid #3399FF 3px';
  el = el.parentNode;
  if(el.innerHTML==''){
   p1 = p2 = e1 = e2 = null;
  }
  var r = el.parentNode.rowIndex +1;
  var c = el.cellIndex +1;
  if(p1==null){
   //el.childNodes[0].style.border = 'solid #ccc 3px';
   p1 = {x:c, y:r};
   e1 = el;
  }
  else{
   p2 = {x:c, y:r};
   e2 = el;
   if(!equal(p1, p2)&&e1.innerHTML==el.innerHTML){
    var path = getPath(p1, p2);
    if(path!=null){
     e1.innerHTML = e2.innerHTML = '';
     arr[p1.y][p1.x] = arr[p2.y][p2.x] = 0;
    }
   }
   if(t1){t1.style.backgroundColor = '';}
   t1 = e1;
   if(t2){t2.style.backgroundColor = '';}
   t2 = e2;
   img1.style.border = 'solid #fff 3px';
   img2.style.border = 'solid #fff 3px';
   p1 = p2 = e1 = e2 = img1 = img2 = null;
   t1.style.backgroundColor = t2.style.backgroundColor = 'lightpink';
  }
 }
}
</script>
<body onload="init();">
 js连连看完美注释版<br />
 <table id="tbl" cellspacing="0" cellpadding="0" border="1">
 </table>
</body>
</html>
Javascript 相关文章推荐
document.open() 与 document.write()的区别
Aug 13 Javascript
自动完成JS类(纯JS, Ajax模式)
Mar 12 Javascript
javascript 拖放效果实现代码
Jan 22 Javascript
GitHub上一些实用的JavaScript的文件压缩解压缩库推荐
Mar 13 Javascript
JavaScript 弹出子窗体并返回结果到父窗体的实现代码
May 28 Javascript
Bootstrap时间选择器datetimepicker和daterangepicker使用实例解析
Sep 17 Javascript
JS实现的驼峰式和连字符式转换功能分析
Dec 21 Javascript
BootStrap Table后台分页时前台删除最后一页所有数据refresh刷新后无数据问题
Dec 28 Javascript
JS身份证信息验证正则表达式
Jun 12 Javascript
jQuery简单判断值是否存在于数组中的方法示例
Apr 17 jQuery
JavaScript实现的拼图算法分析
Feb 13 Javascript
在Layui中操作数据表格,给指定单元格添加事件示例
Oct 26 Javascript
解析Javascript中难以理解的11个问题
Dec 09 #Javascript
深入理解Javascript作用域与变量提升
Dec 09 #Javascript
Javascript全局变量var与不var的区别深入解析
Dec 09 #Javascript
jquery div拖动效果示例代码
Dec 08 #Javascript
jquery垂直公告滚动实现代码
Dec 08 #Javascript
jquery中交替点击事件toggle方法的使用示例
Dec 08 #Javascript
JavaScript 判断用户输入的邮箱及手机格式是否正确
Dec 08 #Javascript
You might like
PHP执行速率优化技巧小结
2008/03/15 PHP
PHP中替换换行符的几种方法小结
2012/10/15 PHP
destoon切换城市后实现logo旁边显示地区名称的方法
2014/08/21 PHP
PHP PDOStatement对象bindpram()、bindvalue()和bindcolumn之间的区别
2014/11/20 PHP
php使用Jpgraph绘制饼状图的方法
2015/06/10 PHP
PHP的Yii框架中使用数据库的配置和SQL操作实例教程
2016/03/17 PHP
PHP将MySQL的查询结果转换为数组并用where拼接的示例
2016/05/13 PHP
PHP fopen函数用法实例讲解
2019/02/15 PHP
javascript学习笔记(十三) js闭包介绍(转)
2012/06/20 Javascript
中文字符串截取的js函数代码
2013/04/17 Javascript
js判断undefined变量类型使用typeof
2013/06/03 Javascript
JavaScript函数模式详解
2014/11/07 Javascript
jquery实现定时自动轮播特效
2015/12/10 Javascript
详解Matlab中 sort 函数用法
2016/03/20 Javascript
新入门node.js必须要知道的概念(必看篇)
2016/08/10 Javascript
jQuery 获取select选中值及清除选中状态
2016/12/13 Javascript
文件上传的几个示例分享【推荐】
2016/12/16 Javascript
使用nodejs下载风景壁纸
2017/02/05 NodeJs
利用Node.js编写跨平台的spawn语句详解
2017/02/12 Javascript
Vue中jsx不完全应用指南小结
2019/11/01 Javascript
VUE 实现动态给对象增加属性,并触发视图更新操作示例
2019/11/29 Javascript
[31:47]夜魇凡尔赛茶话会 第三期01:选手知多少
2021/03/11 DOTA
Python3中多线程编程的队列运作示例
2015/04/16 Python
详解Python的Django框架中的模版继承
2015/07/16 Python
利用python实现汉字转拼音的2种方法
2019/08/12 Python
Python3.7基于hashlib和Crypto实现加签验签功能(实例代码)
2019/12/04 Python
Python-jenkins模块获取jobs的执行状态操作
2020/05/12 Python
Python爬虫如何应对Cloudflare邮箱加密
2020/06/24 Python
JD Sports德国官网:英国领先的运动鞋和运动服饰零售商
2018/02/26 全球购物
介绍一下Java中标识符的命名规则
2014/02/03 面试题
校园联欢晚会主持词
2014/03/17 职场文书
二手房买卖协议书
2014/04/10 职场文书
借款协议书
2014/04/12 职场文书
信用卡逾期证明示例
2014/09/13 职场文书
党员剖析材料范文
2014/09/30 职场文书
html,css,javascript是怎样变成页面的
2023/05/07 HTML / CSS