2

I try to run the number generator and it works correctly but sometimes it returns repeated numbers. I have tried some options but it keeps going the same way or it removes some number. What is the best alternative?

function sorteio() {

  const numeroAleatorio = (min, max) => {
    return Math.floor(Math.random() * 59 + 1)
  };

  const gerarNumerosEntre1a60 = n => {
    const resultado = [];
    for (let i = 0; i < n; ++i) {
      resultado.push(numeroAleatorio(1, 60));
    }
    return resultado;
  }
  
  document.getElementById("resultado").innerHTML = gerarNumerosEntre1a60(6);

}
<button onclick="sorteio()">Sortear numeros!</button>
<h1 id="resultado"></h1>
Andy
  • 61,948
  • 13
  • 68
  • 95
  • 1
    of course, because `numeroAleatorio` has no clue what number was already generated before - if what you want is the numbers 1 to 60 in random order ... start with an array of numbers 1 to 60, and shuffle them – Jaromanda X Sep 01 '22 at 00:05
  • Also known as: that's literally how random numbers work. If you do _any_ kind of reduction (i.e. by making it only generate one of 59 numbers) then you will get repeat numbers because _you should_. If you had zero repeated numbers, that wouldn't be random. At any call to `numeroAleatorio` there's a 1/59 chance that you're going to get _exactly the same number_ as you already had. – Mike 'Pomax' Kamermans Sep 01 '22 at 01:18

3 Answers3

0

The numeroAleatorio function selects a number from min to max randomly, but each selection is independent of the others. The function cannot 'remember' the past choices and select a number different from them.

To select multiple numbers from 1-60, you can push all numbers in one array, do a random shuffle, and select a contiguous subset.

here is another answer showing the Knuth shuffle algorithm: How to randomize (shuffle) a JavaScript array?

// random shuffle
function shuffle(array) {
    let currentIndex = array.length,  randomIndex;
    while (currentIndex != 0) {
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;
        [array[currentIndex], array[randomIndex]] = [
            array[randomIndex], array[currentIndex]];
    }
    return array;
}

const gerarNumerosEntre1a60 = n => {
    let array = [];
    for(let i = 1; i <= 60; i++) {
        array.push(i);
    }
    return shuffle(array).slice(0, n)
}
creaple
  • 135
  • 7
0

JaromandaX mentioned a good alternative in their comment, and here's another.

I've cached the elements up-front, and added a listener to the button (removing the inline JS from the HTML markup). Using a while statement we can loop until six numbers have been added to the resultado array. Within the loop we draw a number and if it's already in resultado loop again, otherwise push the number.

Finally sort the array (because it's a lottery draw), and then join it, adding the string to text content of result.

// Cache the elements, and add an event listener to
// the button
const result = document.querySelector('#resultado');
const button = document.querySelector('button');
button.addEventListener('click', () => sorteio(6));

// Use `min` and `max` within the function
function numeroAleatorio(min, max) {
  return Math.floor(Math.random() * (max - min) + min);
}

// Initialise `n` to 6 if it hasn't
// be supplied as an argument
function sorteio(n = 6) {

  const resultado = [];
  
  // Check the length of `resultado` - if it's
  // less than the value of `n` get a new number.
  // If the number is already in `resultado` loop again,
  // otherwise push the number into the array
  while (resultado.length < n) {
    const number = numeroAleatorio(1, 60);
    if (!resultado.includes(number)) {
      resultado.push(number);
    }
  }
  
  // Finally sort and join the array and add
  // the string to the result text content
  result.textContent = resultado
    .sort((a, b) => a - b)
    .join(', ');

}
<button>Sortear numeros!</button>
<h1 id="resultado"></h1>
Andy
  • 61,948
  • 13
  • 68
  • 95
0

An alternative to Andy answer, using Set

Since adding an existing value to a Set does effectively nothing, this keeps adding values to the set until the size reaches the required count

Warning: It's naive code that doesn't check that count greater than the possible values

function sorteio() {

  const getRandom = (min, max, count) => {
    const result = new Set;
    while (result.size < count) {
      result.add(Math.floor(Math.random() * (max - min + 1)) + min);
    }
    return [...result];
  }
  const gerarNumerosEntre1a60 = n => {
    const resultado = getRandom(1, 60, n);
    return resultado;
  }

  document.getElementById("resultado").innerHTML = gerarNumerosEntre1a60(6);

}
<button onclick="sorteio()">Sortear numeros!</button>
<h1 id="resultado"></h1>
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87