2012-05-06 102 views
3

我遇到了一個問題,我用隨機數生成器編寫了一個遊戲。我需要一個快速的僞隨機場生成器。它不需要加密安全,只需要接受一個向量和一個種子,並給予一個散列值,這個值足夠隨機地欺騙粗略的人工檢查。靜態僞隨機字段生成器

但是,當我給出2d向量並將結果修改爲2時,此代碼未能產生「僞隨機」輸出。它產生大部分棋盤圖案。

我不知道爲什麼,老實說,這將是很酷的知道,但如果我從不知道它,我就不會冒汗。大多數情況下,我認爲這種產生隨機數的方式太可怕了,所以我想知道解決這個問題的另一種方法。也就是說,我真的在尋找資源或指標,以便以這種方式生成隨機數字,而不是問「我做錯了什麼?

基本上,我試圖產生一個「無限」2D噪聲場(我認爲,白噪聲),如果我放入相同的輸入,我可以找回。我寫的代碼是(它應該是一個fnv散列,請原諒模板的東西,我只是把它從代碼中提取出來,稍後我會清除它)。

//Static random number generator, will generate a random number based off of a seed and a coordinate 
template<typename T, typename... TL> 
uint32_t static_random_u32(T const& d, TL const&... rest) { 
    return fnv_hash32(d, rest..., 2938728349u); //I'm a 32-bit prime! 
} 

template<typename T, typename... TL> 
uint32_t fnv_hash32(T const& v, TL const&... rest) { 
    uint32_t hash; 
    fnv_hash32_init(hash); 
    fnv_hash32_types(hash, v, rest...); 
    return hash; 
} 

inline void fnv_hash32_init(uint32_t& hash) { 
    hash = 2166136279u; //another 32-bit prime 
} 

// Should produce predictable values regardless of endianness of architecture 
template<typename T, typename... TL> 
void fnv_hash32_types(uint32_t& hash, T const& v, TL const&... rest) { 
#if LITTLE_ENDIAN 
    fnv_hash32_bytes(hash, (char*)&v, sizeof(v), true); 
#else 
    fnv_hash32_bytes(hash, (char*)&v, sizeof(v), false); 
#endif 
    fnv_hash32_types(hash, rest...); 
} 

inline void fnv_hash32_types(uint32_t& hash) {} 

inline void fnv_hash32_bytes(uint32_t& hash, char const* bytes, size_t len, bool swapOrder = false) { 
    if (swapOrder) { 
    for (size_t i = len; i > 0; --i) 
     fnv_hash32_next(hash, bytes[i - 1]); 
    } else { 
    for (size_t i = 0; i < len; ++i) 
     fnv_hash32_next(hash, bytes[i]); 
    } 
} 

inline void fnv_hash32_next(uint32_t& hash, char byte) { 
    hash ^= byte; 
    hash *= 16777619u; 
} 
+0

你能詳細說明一下僞隨機字段生成器中的「field」是什麼意思嗎? –

+0

是的,字段含義矢量,(即座標在2d,或3d或nd空間) – OmnipotentEntity

回答

2

我不是這方面的專家,但這裏有一個想法和一個指針。

您的主要哈希混合函數fnv_hash32_next非常簡單,實際上並沒有很好地混合。例如,如果您知道「字節」的最低位爲0,則語句hash ^= byte將保留最低位hash不變。並且由於16777619u是奇數,因此hash *= 16777619u始終保持最低位不變:奇數(散列)乘以奇數(16777619u)爲奇數/偶數(散列)乘以奇數(16777619u)爲偶數。

將該參數進一步進行一下,結果的最低位最終將成爲輸入每個字節中最低位的異或值。實際上,恰恰相反,因爲你從hash的初始值開始,在fnv_hash32_init中有一個奇數。這可能會解釋你所看到的模式。事實上,我敢打賭,如果你仔細檢查,你會發現它不是棋盤格。例如,對於每個x,(x,255)的值應該與(x,256)相同。

您使用的方案應該工作得相當好,但您需要更好的散列函數。特別是,你需要混合一點。我之前使用的一個資源是Thomas Wang的書面文章http://www.concentric.net/~ttwang/tech/inthash.htm。他對基本問題以及一些示例代碼進行了簡短而簡潔的描述。此外,不要錯過他與羅伯特詹金斯的文章鏈接:http://www.burtleburtle.net/bob/hash/doobs.html。所有這一切說,從庫中使用像MD5或SHA1這樣的密碼散列可能會容易得多。不要錯過:使用加密哈希不會使您使用任何類型的「加密安全」。但是密碼散列函數往往有你想要的混合類型。

+0

第二個想法......'fnv_hash32_next'可能很好地混合了中/高位。也許不是繪製'result%2',而是繪製'(result >> 16)%2'? – Managu

0

如果你需要做的就是糊弄誰不檢查很辛苦人類,我只想用random_r()srandom_r()從標準庫。它們允許你保留一個私有狀態對象,這樣你可以同時擁有多個不同的(和唯一的)生成器。如果你願意,你可以將它們包裝在一個類中以方便使用。

+0

嗨,我應該強調,這些隨機數需要可預測,可重複,基於種子和其他一些輸入(例如作爲一個領域的座標),我需要同時進行其中的幾個。我的確瞭解到'rand()'函數的存在。 – OmnipotentEntity

+0

我想你知道'rand()':)請在我最近的編輯完成後重新閱讀我的答案(應該是三段而不是一段),看看是否有幫助。 –

+0

我不認爲我完全解釋自己。基本上,如果我放入相同的輸入,我試圖產生一個「無限」2D噪聲場(我認爲,白噪聲),我可以找回。它被這樣調用:'int objectStart = static_random_u32(m_seed,x,y)%2;' – OmnipotentEntity

1

東西IMO很好地工作是

int base[16][16]; // Random base tile 

int random_value(int x, int y) 
{ 
    return (base[y&15][x&15]^
      base[(y>>4)&15][(x>>4)&15]^
      base[(y>>8)&15][(x>>8)&15]^
      base[(y>>12)&15][(x>>12)&15]^
      base[(y>>16)&15][(x>>16)&15]); 
} 

的想法是異或基本隨機瓦數等級水平(我使用這個例子5級)。您添加更多的級別是期限;在這個例子中是16 ** 5。

0

這是柏林噪音的用途。 Minecraft使用Perlin噪音。它可以讓您立即計算場地中任意點的數值,而無需首先計算中間點。如果你隨心所欲地生成你的世界的一部分,然後你生成加入這些任意點的位,它們將完全匹配在一起。

+0

我已經有一個perlin噪聲發生器。我不想要一個平滑的隨機場。我基本上想要白噪音。無論如何,我的問題已經解決了,並且我在我的問題中發佈的代碼之外進行了幾次迭代。感謝您的幫助。 – OmnipotentEntity