下班無事,也寫一個javascript連連看,注釋比較完整,想學的朋友可要看了。
連連看最難的部分應該是路徑搜尋,即滑鼠點的兩點之間看有無可通的路徑。 看過有人寫的遞迴寫法,心裡痒痒,就捉摸了一下,發現不用遞迴的情況下難度也不大。
路徑搜尋由簡到難分析,先分析一條直線上是否可直線連通,再分析一條直線上的兩點通過拐兩個彎是否可通,最後分析不在一條直線上的情況.
在IE6, IE8, firefox3.0.3下測試過.
原創作者: http://blog.csdn.net/sunxing007
轉載請註明出處: http://blog.csdn.net/sunxing007
記得頂一下喲。
<html><br /><head><br /><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><br /><title>JS連連看源碼完美注釋版</title><br /></head><br /><style><br />table{<br />border-collapse: collapse;<br />}<br />td{<br />border: solid #ccc 1px;<br />height: 36px;<br />width: 36px;<br />cursor: pointer;<br />}<br />td img{<br /> height: 30px;<br /> width: 30px;<br /> border: solid #fff 3px;<br /> /*<br /> filter: alpha(opacity=80);<br /> -moz-opacity: 0.8;<br /> opacity: 0.8;<br /> */<br /> }</p><p></style><br /><script><br />/**<br />* js連連看完美注釋版<br />* 原創作者: sunxing007(http://blog.csdn.net/sunxing007)<br />* 轉載請註明出處<br />**/</p><p>//以下部分為路徑搜尋演算法部分,與表現層無關</p><p>//全域變數<br />var X = 16;//總行數<br />var Y = 14;//總列數<br />var types = 15;//圖形種類</p><p>//布局矩陣<br />//為了演算法方便,矩陣的第一行,第一列,最後一行,最後一列都標註為0,天然通路。<br />var arr = new Array(Y);<br />var tbl;//顯示布局的table元素</p><p>var p1 = null;//搜尋路徑用的第1個點的座標<br />var p2 = null;//搜尋路徑用的第2個點的座標<br />var e1 = null;//第1個點對應的元素<br />var e2 = null;//第2個點對應的元素</p><p>//路徑搜尋,給出兩個點,搜尋出通路<br />//通路用可連通的點表示<br />function getPath(p1, p2){<br />//開始搜尋前對p1,p2排序,使p2儘可能的在p1的右下方。<br />//這樣做可以簡化演算法<br />if(p1.x>p2.x){<br />var t = p1;<br />p1 = p2;<br />p2 = t;<br />}<br />else if(p1.x==p2.x){<br />if(p1.y>p2.y){<br />var t = p1;<br />p1 = p2;<br />p2 = t;<br />}<br />}<br />//通過分析連連看中兩點之間的位置關係,逐步由簡到難分析每一種類型<br />//第一種類型, 兩點是否在一條直線上,而且兩點之間可直線連通<br />if((onlineY(p1, p2)||onlineX(p1, p2)) && hasLine(p1, p2)){<br />status = 'type 1';<br />return [p1,p2];<br />}<br />//第二種類型, 如果兩點中任何一個點被全包圍,則不通。<br />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}) ){<br />status = 'type 2';<br />return null;<br />}<br />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}) ){<br />status = 'type 2';<br />return null;<br />}<br />//第三種類型, 兩點在一條直線上,但是不能直線串連<br />var pt0, pt1, pt2, pt3;<br />//如果都在x軸,則自左至右掃描可能的路徑,<br />//每次構造4個頂點pt0, pt1, pt2, pt3,然後看他們兩兩之間是否連通<br />if(onlineX(p1, p2)){<br />for(var i=0; i<Y; i++){<br />if(i==p1.y){<br />continue;<br />}<br />pt0 = p1;<br />pt1 = {x: p1.x, y: i};<br />pt2 = {x: p2.x, y: i};<br />pt3 = p2;<br />//如果頂點不為空白,則該路不通。<br />if(!isEmpty(pt1) || !isEmpty(pt2)){<br />continue;<br />}<br />if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){<br />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 + ')';<br />return [pt0, pt1, pt2, pt3];<br />}<br />}<br />}<br />//如果都在y軸,則自上至下掃描可能的路徑,<br />//每次構造4個頂點pt0, pt1, pt2, pt3,然後看他們兩兩之間是否連通<br />if(onlineY(p1, p2)){<br />for(var j=0; j<X; j++){<br />if(j==p1.x){<br />continue;<br />}<br />pt0 = p1;<br />pt1 = {x:j, y:p1.y};<br />pt2 = {x:j, y:p2.y};<br />pt3 = p2;<br />//如果頂點不為空白,則該路不通。<br />if(!isEmpty(pt1) || !isEmpty(pt2)){<br />continue;<br />}<br />if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){<br />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 + ')';<br />return [pt0, pt1, pt2, pt3];<br />}<br />}<br />}<br />//第四種類型, 兩點不在一條直線上。<br />//先縱向掃描可能的路徑<br />//同樣,每次構造4個頂點,看是否可通<br />for(var k=0; k<Y; k++){<br />pt0 = p1;<br />pt1 = {x:p1.x, y:k};<br />pt2 = {x:p2.x, y:k};<br />pt3 = p2;<br />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 + ')';<br />//特殊情況,如果pt0和pt1重合<br />if(equal(pt0,pt1)){<br />//如果pt2不為空白,則此路不通<br />if(!isEmpty(pt2)){<br />continue;<br />}<br />if( hasLine(pt1, pt2) && hasLine(pt2, pt3) ){<br />return [pt1, pt2, pt3];<br />}<br />else{<br />continue;<br />}<br />}<br />//特殊情況,如果pt2和pt3重合<br />else if(equal(pt2,pt3)){<br />//如果pt1不為空白,則此路不通<br />if(!isEmpty(pt1)){<br />continue;<br />}<br />if( hasLine(pt0, pt1) && hasLine(pt1, pt2) ){<br />return [pt0, pt1, pt2];<br />}<br />else{<br />continue;<br />}<br />}<br />//如果pt1, pt2都不為空白,則不通<br />if(!isEmpty(pt1) || !isEmpty(pt2)){<br />continue;<br />}<br />if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){<br />return [pt0, pt1, pt2, pt3];<br />}<br />}<br />//橫向掃描可能的路徑<br />for(var k=0; k<X; k++){<br />pt0 = p1;<br />pt1 = {x:k, y:p1.y};<br />pt2 = {x:k, y:p2.y};<br />pt3 = p2;<br />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 + ')';<br />if(equal(pt0,pt1)){<br />if(!isEmpty(pt2)){<br />continue;<br />}<br />if( hasLine(pt1, pt2) && hasLine(pt2, pt3) ){<br />return [pt1, pt2, pt3];<br />}<br />}<br />if(equal(pt2,pt3)){<br />if(!isEmpty(pt1)){<br />continue;<br />}<br />if( hasLine(pt0, pt1) && hasLine(pt1, pt2) ){<br />return [pt0, pt1, pt2];<br />}<br />}<br />if(!isEmpty(pt1) || !isEmpty(pt2)){<br />continue;<br />}<br />if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){<br />return [pt0, pt1, pt2, pt3];<br />}<br />}<br />//status='type4';<br />return null;<br />/********** end type 4 **************/<br />}</p><p>function equal(p1, p2){<br />return ((p1.x==p2.x)&&(p1.y==p2.y));<br />}</p><p>function onlineX(p1, p2){<br />return p1.y==p2.y;<br />}</p><p>function onlineY(p1, p2){<br />return p1.x==p2.x;<br />}</p><p>function isEmpty(p){<br />return (arr[p.y][p.x]==0);<br />}</p><p>function hasLine(p1, p2){<br />if(p1.x==p2.x&&p1.y==p2.y){<br />return true;<br />}<br />if(onlineY(p1, p2)){<br />var i = p1.y>p2.y?p2.y:p1.y;<br />i = i+1;<br />var max = p1.y>p2.y?p1.y:p2.y;<br />for(; i<max; i++){<br />var p = {x: p1.x, y: i};<br />if(!isEmpty(p)){<br />break<br />}<br />}<br />if(i==max){<br />return true;<br />}<br />return false;<br />}<br />else if(onlineX(p1, p2)){<br />var j = p1.x>p2.x?p2.x:p1.x;<br />j = j+1;<br />var max = p1.x>p2.x?p1.x:p2.x;<br />for(; j<max; j++){<br />var p = {x: j, y: p1.y};<br />if(!isEmpty(p)){<br />break<br />}<br />}<br />if(j==max){<br />return true;<br />}<br />return false;<br />}<br />}<br />/**<br />* js連連看完美注釋版<br />* 原創作者: sunxing007(http://blog.csdn.net/sunxing007)<br />* 轉載請註明出處<br />**/<br />//以下部分為表現層部分,包括繪圖, 初始化矩陣, 綁定滑鼠事件...<br />function $(id){return document.getElementById(id)}</p><p>var t1, t2;//測試用<br />//圖片基路徑<br />var IMG_PATH = 'http://images.cnblogs.com/cnblogs_com/sunxing007/231491/';<br />//初始化<br />function init(){<br />//構造圖片庫<br />var imgs = new Array(30);<br />for(var i=1; i<=30; i++){<br />imgs[i] = 'r_' + i + '.gif';<br />}<br />tbl = $('tbl');<br />//構造table<br />for(var row=0;row<Y-2;row++){<br />var tr=tbl.insertRow(-1);<br />for(var col=0;col<X-2;col++) {<br />var td=tr.insertCell(-1);<br />}<br />}<br />//構造矩陣<br />for(var i=0; i<Y; i++){<br />arr[i] = new Array(X);<br />for(var j=0; j<X; j++){<br />arr[i][j] = 0;<br />}<br />}<br />var total = (X-2)*(Y-2);<br />var tmp = new Array(total);//產生隨機位置用<br />for(var i=0; i<total; i++){<br />tmp[i] = 0;<br />}<br />for(var i=0; i<total; i++){<br />if(tmp[i]==0){<br />var t = Math.floor(Math.random()*types) + 1;<br />tmp[i] = t;<br />while(true){<br />var c = Math.floor(Math.random()*(total-i)) + i;<br />if(tmp[c]==0){<br />tmp[c] = t;<br />break;<br />}<br />}<br />}<br />}<br />var c = 0;<br />for(var i=1; i<Y-1; i++){<br />for(var j=1; j<X-1; j++){<br />arr[i][j] = tmp[c++];<br />tbl.rows[i-1].cells[j-1].innerHTML = '<img src="' + IMG_PATH + imgs[arr[i][j]] + '" />';<br />}<br />}<br />//綁定滑鼠事件<br /> var img1, img2;<br />document.body.onclick = function(e){<br />var el = document.all?event.srcElement:e.target;<br />if(el.parentNode.tagName!='TD'){<br />return;<br />}<br />if(!img1){<br />img1 = el;<br />}<br />else{<br />img2 = el;<br />}<br />el.style.border = 'solid #3399FF 3px';<br />el = el.parentNode;<br />if(el.innerHTML==''){<br />p1 = p2 = e1 = e2 = null;<br />}<br />var r = el.parentNode.rowIndex +1;<br />var c = el.cellIndex +1;<br />if(p1==null){<br />//el.childNodes[0].style.border = 'solid #ccc 3px';<br />p1 = {x:c, y:r};<br />e1 = el;<br />}<br />else{<br />p2 = {x:c, y:r};<br />e2 = el;<br />if(!equal(p1, p2)&&e1.innerHTML==el.innerHTML){<br />var path = getPath(p1, p2);<br />if(path!=null){<br />e1.innerHTML = e2.innerHTML = '';<br />arr[p1.y][p1.x] = arr[p2.y][p2.x] = 0;<br />}<br />}<br />if(t1){t1.style.backgroundColor = '';}<br />t1 = e1;<br />if(t2){t2.style.backgroundColor = '';}<br />t2 = e2;<br />img1.style.border = 'solid #fff 3px';<br />img2.style.border = 'solid #fff 3px';<br />p1 = p2 = e1 = e2 = img1 = img2 = null;<br />t1.style.backgroundColor = t2.style.backgroundColor = 'lightpink';<br />}<br />}<br />/**<br />* js連連看完美注釋版<br />* 原創作者: sunxing007(http://blog.csdn.net/sunxing007)<br />* 轉載請註明出處<br />**/<br />}<br /></script><br /><body onload="init();"><br />js連連看完美注釋版<br /><br />原創作者: <a href="http://blog.csdn.net/sunxing007">sunxing007</a><br /><br />Date: 2010-02-03<br /><br />轉載請註明出處:<a href="http://blog.csdn.net/sunxing007">http://blog.csdn.net/sunxing007</a><br /><br /><br /><table id="tbl" cellspacing="0" cellpadding="0" border="1"><br /></table><br /></body><br /></html>