AI 貪喫蛇

之前在qq空間、朋友圈和微博裝逼,現在要來實現了。
原因是因爲一張很早的貪喫蛇喫遍全圖的gif,很是華麗,然後當時就感覺這應該是程序實現的,怎麼說呢,雖然是數學專業的高材生(自封的),但當時才大二,對一些最優化算法並不是特別瞭解,而且編程能力還很渣,所以當初也沒有還原這個東西的想法。

現在偶然間又看到這張圖,正好手頭的工作都幹完了,所以有了嘗試實現的想法。因爲工作用的Java麼,爲了省事,就直接選擇了熱咖啡(聽說最近麥當勞改名叫金拱門0.0),正好以前也研究過swing。出於時間原因(加班狗傷不起),而且這次主要關注的是算法,遊戲框架就沒有自己寫,直接使用了某Java實現的貪喫蛇遊戲做了修改,因爲這些代碼是學生時代不知從哪扒的,所以原作者已經不可考了,但是還要感謝原作者的貢獻。

貪喫蛇AI這個東西,在我之前應該已經有很多人搞過。感覺原圖就是個大神,至今我仍然沒有發現他是使用什麼方式實現的。在網上找到過幾篇有關的帖子,某個同學(可能是是很多同學)用BFS寫了一個,參見http://t.cn/RSdtCdF。在我看來BFS是個不錯的策略,然而跑了一下代碼發現這種方式並跑不完全圖,但是可以讓蛇多撐一會。。。還有某位同志用py寫了一個,然而py我對他的庫瞭解不深,沒看懂,只是扒下來跑了一下,發現這種算法在小概率條件下能跑完全圖,但是更多的情況是蛇在繞着一條路線兜圈子。

一開始我的想法是把問題抽象成無向的最短路問題,印象比較深刻的有dijkstra算法和floyd算法,然而實現之後,就發現了問題,在尋路中,要計算蛇頭與食物的最短路徑,並且要躲避蛇身與牆壁,所以我定義蛇身與牆壁的距離爲無窮大。使用簡單的最短路計算時(這應該是一個貪心法),只會考慮當前蛇頭距食物的最短距離,而當蛇喫掉食物時,往往會讓自己陷入某些不好的情景: 
1.蛇身被困在某個與食物(下一個食物)不連通的一個封閉區域裏,因爲周圍都是無窮大,所以蛇找不到食物的位置,不知道往哪走了,這種情況就只能GG了.
2蛇能找到食物,但是喫完實物後會陷入死路無處可走,這種情況下有經驗的玩家一般會選擇繞一繞的思路給蛇騰開位置,但是‘貪心’的蛇不會考慮下一步的路徑,於是也GG了。

所以,實踐證明只用最短路是不行的,以爲隨着蛇的移動地圖的形勢在變化,受到上面同學的啓發,可以發現蛇追着尾巴走可以保證是安全的,因爲蛇尾隨着移動總會留出空間。

接下來設計算法,因爲形勢比較複雜,所以每次只讓蛇走一步。這裏做一個簡單的判斷。最開始我們先用最短路讓程序跑起來,蛇按貪心法走的思路如下
if(沒死){
最短路向是食物移動一步
}else{GG}
當然,我們知道這樣一定會GG,然後,根據我們之前的思路,每走一步都算下蛇頭到食物的路徑,有的話就去喫食物,沒有的話就去追蛇尾。但是有些特殊情況蛇頭到蛇尾和食物都找不到路徑,這裏就要參考一下經典的遊戲邏輯,採用wander的策略,就是讓蛇頭在可行範圍內隨機移動,再去嘗試尋找路徑。
if(蛇頭到食物有路徑){
	if(蛇頭到達食物後能找到走到蛇尾的路徑){
	蛇去喫食物
	}else{
	跟着蛇尾走
	}
}else{
沿着尾巴走
}

     然後這樣又出現了另一種情況,到達一定長度後,蛇頭貌似會一直追蛇尾,從而會來回循環的轉,這樣雖然沒有GG,那也就一直死循環了。到這裏腦子就有點不夠用了。
這裏其實還有一種取巧的辦法,就是讓蛇沿着一條始終可以遍歷整個地圖的路徑來回運動,比如可以讓蛇沿s形運動,然後一側留下一條路逃生,喫完後再繞回來始終這樣走,就可以保證始終不死還可以喫到食物,不過這樣就沒多大意思了。
後來,發現業界的尋路算法中,A*這種啓發式算法用的比較廣泛,然後簡單瞭解了一下,(這裏可以看一下前輩的東西A*算法),然後受到啓發,蛇不一定總要走最短路,蛇在追蛇尾的時候可以走最遠路,這樣的話可以儘量把格子空出來,於是採用了
if(追食物){
走最短路
}
if(追蛇尾){
走最遠路
}

 這裏走最遠路使用的A*,其實走最短路也可以用A*的,不過前邊用了BFS和其他的幾種,懶得寫了。
 然後,我發現還有更坑爹的,(本來不想傳圖片的,因爲麻煩0-0),看圖發現,這樣走會留下很多洞,一開始還沒有多大問題,往後走就會發現這些洞會給蛇造成很大的困擾,中期會讓蛇多走很多路,到後期就可能陷入很不利的環境。這裏給句媽賣批,我都想去改食物出現的算法了。然而這樣太沒意思,還不如讓蛇一直走s跑完全圖。


      沒有辦法,還得去想辦法,自己裝的b含着淚也要裝完。然後就要去想解決方案,要想不留下洞,走的時候就要儘可能多的繞,儘量把空白堆滿,使用分支定界等方法給出了好幾種策略,發現後期還是不可避免的出現了空格,這是就想到了既然s形可以走遍全圖,那麼走到後期時,我們不如就無腦s形繞,反而要比最短路還快一些(發現這裏邊還有一定的哲學道理,應了中國一句老話,欲速則不達,有時候找捷徑還不如踏踏實實按部就班往前走)。
於是我們判斷,當蛇身的格子數佔到地圖的一半後,我們就看做進入後期,這時開始繞。
 雖然還是沒有大神的圖瀟灑,但總算能跑完。代碼在github持續更新,有興趣或有其他思路的朋友可以交流下。


歡迎評論和點贊,如果能去github給個star就更好了。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章