创建和管理两个独立的随机数序列

时间:2012-02-18 17:29:29

标签: iphone objective-c srand

我在使用rand和srand函数生成两个独立的随机序列时遇到了麻烦。详情如下,任何帮助都将非常受欢迎。

我正在为iPhone制作一款益智游戏,通常在随机数生成中我使用arc4功能。然而,对于多人游戏模式,我希望两个玩家在整个游戏中拥有相同的棋子,而我能控制它的唯一方法就是拥有两个可重复的随机序列。如果我然后将种子发送到其他设备,游戏将是相同的。然而,当我使用rand和srand并尝试切换到另一个种子时,序列从头开始,我不得不初始化两个用种子生成的独立序列。

感谢您的回复

6 个答案:

答案 0 :(得分:2)

rand()这样的密码错误的PRNG通过将先前的结果反馈回某个数学过程来进行操作。

为了从中断处继续序列,您所要做的就是存储最后生成的数字并将其用作种子:

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以获取详细信息。

答案 1 :(得分:1)

感谢您的建议,这就是我实现整个事情的方式。我用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

答案 2 :(得分:0)

为你的随机数生成器播种吗?

srand( myIdenticalSeedValueForBothPartners );

请参阅此questionhere [C ++参考]。

如果您不需要多次调用rand():

int nthRandBasedOnSeed( int seed, int count ) {

   srand( seed );

   int result;
   while( 0 < count-- ) {

     result = rand();

   }

   return result;

}

答案 3 :(得分:0)

某些随机数生成器库允许您保存生成器的状态。这样,您可以稍后恢复它,并继续执行正在进行的序列。我所知道的就是RandomLib,它可以在SourceForge上找到。

另一种选择是保存种子,并计算在播种后从发生器中提取值的次数。稍后当你想要继续时,用原始种子重新种植,并拉出相同的数量。这可能不是最好的方法,但如果不做很多的话应该可以正常工作。

答案 4 :(得分:0)

或者,您可以考虑使用种子发送“计数”。这个计数只会指示您在种子系列中的位置,并且每次使用该种子生成随机数时都会增加。这种方法使您可以灵活地使用您喜欢的任何随机生成器,并将通信保持在最低限度。

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();
}

答案 5 :(得分:0)

首先,正如其他人已经指出的那样,您应该使用random()代替rand()。其次,虽然您的单身方法可能对您有用,但您可以使用setstate(3)更轻松地解决您的问题并更加轻松地解决问题。有关如何在两个随机数状态之间切换的示例,请参阅Use of setstate(3) doesn't produce expected sequence of random numbers