Javascript card game: once card is used, never use card again? - javascript

I am creating a card game using Javascript. I got this far with the code and everything works perfectly, but I am having trouble figuring out a way to make sure that once a card is selected it is never picked again.
Preview: https://natialollie.github.io/javascript-card-game/
// function 2: generate and show random card
function generateNumber() {
// combine all card arrays
let allCards = cardArray.concat(acesArray).concat(jackArray).concat(kingArray).concat(queenArray);
// select a random letter within the array
let cardLetter = allCards[Math.floor(Math.random() * allCards.length)];
// generate a random number between 2 and 10
let randomNumber = Math.floor(Math.random() * 9) + 2;
// if generic card is choosen, concatenate letter with random number
if ((cardArray).indexOf(cardLetter) !==-1) {
var genericCard = randomNumber + cardLetter;
var cardToShow = "PNG/" + genericCard + ".png"
} // OR if special card is choosen, leave as is
else {
var specialCard = cardLetter;
cardToShow = "PNG/" + specialCard + ".png"
}
console.log('The card slot with id: ' + "'" + selectedSlot + "'" + ' was selected! The new card file path to show is: ' + cardToShow);
// change the current file path of the card, to the newly generated one
let changeImgSrc = document.getElementById(selectedSlot)
changeImgSrc.src = cardToShow;
// remove file path from cardToShow and store the result
let pathRemoved = cardToShow.replace("PNG/", '').replace(".png", '');
// take the result and append to array, each time a card is shown
usedCard.push(pathRemoved);
console.log(usedCard);
//for cards inside the usedCard array, when you run the function dont include this as a file path option
}

How about this. Filter out all the cards who are found in the usedCards array.
let allCards = cardArray.concat(acesArray).concat(jackArray).concat(kingArray).concat(queenArray);
allCards = allCards.filter(card => usedCards.indexOf(card) === -1)
Alternatively you could keep track of the remaining cards (instead of the used cards) and remove from that list when you use a card.

One method is to use a fixed number table — your cards need to be mapped to an array and removed when picked. Here's a working example I built for a "use-all-numbers" random number generator:
function rand(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
var array = [],
output = document.getElementById("output");
function generatelist() {
for (i = 0; i < 10; i++) {
array.push(i + 1);
}
output.innerHTML += "<br>List is: " + array;
}
generatelist();
function selectnumber() {
x = rand(0, array.length);
output.innerHTML += "<br>Number is: " + array[x];
array.splice(x, 1);
output.innerHTML += "<br>List is: " + array;
if (array.length == 0) {
output.innerHTML += "<br>There are no more numbers! Regenerating list.";
generatelist();
}
}
<button onclick="selectnumber()">Select a number from list</button>
<div id="output"></div>

Related

JS function works just sometimes

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.

Looking to randomly select, concatenate string of text stored in variable

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)";
// }
});

Evaluate a number to numbers in an array in JavaScript

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.

How do I add Images to Divs using JavaScript when the src contains variables?

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;

Javascript: randomly pair items from array without repeats

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)
}

Categories

Resources