我在使用rand和srand函数生成两个独立的随机序列时遇到了麻烦。详情如下,任何帮助都将非常受欢迎。
我正在为iPhone制作一款益智游戏,通常在随机数生成中我使用arc4功能。然而,对于多人游戏模式,我希望两个玩家在整个游戏中拥有相同的棋子,而我能控制它的唯一方法就是拥有两个可重复的随机序列。如果我然后将种子发送到其他设备,游戏将是相同的。然而,当我使用rand和srand并尝试切换到另一个种子时,序列从头开始,我不得不初始化两个用种子生成的独立序列。
感谢您的回复
答案 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 );
如果您不需要多次调用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。