閒來無事,也寫一個javascript連連看,註解比較完整,想學的朋友可要看了。 連連看最困難的部分應該是路徑搜索,即滑鼠點的兩點之間看有無可通的路徑。 看過有人寫的遞歸寫法,心裡癢癢,就捉摸了一下,發現不用遞歸的情況下難度也不大。 路徑搜尋由簡到難分析,先分析一條直線上是否可直線連通,再分析一條直線上的兩點通過拐兩個彎是否可通,最後分析不在一條直線上的情況. 在IE6, IE8, firefox3.0.3下測試. 複製程式碼 程式碼複製程式碼 程式碼 JS连连看源码完美注释版<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> }<br><br><br>//以下部分为路径搜索算法部分,与表现层无关 <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 else if(p1.x==p2.x){<br> if(p1.y>p2.y){<br> var t = p1; <br> p1 = p2; }<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> if(i==p1.y){<br> continue; 🎜> 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> continif( 🎜> }<br> , 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> if( j==p1.x){<br> continue; <br> }<br> pt0 = p1;<br> pt1 = {x:j, y:ptp1. , y:p2.y};<br> pt3 = p2;<br> //若頂點不為空,則該路不通。 <br> if(!isEmpty(pt1) || !isEmpty(pt2)){<br> continue;<br> }<br> continif( 🎜> }<br> , 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>function $(id){return document.getElementById(id)}</x></y></p> <p>var t1, t2;//測試用<br>//圖片基底路徑<br>var IMG_PATH = 'http://www.jb51.net';<br>//初始化<br>function init( ){<br> //建構圖片庫<br> var imgs = new Array(30);<br> for(var i=1; i imgs[i] = 'r_ ' i '.gif';<br> }<br> tbl = $('tbl');<br> //構造table<br> for(var row=0;row<y-2> var tr=tbl.insertRow(-1);<br> for(var col=0;col<x-2> var td=tr.insertCell(-1);<br> var td=tr.insertCell(-1);<br>; }<br> //建構矩陣<br> for(var i=0; i<y i> arr[i] = new Array(X);<br> for(var j== 0; j<x j> 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> tmp[i] = 0;<br> }<br> for(var i=0; i<total i> 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 🎜> =0){<br> tmp[c] = t;<br> break;<br> }<br> )<br> }<br> } for(var j=1; j<x-1 j> arr[i][j] = tmp[c ];<br> tbl.rows[i-1].cells[j-1].innerHTML = '<img src="'%20IMG_PATH%20imgs%5Barr%5Bi%5D%5Bj%5D%5D%20'" alt="JS連連看原始碼完美註解版(推薦)_javascript技巧" >';<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> <br> img2 = el;<br> }<br> el.style.border = 'solid #3399FF 3px';<br> el = 'solid #3399FF 3px';<br> el = el.parentNodeo p1 = p2 = e1 = e2 = null;<br> }<br> var r = el.parentNode.rowIndex 1;<br> var c = el.parentNode.rowIndex 1;<br> var c = el.pcellIndex 1; ){<br> //el.childNodes[0].style.border = 'solid #ccc 3px';<br> p1 = {x:c, y:r};<br> p1 = {x:c, y:r};<br> . }<br> else{<br> p2 = {x:c, y:r};<br> e2 = el;<br> if(!equal(p1, p2)&MLe1.innerHTML) <br> var path = getPath(p1, p2);<br> if(path!=null){<br> e1.innerHTML = e2.innerHTML = '' }<br> }<br> if(t1){t1.style.backgroundColor = '';}<br>h.; <br> if(t2){t2.style.backgroundColor = '';}<br> t2 = e2;<br> img1.style.border = 'solid #orderf 3px'; p1 = p2 = e1 = e2 = img1 = img2 = null;<br> t1.style.backgroundColor = t2.style.background>}<br><br><br> js連連看完美註解版<br><br> <table id="tbl" cellspacing="0" cellpadding="0" border="1"> <br> </table> <br><br></x-1></total></total></x></y></x-2></y-2></p> </div>