How to make the first two numbers of a Math.random sequence are not EQUAL

7

I made a lottery system in order to learn, I will not post the whole code here just the part that I am packed.

It is as follows: The draw of the PC is a sequence of 6 numbers that I present in the DOM (it does not matter), so I want the first two numbers to NEVER be equal.

I've tried this with While but it's not working, see:

    //gera o sorteio de 6 numeros de 1 a 20
    var rn1 = 1 + (Math.round(Math.random() * 19));
    var rn2 = 1 + (Math.round(Math.random() * 19));
    var rn3 = 1 + (Math.round(Math.random() * 19));
    var rn4 = 1 + (Math.round(Math.random() * 19));
    var rn5 = 1 + (Math.round(Math.random() * 19));
    var rn6 = 1 + (Math.round(Math.random() * 19));

    //eis oq eu tentei
    if(rn2 == rn1){ // se rn1 = rn2
        while(rn2 == rn1){ // comece o loop
            gerarnew1 = 1 + (Math.round(Math.random() * 19)); // gera um novo valor de 1 a 20 e roda até que...
                if(gerarnew1 != rn1){ // ...não seja mais = rn1
                    rn2 = gerarnew1; // entao atribuo esse novo numero a rn2
                    break; // paro o loop e, pela logica rn2 agora é != rn1
                }
        }
    }
    //entao sao armazenados aqui e apresentados dps no resto do codigo
    var rsorteio = new Array(rn1,rn2,rn3,rn4,rn5,rn6);

But as I'm posting here it's certainly because it did not work, I run the algorithm several times and one hour it appears with the first two numbers equal.

What am I doing wrong?

Suggest that I post the whole code?

    
asked by anonymous 05.10.2014 / 07:02

3 answers

8

Here's a solution using Fisher-Yates scrambling:

var max = 20;
var set = [];
var i, j, t;
for( var i = 1; i <= max; i++ ) set.push( i );

for( i = 1; i < ( max - 1 ); i++ ) {
  j = i + ( Math.round( Math.random() * ( max - i - 1 ) ) );
  t = set[j];
  set[j] = set[i - 1];
  set[i - 1] = t;
}


// Demonstrando o resultado pegando 6 números
for( i = 0; i < 6; i++ ) document.body.innerHTML += set[i]+'<br>';
document.body.innerHTML += '<a href="javascript:location.reload(true)">Novo sorteio</a>';
    
05.10.2014 / 14:15
6

Here is a more DRY suggestion. That is without repeating code.

var numeros = [];

function novoNumero(index) {
    var sugestao = 1 + (Math.round(Math.random() * 19));
    if (index == 1 && sugestao == numeros[0]) sugestao = novoNumero(index);
    return sugestao;
}
for (var i = 0; i < 6; i++) {
    var numero = novoNumero(i);
    numeros.push(numero);
}

console.log(numeros.join(' - '));
// dá por exemplo: 16 - 12 - 17 - 2 - 19 - 19 

Here is a test running this code 10,000 times. Take a look at the console: link

In this code that I put the function novoNumero accepts as parameter the index, that is the position of the number in the array. The for cycle goes from 0 to 5 and at each iteration it calls the function.

The function creates a new number and, if the value index received is 1 , then it compares with the first number already generated in the previous iteration (ie numeros[0] ). If they are the same, the function calls itself and generates a new number that will again compare.

After that, sure to not have repeated numbers, push that number in the array.

    
05.10.2014 / 08:37
2

I believe the most appropriate way for this problem (do not repeat elements) is to use type set of the javascript because it does not allow duplicate elements. This simplifies both the generation of numbers and the control / end of the loop to generate the card and the game.

Basically it would look something like:

var cartela = new Set();
while(cartela.size < 6) cartela.add(número aleatório)

I have separated the code in three functions, one that generates the card, another one for the soterio and one that counts the correct ones.

function gerarSorteio(){
    var sorteio = new Set();  
    while(sorteio.size < 6){
        sorteio.add(Math.round(Math.random() * 20));
    }
    return sorteio;
}

function marcarDezenas(){
    var cartela = new Set();
    while(cartela.size < 6){
        cartela.add(parseInt(prompt("Informe a Dezena:")));
    }
    return cartela;
}

function resultado(sorteio, cartela){
    var acertos = [];
    for (let item of sorteio){
        if(cartela.has(item)){
            acertos.push(item);
        }
    }
    return acertos;
}

var sorteio = gerarSorteio();
var cartela = marcarDezenas();
var acertos = resultado(sorteio, cartela);

console.log(sorteio);
console.log(cartela);
console.log(acertos);

Example - replit

    
09.01.2018 / 14:54