簡體   English   中英

如何在c上的蛇游戲中隨機產生食物?

[英]How to produce a random food in a snake game on c?

我正在嘗試使用 C 創建一個蛇游戲。

我正在嘗試找到一種有效的算法來生成隨機食物位置。

這是我當前的 generateFood() 函數算法:

  1. 生成隨機食物坐標
  2. 而坐標在蛇頭上 || 身體:
  3. 生成新的隨機食物坐標

這個算法適用於游戲的前半部分,但是當蛇開始變大時。 隨機獲取坐標以最終獲得空閑位置將花費更長的時間復雜度並且極其不一致。

我正在考慮將所有空坐標放入鏈表並移動隨機步驟以獲得坐標。 並且它會相應地更新到蛇坐標,以便它可以在第一次運行時生成隨機食物。

但我發現這種方法不必要地復雜,可能會占用大量內存和時間。

有沒有其他方法可以在 C 上更有效地做到這一點? 謝謝

我認為你需要 2 個數組。

一個包含所有空閑像素的位置,另一個包含空閑像素數組中每個像素的位置,如果它是空閑的。

每當您占用一個新像素時,您就將其從空閑像素數組中刪除。 如果它是最后一個項目,您只需減少可用像素的計數器 如果它不是空閑像素陣列的最后一個像素,則首先將其與空閑陣列的最后一個像素“交換”。

由於空閑像素陣列和空閑像素圖是相互鏈接的,所以占用一個新像素只需要對結構進行 O(1) 次更新; 同樣適用於再次釋放像素時。

現在,為食物隨機選擇一個空閑像素真的很容易,它是一個 O(1) 操作 - 只需從0n_free_pixels - 1選擇一個數字,然后從空閑像素陣列中選擇第ith像素。

對於這種方法,每個像素需要大約 4-8 字節的額外內存; 如果說 320x200 就足夠了,那么 256k 的每像素 4 個字節(兩個數組都將有無符號的短褲)。 但是,如果您將食物放在網格中,並認為如果蛇占據其中的任何部分,則網格位置將無法使用,那么您可以少花錢。


為簡單起見,考慮使用 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  |
|     |     |
+-----+-----+

可能解決問題的一種方法是:

gridSize = getTotalNumberOfCells()
snakeSize = getSnakeSize()
cellsLeft = gridSize-snakeSize
randomCell = random(cellsLeft)

cell = 0
do
    while occupiedBySnake(cell)
        cell++
while randomCell-- > 0

這個方法一個接一個地遍歷單元格,直到遍歷randomCell的單元格數量,不計算被蛇占據的單元格。

也許不是最好的算法,但至少運行所需的時間是可以預測的。 當蛇很小時,它肯定會比你目前的算法慢,但它可能能夠足夠快地處理它。 當然,這在很大程度上取決於細胞的數量。

如果您有一個 300x300 的網格(一個非常大的蛇游戲),您將擁有近 100000 個單元格。 檢查一個單元是否被占用應該能夠在最大 200ns 內完成。 我假設緩存未命中,這種情況很少發生。 200ns * 100000 = 0.02s。 這足以達到 50fps。

請注意,我非常悲觀。 200ns 相當長。 當您訪問內存時,50 到 100 之間更為典型。 但實際上,100000 個單元的網格將始終位於 L2 緩存中,其典型訪問時間為 20ns。 如果將大小減小到 200x200,則整個網格可能適合 L1 緩存,其訪問時間約為 1ns。 所以對於 200x200 的網格,這種方法可以產生 25000fps。 你需要更多還是這樣就足夠了? ;)

但是我可以在您的問題中聞到過早的優化。 它跑得夠快嗎? 如果是,為什么要打擾?

我發現這種方法不必要地復雜,可能會占用大量內存和時間。

好吧,如果您不需要它,那么它肯定過於復雜了。 但是您對內存使用的關注是不必要的。 你真的能想象在一台計算機上運行你的游戲,當你用 C 編碼時,內存使用會成為一個問題嗎? 特別是因為該額外列表的大小會隨網格大小線性增長。 除非您打算從 70 年代初開始在計算機上運行此游戲,否則我可以向您保證,這不會成為問題。

雖然隨機采摘然后增加直到找到空位的速度更快,但隨着蛇的成長,食物靠近蛇的可能性會增加。 因此,隨着時間的推移,游戲變得更加困難,因為靠近蛇的食物比遠離蛇的食物更難吃。 因此,這是計算真正隨機單元(較慢但最隨機)和偽隨機(較快但偏斜)之間的權衡。

最小化(或保持恆定)計算時間的一種方法是跟蹤數組中蛇移動(從尾部移除並從頭部添加)時的空點,並為食物隨機選擇一個索引。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM