Randomize number on click but never the same number - javascript

I want to random a number on clicking button but I don't want same numbers to be randomized any solutions?
$('button').click(function(){
var nomeri = Math.floor(Math.random() * 100);
}
<button>დამაკლიკე</button>

You could use a recursive function to generate a unique number.
I am implementing the function with an array which will hold the value of the previously used numbers and the Math.random() to generate the random number.
steps:
Step 1. Create a function.
Step 2: Generate a random number
step 3: check if it exists in the array
step 4: if already exists then call the function again otherwise we have the unique random number.
if the function exceeds the max random numbers then it will return a negative number. You could handle this according to your need, you could reset the array or something like that.
Try this.
$('button').click(function(){
var nomeri = genRandomNum();
console.log(nomeri);
});
let random = [];
function genRandomNum() {
let randNum = Math.floor(Math.random() * 100);
if (random.length >= 100) {
return -1;
} else if (random.includes(randNum)) {
return genRandomNum();
} else {
random.push(randNum);
return randNum;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Random Number</button>

Here is a more efficient way to do this. Doing it the way Sohail proposed could result in many many function calls, especially once there have been a large share of the available numbers added to the array. Each time it finds a number that has been used before it calls the function again in search of a random number that has not been used yet. It could take a long time to find an unused number.
This way you are guaranteed to get an unused number the first time you call the function.
1) All possible answers are added to an array.
2) Then a random value from that array is returned.
3) The array is then modified to exclude the values already returned.
See: array.splice()
const allPossibleValues = [];
for(let i = 0; i < 100; i++){
allPossibleValues.push(i);
}
$('button').click(function(){
if(allPossibleValues.length){
let nomeri = returnRandomValueFromArray();
console.log(nomeri);
}
else {
console.log("No more values left");
}
});
function returnRandomValueFromArray() {
const randomIndex = Math.floor(Math.random() * allPossibleValues.length);
const randomValue = allPossibleValues[randomIndex];
allPossibleValues.splice(randomIndex, 1);
return randomValue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>დამაკლიკე</button>

Related

How to approach creating array of random numbers with no repeats

I’ve created a lotto number generator and am having trouble making sure no two sets of numbers come out the same. I want to first check that the next generated number doesn’t match a previous one in the array, if it does then generate a new number.
The code:
https://codesandbox.io/s/billowing-leaf-oqdt3?file=/index.html
You can do it step by step by replacing what you have line 46 by:
// Get a random number
var rnd = rand(high);
// If it is already in the array, get another
while (numList.includes(rnd)) {
rnd = rand(high);
}
// Now you know the value is unique, so you can add it to the list.
numList.unshift(rnd);
use a hash:
var numberHash = {}
var num1=generateNum(numberHash);
var num2=generateNum(numberHash);
function generateNum(numberHash) {
var num = rand();
while(numberHash[num]) {
num = rand();
}
numberHash[num]=true;
return num;
}

Generate a non-repeating random number in JavaScript

How do I ensure that I don't get a repeat of a random number? Right now, this isn't working. I'm using a local array to store previous results.
getUniqueRandomNumber(x){
var index;
var viewedIndices = [];
index = Math.floor(Math.random() * (x));
if(viewedIndices.includes(index))
{
viewedIndices.push(index);
this.getUniqueRandomNumber(x);
}
else {
console.log(index);
return index;
}
}
You need to make viewedIndicies persistent, so that further calls of getUniqueRandomNumber can see elements previously added. Rather than keeping track of the indicies, it would probably be easier to keep track of just the plain numbers chosen. You can use a Set instead of an array for less computational complexity (.has is O(1), .includes is O(N)).
const makeGetUniqueRandomNumber = (x) => {
const chosenNumbers = new Set();
return () => {
if (chosenNumbers.size === x) {
throw new Error('No more uniques!');
}
let num;
do {
num = Math.floor(Math.random() * x);
} while (chosenNumbers.has(num));
chosenNumbers.add(num);
return num;
};
};
const getRand5 = makeGetUniqueRandomNumber(5);
console.log(
getRand5(),
getRand5(),
getRand5(),
getRand5(),
getRand5()
);
try {
getRand5();
} catch(e) {
console.log(e.message);
}
const anotherGetRand5 = makeGetUniqueRandomNumber(5);
console.log(
anotherGetRand5(),
anotherGetRand5(),
anotherGetRand5(),
anotherGetRand5(),
anotherGetRand5()
);
You may also generate the whole array of random numbers ahead of time, and then splice each time another is chosen, but that'll be inefficient when the number of possibilities is large but you only need a few random numbers. The right choice depends on the proportion of unique numbers needed in one session to the size of the random range.
If developing in an ancient environment which doesn't understand ES6 (ES2015) syntax, then you can use an array instead of a Set, and pass the code through Babel:
"use strict";
var makeGetUniqueRandomNumber = function makeGetUniqueRandomNumber(x) {
var chosenNumbers = [];
return function () {
if (chosenNumbers.length === x) {
throw new Error('No more uniques!');
}
var num;
do {
num = Math.floor(Math.random() * x);
} while (chosenNumbers.includes(num));
chosenNumbers.push(num);
return num;
};
};
var getRand5 = makeGetUniqueRandomNumber(5);
console.log(getRand5(), getRand5(), getRand5(), getRand5(), getRand5());
try {
getRand5();
} catch (e) {
console.log(e.message);
}
var anotherGetRand5 = makeGetUniqueRandomNumber(5);
console.log(anotherGetRand5(), anotherGetRand5(), anotherGetRand5(), anotherGetRand5(), anotherGetRand5());
You have 2 mistakes, oné is the array inside the function this cleared for each try, and then there is wrong logic ending up in an infinite loop.
const usedIndexes = [];
function getUniqueRandomNumber(x) {
const index = Math.floor(Math.random() * (x));
if (usedIndexes.includes(index)) {
return this.getUniqueRandomNumber(x);
} else {
console.log(index);
usedIndexes.push(index);
return index;
}
}
Also, I would think about using Set, in this situation instead of the array.
const usedIndexes = new Set();
function getUniqueRandomNumber(max, min = 0) {
const newNumber = Math.floor(Math.random() * (max - min) + min);
if (usedIndexes.has(newNumber)) {
return this.getUniqueRandomNumber(max, min);
} else {
usedIndexes.add(newNumber);
return newNumber;
}
}
I have also edited variables names to better reflect their actual use and added a minimum for a random number.
This is not working because every time you call getUniqueRandomNumber it re-initializes your viewedIndices array to empty array. So to make your code work declare this array above the function call.
Do you just want the code you wrote to work or do you want a better solution? Picking random numbers until you don't get a repeat is a recipe for disaster down the line as your program stalls for several seconds trying to find a number that hasn't been used. Sure if you're only asking for a few numbers maybe it won't take forever but then the code sits in your code base and 5 years from now someone else is using it not knowing there is a time bomb in the code. Imagine there are 10000 elements in the array and 9999 have been picked. It could easily take 1 million re-tries before it ends up picking the one unused index.
The code appears to be choosing indices with variable names like index and viewedIndices
One way to pick random elements is just just remove then from the array at random. If you need to make copy of the array
const array = ["a", "b", "c", "d", "e", "f", "g"];
while (array.length) {
const ndx = Math.random() * array.length | 0;
const elem = array.splice(ndx, 1)[0];
console.log(elem);
}
Note: using Math.random() * value | 0 to get a random 0 -> positive integer is faster than Math.floor(Math.random() * value) as | is an operator, not a function attached to the Math object that has to be checked on every call to see if it has been replaced.

adding random value to array and comparing first two value js

I am trying to learn some simple things in js, so what i am trying to achieve is every time I get a random number I want to add it inside an array at he front, then compare the first two values make sure they are not [6,6]
function randomNumber() {
number = Math.floor((Math.random() * 6) + 1);
return number;
}
function addValue() {
var score = [];
score.unshift(randomNumber());
console.log(score);
return score;
}
At the moment what is happening, every time i call the randomNumber the array only stores one value, it does not append it to the list and overweights the previous.
What am I doing wrong and why is it working? thx
the variable you use to store the array needs to be created and passed through the argument list, or stored globally.
when you do var x = [] you are create a NEW empty array.
var score = [];
addValue(score);
addValue(score);
addValue(score);
function randomNumber() {
number = Math.floor((Math.random() * 6) + 1);
return number;
}
function addValue(score) {
score.unshift(randomNumber());
}
console.log(score)

How to generate a new random number (that's different from the previous random number)

I'm trying to change the following (that currently returns a random number from an array), so that each random number is different from the last one chosen.
function randomize(arr) {
return arr[Math.floor(Math.random()*arr.length)];
}
oracleImg = [];
for (var i=1;i<=6;i++) {
oracleImg.push(i);
}
randOracleImg = randomize(oracleImg);
I tried the following, but it's not always giving me a number different from the last number.
function randomize(arr) {
var arr = Math.floor(Math.random()*arr.length);
if(arr == this.lastSelected) {
randomize();
}
else {
this.lastSelected = arr;
return arr;
}
}
How can I fix this?
Your existing function's recursive randomize() call doesn't make sense because you don't pass it the arr argument and you don't do anything with its return value. That line should be:
return randomize(arr);
...except that by the time it gets to that line you have reassigned arr so that it no longer refers to the original array. Using an additional variable as in the following version should work.
Note that I've also added a test to make sure that if the array has only one element we return that item immediately because in that case it's not possible to select a different item each time. (The function returns undefined if the array is empty.)
function randomize(arr) {
if (arr.length < 2) return arr[0];
var num = Math.floor(Math.random()*arr.length);
if(num == this.lastSelected) {
return randomize(arr);
} else {
this.lastSelected = num;
return arr[num];
}
}
document.querySelector("button").addEventListener("click", function() {
console.log(randomize(["a","b","c","d"]));
});
<button>Test</button>
Note that your original function seemed to be returning a random array index, but the code shown in my answer returns a random array element.
Note also that the way you are calling your function means that within the function this is window - not sure if that's what you intended; it works, but basically lastSelected is a global variable.
Given that I'm not keen on creating global variables needlessly, here's an alternative implementation with no global variables, and without recursion because in my opinion a simple while loop is a more semantic way to implement the concept of "keep trying until x happens":
var randomize = function () {
var lastSelected, num;
return function randomize(arr) {
if (arr.length < 2) return arr[0];
while (lastSelected === (num = Math.floor(Math.random()*arr.length)));
lastSelected = num;
return arr[num];
};
}();
document.querySelector("button").addEventListener("click", function() {
console.log(randomize(["a","b","c","d"]));
});
<button>Test</button>
Below code is just an example, it will generate 99 numbers and all will be unique and random (Range is 0-1000), logic is simple just add random number in a temporary array and compare new random if it is already generated or not.
var tempArray = [];
var i=0;
while (i != 99) {
var random = Math.floor((Math.random() * 999) + 0);
if (tempArray.indexOf(random)==-1) {
tempArray.push(random);
i++;
} else {
continue;
}
}
console.log(tempArray);
here is a version which will ensure a random number that is always different from the last one. additionally you can control the max and min value of the generated random value. defaults are max: 100 and min: 1
var randomize = (function () {
var last;
return function randomize(min, max) {
max = typeof max != 'number' ? 100 : max;
min = typeof min != 'number' ? 1 : min;
var random = Math.floor(Math.random() * (max - min)) + min;
if (random == last) {
return randomize(min, max);
}
last = random;
return random;
};
})();
If you want to ALWAYS return a different number from an array then don't randomize, shuffle instead!*
The simplest fair (truly random) shuffling algorithm is the Fisher-Yates algorithm. Don't make the same mistake Microsoft did and try to abuse .sort() to implement a shuffle. Just implement Fisher-Yates (otherwise known as the Knuth shuffle):
// Fisher-Yates shuffle:
// Note: This function shuffles in-place, if you don't
// want the original array to change then pass a copy
// using [].slice()
function shuffle (theArray) {
var tmp;
for (var i=0; i<theArray.length;i++) {
// Generate random index into the array:
var j = Math.floor(Math.random()*theArray.length);
// Swap current item with random item:
tmp = theArray[i];
theArray[j] = theArray[i];
theArray[i] = tmp;
}
return theArray;
}
So just do:
shuffledOracleImg = shuffle(oracleImg.slice());
var i=0;
randOracleImg = shuffledOracleImg[i++]; // just get the next image
// to get a random image
How you want to handle running out of images is up to you. Media players like iTunes or the music player on iPhones, iPads and iPods give users the option of stop playing or repeat from beginning. Some card game software will reshuffle and start again.
*note: One of my pet-peeves is music player software that randomize instead of shuffle. Randomize is exactly the wrong thing to do because 1. some implementations don't check if the next song is the same as the current song so you get a song played twice (what you seem to want to avoid) and 2. some songs end up NEVER getting played. Shuffling and playing the shuffled playlist from beginning to end avoids both problems. CD player manufacturers got it right. MP3 player developers tend to get it wrong.

Check if number is in an array an generate new number if it is

I'm making a simple script to create a random number. The intent of the script is to ultimately cache each random number in an array and then loop through this array when generating new numbers to see if the previous one had already been used. If it has been used then the script would continue looping until a number is created that is not in the array, and then return that number. I wrote the code below and the logic is simple enough but I don't know why it works when launched sometimes and then blows the stack at other times without returning a number.
var oldNumbs = [1,2,3,4,6,7] // dummy data
var randomNumb = Math.floor((Math.random() * 10) +1);
function checkIfInArray(value, array) {
if(array.indexOf(value) > -1){
randomNumb = Math.floor((Math.random() * 10) +1);
checkIfInArray(value, array)
}
else{
return randomNumb
}
}
console.log(checkIfInArray(randomNumb,oldNumbs)); /* sometimes returns a number not in the array and sometimes blows the stack. It mostly blows the stack. */
Simple mistake it is. You need to pass randomNumb instead of value since randomNumb is the new random number you generated.
checkIfInArray(randomNumb , array)
Your 'undefined' comes because you don't return anything if the number is already in the array.
function checkIfInArray(value, array) {
if(array.indexOf(value) > -1){
var randomNumb = Math.floor((Math.random() * 10) +1);
value = checkIfInArray(randomNumb, array);
}
return value;
}
Is this your actual code because you've passing value in to the recursive call to checkIfInArray, this just passes the same random number over and over again, if that number was already in the array it crashes, change it to randomNumb and you should be fine.

Categories