How to make the first two numbers of a sequence Math.Andom are NOT EQUAL

Asked

Viewed 1,135 times

8

I made a lottery system in order to learn, I will not post the entire code here just the part I’m stuck.

The PC draw is a sequence of 6 numbers that I present in the DOM (that doesn’t matter), so I want the first two numbers to NEVER be equal.

I tried it with While but it’s not working, look:

    //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 didn’t work, I run the algorithm several times and one hour it appears with the first two numbers equal.

What am I doing wrong?

Suggest I post the entire code?

  • Dude, really weird. Can you create a jsfiddle? Something else, you can simplify your code that checks for repetitions while (rn1 === rn2) { rn2 = 1 + (Math.round(Math.random() * 19)); }

  • Can you accept any of the answers?

3 answers

11

Follows a solution using Fisher-Yates shuffle.

This algorithm has the characteristic of not repeating the data, because it simply changes the position of the members.

The algorithm is a very simple loop, it starts from the first item, and swaps with some of the following randomly (even with "himself") and can be considered "shuffled" already. This is done with the next item, drawing from it even to the last one (no longer deals with the first one, only from then on). The same is done with the third item (no longer deals with the previous two) and so on.

Follows the code:

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 += 'Clique novamente em "executar" para outro sorteio';

Modern version (1964 :P) of the algorithm:

https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm

  • 2

    You gave the answer I came here to give. The problem is that in this case all right, it is assumed that the array will not be large, but when the range of the numbers is immense it can be a memory problem (store in an array, shuffle and take the first element)

  • 1

    Bacco, then, was to n repeat no yes, but I wanted an answer to n repeat the first two, so that with the rest I would turn to logic. Finally, what did you think of this gambiarra q I did? jsfiddle.net/r3r3ra9a It’s working perfectly at least. The bad news is that if you pass 6 numbers becomes giga, I’m beginner and so on.

  • Aprimorei mas ainda tá 1a merd http://jsfiddle.net/fh0jf07s/

  • @renatoargh I took for base a lottery, in which there may be the pool, with several numbers, and more importantly, in the random homogeneity (that Fisher-Yates gives), but if it is a case in which you want few random of a gigantic collection, I agree that there are more economic methods.

7

Here is a suggestion more DRY. Ie 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’s a test running this code 10,000 times.
Take a look at the console: http://jsfiddle.net/6vvyh0a3/

In this code I put the function novoNumero accepts as parameter the index, ie the position of the number in the array. The cycle for 0 to 5 and every iteration calls the function.

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

After that, sure not to have repeated numbers, push (insert) this number in the array.

  • Seriously, what did you think I did? http://jsfiddle.net/r3r3ra9a/ .

  • I improved a little, but still ta 1a merd http://jsfiddle.net/fh0jf07s/

  • @ropbla9 I do not like to see repeated code. They have to use functions. It does not serve the solution that is in my answer?

  • served yes, perfectly but I made my own to exercise.

  • I could explain your code better?

  • @ropbla9 clear. I edited the question and explained better. Tell if something is unclear.

Show 1 more comment

3

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

Basically it would be something like:

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

I separated the code into three functions one that generates the chart, another for the soterio and one that counts the correct.

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

Browser other questions tagged

You are not signed in. Login or sign up in order to post.