圖-:
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的路了!
說到這里應該明白了吧,好多費話,有點像娘們在說話。
所以目前的尋路算法歸結為一個遞歸算法的基本問題。
先從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幾個,這樣必然會很快的
,詳細的數據已經記不清了。
說了這么多了,應當明白第一步連通算法的思路了吧,我所知道的,都已經盡可能的講出來了。
這個算法完全是自己按照連連看的特點,度身定做的。因為是一步步test出來的,所以我個人
覺得是很自然的,沒有任何高深的地方,完成后,性能也很好,這才覺得是如此的簡單。相信大家
仔細看看就能寫出自己的算法來的吧。
二、整個地圖有沒有解???可以連通的總牌數?
這是一個問題。
解決這個問題之前,我們先來解決提示功能(hint)就是為玩家提供提示,哪一對牌可以連
通。
我的做法是,先把整個地圖中相同牌歸到一起,用數組也好,鏈表也好。
像這樣,
4,4,4,4
5,5,5,5
6,6,6,6
......
然后計算比如4個4之間有哪兩對可以連,至于如何判斷能不能連,第一步算法已經實現了吧,哈哈。
一發現有可以連的牌就退出來,告訴玩家這兩張牌可以連啊!
這就OK了。
這完全是建立在第一步算法的基礎上實現的。
好的,hint功能可以了,
那么,整個地圖沒有解的算法是不是出來了?
是的,如果找不到可以hint的牌,那當然就是沒有解了!
把所有可以hint的對數記下來,就是總的可以連通數了。
至此,與連連看所有算法有關的問題解決完畢。
第二步算法的實現,明顯開銷要大很多,最壞情況應當會是單次連通算法計算量的大約50倍以上
(與牌的總數量和擺的位置有關)還好在一般的服務器上單次連通計算花的時間實在太少了,
實際運行中完全可以很流暢。以上數據都是我估計的理論值,因為實際測試時一直沒有問題,
我也懶得計算出真正比較可靠的均值了。
這一部分也是我認為可以有所改進的部分,公開出來,也希望大家能提供一些更好,更巧妙
的方法,我覺得我計算連通數和有無解的方法是比較笨的方法,幾乎是仗著基本的算法快,一
個一個算出來的。有沒有更好的方法呢?期待中...