JS连连看源码完美注释版(推荐)
JS连连看源码完美注释版(推荐)
发布时间:2016-12-30 来源:查字典编辑
摘要:闲来无事,也写一个javascript连连看,注释比较完整,想学的朋友可要看了。连连看最难的部分应该是路径搜索,即鼠标点的两点之间看有无可通...

闲来无事,也写一个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 = 'http://www.jb51.net';

//初始化

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教程学习
热门Javascript教程学习
编程开发子分类