srand in C - with just one repetition

146 views Asked by At

I'm trying to build a memory game and I want to ask how I can generate a randomic number with just one repetition. Like 1-1, 2-2, 3-3. I will paste here my function that I created and tell me if I have to create another function just to create a condition to create just a pair from numbers.

// 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
}
1

There are 1 answers

6
Jonathan Leffler On

If you have a 3x2 matrix that should be filled with the digits/numbers 1, 1, 2, 2, 3, 3 in some random permutation, then you could do something like:

  1. Allocate an array (vector) of the right size — 6 for the current example.
  2. Populate the array with the correct values — 1, 1, 2, 2, 3, 3 for the current example.
  3. Use an appropriate technique to shuffle the array, and then copy the shuffled data into the target 2D array.
  4. Or select a digit at random from the initial 6 options, then (if necessary) move the last digit into the hole and select the next digit from the remaining 5 options, etc.

You can use the Fisher-Yates shuffling algorithm. You might check in your copy of Knuth The Art of Computer Programming, Volume 2: Seminumerical Algorithms. Or you can look for expositions on Stack Overflow (such as Algorithm to select a single random combination of values, chosen because one of my Google searches also came across it).


Judging from the comments, you want duplicates from your rand() surrogate, so this should work:

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

Or, more succinctly:

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

Simply call duprand() each time you want a random number. You will get the same value twice in a row. This code doesn't provide a resynchronization method; if you want one, you can write one easily enough:

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

What I really wanted was ...

#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;
}

Sample output:

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

Note that because there's no call to srand(), the permutation is fixed. (You might get a different result from what I show, but running this test multiple times will produce the same result each time on your machine.) Add a call to srand() with an appropriate initialization, and you get different sequences. Hack and chop to suit your requirements for smaller matrices.