https://github.com/der3318/tos-autopath
Tower of Saviors - Path Programming among a Board of 30 Runestones
https://github.com/der3318/tos-autopath
automation pillow tower-of-saviors
Last synced: 10 months ago
JSON representation
Tower of Saviors - Path Programming among a Board of 30 Runestones
- Host: GitHub
- URL: https://github.com/der3318/tos-autopath
- Owner: der3318
- Created: 2019-07-07T14:01:14.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2019-08-12T14:34:56.000Z (almost 7 years ago)
- Last Synced: 2025-04-10T06:54:49.550Z (about 1 year ago)
- Topics: automation, pillow, tower-of-saviors
- Language: Python
- Size: 2.47 MB
- Stars: 14
- Watchers: 0
- Forks: 7
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
## 神魔之塔 - 轉珠路徑規劃
### 簡介
給定由六種、三十顆浮石組成的版面,自動分析並選定起手浮石、移動路徑並給出最終生成的版面。演算法搜尋時間約數秒,規劃的路徑步數不超過五十,期望能夠穩定達成七連擊的要求。專案包含了算法本身以及視覺化的代碼,[藍疊](https://www.bluestacks.com/tw/index.html)腳本礙於遊戲公平性不公開。
### 建置需求
|語言|[Python v3.7](https://www.python.org/downloads/)|
|:-:|:-:|
|圖像處理模組|[PIL-Pillow v6.1.0](https://pillow.readthedocs.io/en/stable/)|
|圖像讀寫模組|[imageio v2.5.0](https://imageio.github.io/)|
### 執行與測試
#### 1. 設定輸入(文檔或螢幕截圖)與輸出,其中 D L W F E H 分別代表了暗、光、水、火、木及心浮石
|`config.py`|`input.txt`|`input.jpg`|
|:-:|:-:|:-:|
||||
#### 2. 執行程式 `$python3 search.py`
|執行階段|執行完成|
|:-:|:-:|
|||
#### 3. 判讀輸出,路徑操作與版面評估已寫入 `output.txt`,另提供視覺化圖片
|`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 的路徑,移動步數也在合理的限制之內(因為手機、模擬器的訊號輸入頻率有其上限,更別提若是交由玩家來實現並轉珠),勉強符合期待。
### 參考資源
https://www.ptt.cc/bbs/PuzzleDragon/M.1405269219.A.817.html