如何在C上的蛇游戏中产生随机食物?

时间:2019-03-26 17:20:22

标签: c

我正在尝试使用C创建蛇游戏。

我正在寻找一种有效的算法来产生随机的食物位置。

这是我当前的generateFood()函数算法:

  1. 生成随机食物坐标
  2. 坐标在蛇头上||正文:
  3. 生成新的随机食物坐标

该算法适用于游戏的前半部分,但是当蛇开始变大时。 随机获得一个坐标以最终获得一个自由点将花费更长的时间,而且非常不一致。

我正在考虑将所有空坐标放入链表中 并随机移动步长以达到坐标。并会相应地更新为蛇坐标,以便在第一次运行时可以生成随机食物。

但是我发现这种方法不必要地复杂并且 可能会占用大量内存和时间。

还有其他方法可以使我在C上更有效地做到这一点吗?

3 个答案:

答案 0 :(得分:1)

可能解决问题的一种方法是:

randomCell

此方法一个接一个地遍历该单元,直到它遍历了{{1}}个单元为止,不计算蛇所占据的单元。

也许这不是最好的算法,但是至少运行时间是可以预测的。当蛇很小时,它肯定会比当前算法慢,但有可能能够足够快地处理它。当然,这在很大程度上取决于细胞数量。

如果您拥有300x300的网格(一个非常大型的蛇游戏),那么您将拥有近100000个单元格。检查一个单元是否被占用最多应该可以在200ns内完成。我假设发生高速缓存未命中的情况,这种情况很少发生。 200ns * 100000 = 0.02s。足以达到50fps。

请注意,我非常悲观。 200ns很长。当您访问内存时,通常在50到100之间。但是实际上,L2缓存中将始终有100000个单元的网格,其典型访问时间为20ns。如果将大小减小到200x200,则整个网格很可能适合L1缓存,该缓存的访问时间约为1ns。因此,对于200x200的网格,此方法可以产生25000fps。您需要更多还是足够? ;)

但是我可以在您的问题中嗅到过早的优化。运行足够快吗?如果是,为什么要打扰?

  

我发现这种方法不必要地复杂,可能会占用大量内存和时间。

好吧,如果您不需要它,那么它肯定会过于复杂。但是您不必担心内存使用情况。您真的可以想象在用C进行编码的计算机上运行游戏时内存使用会成为问题吗?特别是因为该额外列表的大小将随网格大小线性增长。除非您打算从70年代初开始在计算机上运行该游戏,否则我可以向您保证这不会成为问题。

答案 1 :(得分:1)

我认为您需要2个数组。

一个包含所有空闲像素的位置,另一个包含空闲像素图,如果空闲则包含每个像素在空闲像素数组中的位置。

只要您占用一个新像素,就会将其从可用像素阵列中删除。如果是最后一项,则只需减少计数器以获取免费像素。如果不是自由像素数组的最后一个像素,则将其与自由数组的最后一个像素“交换”。

由于自由像素阵列和自由像素图都相互链接,因此占用一个新像素只需要对结构进行O(1)更新;再次释放像素时也是如此。

现在,随机选择个食物很简单,这是一个O(1)操作-只需从0n_free_pixels - 1中选择一个数字,然后从可用像素阵列中选择ith像素。

对于这种方法,每个像素需要大约4-8字节的额外内存;如果说320x200就足够了,则每个像素4个字节可存储256k(两个数组都具有无符号的短裤)。但是,如果您将食物放在网格中,并且如果蛇占据了其中的任何部分,都认为网格位置不可用,那么您可以少花些钱。


为简单起见,请考虑使用2x2的地图。一开始所有像素都没有,所以地图的内容应该是

Free pixel map        Free pixel list
+-----+-----+
|0    |1    |         | 0 | 1 | 2 | 3 
|  0  |  1  |
|     |     |
+-----+-----+         n_free = 4
|2    |3    |
|  2  |  3  |
|     |     |
+-----+-----+

然后,您要选择一个要占用的像素,并选择一个介于0到n_free之间的数字-1。在这种情况下,现在1.从索引1(也是1)的空闲像素列表中获取像素位置。 ..

Free pixel map        Free pixel list
+-----+-----+
|0    |1    |         | 0 | 1 | 2 | 3 
|  0  |  1  |               ^
|     |     |
+-----+-----+         n_free = 4
|2    |3    |
|  2  |  3  |
|     |     |
+-----+-----+

我们将该像素标记为自由像素图中的保留像素

Free pixel map        Free pixel list
+-----+-----+
|0    |1    |         | 0 | 1 | 2 | 3 
|  0  |  #  |               
|     |     |
+-----+-----+         n_free = 4
|2    |3    |
|  2  |  3  |
|     |     |
+-----+-----+

由于空闲列表中的位置不是最后一个,我们将交换 将最后一个元素(像素3)移到该位置,并更新自由地图以指向该索引,最后将n_free减小一个:

Free pixel map        Free pixel list
+-----+-----+
|0    |1    |         | 0 | 3 | 2 
|  0  |  #  |               ^
|     |     |
+-----+-----+         n_free = 3
|2    |3    |
|  2  |  1  |
|     |  ^  |
+-----+-----+

如果随后释放了像素1,则可以将其添加到空闲列表的位置n_free,并修改地图以使其指向该元素,最后增加n_free;新状态为

Free pixel map        Free pixel list
+-----+-----+
|0    |1    |         | 0 | 3 | 2 | 1
|  0  |  3  |                       ^
|     |     |
+-----+-----+         n_free = 4
|2    |3    |
|  2  |  1  |
|     |     |
+-----+-----+

答案 2 :(得分:0)

虽然随机采摘然后逐渐增加直到发现一个空的斑点,但随着蛇的成长,食物靠近蛇的可能性将增加。因此,随着时间的推移,游戏变得更加困难,因为紧邻蛇的食物比远离蛇的食物更难食用。因此,要在计算真正的随机单元(速度较慢但大多数随机)和伪随机(速度较快但偏斜)之间进行权衡。

一种最小化(或使其恒定)计算时间的方法是跟踪蛇在阵列中移动(从尾巴移开并从头部移开)的空斑,并随机选择食物的索引。