貪吃蛇AI

貪吃蛇AI

做者:CodeNoob 轉載請標明做者和出處java


序言

前幾天在網上看到一張讓人漲姿式的圖片,這張圖片我很早之前看過,當時就以爲確定是程序實現的,只是當時還比較渣,不會算法。此次學了java也正在學算法,便打算開始實現它,說作就作,let’s do itgit

貪吃蛇

語言選擇

Java,雖然很久不用Swinggithub

最第一版本


Make it work
首先確定是先讓程序能跑,再去想算法,開始確定是在一個矩形裏不斷的隨機出現食物,而後讓蛇在不走出矩形的狀況下去吃,蛇每吃一個食物就會變長。這時問題基本就是,給你一個起點(蛇頭)和一個終點(食物),從起點找到一條可行路到達終點。這個路怎麼走呢,最簡單的就是走曼哈頓距離了.
以下圖,綠色是蛇頭藍色是蛇尾,蛇頭在去吃食物的時候是直接穿過身體的,這是最簡單的方法,先運行起來。算法

初始版本

BFS


搜索路徑的算法其實有多種,分爲盲目式搜索和啓發式搜索。其中盲目式搜索有DFS和BFS,啓發式搜索有A*和有序搜索(或者最佳優先搜索),
這裏我用的BFS,首先將蛇頭節點放入隊列,而後循環彈出隊列直到隊列爲空,爲空返回-1,沒找到路徑,每彈出一個隊列裏的節點,判斷該節點是否是食物,若是不是食物,把該節點添加到vis表說明已經走過,而且把該節點相鄰的上下左右四個節點添加到隊列裏並記錄下節點的父節點(我用的HashMap),添加時若是節點在vis表或者出了牆或者是身體節點,就不添加到隊列裏。若是是食物,返回去食物的第一步的方向,由於我是線程每刷新一次,蛇走一步。這樣每走一步就BFS找最優路徑。安全

BFS版

調了下速度因此比較快,當蛇吃完食物後發現本身沒路去吃另外出現的食物時就會GG了優化

因此不能出現食物就立馬去吃,得先判斷吃完後可否吃下一個,這裏其實能夠在隨機食物的位置時把下一個食物的位置提早隨機出來,不過這樣就有點算做弊的感受。。url

高級版


make it right
當咱們不知道下一個食物的位置時就只能模擬一條蛇去吃了,咱們派一條虛擬蛇(不畫在屏幕上)去吃,虛擬蛇吃後生成的食物也是虛擬的因此咱們不知道真實食物吃完又會在哪出現,吃完怎麼判斷是否能去吃下一個呢?
咱們能夠看最上面的吃徹底圖的能夠發現,當它吃完後能跟着尾巴走就代表是安全的,因而策略是spa

if(能吃到食物)
派虛擬蛇去吃,
if(吃完能跟着蛇尾走) 真蛇去吃
if(吃完不能跟着蛇尾) 真蛇跟着蛇尾走
else
真蛇跟着蛇尾
if(不能吃食物也不能跟着蛇尾)隨便逛逛,
高級版
而後就有較高几率出現了這種狀況,蛇頭會常常圍着蛇尾轉,這裏應該是一直圍着轉的,因爲我後來作了下優化,搞了個計數器大於多少就不跟着隊尾了,直接去吃而後就GG了。

高級進階版

解決辦法仍是得從原圖來,(原圖不知道被我看了多少遍。。)發現蛇頭在追蛇尾時我老是走的最短路徑,其實應該還能夠不那麼快走到蛇尾能夠到繞下彎去,這就不能用BFS了。因而本不肯意寫A*算法的,只好用A*算比較遠的路徑了。(爲何A*不是最遠路徑由於這個怎麼判斷多遠我是用曼哈頓距離的大小判斷遠近,實際是能夠不停繞彎走纔是最遠的,不過這樣就很差寫算法了。)線程

A*其實本質就是BFS加貪心,怎麼貪就是給當前節點周圍的四個節點先估計下哪一個離目標(食物)遠一點或近一點(咱們要找最遠路確定想遠一點),權值表示這個(遠或近的)程度,權值越大越遠,越小越近,不用像BFS那樣四個都走一遍,咱們只走權值最大的那個,就可能離遠一點。3d

具體A*算法步驟以下

//將開始節點放入open表
while(opne表不爲空){
0.在open表找F值最大的(說明離目標最遠),若是有相同咱們選的排在後面的也就是最新添加的。
1.把當前節點從開放列表刪除, 加入到封閉列表;
2.遍歷四個方向的相鄰節點
(0)若是該相鄰節點不可通行或者該相鄰節點已經在封閉列表中,則什麼操做也不執行,繼續檢驗下一個節點;
(1)若是該相鄰節點不在開放列表中,則將該節點添加到開放列表中,並將該相鄰節點的父節點設爲當前節點,同時保存該相鄰節點的G和H值
[0]當終點節點被加入到開放列表做爲待檢驗節點時, 表示路徑被找到,此時終止循環,返回方向;
(2)若是該相鄰節點在開放列表中,則判斷若經由當前節點到達該相鄰節點的G值是否大於或小於(這裏找最遠用大於)原來保存的G值,若大於或小於,則將該相鄰節點的父節點設爲當前節點,並從新設置該相鄰節點的G和H值

//當開放列表爲空,代表已無能夠添加的新節點,而已檢驗的節點中沒有終點節點則意味着路徑沒法被找到,此時也結束循環返回-1;

而後咱們換個策略

吃食物時走最近路徑
追尾巴時走最遠路徑

高級進階版
咱們發現這條小蛇終於會繞彎走啦。。因爲GIf軟件錄製不了那麼長,我分了幾個錄製了,另外三個:
1 2 3
經過最後一個結果能夠看出,因爲是隨機產生的食物,仍是有吃不到的時候,這時就只能優化食物的出現算法或調整尋路算法了。(想要吃滿全圖,能夠一直走S路就能夠了,不過這樣沒意思了)。

最後

若是對源代碼感興趣請戳我 若是有須要優化的地方的話,我想可能BFS太慢了,仍是直接全用A*或許能減小點CPU的壓力,哈哈。

相關文章
相關標籤/搜索