Создание и управление двумя независимыми последовательностями случайных чисел - PullRequest
1 голос
/ 18 февраля 2012

У меня проблемы с генерацией двух независимых случайных последовательностей с использованием функций rand и srand. Подробности ниже, любая помощь будет наиболее ценной.

Я работаю над игрой-головоломкой для iPhone, и обычно для генерации случайных чисел я использую функцию arc4. Однако для многопользовательского режима я хочу, чтобы у обоих игроков были одинаковые фигуры на протяжении всей игры, и единственный способ контролировать это - иметь две повторяющиеся случайные последовательности. Если я затем отправлю семена на другое устройство, игры будут идентичны. Однако когда я использую rand и srand и пытаюсь переключиться на другое начальное число, последовательность начинается с нуля, мне как-то нужно инициализировать две независимые последовательности, созданные с помощью начального числа.

Спасибо за ваши ответы

Ответы [ 6 ]

2 голосов
/ 18 февраля 2012

Криптографически неверные 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 для деталей.

1 голос
/ 20 февраля 2012

Спасибо за предложения, вот как я реализовал все это. Я создал одноэлементный класс с двумя переменными экземпляра - seed1 и seed2 - каждый раз, когда я хочу получить число из первого генератора, я использую метод generator1, то же самое для метода generator2. Seed1 / 2 мгновенно устанавливается на вновь сгенерированное число каждый раз, поэтому я могу просто продолжить с того места, где остановился. В заключение, Джош Касуэлл дал мне всю необходимую мне информацию. Проверьте код, если вам когда-нибудь понадобится что-то подобное. Объект объединяется с семенами 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
0 голосов
/ 26 февраля 2014

Прежде всего, как уже отмечали другие, вы должны использовать random() вместо rand(). Во-вторых, хотя ваш одноэлементный подход может сработать для вас, вы можете решить свою проблему проще и ИМХО более эффективно, используя setstate(3). См. Использование setstate (3) не приводит к ожидаемой последовательности случайных чисел для примера того, как переключаться между двумя состояниями случайных чисел.

0 голосов
/ 19 февраля 2012

В качестве альтернативы, вы можете рассмотреть посылку с семенем "считать".Этот счет просто укажет, где вы находитесь в посеянной серии, и будет увеличиваться каждый раз, когда вы генерируете случайное число с этим семенем.Такой подход дает вам возможность использовать любой генератор случайных чисел, который вам нравится, и сводит к минимуму общение.

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();
}
0 голосов
/ 18 февраля 2012

Некоторые библиотеки генератора случайных чисел позволяют сохранить состояние генератора. Таким образом, вы можете восстановить его позже и продолжить последовательность, которая уже выполняется. Один из тех, кого я знаю, называется RandomLib, и его можно найти на SourceForge.

Другой вариант - сохранить начальное значение и посчитать, сколько раз вы извлекли значение из генератора после заполнения. Позже, когда вы захотите продолжить, перезаряжайте исходным семенем и извлеките такое же количество. Вероятно, это не самый лучший метод, но он должен хорошо работать, если не много.

0 голосов
/ 18 февраля 2012

Вы запустили свой генератор случайных чисел ?

srand( myIdenticalSeedValueForBothPartners );

См. вопрос или здесь [C ++ ссылка].

Если вам не нужно вызывать rand () много тысяч раз:

int nthRandBasedOnSeed( int seed, int count ) {

   srand( seed );

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

     result = rand();

   }

   return result;

}
...