蛇为什么不死?
蛇模型
在吃蛇游戏中,蛇每吃一个苹果,身体就会变长。当蛇碰到障碍物或自己的身体时,游戏结束。我们讨论两种平时玩的最多的蛇地图模型,无墙地图和有墙地图。顾名思义,无墙模型中的蛇在到达地图的极端边缘时,可以从地图的另一边出来。
在有墙的地图里,撞墙就会死。
在两个模型中,找到不死之蛇的关键是找到一个穿越图上所有方块的环,这样你就可以沿着这个环走,在不碰撞身体的情况下吃掉所有的苹果。
无墙地图中的不死蛇
在没有墙壁的地图中,根据地图的行数是奇数还是偶数,有不同的行走方式。
最简单的情况是行数(或列数)是偶数。假设行数为偶数,我们可以通过水平扫描找到一个遍历所有点的回路。画
当行数和列数为奇数时,上述方法不适用,但我们可以通过在第一行和第二行进行W形行走,在其余行进行水平扫描,找到一个遍历所有点的回路。画
挂图中的不死之蛇
有围墙的地图周围有一圈围墙,使得上述两种方法不能直接适用。所以我们需要在围栏内找到蛇的“圈”。
当行数为偶数时,以第一列为一个“环”,可以得到一个遍历所有格点的环。画
当行数和列数为奇数时,似乎找不到遍历所有格点的回路(未证明),但如果删除一个点,比如左上角,就可以得到遍历其他格点的回路。为了解决苹果出现在左上角的问题,我们找到两条路径,它们之间唯一的区别就是是否经过左上角的点。这两条路径可以自由切换。如图所示。只有左上角的苹果是最后一格,蛇吃了这个苹果才会进入绝境。至此,游戏判断格子已满,结束。
快速snake算法
虽然不死蛇算法最终可以遍历所有的方格,但是它的时间复杂度非常高。假设地图是n*n,那么在最坏的情况下,你每吃一个水果,就要走n ^ 2个点。因为有n 2个水果,所以需要n 4个方块才能完成游戏。在吃蛇游戏中,蛇是匀速运动的,所以时间复杂度为O(n ^ 4)。
我们发现,在不死蛇中,当蛇的长度很短时,很多路径都是不必要的。蛇要走很长的路来“消化”它们长长的身体。如果能根据蛇的体长和果实出现的位置找到一些更短的环,那么蛇吃一个果实的时间就会缩短。一个很自然的想法就是寻找一次能吃到水果的最短回路。我们提出了一种基于最小回路的短化快速Snake算法。
最小循环快速snake算法
我们发现,通过添加循环,我们可以从大蛇循环构造几个小循环。蛇可以沿着这些小回路自由进入大回路,而不会与自己的身体发生碰撞。这些小圈圈穿过水果,长度至少是蛇的长度+1(吃完水果会变长)。而且小环和大环相交的方向要一致。如图所示。
图中的灰色通道是我们添加的循环。我们发现,通过添加循环,我们可以获得一些更小的循环。绕着这些环走,蛇可以在更小的路径上吃水果。同时,蛇可以很自然地从小环走到大环(图上绿色虚线)。构造小循环的方式不是唯一的,好的构造方法可以让我们尽快吃到果子。
考虑到蛇吃完一个水果还要去下一个循环,可以在两个循环之间找到最短的路线。这条路线的最长长度是行数n。
所以吃一个水果的时间缩减为(蛇长+1+n)。通过求和,时间复杂度仍然是O(n ^ 4),但是系数降低了。