srand в C - всего с одним повторением

Я пытаюсь создать игру на память и хочу спросить, как я могу сгенерировать случайное число всего за одно повторение. Типа 1-1, 2-2, 3-3. Я вставлю сюда свою функцию, которую я создал, и скажу, нужно ли мне создать другую функцию, просто чтобы создать условие для создания только пары из чисел.

// function to fulfill the table
void preencher_mesa(int matriz[4][4], int dificuldade)
{
    int i, j;
    int lim_col, lim_linha; // limits of the matriz

    for(i=0; i<4; i++)
        for(j=0; j<4; j++)
            matriz[i][j] = 0;

    if(dificuldade == 1)
    {
        lim_col = 3;
        lim_linha = 2;
    }
    else if(dificuldade == 2)
    {
        lim_col = 4;
        lim_linha = 2;
    }
    else if(dificuldade == 3)
    {
        lim_col = 4;
        lim_linha = 4;
    }

    srand(time(NULL));
    for(i=0;i<lim_linha;i++)
    {
        for(j=0; j<lim_col;j++)
        {
            if(dificuldade == 1) // difficulty == 1
            {
                matriz[i][j] = (rand()%3)+1;
            }
            else if(dificuldade == 2) // difficulty == 2
            {
                matriz[i][j] = (rand()%6)+1;
            }
            else if (dificuldade == 3) // difficulty == 3
            {
                matriz[i][j] = (rand()%8)+1;
            }
        }
    }

    mostrar_mesa(matriz); //showtable
}

person Lucca Mello    schedule 21.06.2015    source источник
comment
эта строка: 'if(dificuldade == 1)/dificulty ==1' не компилируется   -  person user3629249    schedule 22.06.2015
comment
этот код не обрабатывает случаи, когда dificuldate равен ‹= 0 и/или ›3   -  person user3629249    schedule 22.06.2015
comment
совет: всегда используйте пробелы для отступов. Никогда вкладки. Это связано с тем, что в зависимости от используемого текстового процессора/редактора (включая страницы stackoverflow) результирующее отображение кода будет отличаться. В то время как пробелы (за исключением шрифта переменной ширины, который не должен использоваться для кода) всегда одинаковы   -  person user3629249    schedule 22.06.2015
comment
предлагаю: вызовите функцию srand() очень рано в функции main(), а затем никогда не вызывайте ее снова.   -  person user3629249    schedule 22.06.2015
comment
Вы имеете в виду, что вам нужна функция случайных чисел, которая возвращает одно и то же число дважды подряд, затем дважды другое число и т. д.? Например, 3, 3, 75, 75, 10043, 10043, 91, 91?   -  person user12205    schedule 22.06.2015
comment
@user3629249: Нет, лучше никогда не использовать пробелы для отступов, только табуляции, чтобы я мог сам выбирать, сколько пробелов мне нужно. Это прекрасно работает, если вы хотите, чтобы вкладка состояла из 2 пробелов, а я хочу, чтобы она была из 8 пробелов, если вы используете пробелы для выравнивания, все будет в порядке. и выглядеть нормально.   -  person Jite    schedule 25.06.2015
comment
@Jite: это работает только для ведущих вкладок; как только вы прошли ведущие вкладки, вам нужно использовать пробелы, чтобы получить нормально выглядящий макет. И вы скоро закончите тем, что будете использовать только пробелы — ну, это займет 10-15 лет, но есть вероятность, что вы это сделаете, несмотря на соглашения ядра Linux. (Возьмите домой: это спорный вопрос, и соглашение не будет достигнуто, и у обеих точек зрения есть свои достоинства и недостатки.)   -  person Jonathan Leffler    schedule 26.06.2015
comment
@JonathanLeffler: Вот о чем я говорю: вкладки для отступов и пробелы для выравнивания. Это будет работать нормально, если вы не начнете пытаться выравнивать строки с разными отступами (пожалуйста, не делайте этого) :-)   -  person Jite    schedule 26.06.2015


Ответы (1)


Если у вас есть матрица 3x2, которая должна быть заполнена цифрами/цифрами 1, 1, 2, 2, 3, 3 в некоторой случайной перестановке, вы можете сделать что-то вроде:

  1. Выделите массив (вектор) нужного размера — 6 для текущего примера.
  2. Заполните массив правильными значениями — 1, 1, 2, 2, 3, 3 для текущего примера.
  3. Используйте соответствующий метод для перетасовки массива, а затем скопируйте перетасованные данные в целевой двумерный массив.
  4. Или выбрать случайным образом цифру из начальных 6 вариантов, затем (при необходимости) переместить последнюю цифру в отверстие и выбрать следующую цифру из оставшихся 5 вариантов и т.д.

Вы можете использовать алгоритм перетасовки Fisher-Yates. Вы можете проверить свою копию книги Кнута The Art of Computer Programming, Том 2: Получисловые алгоритмы. Или вы можете поискать описания в Stack Overflow (например, алгоритм для выберите одну случайную комбинацию значений, выбранную потому, что она также была обнаружена в одном из моих поисковых запросов Google).


Судя по комментариям, вам нужны дубликаты вашего суррогата rand(), так что это должно работать:

int duprand(void)
{
    static int mode = 0;
    static int value = 0;
    if (mode == 0)
    {
        mode = 1;
        value = rand();
    }
    else
    {
        mode = 0;
    }
    return value;
 }

Или, более кратко:

int duprand(void)
{
    static int mode = 0;
    static int value = 0;
    if (mode == 0)
        value = rand();
    mode = !mode;
    return value;
 }

Просто звоните duprand() каждый раз, когда вам нужен случайный номер. Вы получите одно и то же значение дважды подряд. Этот код не предоставляет метод ресинхронизации; если вы хотите, вы можете написать его достаточно легко:

void sync_duprand(void)
{
    int i = duprand();
    int j = duprand();
    if (i != j)
       i = duprand();
}

Чего я действительно хотел, так это...

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

extern void shuffle(int *array, int n);
/*
** rand_int() and shuffle() copied verbatim (but reformatted) from
** https://stackoverflow.com/a/3348142 - an answer by Roland Illig
** (https://stackoverflow.com/users/225757/roland-illig).
*/

static int rand_int(int n)
{
    int limit = RAND_MAX - RAND_MAX % n;
    int rnd;

    do
    {
        rnd = rand();
    } while (rnd >= limit);
    return rnd % n;
}

void shuffle(int *array, int n)
{
    int i, j, tmp;

    for (i = n - 1; i > 0; i--)
    {
        j = rand_int(i + 1);
        tmp = array[j];
        array[j] = array[i];
        array[i] = tmp;
    }
}

/* New code - but hardly novel code */
static void dump_matriz(int matriz[4][4])
{
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
            printf("  %d", matriz[i][j]);
        putchar('\n');
    }
}

int main(void)
{
    int matriz[4][4];

    int *base = &matriz[0][0];
    for (int i = 0; i < 8; i++)
    {
        *base++ = i + 1;
        *base++ = i + 1;
    }

    printf("Before:\n");
    dump_matriz(matriz);

    shuffle(&matriz[0][0], 16);

    printf("After:\n");
    dump_matriz(matriz);

    return 0;
}

Пример вывода:

Before:
  1  1  2  2
  3  3  4  4
  5  5  6  6
  7  7  8  8
After:
  1  7  8  6
  6  2  5  8
  2  4  7  3
  3  5  1  4

Обратите внимание, что из-за отсутствия вызова srand() перестановка фиксирована. (Вы можете получить результат, отличный от того, что я показываю, но выполнение этого теста несколько раз будет давать один и тот же результат на вашем компьютере каждый раз.) Добавьте вызов srand() с соответствующей инициализацией, и вы получите разные последовательности. Рубите и измельчайте в соответствии с вашими требованиями для меньших матриц.

person Jonathan Leffler    schedule 22.06.2015
comment
Прочитав вопрос, я подумал, что ОП спрашивает, как создать случайную функцию, которая возвращает каждое число дважды подряд, например, 3, 3, 75, 75, 10043, 10043, 91, 91 и т. д. Я написал ответьте на это, но после прочтения вашего я не уверен, правильно ли я интерпретировал вопрос (и, следовательно, должен ли я опубликовать свой ответ) ... Что вы думаете? - person user12205; 22.06.2015
comment
Вернуть одно и то же число два раза подряд — это не большое достижение, не так ли? Вы просто используете номер дважды. Поэтому я предполагаю, что требование более сложное. - person Jonathan Leffler; 22.06.2015
comment
Да, @ace, ты должен это сделать! Потому что я все еще думаю, как это работает! - person Lucca Mello; 25.06.2015
comment
@LuccaMello: если вам нужны дубликаты вашего rand(), тогда: int duprand(void) { static int mode = 0; static int value = 0; if (mode == 0) { mode = 1; value = rand(); } else { mode = 0; } return value; } должен выполнить эту работу. Просто звоните duprand() каждый раз, когда вам нужен случайный номер. Вы получите одно и то же значение дважды подряд. Этот код не предоставляет метод ресинхронизации; если вы хотите, вы можете написать его достаточно легко: void sync_duprand(void) { int i = duprand(); int j = duprand(); if (i != j) i = duprand(); }. - person Jonathan Leffler; 25.06.2015
comment
На данный момент мне нужно предположить, что у меня есть 8 пар чисел, например: (1,1)(2,2)(3,3),(4,4),(5,5),(6, 6),(7,7),(8,8) и мне нужно, чтобы это число перетасовывалось в таблице, я хочу, чтобы это число занимало разные позиции в этой таблице (matriz[4][4]). Уровень 1 — легкий — всего 3 пары случайных чисел в этой таблице, уровень 2 — средний 4 пары и уровень 3 — сложный — 8 пар @Jonathan Leffler - person Lucca Mello; 25.06.2015
comment
Итак, мое первоначальное предложение - это то, что вам нужно. Действуй. SO-поиск по '[c] fisher yates shuffle' довольно легко находит пригодный для использования код. - person Jonathan Leffler; 25.06.2015