我正在尝试使用C创建蛇游戏。
我正在寻找一种有效的算法来产生随机的食物位置。
这是我当前的generateFood()函数算法:
该算法适用于游戏的前半部分,但是当蛇开始变大时。 随机获得一个坐标以最终获得一个自由点将花费更长的时间,而且非常不一致。
我正在考虑将所有空坐标放入链表中 并随机移动步长以达到坐标。并会相应地更新为蛇坐标,以便在第一次运行时可以生成随机食物。
但是我发现这种方法不必要地复杂并且 可能会占用大量内存和时间。
还有其他方法可以使我在C上更有效地做到这一点吗?
答案 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)操作-只需从0
到n_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)
虽然随机采摘然后逐渐增加直到发现一个空的斑点,但随着蛇的成长,食物靠近蛇的可能性将增加。因此,随着时间的推移,游戏变得更加困难,因为紧邻蛇的食物比远离蛇的食物更难食用。因此,要在计算真正的随机单元(速度较慢但大多数随机)和伪随机(速度较快但偏斜)之间进行权衡。
一种最小化(或使其恒定)计算时间的方法是跟踪蛇在阵列中移动(从尾巴移开并从头部移开)的空斑,并随机选择食物的索引。