做者:CodeNoob 转载请标明做者和出处java
前几天在网上看到一张让人涨姿式的图片,这张图片我很早之前看过,当时就以为确定是程序实现的,只是当时还比较渣,不会算法。此次学了java也正在学算法,便打算开始实现它,说作就作,let’s do itgit
Java,虽然很久不用Swinggithub
Make it work
首先确定是先让程序能跑,再去想算法,开始确定是在一个矩形里不断的随机出现食物,而后让蛇在不走出矩形的状况下去吃,蛇每吃一个食物就会变长。这时问题基本就是,给你一个起点(蛇头)和一个终点(食物),从起点找到一条可行路到达终点。这个路怎么走呢,最简单的就是走曼哈顿距离了.
以下图,绿色是蛇头蓝色是蛇尾,蛇头在去吃食物的时候是直接穿过身体的,这是最简单的方法,先运行起来。算法
搜索路径的算法其实有多种,分为盲目式搜索和启发式搜索。其中盲目式搜索有DFS和BFS,启发式搜索有A*和有序搜索(或者最佳优先搜索),
这里我用的BFS,首先将蛇头节点放入队列,而后循环弹出队列直到队列为空,为空返回-1,没找到路径,每弹出一个队列里的节点,判断该节点是否是食物,若是不是食物,把该节点添加到vis表说明已经走过,而且把该节点相邻的上下左右四个节点添加到队列里并记录下节点的父节点(我用的HashMap),添加时若是节点在vis表或者出了墙或者是身体节点,就不添加到队列里。若是是食物,返回去食物的第一步的方向,由于我是线程每刷新一次,蛇走一步。这样每走一步就BFS找最优路径。安全
调了下速度因此比较快,当蛇吃完食物后发现本身没路去吃另外出现的食物时就会GG了优化
因此不能出现食物就立马去吃,得先判断吃完后可否吃下一个,这里其实能够在随机食物的位置时把下一个食物的位置提早随机出来,不过这样就有点算做弊的感受。。url
make it right
当咱们不知道下一个食物的位置时就只能模拟一条蛇去吃了,咱们派一条虚拟蛇(不画在屏幕上)去吃,虚拟蛇吃后生成的食物也是虚拟的因此咱们不知道真实食物吃完又会在哪出现,吃完怎么判断是否能去吃下一个呢?
咱们能够看最上面的吃彻底图的能够发现,当它吃完后能跟着尾巴走就代表是安全的,因而策略是spa
if(能吃到食物)
派虚拟蛇去吃,
if(吃完能跟着蛇尾走) 真蛇去吃
if(吃完不能跟着蛇尾) 真蛇跟着蛇尾走
else
真蛇跟着蛇尾
if(不能吃食物也不能跟着蛇尾)随便逛逛,
解决办法仍是得从原图来,(原图不知道被我看了多少遍。。)发现蛇头在追蛇尾时我老是走的最短路径,其实应该还能够不那么快走到蛇尾能够到绕下弯去,这就不能用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;
而后咱们换个策略
吃食物时走最近路径
追尾巴时走最远路径
若是对源代码感兴趣请戳我 若是有须要优化的地方的话,我想可能BFS太慢了,仍是直接全用A*或许能减小点CPU的压力,哈哈。