闲来无事,也写一个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);
}