Ir ao conteúdo
  • Cadastre-se

C Como faço para gerar números aleatórios repetindo os números 2 vezes?


Visitante

Posts recomendados

Fala galera! sou iniciante em C e tô precisando gerar números repetidos, 10 números em especifico de 1 a 9 apenas. Quero armazenar em um vetor de 10 posições só que tem que repetir duas vezes tipo {1, 4, 6, 1, 7, 6, 4, 8, 7, 8}, tipo eles tem que se repetir uma vez só em qualquer posição do vetor para gerar pares de números iguais, estou usando a função srand, mas não sei gerar números aleatórios dessa forma. Se alguém souber me ajude

Link para o comentário
Compartilhar em outros sites

@André Gomides

1 hora atrás, André Gomides disse:

tem que repetir duas vezes tipo {1, 4, 6, 1, 7, 6, 4, 8, 7, 8}, tipo eles tem que se repetir uma vez só

não entendi bem isso , não , como vai repetir duas vezes mas ao mesmo tempo vai repetir só uma vez  ?   ,   mas se o que você quer dizer é que quer gerar números para preencher o vetor , de modo que não seja inserido nenhum número igual ao outro no vetor ,   então faça uma comparação do número gerado com todos os outros números que já estejam no vetor ,  e se você Quiser / puDer , poste o enunciado completo e algum código que você já tenha feito sobre esse exercício , e assim poderemos ajudar caso precise de alguma correção  . , .  ,     ,

Link para o comentário
Compartilhar em outros sites

@devair1010 deixa eu tentar explicar melhor... Preciso de 5 pares de números para preencher o vetor de 10 posições, de modo que eles se repitam em alguma posição do vetor. Exemplo: o número 1 deve aparecer em duas posições do vetor, o número 2 deve aparecer em duas posições do vetor... As posições do vetor em que os números aparecem devem ser aleatório. Estou fazendo um joguinho bem simples pra final de semestre, em que o usuário tem que digitar as posições do vetor em que os números são iguais, é um jogo de memória bem simples, por isso preciso que o vetor mude as posições para o jogo não ficar igual todas as vezes que for jogado.

Link para o comentário
Compartilhar em outros sites

17 minutos atrás, André Gomides disse:

Preciso de 5 pares de números para preencher o vetor de 10 posições, de modo que eles se repitam em alguma posição do vetor. Exemplo: o número 1 deve aparecer em duas posições do vetor, o número 2 deve aparecer em duas posições do vetor... As posições do vetor em que os números aparecem devem ser aleatório

 

Eu postei um programa hoje que explica um modo de fazer isso. Sugiro dar uma olhada lá em 

 

 

Mas o simples é: pegue um dos x valores RESTANTES lá dos 5, use o simples, RAND()%x. Seu tabuleiro vai ter y posições livres, sorteie uma com o óbvio rand() % y e coloque o símbolo lá. Óbvio, diminui y porque usou uma posição. Como são pares, faz a mesma coisa de novo: rand()%y e põe o cara lá de novo.  Faz isso para os 5 símbolos e pronto. Claro que ao final vai restar um símbolo e duas casas vazias no tabuleiro.

 

Veja o programa que mostrei e se não entender escreva de novo. Lá tem a saída passo a passo

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

@André Gomides Seu código deve gerar 5 números aleatórios sem repetição. Para controlar isso você pode usar outro vetor de dez posições e atribuir 1 quando determinado valor aparecer. As posições que vão receber esses números também serão aleatórias, para atribuir de 2 em 2, e você deve controlar para não escrever mais de uma vez na mesma posição.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Fiz o código para gerar os pares aleatórios F5Rua4D.gif:

 

 

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

int aleatorio(int minimo, int maximo)
{
    return (rand() % ((maximo + 1) - minimo)) + minimo;
}

int main(void)  
{
    #define MAX_OBJECTS 5
    static int vetor[2*MAX_OBJECTS];
    int indice[2];
    int numero;
    static int numeros[MAX_OBJECTS];
    int repetido[2*MAX_OBJECTS] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
    int i = 0;
    int k = 0;
    srand(time(NULL));
    do
    {
        setpoint0:
        numero = aleatorio(1, 9);
        for(int j = 0; j < 2*MAX_OBJECTS; j++)
        {
            if(numero == numeros[j])    goto setpoint0;
        }
        numeros[k] = numero;
        k++;
        setpoint1:
        indice[0] = aleatorio(0, 9);
        for(int j = 0; j < 2*MAX_OBJECTS; j++)
        {
            if(indice[0] == repetido[j])    goto setpoint1;
        }
        vetor[indice[0]] = numero;
        repetido[i] = indice[0];
        i++;
        setpoint2:
        indice[1] = aleatorio(0, 9);
        for(int j = 0; j < 2*MAX_OBJECTS; j++)
        {
            if(indice[1] == repetido[j])    goto setpoint2;
        }
        vetor[indice[1]] = numero;
        repetido[i] = indice[1];
        i++;
    }
    while(i < 2*MAX_OBJECTS);
    printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", vetor[0], vetor[1], vetor[2], vetor[3], vetor[4],
    vetor[5], vetor[6], vetor[7], vetor[8], vetor[9]);
    return 0;
}

 

 

 

Espero ter ajudado GbhmuXl.gif.

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

:) Legal ter voltado ao forum e postado o código de sua solução.

 

Devia ser o comum, mas não é.

 

Em relação ao programa, sugiro fazer como eu expliquei no outro tópico. Todo mundo faz assim.

 

Essa noção de marcar os "nós visitados", o vetor repetidos que usou, é comum em outros casos, em especial com grafos, aqueles programas de caminho entre pontos, por exemplo. E nesse caso é para evitar ciclos em uma rota no tráfego, por exemplo.

 

Mas no seu caso não é uma boa ideia.

 

Entenda:

 

Vai precisar de um número potencialmente enorme de chamadas a aleatorio() a toa. Conforme aumentar MAX_OBJECTS vai fazer um número enorme de chamadas, perto do fatorial de MAX_OBJECTS.

 

Analogia 

 

Seria como se no sorteio da loteria a bolinha sorteada voltasse para o globo antes de cada sorteio. E aí alguém marcasse em repetidos se o número já saiu.

 

Consequência:

 

Se tiver 500 números para sortear, por exemplo, ao final de 490 deles vai ter só 10 livres, 2 em cada 100. Mas vai continuar sorteando entre os 500, com 2% de chance apenas. Vai fazer umas 50 chamadas. 

 

E aí ainda terá 9 livres, com uma chance ainda menor.

 

Quando restarem 2 só, vai sortear entre 500 até aparecer um dos dois.

 

Esse trecho:
 

    do
    {
        setpoint0:
        numero = aleatorio(1, 9);
        for(int j = 0; j < 2*MAX_OBJECTS; j++)
        {
            if(numero == numeros[j])    goto setpoint0;
        }
      // ...
      
    } while()

 

é problemático. É um loop que dura ENQUANTO não preencher o vetor com uma sequência de valores não repetidos. Tem um comando com esse nome em C, while. Usar goto não é nada demais, no entanto é preciso ter uma razão para usar labels em um lugar onde um loop while seria provavelmente muito mais claro

 

Mais sobre o programa:

 

    static int vetor[2*MAX_OBJECTS];

 

Qual a razão de um vetor estático em main() se ao encerrar main() o programa termina?

 

Sobre isso:
 

    printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", vetor[0], vetor[1], vetor[2], vetor[3], vetor[4],
    vetor[5], vetor[6], vetor[7], vetor[8], vetor[9]);

 

Que faria se fossem 500 caras ao invés de 10? Deve imaginar que não está bom assim. Use um loop como usou 3 linhas acima.

 

 

Sobre suas chamadas a aleatorio()

 

image.png.e368261080e082a2ab87b8c53cb36967.pngEstá chamando uma função com 3 argumentos e apenas com valores constantes. Isso sugere que tem algo errado.

 

E ao ver a função fica mais claro ainda. já que é uma simples expressão x + rand()%y. Escreva o simples. 

 

aleatorio(1,9) é a mesma coisa que 1 + rand() % 9

aleatorio(0,9) é a mesma coisa que rand() % 10

 

int aleatorio(int minimo, int maximo)
{
    return (rand() % ((maximo + 1) - minimo)) + minimo;
}

 

Não escreva assim. 

Recomendo fazer lago mais genérico porque pode usar no futuro. Esse caso seu preenche todo o tabuleiro, mas no fundo é a mesma coisa que o Campo Minado, onde se preenche o tabuleiro com algumas minas apenas.

 

Batalha Naval tem um algoritmo parecido com o que usa aqui, porque precisa escolher peças de vários tipos e não vai usar o tabuleiro todo

 

cartelas do bingo são assim também, já que usa um certo número de valores para a cartela, a partir de um número maior de bolinhas possíveis...

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Esta é a forma que comentei acima,

 

O loop do A é para evitar repetição e nele gero outro aleatório enquanto algum número sai mais de uma vez. Outra forma que eu tinha pensando nesse loop era apenas incrementar a variável A com 1 e módulo de 10 (MAX) para pegar a próxima posição sem atribuição de 1. O outro loop interno é o do controle do vetor para atribuir o valor a alguma posição com zero. Usar esses loops internos não é a melhor forma já que eles vão ficar rodando enquanto um número repetido aparece e acho que o mais indicado é usar um algoritmo específico para tratar isso, mas é só uma alternativa.

 

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

#define MAX 10

int main(void){
    int repetido[MAX] = {0};
    int vetor[MAX] = {0};

    srand(time(NULL));
    for(int i = 0; i < MAX/2; i += 1){
        int A = rand() % MAX;
        int indices = 0;
        while(repetido[A]){
            A = rand() % MAX;
        }
        repetido[A] = 1;
        do{
            int B = rand() % MAX;
            if(!vetor[B]){
                vetor[B] = A + 1;
                indices += 1;
            }
        }while(indices != 2);
        
    }
    for(int i = 0; i < MAX; i += 1){
        printf(" %d", vetor[i]);   
    }
    return 0;
}

 

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Olá!

 

#1 "estou usando a função   srand   (de stdlib.h), mas não sei gerar números aleatórios dessa forma. Se alguém souber me ajude"

Em 03/08/2021 às 11:06, André Gomides disse:

Fala galera! sou iniciante em C e tô precisando gerar números repetidos, 10 números em especifico de 1 a 9 apenas. Quero armazenar em um vetor de 10 posições só que tem que repetir duas vezes tipo {1, 4, 6, 1, 7, 6, 4, 8, 7, 8}, tipo eles tem que se repetir uma vez só em qualquer posição do vetor para gerar pares de números iguais, estou usando a função srand, mas não sei gerar números aleatórios dessa forma. Se alguém souber me ajude

 

#2 "As posições do vetor em que os números aparecem devem ser aleatório"

Em 03/08/2021 às 12:45, André Gomides disse:

@devair1010 deixa eu tentar explicar melhor... Preciso de 5 pares de números para preencher o vetor de 10 posições, de modo que eles se repitam em alguma posição do vetor. Exemplo: o número 1 deve aparecer em duas posições do vetor, o número 2 deve aparecer em duas posições do vetor... As posições do vetor em que os números aparecem devem ser aleatório. Estou fazendo um joguinho bem simples pra final de semestre, em que o usuário tem que digitar as posições do vetor em que os números são iguais, é um jogo de memória bem simples, por isso preciso que o vetor mude as posições para o jogo não ficar igual todas as vezes que for jogado.

 

 

#R resolve-se, usualmente, com qualquer algoritmo de embaralhamento

por exemplo,

 

Embaralhamento de Fisher-Yates


 

O recurso da linguagem (C) necessário tem no básico.

[:)@André Gomides

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Em 03/08/2021 às 12:45, André Gomides disse:

deixa eu tentar explicar melhor... Preciso de 5 pares de números para preencher o vetor de 10 posições, de modo que eles se repitam em alguma posição do vetor. Exemplo: o número 1 deve aparecer em duas posições do vetor, o número 2 deve aparecer em duas posições do vetor... As posições do vetor em que os números aparecem devem ser aleatório. Estou fazendo um joguinho bem simples pra final de semestre, em que o usuário tem que digitar as posições do vetor em que os números são iguais, é um jogo de memória bem simples, por isso preciso que o vetor mude as posições para o jogo não ficar igual todas as vezes que for jogado

 

8 horas atrás, Midori disse:

O loop do A é para evitar repetição e nele gero outro aleatório enquanto algum número sai mais de uma vez. Outra forma que eu tinha pensando nesse loop era apenas incrementar a variável A com 1 e módulo de 10 (MAX) para pegar a próxima posição sem atribuição de 1. O outro loop interno é o do controle do vetor para atribuir o valor a alguma posição com zero. Usar esses loops internos não é a melhor forma já que eles vão ficar rodando enquanto um número repetido aparece e acho que o mais indicado é usar um algoritmo específico para tratar isso, mas é só uma alternativa

 

Tem razão, @Midori. O programa que postou, se usar 210805 para srand() por exemplo, precisa de 29 chamadas para preencher os 10 números. E fica pior, claro, conforme cresce MAX, Para 5000 elementos seu programa usaria nada menos que 59.128 chamadas. E foi até um caso feliz. Pode demorar MUITO mais.

 

"algoritmo específico" pode ser o caso, mas também pode ser exagero: fazendo uma analogia com o Bingo da igreja, trata-se apenas de não colocar de volta as bolinhas que já saíram. E ninguém faria isso no mundo real. E assim um programa que tenta replicar isso não deve fazer. 

 

O seu exemplo não funciona para esse caso: eis a saída do seu exemplo:

 

 9 3 2 2 3 10 9 10 7 7

 

Depois de 29 chamadas a rand() para conseguir os 10 números seu programa mostra isso. Só que não é esse o objetivo. Como @André Gomideso autor explicou é uma versão do popular Jogo da Memória. É preciso sortear 5 pares de números nas 10 posições do tabuleiro, e não simplesmente arrumar uma permutação dos números de 1 a 10.

 

Sobre o tal algoritmo

 

Eu expliquei isso passo a passo em C e C++ nesse tópico: 

 

Postei nessa semana e lá tem uma discussão e um exemplo passo a passo. Trata-se do que qualquer criança com um baralho faz, o que a CEF faz nos sorteios, o que o bingo faz há séculos, o que se faz no sorteio de amigo secreto todo fim de ano que não tem pandemia...

 

 Algo como o "algoritmo" Fisher-Yates :), que me parece ser uma frescura.

 

Um exemplo para esse caso, em C

 

De todo modo vou mostrar uma função aqui que pode fazer isso sempre, com (N-1) chamadas para N valores, como se faz desde muito antes dos computadores.

 

Para ter uma analogia mais acessível que simples números, vou usar os símbolos
 

    const char* simbolo[] = {"10", "J", "Q", "K", "A"};

 

Sim, são cartas do baralho, sem naipes.

 

Temos 10 posições no mapa, como poderiam ser 30, um número comum no jogo de memória que você pode jogar online aqui

 

O que se espera é uma sequência assim
 

K Q A K J 10 10 Q J A

 

Distribuindo os 5 pares nas 10 posições. Aí o programa desenha a tela e o jogo segue

 

A função
 

    int* sorteados(unsigned N, int menor, int maior)

 

retorna um vetor de N inteiros entre menor e maior inclusive. 

 

Exemplo:
 

    sorteados(11,-5,5)

vai retornar um vetor com esses 11 números em ordem aleatória. Para a mesma seed 210805:

 

3 5 -1 -4 -2 2 4 -5 1 -3 0

 

Com exatamente  N-1 = 10 chamadas a rand() 

 

Eis uma implementação comum e genérica da tal função:

 

// retorna um vetor de 'N' valores inteiros
// entre 'menor' e 'maior' em ordem aleatoria.
// Ex (10,0,100) retorna 10 valores entre 0 e 100
// inclusive. Ex: (12,0,11) retorna o vetor com 
// todos os 12 numeros em ordem aleatoria.
//
// ARFNeto 2021
int* sorteados(unsigned N, int menor, int maior)
{
    unsigned cjto = maior - menor + 1;
    if (cjto < 2) return NULL;  // tem que ter um par ao menos
    if (N == 0) return NULL;    // bobagem, mas...
    if (N > cjto) N = cjto;     // por sanidade :)
    int* v = (int*)malloc(cjto * sizeof(int));  // cria o vetor
    if (v == NULL) return NULL;                 // deu pau
    // numera as bolinhas
    for (unsigned i = 0, valor = menor; i < cjto; i += 1)
        *(v + i) = valor++;
    // as "bolinhas" estão em ordem: faz os sorteios
    for (unsigned i = 1; i < cjto; i += 1)
    {
        int outra    = i + rand() % (cjto - i);  // uma das outras
        int temp     = *(v + i - 1);             // a primeira bolinha
        *(v + i - 1) = *(v + outra);             // troca pela outra
        *(v + outra) = temp;
    };  // for()
    return v;
};

 

Não tem nem 20 linhas.

 

Usando essa função para esse caso, em 😄

 

int main(void)
{
    srand(210805);
    const char* simbolo[] = {"10", "J", "Q", "K", "A"};
    int*        par       = sorteados(5, 0, 4);
    int*        sorteio   = sorteados(10, 0, 9);

    char*       grade[10] = {0};  // o mapa do jogo
    for (int i = 0; i < 5; i += 1)
    {   grade[sorteio[i]]     = (char*)simbolo[par[i]];
        grade[sorteio[5 + i]] = (char*)simbolo[par[i]];
    }
    for (int i = 0; i < 10; i += 1) printf("%s ", grade[i]);
    free(par), free(sorteio);
    return 0;
}

 

E também não tem nem 20 linhas.

 

O que mostra o programa
 

K A Q A 10 J K 10 Q J

 

Como funciona?

 

São dois sorteios, um para os pares e outro para o tabuleiro. Claro que um é o dobro do outro, é o jogo da memória afinal, não vamos esquecer :D (ok, foi pobre essa)

 

Para ficar mais bonitinho usamos um vetor de strings. Assim fica fácil trocar por qualquer outra coisa, como nomes ou palavras.

 

Os dois "sorteios" são feitos com 13 chamadas a rand() para cada jogo: (10 - 1) + (5 - 1)

 

Usando char* para o tabuleiro facilita bem as coisas. Feitos os sorteios basta preencher os espaços. Só que ao invés de usar os índices do vetor o programa usa os índices determinados pela função. E para aproveitar o loop divide o tabuleiro em metades simétricas. Mais fácil mostrar do que explicar:
 

    for (int i = 0; i < 5; i += 1)
    {   grade[sorteio[i]]     = (char*)simbolo[par[i]];
        grade[sorteio[5 + i]] = (char*)simbolo[par[i]];
    }

 

É só isso.

 

O programa completo
 


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

int* sorteados(unsigned, int, int);

int main(void)
{
    srand(210805);
    const char* simbolo[] = {"10", "J", "Q", "K", "A"};
    int*        par       = sorteados(5, 0, 4);
    int*        sorteio   = sorteados(10, 0, 9);

    char*       grade[10] = {0};  // o mapa do jogo
    for (int i = 0; i < 5; i += 1)
    {   grade[sorteio[i]]     = (char*)simbolo[par[i]];
        grade[sorteio[5 + i]] = (char*)simbolo[par[i]];
    }
    for (int i = 0; i < 10; i += 1) printf("%s ", grade[i]);
    free(par), free(sorteio);
    return 0;
}


// retorna um vetor de 'N' valores inteiros
// entre 'menor' e 'maior' em ordem aleatoria.
// Ex (10,0,100) retorna 10 valores entre 0 e 100
// inclusive. Ex: (12,0,11) retorna o vetor com 
// todos os 12 numeros em ordem aleatoria.
//
// ARFNeto 2021
//
int* sorteados(unsigned N, int menor, int maior)
{
    unsigned cjto = maior - menor + 1;
    if (cjto < 2) return NULL;  // tem que ter um par ao menos
    if (N == 0) return NULL;    // bobagem, mas...
    if (N > cjto) N = cjto;     // por sanidade :)
    int* v = (int*)malloc(cjto * sizeof(int));  // cria o vetor
    if (v == NULL) return NULL;                 // deu pau
    // numera as bolinhas
    for (unsigned i = 0, valor = menor; i < cjto; i += 1)
        *(v + i) = valor++;
    // as "bolinhas" estão em ordem: faz os sorteios
    for (unsigned i = 1; i < cjto; i += 1)
    {
        int outra    = i + rand() % (cjto - i);  // uma das outras
        int temp     = *(v + i - 1);             // a primeira bolinha
        *(v + i - 1) = *(v + outra);             // troca pela outra
        *(v + outra) = temp;
    };  // for()
    return v;
};
// fim

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...