有時候可能會遇到這樣的需求:
2.拼圖遊戲每次重新開始時需要隨機初始化碎片的位置,要求隨機出的位置不得重複
演算法:集合的偽隨機遍歷
語言:c++
輸入:源集合source
輸出:一連串不重複的隨機數,隨機數個數等於source集合元素的個數。
標頭檔案及全域性變數:
#include #include #include #include int gnum = 26;
char gsource[26] = ;
char gresult[26] = ;
std::unordered_setghashset;
方案一:第一次通過隨機數取得source集合中的元素後,存放到另乙個陣列(result陣列)當中;然後接下來每次取得source集合的元素後與result陣列內的元素比較,若有重複則重新取。
void test1()
} // 通過校驗
if (isdifferent)
gresult.push_back(gsource[temp]);
} for (const char& t : gresult)
}
方案二:將source集合中的元素隨機地插入到hashset中,直到hashsize長度等於集合長度。
void test2()
for (const char& t : ghashset)
}
這兩種方法得到資料都有點硬著頭皮上的感覺,其實隨機遍歷就像在跳著走一條直線,從某個元素開始前進x步或者後退y步,最終足跡踩遍整條直線。
void test3()
for (int i = 0; i < gnum; ++i)
while (nextmember <= 0 || nextmember > gnum);
gresult.push_back(gsource[nextmember-1]);
std::cout << nextmember-1<
} for (const char& t : gresult)
}
上述演算法要注意prime要大於gnum且是素數,如本例取prime為29(gnum=26),此時再由ra,rb,rc三個隨機取得的在1-29以內的數得到skip,要保證skip值可以被prime除盡。
額外輸出一下nextnumber-1,即隨機獲取的source集合索引數。比如,q對應26字母表中第17個字母,source[16].
可以觀察到,每個數字之間差值是有規律的(因為nextnumber每次+=skip值後%=prime):
-12,+17,-12,+5,-12,+17,-12,+17,-12,+17...
可以觀察到每次隨機取的索引數有一些規律:
1.當數字大於等於12時,每次後退12.
2.當數字小於等於8時,每次前進17.
3.當數字在大於8,小於12時,由於此時前進17會超過最大索引數25,所以前進5.
這樣一來,就偽隨機地遍歷了整個集合,同時其中的規律又可以由自己控制。
比如我們將prime換為31:
顯然,此時:後退15,前進16,超過索引時前進1.
那你有可能會覺得這樣一來隨機數似乎沒什麼神秘感了,容易被發現規律。
實際上我們可以寫乙個專門取素數的類primesearch,prime在每次「隨機」取完1-n個元素時,
prime = primesearch.getnextprime();,然後呢,primesearch內部如何取素數是我們可以提前定義的。
這樣一來,就可以定製出滿足需求的隨機遍歷了,較第
一、第二種方案更為高階。
的確是偽隨機
c語言的 裡 rand 函式可以產生 0 rand max 包括 之間的隨機數,通常是經過 srand 函式進行初始化後再使用。rand max 的值預設是 32767 即 2 15 1 在 裡的定義是 define rand max 0x7fff 所以如果需要求 a,b 顯然要有 b rand m...
偽隨機與實驗
眾所周知,計算機產生的是偽隨機數。所謂偽隨機,就是 當知道種子和隨機產生演算法之後,就可以完全確定出隨機數序列了。並且這個隨機數序列是迴圈重複的。不同的隨機產生演算法的迴圈週期不同 好的隨機產生演算法的迴圈週期會很長。有的文章提到,可以通過引入系統以外的變數來達到真隨機的目的,比如 unix 維護了...
偽隨機演算法同步
一般來說網遊要求邏輯在服務端計算,原因是一方面利於玩家之間邏輯同步的實現,另一方面伺服器做仲裁方,防止玩家作弊。但在有些情況下,由於一些邏輯要求的實時性很高,我們不得不把一些邏輯的判斷放在客戶端,以保證遊戲的流暢感。比如動作遊戲中,玩家受擊時的動作切換,如果需要根據屬性邏輯計算的結果切換到不同被動動...