圖-:
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
這是一張連連看的地圖,假設(shè)標8和9的部分是兩張相同的牌。
在數(shù)組矩陣中,0表示沒有牌,大于1表示有牌。至于是什么牌,那是隨機的了。
不要告訴我,你說的“布局算法”是指怎么把牌剛剛好放上去,那個無所謂什么
算法,你只要首先在地圖數(shù)組中準備好偶數(shù)個1,在布牌時保證每種牌是偶數(shù)個
(不同種類的牌用大于1的數(shù)來表示),相應(yīng)地放入每個1的位置上就可以了。
一、計算地圖上這兩張牌能不能連通(當然能了,哈哈)。
這是連連看尋路算法的第一步。
先定義一下兩張牌能連的充分條件:
1.兩張牌是同一種。
2.兩張牌之間有一條全是0的路可以連通。
3.這一條路不能有兩個以上的拐角(corner)
滿足這三個條件,就可以認為這兩張牌是可以連的。
首先,我們依據(jù)前兩個條件來完成一個基本的尋路算法。
我們的目的是從8到9找出一條可以連通的路來。
那么很明顯從8到9的第一步一其有四個方向可以選擇,分別是東,南,西,北
(e, s, w, n以中國地圖方向為標準)四個方向,在第一步中我們首先假設(shè)四
個方面沒有任何優(yōu)劣,那么我可以任意選擇一個方向移動,那就是東面吧。
圖二:
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,表示沒有牌阻擋。
那么現(xiàn)在尋路的問題就變成了,如何從-8找連通9的路了!
說到這里應(yīng)該明白了吧,好多費話,有點像娘們在說話。
所以目前的尋路算法歸結(jié)為一個遞歸算法的基本問題。
先從8到找到下一個結(jié)點-8,再用同樣的規(guī)則,從-8找到下一個結(jié)點,比如-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,就算成功以,如要有一步不能走下去了,
就再退回上個結(jié)點,向別的方向發(fā)展,都不行,就再退回上級結(jié)點,再向別的方向發(fā)展,
這里的邏輯就是遞歸的思想了。
用這樣的方法寫出來的算法已經(jīng)能在最優(yōu)的情形下用了,比如從8,到-88,哈哈。
但在稍微復(fù)雜的情況下,會產(chǎn)生奇多的遞歸結(jié)點。P4機也跑不動啊。我試過,哈哈。
那么第二步就是為(e,s,w,n)四個方向加權(quán),也就是讓它們之間有一個優(yōu)先權(quán),說白了就
是先試哪一條路。決定的法則應(yīng)該有好幾個吧,比如以9號的位置來看,它處于8號的東南面,
那試路時當然應(yīng)當優(yōu)先選擇東面和南面,再比如9號如果牌8號的正東面,那當然是選擇正東了。
再比如,當走到-8的位置時,明顯只能再走三個方向,因為它是不能回頭的。
經(jīng)過這樣的處理,遞歸算法生成的結(jié)點數(shù)會明顯變少,會更快的找到成功的路。但性能在最壞情況
下沒有本質(zhì)改變。
接下來,第三步,我們把第三個充分條件加進來,來解決根本問題。
3.這一條路不能有兩個以上的拐角(corner)
按照面向?qū)ο蟮乃枷耄茏匀坏模医o每個在遞歸算法中生成的位置結(jié)點加上了個corner的屬性,
來記錄這條路到目前為止拐了幾個角。
這樣一下子就好辦了啊。如果發(fā)現(xiàn)這個結(jié)點已經(jīng)拐了兩個彎時,如果要再拐彎,或者到達9之前注定
要再增加cornor時,就果斷over,返回上級結(jié)點。
注意,要把二、三兩步的條件綜合起來詳細規(guī)劃一個個可能性,盡可能提早讓不可能的結(jié)點OVER,
這就是提高性能的關(guān)鍵吧。算法預(yù)見性越強,性能就越高吧。
我們的算法在賽揚500,256M的機器上,10萬次平均結(jié)果是一次運算花時不超過0.1毫秒,算得還不
精確,速度確實很快,因為在很壞的情形下,產(chǎn)生的最大結(jié)點數(shù)是690幾個,這樣必然會很快的
,詳細的數(shù)據(jù)已經(jīng)記不清了。
說了這么多了,應(yīng)當明白第一步連通算法的思路了吧,我所知道的,都已經(jīng)盡可能的講出來了。
這個算法完全是自己按照連連看的特點,度身定做的。因為是一步步test出來的,所以我個人
覺得是很自然的,沒有任何高深的地方,完成后,性能也很好,這才覺得是如此的簡單。相信大家
仔細看看就能寫出自己的算法來的吧。
二、整個地圖有沒有解???可以連通的總牌數(shù)?
這是一個問題。
解決這個問題之前,我們先來解決提示功能(hint)就是為玩家提供提示,哪一對牌可以連
通。
我的做法是,先把整個地圖中相同牌歸到一起,用數(shù)組也好,鏈表也好。
像這樣,
4,4,4,4
5,5,5,5
6,6,6,6
......
然后計算比如4個4之間有哪兩對可以連,至于如何判斷能不能連,第一步算法已經(jīng)實現(xiàn)了吧,哈哈。
一發(fā)現(xiàn)有可以連的牌就退出來,告訴玩家這兩張牌可以連啊!
這就OK了。
這完全是建立在第一步算法的基礎(chǔ)上實現(xiàn)的。
好的,hint功能可以了,
那么,整個地圖沒有解的算法是不是出來了?
是的,如果找不到可以hint的牌,那當然就是沒有解了!
把所有可以hint的對數(shù)記下來,就是總的可以連通數(shù)了。
至此,與連連看所有算法有關(guān)的問題解決完畢。
第二步算法的實現(xiàn),明顯開銷要大很多,最壞情況應(yīng)當會是單次連通算法計算量的大約50倍以上
(與牌的總數(shù)量和擺的位置有關(guān))還好在一般的服務(wù)器上單次連通計算花的時間實在太少了,
實際運行中完全可以很流暢。以上數(shù)據(jù)都是我估計的理論值,因為實際測試時一直沒有問題,
我也懶得計算出真正比較可靠的均值了。
這一部分也是我認為可以有所改進的部分,公開出來,也希望大家能提供一些更好,更巧妙
的方法,我覺得我計算連通數(shù)和有無解的方法是比較笨的方法,幾乎是仗著基本的算法快,一
個一個算出來的。有沒有更好的方法呢?期待中...