AI贪吃蛇的N种死法及通用解法

1.简要介绍:

在一个n*m的网格面板里,面板里有一些障碍物,面板周围是墙壁。起始长度为3的蛇,会通过游走不断进食豆子,每吃一个豆子,身子长度也会加1。当蛇吃完当前面板里的所有豆子后,面板会重新刷新十个豆子,且豆子不会刷新在蛇身上或障碍物上,蛇身长度越长,获胜的几率越大。蛇的行走方向只能是上,下,左,右,每次行进一格,且蛇身除了蛇尾一小格,均视为障碍物。易得知,随着蛇身长度增加,暴毙概率也会大大增加,下面会列出一些小编考虑到的一些情况,并给出相应解法,如果大家有其它想法,欢迎大家留言讨论哦!
在这里插入图片描述在这里插入图片描述 蛇的死法千千万万,自己成环暴毙,对方蛇围堵暴毙,障碍物阻挡暴毙。。。
图中一共列出了蛇的十一种死法,当然这些只是一小部分,大部分都大同小异。本题的目的是尽可能吃到更多的食物,而前提是,蛇不能碰到障碍物(包括自身,对方蛇身,面板内固定障碍物,墙壁)。所以题目的核心问题就成了如何防止蛇暴毙的问题了。因为自身算法功底薄弱,在解决这个问题上也花了很多时间,走了很多弯路,最后也算是找到了一种通法,在这也会分享给大家。但是,与其直接告诉大家结果,我觉得更重要的是思考过程,如何一步步的靠近最终的解法,接下来就是我在写这题的思考历程。

思考一:

通过最短路径算法找到目标食物的坐标后,若给出一方向,如何判断该方向是否可行。最先想到的就是:确定蛇移动前蛇头的坐标(x,y),假设该蛇头在该方向上移动,走到了下一个,得出(x2,y2)。如果(x2,y2)的坐标位置是障碍物的话(包括自身,对方蛇身,面板内固定障碍物,墙壁),那么该方向不可走。遍历四个方向,如果满足该条件,则蛇可在该方向上行进。
在这里插入图片描述

思考二:

因为在测试过程中,出现了蛇头走死路的情况,而且频率较大,如下图所示。针对这种问题给出了解决方法,此时的蛇头如果向右走一格,代入思考一,因为该格不是障碍物,所以判定向右走可行,而走完之后便是死路。要想避免这种死法,解决的方法是“预判”。如果该蛇头在该方向上走到下一格,判断蛇头周围四个方向是否都是障碍物,如果是,那么就是图中的思路情况,那么判定该方向不可行进。
在这里插入图片描述

思考三:

现在可以排除死路口为1的情况了,那么如果是下图所示的情况呢,死路口为2,死路依旧是直线,死路口为3呢?(死路口的意思是,蛇头到死路尽头的格子数)。针对死路口成直线的情况给出通法,可以确定,如果蛇型为类似图中所示的矩形入口,且只有一条格子,蛇身形成闭合路,那么蛇往下走是必死的。
现在的问题是如何确定蛇身为如下情形,这里给出解决方法。如果蛇头正前方为障碍物,那么蛇头有两个方向可以走,往蛇头的左边,或者蛇头的右边。下面先以下图为例进行说明,如果蛇头(x,y)往下行进,那么在蛇头同列的下方,必然能找到自己身体的一部分,该部分坐标很容易确定(x2,y)。接下来判断,蛇头和该部分横坐标范围内(此处横列和直角坐标系的横列相反),纵坐标为(y-1)或(y+1)的格子是否都是自己的身体。用另一种描述来说,就是,在这个横坐标的范围内,在蛇头左右两纵列的蛇身数是否为2*(x2-x1)。如果是,那么就是该图情形,蛇头不可向该方向行进。
在这里插入图片描述

思路四:

因为上述情况确实过于特殊,如果是下图中的两个图形又该怎么办呢?经过上述的三种判定,依旧会进去,这里提前说明以下,如果封闭的空间很小,而多余的蛇身又很长的话,是不可能从里面空间盘旋几圈出来的,极限出来的情况我们暂时忽略。因为封闭的图形是不规则图形,我们不可能通过蛇身的每个部位的坐标来计算围成的面积大小,那么我们这里将问题简化以。
我们现在可以确定的是蛇头坐标和蛇头顶住的身体的坐标,可以确定该身体部位是蛇的第几个格子,这样我们就得出了围成面积的周长,通过周长来计算出围成的最大面积,如果在成环外的蛇身部分的格子数大于围成的最大面积,那么显然是不能进去的。这里可能会有人问,怎么可能每次围成的都是正规矩形,那么有些情况蛇头明明可以从环中出来,却判定不可行,不是就错过了很多蛇逃生的机会了嘛?是这样的,这时你可以通过多次测试,调整该最大面积前的系数,比如多乘个3/4,或者1/2,因题而异吧。 通过该方法,我们就规避了大部分成环的可能情况。 在这里插入图片描述

思路五:

通过测试发现,蛇身会是如下情形,如果用上述的周长来计算面积的方法,这里它会判定该蛇头可向下移动,但这里显然是死路。而且上述方法只考虑到蛇自身成环,那么如果和对方的蛇或者墙壁成环呢,是不是就没法判定了?是的,因为上述方法并没有将其他障碍物考虑在内,那么这里给出最终解法,也是我目前能想到的容错率最高的方法。
该方法的核心思想是“递归”。我们将所有障碍物(包括自身,对方蛇,固定障碍物,墙壁)全部存入新建的二维数组里,是障碍物的赋值为1,不是障碍物的赋值为0。当如图所示的蛇头往下走时,通过前面的判定,下一格一定不会时障碍物,及该格子的障碍数组里显示的是0,那么对该格子的上下左右四个方向进行递归,如果是0的话,则空格的数量加一,直到递归结束,遍历完所有为0的格,可以准确的计算出可行空间。这里有个小问题,会不会两个相邻的空格来来回回重复递归,然后空格数量一直加呢?
会的,解决方法也很简单,在创建一个路径遍历的二维数组,全部初始化为0,对已经递归过的格子,赋值1,每次递归前必须判断下一个格子的路径遍历数组的值是否为1,如果是,说明已经遍历过,如果不是,则可递归。最后比较环外蛇身的部分格子数,如果该数量远小于(也可自定系数)环内空格数,则判定可以往环内行进。
在这里插入图片描述

总结

以上是小编能想出来的容错率最小的方法了,真不容易,果然是算法不过关,干啥啥不行。大家如果还有不明白的地方,欢迎大家留言讨论哦!小编看到会一一解答的,当然如果有更好的方法,欢迎大家分享!

发布了7 篇原创文章 · 获赞 7 · 访问量 321

猜你喜欢

转载自blog.csdn.net/Achenming1314/article/details/105022418