As the title says, I have a JavaScript function that doesn't always work and I don't know why.JS:
function weapon() {
var players = document.getElementById("playersList").value.split(",")
var rand2
var newPlayers = ""
var num = players.length - 1
for (var i = 0; i < num; i++) {
rand2 = Math.floor(Math.random() * num)
newPlayers += (players[rand2].trim() + ",")
if (i != num) {
newPlayers += "\n"
}
players.splice(rand2, 1)
}
newPlayers += players[0]
document.getElementById("playersList").value = newPlayers
}
HTML:
<textarea id="playersList"></textarea>
<button onclick="weapon()">RANDOMIZE</button>
There's actually more code in the function but that portion works every time.
It looks like the code can intermittently fail at this line:
newPlayers += (players[rand2].trim() + ",")
At the end of your for loop, you call:
players.splice(rand2, 1)
where splice mutates the state of players, and reduces the amount of items in the array by 1.
When the next iteration of the loop is called, rand2 has the possibility of generating a value that is greater than the amount of items in the players array. You will then receive an error if you try to access an index position which doesn't exist.
Problem
In my scripts.js the variable var fullURL = not getting the actual text to be tweeted out in the teaser1, teaser2 and teaser3 that I've stored in a variable. I basically want one of the three teasers to be randomly selected when people click fa-twitter
scripts.js
function shareTeam(){
$(".fa-twitter").click(function(){
// Grabs the names of all the players in the span
// Sets a variable marking the indexOf each of the names
// If the index doesn't find a space, it returns -1, which returns the full name
// Otherwise it will return only what follows the space
var lastNames = $("li span").map(function() {
var name = $(this).text();
var index = name.indexOf(" ");
return index == -1 ? name : name.substring(index + 1);
}).get();
console.log(lastNames);
var regularNames = lastNames.slice(0, 3); // Same as below, but no shuffling
regularName1 = regularNames[0]; // Forward
regularName2 = regularNames[1]; // Forward
regularName3 = regularNames[2]; // Defenseman
// Find me a random number between 1 and 3
// Where 1 is the start number and 3 is the number of possible results
var teaser = "teaser";
var rand = Math.floor(Math.random() * 3) + 1;
console.log(rand);
// Concatenate the two strings together
teaseRand = teaser.concat(rand);
// These are the components that make up that fullURL
var baseURI = "https://twitter.com/intent/tweet?url=";
var twitterUsername = "stltoday";
var interactiveURL = "http://graphics.########.com/STLblues";
// Randomly generate one of three teasers
var teaser1 = regularName3 + " to " + regularName2 + " back to " + regularName1 + " — GOAL! Create your own all-team #STLBlues team: ";
var teaser2 = "I picked my #STLBlues dream team. See which players I've chosen and build your own: ";
var teaser3 = "My #STLBlues team will skate circles around yours! Pick your team: ";
// This is the full url that will be switched in and out
// var fullURL = baseURI+interactiveURL+"&via="+twitterUsername+"&text="+teaseRand;
var fullURL = baseURI+interactiveURL+"&via="+twitterUsername+"&text="+teaseRand;
// It needs to be encoded properly as well
var encodedURL = encodeURIComponent(fullURL)
console.log(fullURL);
console.log(encodedURL);
// Change the href to the link every time the Twitter button is clicked
var changeLink = $("link--twitter").attr("href", encodedURL);
// if (lastNames.length === 6) {
// } else {
// // Generic teaser
// var teaser4 = "Pick your #STLBlues dream team from 50 of the best #StLouisBlues to hit the ice: " + interactiveURL + " (via #stltoday)";
// }
});
}
Unfortunately this teaseRand value will be either "teaser1" or "teaser2" or "teaser3" and not the value of your variables teaser1 or teaser2 or teaser3 if that makes sense. For your requirement you will need to add the teasers to an array and then randomly access from it. For e.g. if the array is called teaser then you will need to do teaser[rand] and obviously you will need to calculate the rand from 0 to 2 instead 1 to 3 like you have done now.
Please check the codepen that i have created here
http://codepen.io/19sthil80/pen/VKPqkR?editors=1111
$(document).ready(function(){
var teasers = [];
// Grabs the names of all the players in the span
// Sets a variable marking the indexOf each of the names
// If the index doesn't find a space, it returns -1, which returns the full name
// Otherwise it will return only what follows the space
var lastNames = $("li span").map(function() {
var name = $(this).text();
var index = name.indexOf(" ");
return index == -1 ? name : name.substring(index + 1);
}).get();
console.log(lastNames);
var regularNames = lastNames.slice(0, 3); // Same as below, but no shuffling
regularName1 = regularNames[0]; // Forward
regularName2 = regularNames[1]; // Forward
regularName3 = regularNames[2]; // Defenseman
// Find me a random number between 1 and 3
// Where 1 is the start number and 3 is the number of possible results
var teaser = "teaser";
var rand = Math.floor(Math.random() * 3);
console.log(rand);
// Concatenate the two strings together
teaseRand = teaser.concat(rand);
// These are the components that make up that fullURL
var baseURI = "https://twitter.com/intent/tweet?url=";
var twitterUsername = "stltoday";
var interactiveURL = "http://graphics.########.com/STLblues";
// Randomly generate one of three teasers
var teaser1 = regularName3 + " to " + regularName2 + " back to " + regularName1 + " — GOAL! Create your own all-team #STLBlues team: ";
var teaser2 = "I picked my #STLBlues dream team. See which players I've chosen and build your own: ";
var teaser3 = "My #STLBlues team will skate circles around yours! Pick your team: ";
teasers.push(teaser1);teasers.push(teaser2);teasers.push(teaser3);
// This is the full url that will be switched in and out
// var fullURL = baseURI+interactiveURL+"&via="+twitterUsername+"&text="+teaseRand;
var fullURL = baseURI+interactiveURL+"&via="+twitterUsername+"&text="+teasers[rand];
// It needs to be encoded properly as well
var encodedURL = encodeURIComponent(fullURL)
console.log(fullURL);
console.log(encodedURL);
// Change the href to the link every time the Twitter button is clicked
var changeLink = $("link--twitter").attr("href", encodedURL);
// if (lastNames.length === 6) {
// } else {
// // Generic teaser
// var teaser4 = "Pick your #STLBlues dream team from 50 of the best #StLouisBlues to hit the ice: " + interactiveURL + " (via #stltoday)";
// }
});
I am making a random number generator to assign tasks. I want to give everyone a random number then generate the random number. I then want to list the people in order of how close they were.
I thought maybe to iterate through the array and find the absolute difference between the winningNumber and the numbers in the way. However, I'm not sure how to link the numbers back to the name in the list.
How can I evaluate these numbers?
Fiddle here.
HTML:
Random Number Assigner
<p>Have tasks to assign but no volunteers? Sign them up here</p>
<div id="input-area">
<input type="text" placeholder="Lucky person here" id="input">
<button id="button">Add Them!</button>
<br>
<br>
<button id="random">Generate Random Number</button>
</div>
<hr>
<div id="list-area">
<ul id="list"></ul>
</div>
CSS:
#input-area {
width: 100%;
border: 1px solid black;
}
JavaScript:
function randomNumber() {
return Math.round((Math.random()) * 100);
};
var randomNumberValue;
var winningNumber;
var myArray = [];
$(document).ready(function () {
console.log("The JavaScript has loaded");
$('#button').on('click', function () {
randomNumberValue = randomNumber();
var inputValue = $('#input').val();
if (inputValue === "") {
return;
};
$('#list').append("<ul>" + inputValue + ": " + randomNumberValue + " </ul>");
myArray.push(randomNumberValue);
$('#input').val("");
});
$('#random').on('click', function () {
myArray.sort();
winningNumber = randomNumber();
if (winningNumber === 0) {
winningNumber++;
};
console.log(myArray);
console.log("The winning number is: " + winningNumber);
for (var i = 0; i < myArray.length; i++) {
i - winningNumber;
};
console.log(myArray);
});
});
With some small adaptions:
function randomNumber() {
return Math.round((Math.random()) * 100);
};
var randomNumberValue;
var winningNumber;
var myArray = [];
$(document).ready(function () {
console.log("The JavaScript has loaded");
$('#button').on('click', function () {
var randomNumberValue = randomNumber();
var inputValue = $('#input').val();
if (inputValue === "") {
return;
};
// an item in a list is the <li> element
$('#list').append("<li>" + inputValue + ": " + randomNumberValue + " </li>");
// to simplify things I've used normal arrays for storage
// instead of a list of {key:value} pairs
// Advantage of {key:value} pairs here would be an easier check for multiple name entries
myArray.push([randomNumberValue,inputValue]);
$('#input').val("");
});
$('#random').on('click', function () {
// not needed in this simple algorithm
// You can use a binary search if the array is sorted which would make it faster
// but also much more complicated and isn't worth the hassle for small lists
//myArray.sort();
var winningNumber = randomNumber();
// get the first number for a start (numbering starts at zero)
var current = myArray[0][0];
// we need something to keep the position of the entry
var pos = 0;
console.log("The winning number is: " + winningNumber);
for (var i = 0; i < myArray.length; i++) {
// the actual number at position i in the array
var value = myArray[i][0];
/*
Compute two differences
a) between the drawn number and the actual number
b) between the drawn number and the last number that was
nearest to the last actual number
If the actual difference a is smaller than the last difference
it is better, hence we keep it. We have to know where it was to
be able to name the winner and keep the position to do so.
*/
if(Math.abs(winningNumber - value) < Math.abs(winningNumber - current)){
current = value;
pos = i;
}
// No "else" here because, well, we don't need to do anything, just go on
// until something is found.
};
console.log("The winner is: " + myArray[pos][1]);
console.log(myArray.join(" | "));
});
});
One caveat: you do not check for double entries. Both, the name and the random number can repeat and need to be checked, otherwise it may fail in curious ways.
I have a function that is supposed to add 10 random images to a div by generating a number at random. This is the function:
function Images()
{
clore();
var total = 133;
var gif = 3;
var name = "FileName";
var i = 0;
while (i < 10)
{
var num = random.nextInt(total - 1 + 1) + 1;
if(num > (total - gif))
{
var type = ".gif";
}else{
var type = ".jpg";
}
var elem = document.createElement("img");
elem.src = 'images/' + name + '/' + num + type;
document.getElementById("DIV").appendChild(elem);
i++;
}
}
clore() - Clears the innerhtml of the div
var total - the total number of ALL images in the folder
var gif - the total number of .gif images in the folder
var name - the name of the folder the images are in
The images are named 1 to 133, all of them are .jpg except the last three which are .gif.
So it goes: 1.jpg.....130.jpg then 131.gif.....133.gif .
I know the function is running because the clore function clears the div but nothing happens after that.
I also know I am not using any reserved terms as I have changed all of the names repeatedly?
The issue is the line where you have:
var num = random.nextInt(total - 1 + 1) + 1;
Instead it should be:
var num = Math.floor(Math.random() * total) + 1;
I am trying to make a very basic "secret santa" generator as one of my first Javascript projects. I have searched for hours for a solution to this problem but so far nothing has worked that I have found.
I have an array of names which need paired to each other. I successfully have them pairing to each other, but right now someone can be drawn twice. I am pushing the randomly chosen names to another array but I can't find a way to check the randomly chosen names against the ones already chosen.
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
var used = [];
var picks = [];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
}
for( var i = 0; i < names.length; i++){
var random = Math.floor(Math.random()*names.length)
if(names[random] == names[i]) {
names[random] = names[random++];
picks.push(names[i] + " gets " + names[random]);
used.push(names[random]);
} else {
picks.push(names[i] + " gets " + names[random]);
used.push(names[random]);
}
}
console.log("picked array: ")
for(var k=0; k<picks.length; k++) {
console.log(picks[k]);
}
console.log("used array: " + used);
Thank you in advance for any help.
Create two arrays with the names, shuffle them, and make sure you don't pick the same name from both arrays :
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
} else {
var arr1 = names.slice(), // copy array
arr2 = names.slice(); // copy array again
arr1.sort(function() { return 0.5 - Math.random();}); // shuffle arrays
arr2.sort(function() { return 0.5 - Math.random();});
while (arr1.length) {
var name1 = arr1.pop(), // get the last value of arr1
name2 = arr2[0] == name1 ? arr2.pop() : arr2.shift();
// ^^ if the first value is the same as name1,
// get the last value, otherwise get the first
console.log(name1 + ' gets ' + name2);
}
}
FIDDLE
I would suggest a different approach. Shuffle, split, and zip, no mutation:
var splitAt = function(i, xs) {
var a = xs.slice(0, i);
var b = xs.slice(i, xs.length);
return [a, b];
};
var shuffle = function(xs) {
return xs.slice(0).sort(function() {
return .5 - Math.random();
});
};
var zip = function(xs) {
return xs[0].map(function(_,i) {
return xs.map(function(x) {
return x[i];
});
});
}
// Obviously assumes even array
var result = zip(splitAt(names.length/2, shuffle(names)));
//^
// [
// [ 'Nick', 'Kimmy' ],
// [ 'Sean', 'Johnny' ],
// [ 'Kyle', 'Brian' ],
// [ 'Cotter', 'Pat' ],
// [ 'Emily', 'Jeremy' ]
// ]
There is a multitude of ways you can achieve this.
The fastest to code, but not necessarily the randomest is:
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
function getPicks(names) {
return names.slice(0).sort(function(){ return Math.random()-0.5 }).map(function(name, index, arr){
return name + " gets " + arr[(index+1)%arr.length];
});
}
getPicks(names);
This is not very random because the shuffling isn't very good and also because you get a single cycle each time. There can be no two cycles A->B->C->A D->E->D.
If you want it to have a random number of cycles of variable length, you can split the names array in several arrays and do the above for each of them, then concatenate the results (see elclanrs).
Finally, the last solution is for each person to pick a person at random and if it's the same one, simply pick again. If the last name remaining in both arrays is the same, simply swap it with another pair.
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
var a = names.slice(0);
var b = names.slice(0);
var result = [];
while (a.length > 1) {
var i = extractRandomElement(a);
var j = extractRandomElement(b);
while (i===j) {
b.push(j);
j = extractRandomElement(b);
}
result.push({ a:i, b:j });
}
if (a[0] === b[0]) {
result.push({ a:a[0], b:result[0].b });
result[0].b = a[0];
} else {
result.push({ a:a[0], b:b[0] });
}
var pairs = result.map(function(item){ return item.a + ' gets ' + item.b});
function extractRandomElement(array) {
return array.splice(Math.floor(Math.random()*array.length),1)[0];
}
I'm a tad late, but thought I'd throw my answer in here. It essentially does the same thing #adeneo's does, but it uses the same basic code as OP:
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
pickpool = names.slice(0); // Slice the array at the first element to copy it by value
var used = [];
var picks = [];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
}
for( var i = 0; i < names.length; i++){
var random = Math.floor(Math.random()*pickpool.length)
if(names[random] == names[i]) {
// names[random] = names[random++];
picks.push(names[i] + " gets " + pickpool[random++]);
pickpool.splice(random++,1);
} else {
picks.push(names[i] + " gets " + pickpool[random]);
pickpool.splice(random,1);
}
}
console.log("picked array: ");
for(var k=0; k<picks.length; k++) {
console.log(picks[k]);
}
http://jsfiddle.net/SNJpC/
If you don't need to keep the original array you can remove the names as they get selected and each time you pick a name check that it isn't an empty string before pushing it to the next array.
Another consideration...
If you are trying to make a 'Secret Santa' generator, by using random method you can get the same pair next year, and next...
This is another solution where you get all the possible pairs (without repeating a name itself or a pair) for multiple years.
var names = ["Sean", "Kyle", "Emily", "Nick", "Cotter", "Brian", "Jeremy", "Kimmy", "Pat", "Johnny"];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
} else {
const arr1 = names.slice()
let arr2 = names.slice();
let countDown = number => {
if (number === 1) {
return;
}
const last = arr2.pop([number - 1]);
arr2.unshift(last);
let pairs = [];
arr1.map(item => {
const index = arr1.indexOf(item);
pairs.push(`${arr1[index]} gets ${arr2[index]}`)
})
console.log(pairs)
return countDown(number - 1);
}
countDown(names.length)
}