I have some code to randomly highlight one name from a list (this works - see this fiddle):
function pickRandom() {
var random = Math.floor(Math.random() * 6);
$('.stname').css('background','none').eq(random).css('background','yellow');
}
But I'd like to make sure that the same names don't come up over and over. So I intend to remember the last 3 chosen indexes as a blacklist:
var recentlyAsked = new Array();
function pickRandom() {
var random;
do {
random = Math.floor(Math.random() * 6);
} while ($.inArray(random,recentlyAsked));
recentlyAsked.push(random);
if (recentlyAsked.length >= 4) recentlyAsked.shift();
$('.stname').css('background','none').eq(random).css('background','yellow');
}
This is not working; see this fiddle. Warning: it causes the browser to hang.
Any suggestions, please?
do {
random = Math.floor(Math.random() * 6);
} while ($.inArray(random,recentlyAsked));
Runs forever because inArray returns -1 when an item is not found in the array, which is a truthy value. 0 is the only number that is a falsy value. Your array is initially empty so nothing is found.
Fix it with :
do {
random = Math.floor(Math.random() * 6);
} while ($.inArray(random,recentlyAsked) > -1);
This will stop when it returns -1(not found)
var ids=['a','b','c'];
var old=['d','e','f'];//At the beginning this will need populated with 3 random values
var ran=Math.floor(Math.random() * ids.length);
var ele=ids.splice(ran,1);
old.push(ele);
ids.push(old.shift());
highlight(ele);
Here is a slightly alternative way to do what you want. The idea is just remove chosen elements and then add it back in to the original array.
Just thought I would throw my code out there:
var randomArray = new Array(0, 1, 2, 3, 4, 5);
var pastArray = new Array();
function pickRandom() {
var random = Math.floor(Math.random() * randomArray.length);
$('.stname').css('background', 'none').eq(randomArray[random]).css('background', 'yellow');
if (pastArray.length < 3) {
pastArray.unshift(randomArray[random]);
randomArray.splice(random, 1);
} else {
pastArray.unshift(randomArray[random]);
randomArray.splice(random, 1, pastArray.pop());
}
console.log("possible values: [" + randomArray + "]");
console.log("past values: [" + pastArray + "]");
}
Values are moved back and forth from the current and past values. There is no need to prepopulate values as 'past', so it starts out truly random.
Related
I'm trying to create an array with three unique random numbers between 1 and 14. I've found similar questions on Stackoverflow and used the code to help me create my existing code.
It works well most of the time, but occasionaly it will create an array with two of the same numbers. Here is the offending code:
function noDuplicates (sideRandom) {
sideArray.splice(sideRandom, 1);
let sideRandom2 = Math.floor(Math.random() * 14) + 1;
sideArray.push(sideRandom2);
console.log("I've had to add " + sideRandom2)
}
function sortNumbers(array) {
array.sort(function(a, b) {
return a - b;
});
}
document.getElementById("randomiser").addEventListener("click", function () {
for (let i = 0; sideArray.length <3; i++) {
let sideRandom = Math.floor(Math.random() * 14) + 1;
console.log(sideRandom);
if (sideArray.includes(sideRandom) === false) {
sideArray.push(sideRandom);
} else {
noDuplicates(sideRandom);
};
}
console.log(sideArray);
});
I suspect the issue is that sometimes the noDuplicates function generates the same random number as sideRandom, but I can't see a way around it. can you help?
Use set with while loop to make sure we got required number of unique random numbers
// Get unique random indexes
const random = (num, count) => {
const set = new Set();
while (set.size < count) {
set.add(Math.floor(Math.random() * num) + 1);
}
return [...set];
};
document.getElementById("randomiser").addEventListener("click", function () {
console.log(random(14, 3));
});
<button id="randomiser"> Get 3 random </button>
I take a look at your code: If there is a double you call noDuplicates and try to get a non double number but there you make some mistakes.
Why using Array#splice method? It will return the array without the first element (you don't user this result) and leave the original unchanged. So this line does anything. By the way why you want to delete the first element, youz didn't add the double random-number so there is anything do delete.
Afterwards you build another new randomnumber and push it to your array without checking. By this you get your dublettes.
Better way: If you finf a double set a flag on true and when you next add a number by this you can add your hint and reset the flag to false. So everything is one function.
document.getElementById("randomiser").addEventListener("click", function () {
let sideArray = [];
let double = false;
for (let i= 0; sideArray.length <3; i++) {
let sideRandom = Math.floor(Math.random() * 14) + 1;
console.log(sideRandom);
if (sideArray.includes(sideRandom) === false) {
if (double) {
double = false;
console.log("I've had to add " + sideRandom);
}
sideArray.push(sideRandom);
} else {
double = true;
}
}
console.log(sideArray.toString());
});
<button id='randomiser'>Click</button>
You can do this pretty easily with rando.js and slice. Plus, it's human-readable and cryptographically secure. randoSequence(1, 14) creates a shuffled array of all numbers from 1 through 14, and slice(0, 3) slices out the first three values from that shuffled array.
console.log(randoSequence(1, 14).slice(0, 3));
<script src="https://randojs.com/2.0.0.js"></script>
I am writing a script where I have to randomly generate a number from an array and then remove the number so that it cannot be generated again. What appears to be happening is that the number generated, after being spliced, is removing other numbers from my array. I assume it is being subtracted. Here is the necessary code:
var randNum = [0,1,2,3,4,5,6,7,8,9];
function clickHandler ()
{
output = randNum[Math.floor(Math.random() * randNum.length)];
console.log("This is the generated number:" + output);
randNum.splice(output);
console.log("This is the resulting array without the generated number:" + randNum);
}
You mix up value and index.
Array#splice needs a count for splicing elements. If not supplied, splice splices all items from the given index to the end.
var randNum = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function clickHandler() {
var index = Math.floor(Math.random() * randNum.length);
console.log("This is the generated number: " + randNum[index]);
randNum.splice(index, 1);
console.log("This is the resulting array without the generated number: " + randNum);
}
clickHandler();
clickHandler();
Use randNum.splice(index, 1); to remove only one number from array
If deleteCount is omitted, or if its value is larger than array.length - start (that is, if it is greater than the number of elements left in the array, starting at start), then all of the elements from start through the end of the array will be deleted
MDN
This is another way of doing it.
let numbersLeft = [0,1,2,3,4,5,6,7,8,9];
let numbersPulled = [];
function generateNumber(){
let randomNumber = randNum[Math.floor(Math.random() * randNum.length)];
return randomNumber;
}
function clickHandler () {
let numberToPull = generateNumber();
if ( numbersPulled.indexOf(numberToPull) != -1){
numbersLeft.splice(numberToTest, 0);
numbersPulled.push(numberToTest);
} else {
console.log('That number has already been pulled!');
}
}
I am new to Javascript and working with the basics. I am wanting to create an array whose individual elements are randomly drawn, one at a time, with a click of a button, until all array elements are displayed on the screen. The code I have is almost there. But the issue is that when it runs, it always grabs 2 elements on the first button click, rather than 1. It runs well for the remaining elements. Sure would appreciate some insight to this problem. Thank you.
var myArray=['1','2','3','4','5','6','7']
var text = "";
var i;
function RandomDraw() {
for(i = 0; i < myArray.length; i+=text) {
var ri = Math.floor(Math.random() * myArray.length);
var rs = myArray.splice(ri, 1);
document.getElementById("showSplice").innerHTML = text+=rs;
//document.getElementById("showArrayList").innerHTML = myArray;
}
}
It "always" draws 2 elements because of the i+=text. Your array is small thus the loop needs 2 iteration (of cocatinating the strings to get the number i) to go over myArray.length.
First iteration:
i = 0 => 0 < myArray.length => true
prints number
Second iteration: (say '4' get choosen)
i = i + text and text = '4' => i = "04" => "04" < myArray.length => true
prints number
Third iteration: (say '3' get choosen)
i = i + text and text = '43' => i = "0443" => "0443" < myArray.length => false
loop breaks
So there is a possibility that two elements get printed. Depending on the length of the array, there could be more.
You don't need the loop, just choose a number and print it:
function RandomDraw() {
if(myArray.length > 0) { // if there still elements in the array
var ri = Math.floor(Math.random() * myArray.length); // do your job ...
var rs = myArray.splice(ri, 1);
document.getElementById("showSplice").textContent = rs; // .textContent is better
}
else {
// print a message indicating that the array is now empty
}
}
Another solution is to shuffle the array and then, on each click, pop the element from the shuffled array.
function shuffle(array) {
return array.sort(function() { return Math.random() - 0.5; });
}
var button = document.getElementById('button');
var origin = ['1','2','3','4','5','6','7'];
var myArray = shuffle(origin);
var currentValue = null;
button.onclick = function() {
currentValue = myArray.pop();
if(!!currentValue) {
console.log(currentValue);
}
}
<button id='button'>
get element
</button>
You can shuffle the array again on each click, but I think it is not necessary whatsoever...
If you're wondering about Math.random() - 0.5:
[...] Math.random is returning a number between 0 and 1. Therefore, if you call Math.random() - 0.5 there is a 50% chance you will get a negative number and 50% chance you'll get a positive number.
If you run a for loop and add these results in an array, you will effectively get a full distribution of negative and positive numbers.
https://teamtreehouse.com/community/mathrandom05
I would do it this way:
let myArray=['1','2','3','4','5','6','7']
function RandomDraw(){
const selectedIndex = Math.floor(Math.random() * myArray.length);
const selected = myArray[selectedIndex]
myArray = myArray.slice(0, selected).concat(myArray.slice(selected + 1));
return selected;
}
Every time you call RandomDraw it will return a random number, without repeating.
The way I understand it, you want to draw every items from the array after a single click. So the loop is needed.
As others have said, there are several issues in your for loop :
that i+= text makes no sense
you are looping until i reaches the length of your array, but you are splicing that array, hence reducing its length
You could correct your for loop :
function RandomDraw() {
var length = myArray.length;
var ri = 0;
for (var i=0;i<length;i++) {
ri = Math.floor(Math.random() * myArray.length);
console.log("Random index to be drawn : " + ri);
// removing that index from the array :
myArray.splice(ri, 1);
console.log("myArray after a random draw : ", myArray);
}
}
Or, you could use a while loop :
function RandomDraw() {
var ri = 0;
while (myArray.length > 0) {
ri = Math.floor(Math.random() * myArray.length);
console.log("Random index to be drawn : " + ri);
// removing that index from the array :
myArray.splice(ri, 1);
console.log("myArray after a random draw : ", myArray);
}
}
I'm creating a battleship game, and I'm trying to randomize the computer's ships. However, it sometimes randomizes the same location more than once, thus creating less than 8 ships in some rounds. I tried to fix this using indexOf but I can't seem to get it to work no matter how I change the code. If the randomized number is in the array shipLocations then I want to reroll the number again until it's a number that doesn't match any number in the array. Any ideas?
var shipLocations = [];
function randShips() {
for (i = 0; i < 8; i++) {
var randomize = Math.floor(Math.random() * 64 + 1);
if (shipLocations.indexOf(randomize) == true) {
var randomize = Math.floor(Math.random() * 64 + 1);
}
else {
shipLocations.push(randomize);
}
} //end of i loop
} //end of randShips()
randShips();
console.log(shipLocations);
EDIT: So after trying out a few of the answers, this seems to be working the way it should be after testing about 100 times.
var shipLocations = [];
function randShips() {
while (shipLocations.length < 8) {
var randomize = Math.floor(Math.random() * 64 + 1);
while (shipLocations.indexOf(randomize) > -1) {
randomize = Math.floor(Math.random() * 64 + 1);
}
shipLocations.push(randomize);
}
}
randShips();
var shipLocations = [];
function randShips() {
while ( shipLocations.length < 8 ) {
var randomize = Math.floor(Math.random() * 64 + 1);
while ( shipLocations.indexOf(randomize) >= 0 ) {
randomize = Math.floor(Math.random() * 64 + 1);
}
shipLocations.push(randomize);
}
} //end of randShips()
randShips();
console.log(shipLocations);
Since you want 8 unique values, it's quite possible that 2 numbers created in a row are both in the array already. So I think you'll want to do a while:
while (shipLocations.indexOf(randomize) != -1) {
randomize = Math.floor(Math.random() * 64 + 1);
}
The var part shouldn't be there, that is only necessary for the first instance of the variable.
In javascript false conditions are returned with a value of -1.
Hence, change the if-else condition to :
if (shipLocations.indexOf(randomize) != -1) { //true condition equivalent
var randomize = Math.floor(Math.random() * 64 + 1);
}
else {
shipLocations.push(randomize);
}
indexOf doesn't return boolean value, it returns the index (int) of the matched element.
So the code should be
if (~shipLocations.indexOf(randomize)) {
var randomize = Math.floor(Math.random() * 64 + 1);
}
You could use this function to get a true unique number that for the array.
function uniqueRandom( arr) {
var num = Math.floor(Math.random() * 64 + 1);
if (~arr.indexOf(num)) {
uniqueRandom(arr);
} else {
return num;
}
}
Btw, the logic you had written has a problem. If you found a duplicate number, you just randomize it again, without pushing it into the array. so using a while or a recursive function should do the job quite well.
var links = ["http://www.google.com/", "http://www.cnn.com/", "http://www.bbc.com/", "http://www.nbc.com/"];
var random = Math.round(Math.random() * 4);
var previous = [];
previous.push(random);
return previous
for (var i = 0; i < previous.length; i++) {
while (previous[i] == random) {
random = Math.round(Math.random() * 4);
}
}
window.location = links[random];
I'm trying to make a code that will be used to lead users to a random site from a set of sites. This will be activated by a button in google sites, I just haven't gotten to the html part. Anyways, when I try to run this code in jsfiddle, the output is just a blank screen. Whats wrong? here's my logic
An array of the set sites.
'random' picks a number between 0 and 4, which corresponds to the sites in the array
an empty array
This pushes 'random's output to the empty array
This for loop checks to see if there is any data in the empty array
While loop says "ok, if random chooses a number already in the array 'previous', I will run random again.
Once an unchosen number is outputted, a new window opens to the chosen site.
Sadly, it's not performing this way. Any tips?
Edit: Jsfiddle
I think a slight reworking of the code might do the trick with particular emphasis on removing the loop:
var links = ["http://www.google.com/", "http://www.cnn.com/", "http://www.bbc.com/", "http://www.nbc.com/"];
var previous = [];
function showLink() {
if (previous.length !== links.length) {
var random = Math.round(Math.random() * ((links.length - 1) - 0) + 0 );
if (previous.indexOf(links[random]) > -1) {
showLink();
} else {
console.log(links[random], previous)
previous.push(links[random]);
}
} else {
console.log('No more links');
}
}
And at this point just keep calling showLink until you run out of links.
Demo
var links = ["http://www.google.com/", "http://www.cnn.com/", "http://www.bbc.com/", "http://www.nbc.com/"];
var random = Math.round(Math.random() * 4);
var previous = [];
previous.push(random);
for (var i = 0; i < previous.length; i++) {
while (previous[i] == random) {
random = Math.round(Math.random() * 4);
}
}
window.location = links[random];
You were missing a bracket, and you had a return statement before your for loop. So of course it wasn't working since the code under the return statement was unreachable the way you had it written.