2016-12-22 3 views
0

Я хочу создать серию «случайных» уникальных номеров, для использования в карточной игре! Эти цифры должны быть между 0 и 81. На данном этапе меня не волнует безопасность или скорость, я просто хочу, чтобы что-то просто выполнялось.Предложение об уникальных значениях генерации

В моем коде ниже мне удалось создать 2 уникальных случайных числа в массиве, который их содержит, но остальные 10 номеров не меняются, но остаются -1, что было начальным значением. Я нашел еще точные способы генерации случайных чисел, но я буду проверять их на более позднем этапе!

#include <stdio.h> 
#include <stdlib.h> 




int getRandomNumber(int Min, int Max) 
{ 
    double rnd= (double)rand()/((double)RAND_MAX+1); 
    return (int)(rnd*(Max-Min+1))+Min; 
} 
int main() 
{ 
    int j,counter,temp,deck[13]; 
    srand(time(NULL)); 
    int i; 
    counter=1; 
    for (i=0;i<12;i++) 
     {deck[i]=-1; 
     temp = getRandomNumber(0,81); 

     for (j=0;j<=i;j++) 
      {if (temp==deck[j]) 
       {counter=0;} 
      if (counter!=0) 
       deck[i]=temp; 
      } 
     } 
    for(i=0;i<12;i++) 
     printf("%d ",deck[i]); 

} 
+2

Здесь очень много вопросов о выборе уникального номера. Один из способов состоит в том, чтобы начать с массива доступных чисел, произвольно выбрать индекс массива * и удалить этот элемент из массива. Вот [один такой ответ] (http://stackoverflow.com/a/27867571/4142924). –

+5

Если вы уже знаете домен вашего нужного набора чисел (0..81), почему бы просто не загрузить последовательность этих 82 значений, а затем сделать простой [Fisher-Yates shuffle] (https: //en.wikipedia .org/wiki/Fisher% E2% 80% 93Yates_shuffle). – WhozCraig

+0

вопрос говорит о числах МЕЖДУ 0 и 81 I.E. 1 ... 80. Вы можете использовать этот оператор: 'value = (rand()% 80) +1;', Если вам не нужны какие-либо повторяющиеся числа, то с каждым новым значением «искать» массив, чтобы убедиться, что он еще не находится в массиве перед тем как вставить новое значение в массив. – user3629249

ответ

1

Ваш код имеет один из страннее отступов и компоновочных схем скобки я когда-либо видел:

#include <stdio.h> 
#include <stdlib.h> 

int getRandomNumber(int Min, int Max) 
{ 
    double rnd= (double)rand()/((double)RAND_MAX+1); 
    return (int)(rnd*(Max-Min+1))+Min; 
} 

int main() 
{ 
    int j,counter,temp,deck[13]; 
    srand(time(NULL)); 
    int i; 
    counter=1; 
    for (i=0;i<12;i++) 
     {deck[i]=-1; 
     temp = getRandomNumber(0,81); 

     for (j=0;j<=i;j++) 
      {if (temp==deck[j]) 
       {counter=0;} 
      if (counter!=0) 
       deck[i]=temp; 
      } 
     } 
    for(i=0;i<12;i++) 
     printf("%d ",deck[i]); 

} 

конвертируется в более ортодоксальный стиль (Allman, более или менее - см Википедии на Indent style) , вы получите:

#include <stdio.h> 
#include <stdlib.h> 

static int getRandomNumber(int Min, int Max) 
{ 
    double rnd = (double)rand()/((double)RAND_MAX + 1); 
    return (int)(rnd * (Max - Min + 1)) + Min; 
} 

int main(void) 
{ 
    int j, counter, temp, deck[13]; 
    srand(time(NULL)); 
    int i; 
    counter = 1; 
    for (i = 0; i < 12; i++) 
    { 
     deck[i] = -1; 
     temp = getRandomNumber(0, 81); 

     for (j = 0; j <= i; j++) 
     { 
      if (temp == deck[j]) 
      { 
       counter = 0; 
      } 
      if (counter != 0) 
       deck[i] = temp; 
     } 
    } 
    for (i = 0; i < 12; i++) 
     printf("%d ", deck[i]); 
} 

static и int main(void) необходимы, чтобы получить код мимо моих вариантов компиляции по умолчанию; в противном случае они косметические.

Теперь мы можем видеть некоторые проблемы. counter устанавливается на 1 один раз, вне внешнего контура; он устанавливается в 0, иногда внутри цикла, но как только это произойдет, он никогда не будет сброшен до 1, поэтому дополнительные номера не добавляются к deck. Вам нужно переделать внутренний цикл, может быть, как это:

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 

static int getRandomNumber(int Min, int Max) 
{ 
    double rnd = (double)rand()/((double)RAND_MAX + 1); 
    return (int)(rnd * (Max - Min + 1)) + Min; 
} 

int main(void) 
{ 
    int deck[13]; 
    srand(time(NULL)); 
    for (int i = 0; i < 12; i++) 
    { 
     int temp = getRandomNumber(0, 81); 
     deck[i] = -1; 

     int counter = 1; 
     for (int j = 0; j <= i; j++) 
     { 
      if (temp == deck[j]) 
      { 
       counter = 0; 
       break; 
      } 
     } 
     if (counter != 0) 
      deck[i] = temp; 
     else 
      i--; // Try again with a new random choice for the same i 
    } 
    const char *pad = ""; 
    for (int i = 0; i < 12; i++) 
    { 
     printf("%s%d", pad, deck[i]); 
     pad = " "; 
    } 
    putchar('\n'); 
    return 0; 
} 

Мне не нравится хвостовые пробелы, так что цикл печати заботится, чтобы обеспечить их нет.

Пример вывода с getRandomNumber() - на MacOS Сьерра 10.12.2 с GCC 6.3.0:

7 73 38 61 11 13 41 66 29 39 72 20 
7 2 18 17 54 31 45 40 34 22 63 16 
7 13 80 54 16 49 14 58 28 53 23 26 
7 24 60 10 67 53 69 32 23 2 66 12 
7 34 40 48 21 3 57 43 6 18 27 80 
7 45 20 3 65 21 61 17 12 69 66 27 
7 67 62 78 70 57 68 46 9 2 72 39 
7 77 41 34 32 75 72 20 64 78 33 25 
7 6 21 72 76 11 75 38 73 27 64 33 
7 17 1 27 37 28 80 49 12 67 59 36 

Это первый номер не очень случайно - вскоре после этой последовательности испытаний, она изменилась с 7 до 8 , но был одинаково неслучайным. Альтернативный способ генерации случайных чисел является:

static int getRandomNumber(int Min, int Max) 
{ 
    int rnd; 
    int range = (Max - Min + 1); 

    while ((rnd = rand()) > RAND_MAX - (RAND_MAX % range)) 
     ; 

    return (rnd % range) + Min; 
} 

Это позволяет избежать смещения от того факта, что 82 не делится RAND_MAX точно, что бы утяжелить распределение нижних чисел немного выше, чем верхние числа в диапазон 0..81. Он также избегает неожиданно непротиворечивого первого номера, хотя новый первый номер также является полурепрессивным, когда тесты выполняются с интервалом в 1 секунду.

Примеры результатов:

48 33 28 78 14 2 81 13 23 75 38 40 
45 42 74 1 11 68 17 33 78 49 23 80 
42 51 38 3 5 52 35 56 54 23 59 41 
39 60 2 8 36 53 79 30 72 75 62 37 
36 69 45 10 78 20 71 17 6 53 54 30 
33 78 9 15 75 7 40 61 27 36 70 68 
30 5 55 17 69 73 25 63 37 1 21 71 
27 14 19 66 57 43 1 13 3 65 71 21 
24 26 62 63 41 61 68 28 67 20 74 17 
21 35 26 57 28 79 47 44 2 52 60 77 

Обратите внимание, что первое число уменьшается на 3; второй, похоже, увеличивается на 9; тьфу - случайность не так уж и хороша. Хорошо известно, что rand() часто не является высококачественным PRNG (генератором псевдослучайных чисел), но я немного удивлен этим, по-видимому, систематическим поведением с семенами, которые каждый раз отличаются на 1.

На моем Mac, когда я изменил srand() к srandom() и rand() к random(), я лучше (как, более непредсказуемым) результаты:

29 1 7 11 25 52 63 15 26 55 75 64 
40 4 64 18 8 57 73 27 38 15 60 28 
43 3 27 17 1 58 26 72 73 18 20 7 
76 16 27 43 64 20 63 30 35 17 33 57 
79 47 32 33 6 30 35 7 38 55 25 61 
69 57 79 75 15 54 5 35 21 46 65 61 
30 79 66 14 56 39 19 8 50 47 76 33 
62 65 81 44 52 39 25 30 54 12 24 68 
27 49 60 72 53 35 14 41 63 46 45 65 
67 39 9 11 60 19 64 73 43 17 21 26 

И страница людей Mac для random() еще предлагает использовать arc4random() вместо , но это намного лучше, чем просто rand(). То, что вы найдете в других системах, будет зависеть от возможностей, предоставляемых системой - rand() может быть не таким ужасным, как кажется на Mac. В принципе, будьте осторожны с выбором PRNG - особенно если вы собираетесь использовать систематически созданные семена (например, текущее время).

0

Для целей, которые вы предлагаете (генерируя случайную последовательность чисел от 0 до 81, где каждый элемент отличается от других), вам понадобится определенный тип генератора случайных чисел (RNG), который может генерировать все возможные перестановки из 82 пунктов (выраженные как 82!, или 82 факториала). Однако только ограниченный выбор ГСЧ может это сделать. В частности, реализация функции C rand() не определена, поэтому не гарантируется генерация множества перестановок.

Генератор псевдослучайных чисел (PRNG, тип используемого здесь RNG) не может генерировать более случайные числовые последовательности, чем его период. Для перестановок 82! ни один PRNG с периодом менее 82! может сделать это (следующая максимальная мощность 2 равна 2 , что означает, что генератору требуется затратить не менее 408 бит, или 51 байт, для этого возможно сделайте так - и 51 байт намного больше, чем srand обычно может принимать). В качестве альтернативы для этой цели вам будет рекомендовано использовать RNG, который генерирует «непредсказуемые» номера, которые не являются стандартом ни на языке C, ни на C-библиотеке. См. «Перетасовка» и «Непредсказуемые ГСЧ» в my article on randomness для получения дополнительной информации.

Смежные вопросы