連連看演算法的實現 收藏
圖-:
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 8, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 9, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
這是一張連連看的地圖,假設標8和9的部分是兩張相同的牌。
在陣列矩陣中,0表示沒有牌,大於1表示有牌。至於是什麼牌,那是隨機的了。
不要告訴我,你說的「布局演算法」是指怎麼把牌剛剛好放上去,那個無所謂什麼
演算法,你只要首先在地圖陣列中準備好偶數個1,在布牌時保證每種牌是偶數個
(不同種類的牌用大於1的數來表示),相應地放入每個1的位置上就可以了。
一、計算地圖上這兩張牌能不能連通(當然能了,哈哈)。
這是連連看尋路演算法的第一步。
先定義一下兩張牌能連的充分條件:
1.兩張牌是同一種。
2.兩張牌之間有一條全是0的路可以連通。
3.這一條路不能有兩個以上的拐角(corner)
滿足這三個條件,就可以認為這兩張牌是可以連的。
首先,我們依據前兩個條件來完成乙個基本的尋路演算法。
我們的目的是從8到9找出一條可以連通的路來。
那麼很明顯從8到9的第一步一其有四個方向可以選擇,分別是東,南,西,北
(e, s, w, n以中國地圖方向為標準)四個方向,在第一步中我們首先假設四
個方面沒有任何優劣,那麼我可以任意選擇乙個方向移動,那就是東面吧。
圖二:
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 8, -8, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 9, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
我從8向東移動了一步,所以到達了-8的位置,我之所以可以移到-8位置,很明顯,
是因為-8的位置上原來是乙個0,表示沒有牌阻擋。
那麼現在尋路的問題就變成了,如何從-8找連通9的路了! [page]
說到這裡應該明白了吧,好多費話,有點像娘們在說話。
所以目前的尋路演算法歸結為乙個遞迴演算法的基本問題。
先從8到找到下乙個結點-8,再用同樣的規則,從-8找到下乙個結點,比如-88。。。
圖三:
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 8, -8, -88, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 9, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
如果一直都能ok,沒有阻礙的話,最後找到了9,就算成功以,如要有一步不能走下去了,
就再退回上個結點,向別的方向發展,都不行,就再退回上級結點,再向別的方向發展,
這裡的邏輯就是遞迴的思想了。
用這樣的方法寫出來的演算法已經能在最優的情形下用了,比如從8,到-88,哈哈。
但在稍微複雜的情況下,會產生奇多的遞迴結點。p4機也跑不動啊。我試過,哈哈。
那麼第二步就是為(e,s,w,n)四個方向加權,也就是讓它們之間有乙個優先權,說白了就
是先試哪一條路。決定的法則應該有好幾個吧,比如以9號的位置來看,它處於8號的東南面,
那試路時當然應當優先選擇東面和南面,再比如9號如果牌8號的正東面,那當然是選擇正東了。
再比如,當走到-8的位置時,明顯只能再走三個方向,因為它是不能回頭的。
經過這樣的處理,遞迴演算法生成的結點數會明顯變少,會更快的找到成功的路。但效能在最壞情況
下沒有本質改變。
接下來,第三步,我們把第三個充分條件加進來,來解決根本問題。
3.這一條路不能有兩個以上的拐角(corner)
按照物件導向的思想,很自然的,我給每個在遞迴演算法中生成的位置結點加上了個corner的屬性,
來記錄這條路到目前為止拐了幾個角。
這樣一下子就好辦了啊。如果發現這個結點已經拐了兩個彎時,如果要再拐彎,或者到達9之前注定
要再增加cornor時,就果斷over,返回上級結點。
好,就說到這兒吧,不能再多說了,否則就是等於把**公開了,哈哈。
注意,要把
二、三兩步的條件綜合起來詳細規劃乙個個可能性,盡可能提早讓不可能的結點over,
這就是提高效能的關鍵吧。你的演算法預見性越強,效能就越高吧。
我們的演算法在賽揚500,256m的機器上,10萬次平均結果是一次運算花時不超過0.1毫秒,算得還不精確,速度確實很快,因為在很壞的情形下,產生的最大結點數是690幾個,這樣必然會很快的
,詳細的資料已經記不清了。
說了這麼多了,應當明白第一步連通演算法的思路了吧,我所知道的,都已經盡可能的講出來了。 [page]
這個演算法完全是自己按照連連看的特點,度身定做的。因為是一步步test出來的,所以我個人
覺得是很自然的,沒有任何高深的地方,完成後,效能也很好,這才覺得是如此的簡單。相信大家
仔細看看就能寫出自己的演算法來的吧。
二、整個地圖有沒有解???可以連通的總牌數?
這是乙個問題。
解決這個問題之前,我們先來解決提示功能(hint)就是為玩家提供提示,哪一對牌可以連
通。 我的做法是,先把整個地圖中相同牌歸到一起,用陣列也好,鍊錶也好。
像這樣,
4,4,4,4
5,5,5,5
6,6,6,6
......
然後計算比如4個4之間有哪兩對可以連,至於如何判斷能不能連,第一步演算法已經實現了吧,哈哈。
一發現有可以連的牌就退出來,告訴玩家這兩張牌可以連啊!
這就ok了。
這完全是建立在第一步演算法的基礎上實現的。
好的,hint功能可以了,
那麼,整個地圖沒有解的演算法是不是出來了?
是的,如果找不到可以hint的牌,那當然就是沒有解了!
把所有可以hint的對數記下來,就是總的可以連通數了。
至此,與連連看所有演算法有關的問題解決完畢。
第二步演算法的實現,明顯開銷要大很多,最壞情況應當會是單次連通演算法計算量的大約50倍以上
(與牌的總數量和擺的位置有關)還好在一般的伺服器上單次連通計算花的時間實在太少了,
實際執行中完全可以很流暢。以上資料都是我估計的理論值,因為實際測試時一直沒有問題,
我也懶得計算出真正比較可靠的均值了。
這一部分也是我認為可以有所改進的部分,公開出來,也希望大家能提供一些更好,更巧妙
的方法,我覺得我計算連通數和有無解的方法是比較笨的方法,幾乎是仗著基本的演算法快,一
個乙個算出來的。有沒有更好的方法呢?期待中,我也會再想想,太忙,太懶,主要是懶,覺得
可以用就行了。
連連看演算法的實現
圖 0,0,0,0,0,0,0,0,0,0 0,8,0,0,0,0,0,0,0,0 0,0,0,0,0,0,0,0,0,0 0,0,0,0,0,0,0,0,0,0 0,0,0,0,0,0,0,0,0,0 0,0,0,0,0,0,0,0,0,0 0,0,0,0,0,0,0,0,0,0 0,0,0,0,...
連連看演算法
前幾天看了下a 演算法,發現並不能實現連連看。a 演算法是尋找最短路徑的一種高效率的演算法,而連連看的路徑並不一定是最短的。連連看的路徑最多只能轉折3次,因此判斷兩點的可延伸點是否有重複的,如果有,折為0或1 可消除,如果沒有,再判斷每個延伸點的延伸點與目標點的延伸點是否有重複的,有則表示可以消除並...
連連看演算法
分類判斷法 這裡實質上是一種遞迴的思想,要判斷a與b能否通過一條有n個轉角的路徑相連,可以轉化為判斷能否找到c,c與a能直線相連,且c與b能用一條有n 1個轉角的路徑相連。若這樣的c存在,那麼a與b就可以通過一條有n個轉角的路徑相連。根據轉角數不得超過2個的規則,我們可以分為轉角數分別為0個 1個 ...