0

I am trying to create a function that generates a random number from a given interval, but I want to be able to generate only 3 identical consecutive numbers. For example, if a have the interval [0,4) I want:

  • Accepted: 1, 2, 2, 2, 1, 0
  • Not accepted: 1, 2, 2, 2, 2, 3, 0

I've found on multiple threads functions that generates a different number than the previous one, but I don't know how to change it to accomplish what I need. Any thoughts?

oiis9719
  • 3
  • 3
  • 1
    depending on what your usage case is, it is a bad idea to code too many rules into the function- the more you restrict randomness, the more patterns will arise. – JoSSte Oct 01 '20 at 12:54
  • Can you be more specific? I can't understand your rules with the given info and example. Please give a more elaborative example with some explanation – Siddhant Varma Oct 01 '20 at 13:10
  • show us the code you wrote so far – Omri Attiya Oct 01 '20 at 13:11
  • You may store the last three numbers generated outside the function and check if the new generated number is not the same as the stored ones – Joulss Oct 01 '20 at 13:11
  • Not so much clear on your question and language used.. However refer here for random number generation and use n-1, n-2 index within the new range to detect if there are any violations of the 3 consecutive rules. https://stackoverflow.com/questions/363681/how-do-i-generate-random-integers-within-a-specific-range-in-java – bijayk Oct 01 '20 at 13:38

4 Answers4

0

Try this

function randomBetween(min, max, limit = 3) {
  if (min > max) {
    [max, min] = [min, max];
  }

  function getBetween(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
  }

  let last;
  let count = 0;

  return function generate() {
    const result = getBetween(min, max);

    count = (result === last) ? count + 1 : 0;

    if (count > limit) {
      return generate();
    }

    last = result;

    return result;
  };
}
Kayac
  • 64
  • 1
  • 8
0

You must completely reset your counter, when you generate a different number. Not just decrease it.

function setRandomInterval(min, max, allowedRepeats) {
  var last,            // keeping the last random value
      repeatCount = 0, // count of repeated value
      getR = function () { return Math.floor(Math.random() * (max - min)) + min; };

  if (min >= max) {
    throw 'Selected interval [' + min + ', ' + max + ') does not work for random numbers.';
  }
    
  return function () {
    var r = getR();
    if (r != last) {  
      repeatCount = 0;  //no repeat yet
    } else if (repeatCount < allowedRepeats) { //new number is equal to last one, but it's still ok
      repeatCount++;  //just increase the number of repeats
    } else {  //new number is equal to last, and allowed number of repeats is reached
      while (r == last) {  //must create a different number
        r = getR();
      }
      repeatCount = 0;  //reset the repeatCount
    }
    return last = r;  //save r as last number and return it
  };
}



var getRandom = setRandomInterval(0, 4, 2);  //call with 2 allowed repeats to allow a sequence of three equal numbers
derpirscher
  • 14,418
  • 3
  • 18
  • 35
  • Thank you for sharing me the details about the execution! I learned from it and I am grateful for the amount of time and effort you put into this helping me. The code works and I understand now where I was doing wrong. – oiis9719 Oct 02 '20 at 07:42
0

Here's a snippet that prevent from the same number to randomize more than 3 times. If the count of the number is greater than the limit the randomNumber is called again (and so on until it won't get the same value.

You can see (when running it) that the largest sequence is 3.

const limit = 3;
let last = null,
  count = 0;

function getRndInteger(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

function randomNumber(min, max) {
  let num = getRndInteger(min, max);
  if (last !== num) {
    last = num;
    count = 0;
  }
  count++;
  if (count > limit) {
    num = randomNumber(min, max);
  }
  return num;
}

for (let i = 0; i < 20; i++)
  console.log(randomNumber(0, 2));
Omri Attiya
  • 3,917
  • 3
  • 19
  • 35
0

Here is an approach that's uses a nice feature of modern JS. Generators..

Using generators you can create composable code. Instead of creating 1 function that does this one specific thing, you can compose a function than stream together multiple generators. This is great for making re-usable code.

Below I've created 3 function,.

  • randomValues => this just generates random number between a range.
  • repeatLimit => this generator just prevents x amount of repeated values
  • iterCount => this generator stop after count iterations

All you do then is compose all these generators together, but the bonus is that these generators can be used in other places. eg. [...repeatLimit(3, [1,1,1,1, 0,0,0,0])] would return 1,1,1,0,0,0.

function* randValues(min, max) {
  const range = max - min;
  while (true) 
    yield min + Math.trunc(Math.random() * range);
}

function* repeatLimit(limit, gen) {
  let rcount = 0, rvalue;
  for (let g of gen) {
    if (rvalue === g) rcount += 1; else rcount = 1;
    rvalue = g;
    if (rcount <= limit) yield g;
  }  
}

function* iterCount(count, gen) {
  for (let g of gen) {
    yield g;
    count --;
    if (count <= 0) break;
  }
}


const gen = 
  iterCount(22, repeatLimit(3, randValues(0, 2)));

for (const r of gen) {
  console.log(r);
}
Keith
  • 22,005
  • 2
  • 27
  • 44
  • 1
    Thank you for making this code so clean and re-usable. It works perfectly and I've learned from it more than I was thinking, I appreciate it! – oiis9719 Oct 02 '20 at 07:47