How to access the value of a math.random calculation? - javascript

I'm writing a program that simulates a card shuffler. The program should randomly selects a random image within an array and displays it to the screen. Then it deletes that image from the array before running again. The problem I'm having is storing the value of the randomized number so I can delete said array position from the array. I'm pretty sure the math.random calculation needs to be within a function, but I'm having a hard time using that value to randomize the array position while simultaneously storing that random value.
var shuffler = {
cards: [...]
displayCard: function() {
document.getElementById("card-1").style.backgroundImage = 'url(' +
shuffler.cards[shuffler.randomizer()] + ')';
},
randomizer: function() {
Math.floor(Math.random() * shuffler.cards.length) = randomized;
return this.randomized;
shuffler.cards.splice(randomized, 1)
}
}
shuffler.displayCard();

You cannot store the value correctly because following line is errorsome
Math.floor(Math.random() * shuffler.cards.length) = randomized;
= sign in programming is not like = in math. It just assigns the value of right side to left side. Thus, you should do it like this instead:
this.randomized = Math.floor(Math.random() * shuffler.cards.length);

There are two problems. First one is with assignment of randomized. See the line
Math.floor(Math.random() * shuffler.cards.length) = randomized;
Here the LeftHandSide of assignment expression is an expression which is wrong. It should be
let randomized = Math.floor(Math.random() * shuffler.cards.length);
The second problem is that you are using splice() after return move it before return
The last problem is that you are using the variable name inside the methods of the object. You should use this instead of shuffler. The final code will look like.
var shuffler = {
cards: [...]
displayCard: function() {
document.getElementById("card-1").style.backgroundImage = 'url(' +
this.cards[this.randomizer()] + ')';
},
randomizer: function() {
let randomized = Math.floor(Math.random() * shuffler.cards.length);
this.cards.splice(randomized, 1)
return randomized;
}
}
shuffler.displayCard();

In the code snippet you have you're returning before you splice from your array, making it dead code that's unreachable.
In terms of answering the title of this question, you're in the right spirits of just simply storying the random number as a variable, however you need to have proper syntax.

bro check your syntax
randomizer: function() {
Math.floor(Math.random() * shuffler.cards.length) = randomized;
return this.randomized;
shuffler.cards.splice(randomized, 1)
}
I think it will be
randomizer: function() {
this.randomized = Math.floor(Math.random() * this.cards.length);
this.displayCard(this.randomized);
shuffler.cards.splice(this.randomized, 1);
return this.randomized;
}
and you also need to declare randomized property in your shuffler object.
You also need to fix your displayCard method.
displayCard: function(index) {
document.getElementById("card-1").style.backgroundImage = 'url(' +
shuffler.cards[index] + ')';
}

Related

How can i make my random number generator stop producing the same numbers?(Javascript)

I have created a random number generator and I want to avoid repeating the same values.
Here is my code:
function function1() {
var randomNumber = Math.floor(Math.random() * 30) + 1;
var imgName = "pic (" + randomNumber + ").jpg";
document.getElementById("imgid2").src="Pictures" + "/" + imgName;
}
To prevent repetitions, generate a shuffled array of all possible values. randojs.com makes it easy to do this. For a shuffled array of all numbers 0-30, all you have to say is:
var sequence = randoSequence(30);
console.log(sequence);
<script src="https://randojs.com/1.0.0.js"></script>
So, to convert your code, all you'll have to do is:
var sequence = randoSequence(30);
function function1() {
if(sequence.length == 0){//refill the array once we've completely iterated through all possible values
sequence = randoSequence(30);
}
var randomNumber = sequence.pop();
var imgName = "pic (" + randomNumber + ").jpg";
document.getElementById("imgid2").src="Pictures" + "/" + imgName;
}
Note that this code also loops through the complete set of all possible values AGAIN once we've run out. Like I said, this code uses randojs.com, so if you want to use it, make sure you toss this in the head tag of your html document:
<script src="https://randojs.com/1.0.0.js"></script>
Here's a proof of concept if you just want to hit "run" and see it work:
var sequence = randoSequence(30);
function function1() {
if (sequence.length == 0) { //refill the array once we've completely iterated through all possible values
sequence = randoSequence(30);
console.log("ALL POSSIBLE VALUES REFILLED.");
}
console.log(sequence.pop());
}
for (var i = 0; i < 35; i++) function1();
<script src="https://randojs.com/1.0.0.js"></script>
If you don't want repeats, one approach is to generate array of all possible values and then take random value from array everytime (and remove it at the same time). That way values never repeat.

JS create an array with unique random numbers

Full code looks like this, ideally we have 4 div boxes that need to be randomly filled with random numbers ansValue, one of them (rightAnsValue with its rightAnsId) is already done and works fine, I've managed to make it unique in comparison to others (code without commented section). But met a problem with making others unique, I keep having some identical values in my boxes. In comments is one way I tried to solve this, but pretty sure there is a much simpler and smarter solution that actually works. I would appreciate if you could help to find an understandable solution to this problem.
(P.S. I've seen similar questions but they are either too dificult or done without JS.)
function createAnswers(){
for(ansId=1; ansId<5; ansId++){
if(ansId!=rightAnsId){
for(i=1; i<10; i++){
digitArray[i-1] = i;
}
genNewRandNum();
// ansArray.length = 3;
// ansArray.push(ansValue);
// for(k=0; k<3; k++){
// if(ansArray[k] == ansArray[k+1] || ansArray[k] == ansArray[k+2]){
// genNewRandNum();
// ansArray[k] = ansValue;
// }else if(ansArray[k+1] == ansArray[k+2]){
// genNewRandNum();
// ansArray[k+1] = ansValue;
// }else{
// break;
// }
// }
if(ansValue!=rightAnsValue){
document.getElementById("box" + ansId).innerHTML = ansValue;
}else{
genNewRandNum();
document.getElementById("box" + ansId).innerHTML = ansValue;
}
}
}
}
The way I generate new numbers:
function genNewRandNum(){
rand1 = digitArray[Math.floor(Math.random() * digitArray.length)];
rand2 = digitArray[Math.floor(Math.random() * digitArray.length)];
ansValue = rand1 * rand2;
}
Replace your genNewRandNum() with below code. I have used IIFE to create a closure variable alreadyGeneratedNumbers thats available inside the function generateRandomNumber() thats returned.
So everytime genNewRandNum() is executed, it checks against alreadyGeneratedNumbers to make sure it always returns a unique between 1 and 9.
var genNewRandNum = (function(){
var alreadyGeneratedNumbers = {};
return function generateRandomNumber() {
var min = Math.ceil(1),
max = Math.floor(9);
randomNumber = Math.floor(Math.random() * (max - min + 1)) + min;
if(alreadyGeneratedNumbers[randomNumber]) {
return generateRandomNumber();
} else {
alreadyGeneratedNumbers[randomNumber] = randomNumber;
return randomNumber;
}
}
})();
console.log(genNewRandNum());
console.log(genNewRandNum());
console.log(genNewRandNum());
console.log(genNewRandNum());
console.log(genNewRandNum());
console.log(genNewRandNum());
console.log(genNewRandNum());
console.log(genNewRandNum());
console.log(genNewRandNum());
Note: If you call genNewRandNum() for the 10th time it will throw error. So if you have a use case where you would need to reset it after all numbers from 1 to 9 are returned, then you need to add code to handle that
The easiest way to brute-force this is to use accept/reject sampling. You can do something like so:
uniqueRandomNumbers = function(n, nextRandom)
{
var nums = {}; var m = 0;
while(m < n)
{
var r = nextRandom();
if(! nums.hasOwnProperty(r))
{
nums[r] = true; m++;
}
}
return Object.keys(nums);
}
Here I'm using the fact that js objects are implemented as hashmaps to get a hashset. (This has the downside of converting the numbers to strings, but if you're not planning on imediately doing arithmetic with them this is not a problem.)
In order to get four unique integers between 0 and 9 you can then do something like:
uniqueRandomNumbers(4, function() { return Math.floor(Math.random() * 10); })
If you want something a little better than brute force (which probably isn't relevant to your use case but could help someone googling this), one option is to go through each element and either take or leave it with an appropriate probability. This approach is outlined in the answers to this question.

I don't understand how jQuery .each() and .html() methods work

Im Timo. I'm new at web programming and I have this issue. I have made a simple html table with 3 rows. Each td has to have a random numeric value. My problem is that my code puts the same value at every td element.
http://jsfiddle.net/timosergio/30ydu4oe/
Down below is my js code:
$(function() {
randomValues();
//alert(1);
});
var randomValues = function(){
var $td = $('.table').find('td');
// each td has to have a different random value
var random_values = Math.random() * 100 ;
$td.each(function(i){
//console.log(i + ":" + Math.random() * 100);
$td.eq(i).text(random_values);
});
};
This is because you're generating a single random value then using that for each of the tds, rather than generating a new one for each td. So:
$td.each(function(i){
$td.eq(i).text(Math.random(Math.random() * 100));
});
In other words, generate the random value inside the loop, not outside of it.
Furthermore, understand that, inside each callbacks, the context, i.e. this, points to the element being considered. So you don't need
$td.eq(i).text(...
but merely
$(this).text(...
$.each() is essentially a foreach loop. You need to create a new random value on each iteration.
Like this:
var randomValues = function() {
var $td = $('.table').find('td');
// each td has to have a different random value
$td.each(function(i){
//console.log(i + ":" + Math.random() * 100);
var random_value = Math.random() * 100 ;
$td.eq(i).text(random_value);
});
}
It's because your random value is generated before the each statement, so the same value is being used each time.
Move your Math.random()*100 into your .text() and all should work.
The problem has nothing to do with .each() or .html(). You have generated the random value just once and setting the same value to each of the td. You need to do this.
var randomValues = function(){
var $td = $('.table').find('td');
// each td has to have a different random value
// var random_values = Math.random() * 100 ;
$td.each(function(i){
//console.log(i + ":" + Math.random() * 100);
$td.eq(i).text(Math.random() * 100);
});
};

JavaScript function will only work once

I have a JavaScript function that is triggered onchange. What it does is take the value from a input field and then add it to the value entered in another field and then display the answer in a different field.
It works fine the first time, but when I enter a new value and leave the field there is an error: TotalPurchasePrice is not a function
function TotalPurchasePrice(BuyinPrice, TopupAmount) {
var BuyinPrice
var TopupAmount
BuyinPrice = BuyinPrice.toString().replace(/\£|\,/g, '');
TopupAmount = TopupAmount.toString().replace(/\£|\,/g, '');
TotalPurchasePrice = (BuyinPrice * 1) + (TopupAmount * 1);
document.getElementById('tTotalPurchasePrice').value = TotalPurchasePrice;
}
Can anyone tell me why this would only work once?
This line :
TotalPurchasePrice = (BuyinPrice * 1) + (TopupAmount * 1);
replaces the TotalPurchasePrice function by a number. Then it's not a function, hence the error you have.
Use a different variable name :
var totalPrice = (BuyinPrice * 1) + (TopupAmount * 1);
document.getElementById('tTotalPurchasePrice').value = totalPrice;
You could also simply have added the var keyword but it would have made the code confusing.
A way to reduce the probability of such errors is to follow best practices when naming functions and variables. Here you should have named your function as a verb to denote an action instead of a value.
You're are confusing JavaScript with VBScript here.
To return value use return keyword:
return (BuyinPrice * 1) + (TopupAmount * 1);
Then outside the function have such line:
document.getElementById('tTotalPurchasePrice').value = TotalPurchasePrice(BuyinPrice, TopupAmount);
Assigning the value of a variable inside a function without stating it with var (TotalPurchasePrice in your case) means that the variable is global.
Since you could have the function declaration written as: var TotalPurchasePrice = function(BuyinPrice, TopupAmount) {}, you are just overriding it.
You could either rename the variable inside the function or add a var statement in front of it like:
var TotalPurchasePrice = (BuyinPrice * 1) + (TopupAmount * 1);

Javascript: Math.floor(Math.random()*array.length) not producing a random number?

This on e is a doozey.
I have while loop to generate a random number that is not the same as any other random number produced before. The random number is used to select a text value from an object.
for example:
quoteArray[1] = "some text"
quoteArray[2] = "some different text"
quoteArray[3] = "text again"
quoteArray[4] = "completely different text"
quoteArray[5] = "ham sandwich"
This is part of a larger function and after that function has cycled through = quoteArray.length it resets and starts the cycle over again. The issue I am hitting is that the following code is SOMETIMES producing an infinite loop:
//Note: at this point in the function I have generated a random number once already and stored it in 'randomnumber'
//I use this while statement to evaluate 'randomnumber' until the condition of it NOT being a number that has already been used and NOT being the last number is met.
while(randomnumber === rotationArray[randomnumber] || randomnumber === lastnumber){
randomnumber = Math.floor(Math.random() * (quoteArray.length));
}
When I console.log(randomnumber) - when I am stuck in the loop - I am just getting '0' as a result. When stuck in the loop it doesn't appear as though Math.floor(Math.random() * (quoteArray.length)) is producing a random number but rather just '0' infinitely.
can anyone tell me why I am running into this problem?
EDIT: Here is the complete pertinent code with function + variable declarations
// Function to initialize the quoteObj
function quoteObj(text,cname,ccompany,url,height) {
this.text=text;
this.cname=cname;
this.ccompany=ccompany;
this.url=url;
this.height=height;
}
// Populate my quotes Object with the quotation information from the XML sheet.
var qObj = new quoteObj('','','','');
var quoteArray = new Array();
var counter = 0;
//cycles through each XML item and loads the data into an object which is then stored in an array
$.ajax({
type: "GET",
url: "quotes.xml",
dataType: "xml",
success: function(xml) {
$(xml).find('quote').each(function(){
quoteArray[counter] = new quoteObj('','','','');
console.log(quoteArray[counter]);
quoteArray[counter].text = $(this).find('text').text();
quoteArray[counter].cname = $(this).find('customer_name').text();
quoteArray[counter].ccompany = $(this).find('customer_company').text();
quoteArray[counter].url = $(this).find('project').text();
++counter;
});
}
});
// This is the setion that is generating my infinite loop issue.
// I've included all of the other code in case people are wondering specific things about how an item was initialized, etc.
// Generate a random first quote then randomly progress through the entire set and start all over.
var randomnumber = Math.floor(Math.random() * (quoteArray.length));
var rotationArray = new Array(quoteArray.length);
var v = 0;
var lastnumber = -1;
bHeight = $('#rightbox').height() + 50;
var cHeight = 0;
var divtoanim = $('#customerquotes').parent();
//NOT RELATED//
// Give the innershadow a height so that overflow hidden works with the quotations.
$(divtoanim).css({'height' : bHeight});
// Rotate the Quotations Randomly function.
setInterval(function(){
randomnumber = Math.floor(Math.random() * (quoteArray.length));
//checks to see if the function loop needs to start at the beginning.
if(v == (quoteArray.length)){
rotationArray.length = 0;
v = 0;
}
//determines if the random number is both different than any other random number generated before and that is is not the same as the last random number
while(randomnumber === rotationArray[randomnumber] || randomnumber === lastnumber){
randomnumber = Math.floor(Math.random() * (quoteArray.length));
}
lastnumber = randomnumber;
rotationArray[randomnumber] = randomnumber;
++v;
//NOT RELATED//
//animation sequence
$('#ctext, #cname').animate({'opacity':'0'},2000, function(){
$('#ctext').html(quoteArray[randomnumber].text);
$('#cname').html('- ' + quoteArray[randomnumber].cname);
cHeight = $('#customerquotes').height() + 50;
adjustHeight(bHeight,cHeight,divtoanim);
$('#ctext').delay(500).animate({'opacity':'1'},500);
$('#cname').delay(1500).animate({'opacity':'1'},500);
});
},15000);
This is an asynchronous problem: the array quoteArray is empty when the code runs, because it fires off the ajax request, and moves on. Anything that depends on quoteArray should be inside the success function of $.ajax.
The array has a length when you type quoteArray.length in the console, only because by that time the Ajax request has completed.
have you tried something like
Math.floor(Math.random() * (5));
To make sure the array length is being found properly?
First, since you updated your question, be sure that you are handling asynchronous data properly. Since an ajax call is asynchronous, you will need to be sure to only run the randomizer once the call is successful and data has been returned.
Second, assuming you are handling the asyc data properly, the size of your result set is likely it is too small. Thus, you are probably randomly getting the same number too often. Then, you can't use this number because you have already done so.
What you need to do is pop off the parts that are already used from the results array each time. Recalculate the array length, then pull a random from that. However, the likelihood of this feeling random is very slim.
There is probably a more efficient way to do this, but here's my go:
var results = ['some text','some text2','some text3','some text4','some text5', /* ...etc */ ],
randomable = results;
function getRandomOffset( arr )
{
var offset,
len;
if( arr.length < 1 )
return false;
else if( arr.length > 1 )
offset = Math.floor(Math.random() * arr.length );
else
offset = 0;
arr.splice( offset, 1 );
return [
offset,
arr
];
}
while( res = getRandomOffset( randomable ) )
{
// Set the randomable for next time
randomable = res[1];
// Do something with your resulting index
results[ res[0] ];
}
The arrgument sent to the function should be the array that is returned form it (except the first time). Then call that function as you need until it returns false.

Categories

Resources