15
respostas

Atividade 7

É possível que esse trecho de código

for(i = 0; i < 6; i++) {
    numerosSorteados[i] = (Math.round(Math.random() * 59) + 1);
}

Que é responsável por seleciona aleatoriamente 6 números de 01 a 60 insira números iguais no array? tipo: numerosSorteados[29,33,47,12,29,41]? espero que tenham entendido meu ponto de vista na pergunta, ou seja, gostaria de saber mesmo se a risco do math.random() seleciona números iguais.

15 respostas

Oi Luan, Eu tinha pensado em fazer algo do tipo: - Função 1: que sorteia UM número e checa se esse número sorteado já existe, se não existe dá PUSH no array, caso contrário faz nada - Função 2: que roda Função 1 até o array ter um LENGTH de 6. Fez sentido? O código vai ficar bem mais complexo do que você estava pensando, mas esse foi o meu jeito de resolver o problema.


Existe um meio de resolver com recursividade (a função chamar ela mesma, mas seria um pouco mais complexo). - Função 1: que sorteia UM número e checa se esse número sorteado já existe, se não existe dá PUSH no array, caso contrário chama a Função 1 de novo. - Função 2: roda a "Função 1" 6 vezes.

Você pode percorrer o array e ver se o número gerado no Random já está no array, caso esteja, roda de novo a função até conseguir incluir um número novo. Outra possibilidade (Mais rápido que percorrer o Array) seria criar um Hash para cada número adicionado ao Array. Antes de adicionar o número no Array vc da um get no Hash e verifica se o numero existe, caso sim, volta e faz de novo. A única vantagem é não ter que percorrer o Array.

tenta por em pratica essa logica do ivan, pensei no mesmo já que é possível a repetição de números e ninguém quer um sorteio de mega-sena com 2 números no resultado iguais. no caso terei um for dentro de outro, encapsulamento. Tentarei digita esse código. No caso Hash pode ser uma boa no entanto ainda não o domino.

Luan, como é um array de apenas 6 números e a performance não é tão importante, pode ser feito dois for mesmo. Um para preencher o array de 6 posições e um outro para verificar se o número já existe. Acredito que seja a melhor opção. Qualquer coisa pode postar o código que ajudo. Abraço.

Olá Luan! Como ja foi dito por seus colegas, da forma como você fez é possível que a array de números sorteados tenha dois números repetidos. Veja o código que fiz abaixo que impede que tenha repetição:

for(i = 0; i < 6; i++) {
        numero = (Math.round(Math.random() * 59) + 1);
        for (n = i - 1; n >= 0; n--){
            if(numerosSorteados[n] == numero){
                numero = (Math.round(Math.random() * 59) + 1);
                i--;
            }
        }
        numerosSorteados[i] = numero;
    }

Espero ter ajudado. Bons Estudos!

Olá Romário obrigado pela a ajuda no entanto ficou algo confuso pra min ainda, peço desculpas por minha ignorância,

for (n = i - 1; n >= 0; n--){
            if(numerosSorteados[n] == numero){
                numero = (Math.round(Math.random() * 59) + 1);
                i--;
            }

Nesse trecho do código o que de fato ele está fazendo? no primeiro ciclo do for a variável "i" é igual a zero, dai a variável "numero" recebe um valor randômico de 01 a 60, entretanto quando entre no for que esta encapsulado a variável ainda possui o mesmo valor, e neste momento o programa diz: n= i "que é zero" menos 1, ou seja (0-1= -1), minha pergunta é, Eu não estaria a tentar acessar uma posição inexistente do array, sendo que os endereços de um array iniciam-se do 0?

Agradeço a ajuda.. Gostaria de enteder isso.

Olá Luan e Romário:

Primeiramente, Luan, o algoritmo que o Romário publicou deveria funcionar da seguinte forma:

O for externo é responsável por caminhar em um array preenchendo as posições com valores randômicos, entre 1 e 60.

Já o for interno é responsável por fazer uma verificação invertida de todos os valores da posição atual de i (seja essa qual for) até a posição inicial do vetor. Ao fazer isso, ele verifica se o número gerado é igual à algum numero já existente no array e, caso o mesmo seja, gera um número novo que, após a verificação, será inserido na posição atual de i.

Vamos ilustrar da seguinte forma:

i = 4. Ou seja, estamos na posição 3 do nosso vetor. Na realização do segundo for, o n vai receber 3 (i - 1) e será feita uma verificação entre o valor presente na posição 3 do array e o número (que foi gerado aleatoriamente). Caso o valor na posição 3 seja igual ao gerado, o algoritmo gera um novo número e volta uma posição no array e continua fazendo as verificações (aqui encontramos um problema que vou discorrer sobre mais a frente) até chegar à primeira posição. Assim que o loop termina, ele insere o elemento na posição i (que é a posição do array em que estávamos originalmente).

Quanto à sua dúvida " Eu não estaria a tentar acessar uma posição inexistente do array" - não. Lembre-se que o segundo elemento do for é um verificador. No for que o Romário utilizou, ele verifica se n é maior ou igual à zero. Caso i seja 0, n passa a ser -1 e não é aceito no verificador. Logo, o for interno não inicia e o for externo avança.

Agora, para os dois. Primeiramente, gerar uma sequência de números não repetidos com o uso de um PRNG não é uma tarefa exatamente fácil (especialmente se o intervalo for pequeno). Há de se considerar o seguinte: apesar de as chances de números repetidos acontecerem serem pequenas para um PRNG, o fato de utilizarmos a função floor (arrendondando para baixo) e termos um limite de 60 números, faz com que essa chance seja alta. Qual seria a solução? Verificar valor por valor e, caso haja um valor repetido, gerar um valor novo (que foi mais ou menos o que o Romário tentou fazer.

O problema que ocorre é: quem me garante que, quando eu gero um número novo, este não vai ser igual à outro número já existente?

Considerem o caso abaixo:

Tenho um array com 10 posições e quero preenchê-lo com valores que vão de 1 à 10. Eu caminho no vetor gerando um número aleatório para cada posição e, a cada posição, verifico se os valores gerados anteriormente são iguais ao que acabei de gerar. Isso parece bem simples. Mas imaginem o seguinte:

Atualmente estou na posição 8 e, graças à meu algoritmo, nenhum dos números se repetiu até o momento. Porém, quando eu gero o número da 8a posição, o mesmo coincide com o número da 6a posição. Com o algoritmo proposto pelo Romário, eu simplesmente geraria um número novo e verificaria as posições anteriores à 6a para ver se algum outro elemento repetiu-se. O que o Romário não considerou foi: o que acontece se, agora, o número novo coincidir com a 7a posição (que, na minha verificação, "ficou para trás")?

Como vocês podem ver, é um processo muito mais complexo do que parece ser.

Uma solução para o problema seria, ao invés de gerar um número aleatório entre 1 e 60, escolher um número em uma lista contendo apenas os números não previamente escolhidos. Uma forma de fazer isso seria com uma lista (FIFO) onde, para cada elemento adicionado ao array, o mesmo elemento seria removido da lista. Dessa forma, seria garantido que qualquer elemento "gerado" seria novo e não repetido no array.

Espero ter ajudado (apesar de crer que deixei mais dúvidas do que respostas). Qualquer coisa, é só entrar em contato.

Obrigado Wladimir, de fato posso dizer que fiquei mais confuso mas no entanto é interessante entender que mais pra frente estudando e me empenhando vou conseguir resolver problemas assim.

Acho que uma forma de resolver que eu acho interessante é:

<meta charset="UTF-8">
<script>
var sorteados = []; // cria o array para os números sorteados
var sorteio1numero = function(array) { //sorteia um número e verifica se é igual aos outros, se for igual roda a função de sorteio de novo
    var numero = (Math.round(Math.random() * 59) + 1);
        var diferente = true;
    for (var i =0; i < (array.length -1); i++) {
        if(array[i] == numero){
            diferente = false;
        }
    }
    if(diferente == true){
        array.push(numero);
    } else {
        sorteio1numero(array);
    }
}

for(var i=1; i<=6; i++){ //roda a função de sorteio 6 vezes
    sorteio1numero(sorteados);
}

document.write(sorteados);

</script>

Essa é uma forma de fugir do erro de sortear o mesmo número. Roda a mesma função de novo caso algum número seja igual. É provável que alguém faça isso de um jeito mais elegante do que eu, mas essa foi a minha ideia de resolver.

Apesar do custo envolvido, no caso geral (que é desprezível para um array de 6 posições, felizmente), é uma ótima solução pois garante que todo o array seja comparado a cada geração de número. Muito bom, Ivan.

Gente, Acho que vou dificultar um pouco a coisa. O problema da minha solução é que quando tem um número igual, eu rodo uma função dentro de uma função. Isso, pelo que eu entendo, gasta mais memória no computador, não? Imagina que eu dou o azar de repetir o número várias vezes, eu vou gerar quase o efeito de abrir vários programas juntos. Tem alguma forma de matar a função mãe, antes de rodar a seguinte? Quanto isso pode prejudicar o meu programa?


Tentando explicar de forma mais leve. Minha função sorteio1numero, chama ela mesma de novo no caso do número ser igual, mas ela não se encerra. Se o número bater igual 3 vezes, vou ter 4 funções sorteio1numero rodando ao mesmo tempo. Tem alguma forma de matar a função mãe, antes de rodar a seguinte? Quanto isso pode prejudicar o meu programa?


Uma solução seria:
<meta charset="UTF-8">
<script>
var sorteados = []; // cria o array para os números sorteados
var sorteio1numero = function(array) { //sorteia um número e verifica se é igual aos outros, se for igual acaba a função ali
    var numero = (Math.round(Math.random() * 59) + 1);
        var diferente = true;
    for (var i =0; i < (array.length -1); i++) {
        if(array[i] == numero){
            diferente = false;
        }
    }
    if(diferente == true){
        array.push(numero);
    } 
}

while(sorteados.length < 6){ //roda a função de sorteio até ter 6 numeros
    sorteio1numero(sorteados);
}

document.write(sorteados);

</script>

Mas acho esse resultado menos elegante do que o outro. Não?

Então, no escopo deste problema, as chances de sua função recursiva representar um "perigo" em termos de processamento são praticamente nulas. Então, na prática, você não precisa se preocupar com a implementação já que ela resolve a questão da repetição dos números.

No caso geral, onde não sabemos o tamanho do array nem o intervalo de números sorteados, também não é um problema muito grande. Essa implementação só teria um custo alto, de fato, no pior caso (tamanho do array é o intervalo de sorteio), pois o número de ciclos da recursão tende a crescer muito. Neste caso, seu segundo algoritmo, que não utiliza recursão, seria o recomendado.

Quanto à elegância, quando se trabalha profissionalmente com desenvolvimento, você percebe que, muitas vezes, vale a pena abrir mão de um código elegante por um eficiente. Então eu não me preocuparia com isso.

Valeu, Wladimir! Ajudou bastante. Eu sempre fico pensando em fazer coisas elegantes, mas você está certíssimo. Eficiência deve ser o objetivo.

Boa tarde, testei aqui e acho q resolvi o problema, segue cod abaixo.

function sorteio (tentativas){ sorteado = [] for (i = 0; sorteado.length < tentativas; i++) { sorteando = parseInt(Math.random()*60); for (k = 0; k < 6; k++){ if (sorteando == sorteado[k]) { break; }else{ sorteado.push(sorteando) console.log(sorteado); break; } } } return sorteado; }

O cod q postei acima ainda tem furos na verificação de números repetidos, consegui consertar no cod abaixo, agora ele verifica todos os números antes de registrar, antes verificava 1 e registrava, verificava outro e registrava, dessa forma tinha brechas e continuava registrando números repetidos.

Eu uso a variável "tentativas" = 6 só que não aparece aqui. Dessa forma, se eu quiser mudar o numero de jogadas para 4, por exemplo, eu só mudo uma variável.

function sorteio (tentativas){
        sorteado = []
        for (i = 0; sorteado.length < tentativas; i++) {
            sorteando = parseInt((Math.random()*59)+1);
            for (k = 0; k < tentativas; k++){
                duplicado = []
                if (sorteando == sorteado[k]) {
                    break;
                }else{
                    duplicado[k] = sorteando
                }
            }

            if (duplicado.length == tentativas)
            {sorteado.push(sorteando)
            console.log(sorteado);}    

        }
        return sorteado;
    }