給定由六種、三十顆浮石組成的版面,自動分析並選定起手浮石、移動路徑並給出最終生成的版面。演算法搜尋時間約數秒,規劃的路徑步數不超過五十,期望能夠穩定達成七連擊的要求。專案包含了算法本身以及視覺化的代碼,藍疊腳本礙於遊戲公平性不公開。
語言 | Python v3.7 |
---|---|
圖像處理模組 | PIL-Pillow v6.1.0 |
圖像讀寫模組 | imageio v2.5.0 |
config.py |
input.txt |
input.jpg |
---|---|---|
執行階段 | 執行完成 |
---|---|
initBoard.png |
bestBoard.png |
path[01-N].png and path.gif |
---|---|---|
這其實是一個範圍相當廣的搜尋問題,忽略斜轉的話,每個狀態都還能夠生成四個子狀態,連起始點都有三十個位置可以選擇。就算只考慮回頭之外的三個方向,二十步的移動範圍內,就有超過 3^20(三十四億)種可能。除此之外,「版面的評分」從演算法複雜度的角度來看雖是常數,但是相對「大」的常數。
撇除爆搜之外,這裡也分析了一些知名的策略。首先是線性規劃:5x6 版面的最佳解,並沒辦法保證可以從 4x6 3x6 ... 1x1 等較小的問題組合而得,因為最佳解中某一組浮石可能恰好穿過了切割的界線。此外,也不能保證可以從較少步數的最佳解推得,因為可能前面的步數都用於整理版面,在最後幾步才生成大量的 Combo。同理,Divide & Conquer 及 Prune & Search 都會面臨同樣的問題。Branch & Bound 倒是可以採用,因為一次移動最多只會生成兩個 Combo,若問題有限制最大的步數,可以在接近葉子處進行剪枝,不過,這對複雜度並沒有太大的影響,問題的難度並沒有被降低。在這個前提之下,要找出最佳解,以目前計算機的運算能力是無法做到的,故只能退而求其次在時限壓力下尋找較佳的解。
若只是尋找「較佳」的解,也許可以從子問題來進行推導。十步內最好的解,再走十步,也許是二十步內不錯的解,而二十步內不錯的解,再走十步,說不定就變成了三十步內的解。這個想法相當直觀,也滿有道理的,很少有機會是五十步的前四十步轉得亂七八糟,最後突然莫名其妙生出五到八個 Combo。當然,這裡得先定義一個版面的「好壞」該如何評估。最接近人認知的方式,就是 Combo 越高越好,此外,消除的浮石越多越好而走過的步數越短越好。照著這個邏輯,開始第一步的測試。
實際測試之後卻發現,這個作法很容易卡在四 Combo 左右,而且後面的步數幾乎都沒有任何用途。原因在於,前幾步數的解產生的 Combo 位置其實都不太好,以至於後面很難再有什麼進展,每次搜尋只有十步的 Quota,根本不可能把原本的 Combo 換個位置再弄出更好的版本。
要解決這個問題,得從「評估」的地方下手,需要多一個指標,來描述「Combo 位置」的好壞。為了不讓問題太過複雜,並降低「評估時間」的「常數大小」,這裡直接檢查版面的四個角落有沒有已完成的 Combo,並用這個指標來代表「Combo 位置」的好壞。畢竟一個長在左下角的 Combo,應該比杵在正中央的來得好一些,既不會影響後續的移動,也不需要再花心思維護。
但這項指標並不是整個搜尋階段都適用,理想的情況下,應該是路徑的越前期越需要考慮,而到了接近轉珠結尾的地方,其實也不是那麼需要在乎「Combo 位置」到底在哪。因此這裡將整個搜尋歷程拆成五個階段,每階段十步,此外,隨著階段越往後,這項指標的影響力就越降越低。重新測試之後,表現提升了許多,五、六以上的 Combo 數不再那麼少見,但仍然有改進的空間。
承上所述,演算法會將整個搜尋的歷程每十步拆作一個階段,並依據上個階段最好的版面來當作起始。不過這裡仍然少考慮了一個關鍵的要素:起始的浮石停在哪裡。舉例來說,十步的時候某個版面共有三個 Combo,但是起始的浮石正好是三個 Combo 中的其中一個。因為在階段與階段之間,並不能更換移動中的浮石,因此若繼續移動,這個 Combo 勢必會瓦解。這個意思是,這樣的版面,可能只配給予和其他兩 Combo 版面相同的分數,因為起手的那個浮石還要繼續移動。
為此,評估的代碼得多加入一項指標:起手浮石是否影響 Combo 組成。當然,這個指標同樣也只在第一到四階段適用,最後一個階段離手候將是最終的版面,不需要考慮這個要素。測試得到的結果,可以發現穩定性又更提高了一些,但七連擊以上仍需要相當的運氣。
到這裡為止,起手的浮石一直都是隨機挑選的,因為還沒有相對應的「邏輯」或是「評分方式」來決定該由哪裡下手。若是由玩家來進行,可能得考慮到會不會檔畫面、順不順手,但電腦則不需要。另外,機器的優勢在於它能夠進行「測試」。
因此,這裡就不做太多人工的介入,直接讓三十個位置進行轉珠測試,看看從哪裡開始的版面比較好,選它就是了。不過,完整的測試畢竟太花時間,若只是決定一個「不錯」的起手位置,可以考慮只走較少的步數,來看看版面的變化與好壞。
加入這個環節之後,基本上整個程序漸趨穩定,既不會需要無盡的運算能力,也能夠規劃出相對高 Combo 的路徑,移動步數也在合理的限制之內(因為手機、模擬器的訊號輸入頻率有其上限,更別提若是交由玩家來實現並轉珠),勉強符合期待。