我无法使用 rand 和 srand 函数生成两个独立的随机序列。详细信息如下,任何帮助将不胜感激。
我正在为 iPhone 开发一款益智游戏,通常我使用 arc4 函数来生成随机数。但是对于多人模式,我希望两个玩家在整个游戏中都拥有相同的棋子,而我可以控制它的唯一方法是拥有两个可重复的随机序列。如果我然后将种子发送到另一台设备,游戏将是相同的。但是,当我使用 rand 和 srand 并尝试切换到另一个种子时,序列从头开始,我必须以某种方式初始化使用种子生成的两个独立序列。
谢谢您的反馈
我无法使用 rand 和 srand 函数生成两个独立的随机序列。详细信息如下,任何帮助将不胜感激。
我正在为 iPhone 开发一款益智游戏,通常我使用 arc4 函数来生成随机数。但是对于多人模式,我希望两个玩家在整个游戏中都拥有相同的棋子,而我可以控制它的唯一方法是拥有两个可重复的随机序列。如果我然后将种子发送到另一台设备,游戏将是相同的。但是,当我使用 rand 和 srand 并尝试切换到另一个种子时,序列从头开始,我必须以某种方式初始化使用种子生成的两个独立序列。
谢谢您的反馈
密码学上的错误 PRNG 就像rand()
通过将先前的结果反馈到某个数学过程来进行操作。
为了从中断的地方继续序列,您所要做的就是存储最后生成的数字并将其用作种子:
srand(time(0));
int player1_rand_num = rand();
NSLog(@"Player 1: %d, %d, %d", rand(), rand(), rand());
srand(7);
int player2_rand_num = rand();
NSLog(@"Player 2: %d, %d, %d", rand(), rand(), rand());
// Re-seed Player 1 sequence
srand(player1_rand_num);
// Displays the same "random" numbers as the first NSLog
NSLog(@"Player 1 again: %ld, %ld, %ld", rand(), rand(), rand());
// and so on...
该random()
函数生成更好的随机数,并具有一对单独的函数,initstate()
它们setstate()
将为您提供生成器的状态。您可以存储状态并将其传递到setstate()
以从中断的位置恢复序列。我指导您man 3 random
了解详细信息。
首先,正如其他人已经指出的那样,您应该使用random()
而不是rand()
. 其次,虽然您的单例方法可能对您有用,但您可以更轻松地解决您的问题,恕我直言,使用setstate(3)
. 有关如何在两个随机数状态之间切换的示例,请参阅使用 setstate(3) 不会产生预期的随机数序列。
感谢您的建议,这就是我实现整个事情的方式。我创建了一个带有 2 个实例变量的单例类 - seed1 和 seed2 - 任何时候我想从第一个生成器中获取一个数字,我使用方法 generator1,与 generator2 方法相同。每次将 seed1/2 立即设置为新生成的数字,这样我就可以从中断的地方继续。总之,乔什·卡斯威尔(Josh Caswell)给了我所有我需要的信息。如果您需要类似的东西,请查看代码。该对象以种子 1 和 1 初始化,但在游戏过程中它们被替换为两个设备共享的其他数字。
@implementation RandomNumberGenerator
@synthesize seed1,seed2;
static RandomNumberGenerator *sharedGenerator = nil;
+(RandomNumberGenerator *) sharedInstance
{
if(!sharedGenerator) {
sharedGenerator = [[RandomNumberGenerator alloc] initWithSeed1:1 andSeed2:1];
}
return sharedGenerator;
}
-(id) initWithSeed1:(int) seedOne andSeed2:(int) seedTwo{
self = [super init];
if (self)
{
seed1 = seedOne;
seed2 = seedTwo;
}
return self;
}
-(int) generator1{
srand(seed1);
int j = rand();
seed1 = j;
return abs(j);
}
-(int) generator2 {
srand(seed2);
int k = rand();
seed2 = k;
return abs(k);
}
-(int) giveRandom {
//return abs(arc4random());
return abs(arc4random());
}
@end
或者,您可以考虑随种子发送“计数”。该计数将仅指示您在种子系列中的位置,并且每次使用该种子生成随机数时都会增加。这种方法使您可以灵活地使用您喜欢的任何随机生成器,并将通信保持在最低限度。
int playerSeed = 12345;
int playerRndCount = 0;
int generateRandomNumber() {
playerRndCount++;
return rand();
}
void synchSeed(seed, count) {
srand(seed);
for (int i=0; i<count; i++)
generateRandumNumber();
}
一些随机数生成器库允许您保存生成器的状态。这样,您可以稍后恢复它,并继续进行已经在进行的序列。我知道一个叫做 RandomLib,它可以在 SourceForge 上找到。
另一种选择是保存种子,并计算在播种后从生成器中提取值的次数。稍后当你想继续时,用原来的种子重新播种,并拉出相同的数量。这可能不是最好的方法,但如果不做很多,应该可以正常工作。