Pure Javascript, Cannot assign variables to an array - javascript

I am still learning JS (not jquery). So in learning, I am starting with a simple game. I found a problem. I cannot get these arrays to work, as they are producing a NaN.
var clickMultiplier = 1.11;
var idleMultiplier = 1.15;
var idleBuffsCost = [];
idleBuffsCost[0] = 100;
var clickBuffsCost = [];
clickBuffsCost[0] = 100;
var trainerBuffsCost = [];
trainerBuffsCost[0] = 1250;
for (i = 1; i <= 20; i++) {
var j = i - 1;
idleBuffsCost[i] += idleBuffsCost[j] * idleMultiplier;
clickBuffsCost[i] = clickBuffsCost[i] + clickBuffsCost[j] * clickMultiplier;
trainerBuffsCost[i] += trainerBuffsCost[j] * 1.25;
}
console.log(clickBuffsCost[0]); // works = 100
console.log(clickBuffsCost[1]); // does not work NaN
What am I doing wrong?
Also, I am used to doing arrays (like the above) as
... idleBuffsCost[i-1]
However, that does not seem to be working.
What do you think? Am I not seeing the forest for the trees (I normally program in php/mysql/pascal/qb64(and other derivations) and a few more languages - just adding JS to the list hahaha)
ps the different assignments are because I was trying different logic operations.
thanks to a few people here - I made a simple mistake. the loop was trying to assign a value to an index that was not assigned yet. Here is the fix - I removed the += and left just =
idleBuffsCost[i] = idleBuffsCost[j] * idleMultiplier;
clickBuffsCost[i] = clickBuffsCost[j] * clickMultiplier;
trainerBuffsCost[i] = trainerBuffsCost[j] * 1.25;
special thanks to: #certainPeformance, #Wais Kamal and #David I wish I could green check them all. But they were helpful none-the-less, Thanks guys!

There is a little mistake in your code. Search this line of code.
clickBuffsCost[i] = clickBuffsCost[i] + (clickBuffsCost[j] * clickMultiplier);
change to:
clickBuffsCost[i] = clickBuffsCost[j] + (clickBuffsCost[j] * clickMultiplier); // notice the difference after the = part
Since i will start at 1, clickBuffsCost[1] is undefined because clickBuffsCost only consists of one item at the beginning.

Here is where you've gone wrong:
for (i = 1; i <= 20; i++) {
var j = i - 1;
idleBuffsCost[i] += idleBuffsCost[j] * idleMultiplier;
clickBuffsCost[i] = clickBuffsCost[i] + (clickBuffsCost[j] * clickMultiplier);
trainerBuffsCost[i] += trainerBuffsCost[j] * 1.25;
}
First of all, define i before using it. Defining variables is good programming practice.
clickBuffsCost[i] = clickBuffsCost[i] + (clickBuffsCost[j] * clickMultiplier);
In the first iteration of your loop, i has the value 1, while j has the value 0. You are setting the second element of clickBuffsCost as clickBuffsCost[i] + (clickBuffsCost[j] * clickMultiplier). clickBuffsCost[i] (which is equal to clickBuffsCost[1] in this case) is undefined, which is why you are getting NaN when calling console.log(clickBuffsCost[0]).

You need to initialise your array lengths. For example, if you know you have 20 elements in an array, you should initialise an array as follows:
const testArr = new Array(20);.
Alternatively, if you don't know the length of your array, instead of indexing the ith element of the array and assigning it a value, you could use the array push(..) function. This method means you do not have to initialise an array with a length.
You can read more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

Related

simplify javascript array with loop syntax

I have a javascript array defined as below:
var hexgon = ['M',r*Math.cos(0/180*Math.PI),r*Math.sin(0/180*Math.PI)
,r*Math.cos(30/180*Math.PI),r*Math.sin(30/180*Math.PI)
,r*Math.cos(90/180*Math.PI),r*Math.sin(90/180*Math.PI)
,r*Math.cos(150/180*Math.PI),r*Math.sin(150/180*Math.PI)
,r*Math.cos(210/180*Math.PI),r*Math.sin(210/180*Math.PI)
,r*Math.cos(270/180*Math.PI),r*Math.sin(270/180*Math.PI),
,r*Math.cos(330/180*Math.PI),r*Math.sin(330/180*Math.PI),'Z']
How to use a loop to simplify this logic?
If you did not intend two commas in a row after the twelth element then this:
var hexgon = ['M', ...[0,30,90,150,210,270,330].flatMap(d => [r*Math.cos(d/180*Math.PI),r*Math.sin(d/180*Math.PI)]), 'Z']
If you can have a constant value as a step that gets added to Math.cos() and Math.sin() statements we might be able to do something.
Let's say we want to add 30 each time to the each array's element, we can do something like this: (Also noticed there are M and Z characters at the beginning and end of your array)
const newHexgon = new Array(16);
newHexgon[0] = 'M';
newHexgon[newHexgon.length - 1] = 'Z';
let counter = 0;
let step = 30;
for (let i = 1; i < newHexgon.length - 1; i += 2) {
newHexgon[i] = Math.cos(((counter * step) / 180) * Math.PI);
newHexgon[i + 1] = Math.sin(((counter * step) / 180) * Math.PI);
counter++;
}
console.log(newHexgon);
I created an array with a length of 16 and set the first and last elements to "M" and "Z" as in your array. Then I will loop every two elements at a time i += 2 and set the Math calculations and after finished in each iteration the counter gets added by one.

How to check if a generated number already exists

This code below creates a random costumer number and prints it out with a simple console log, but one feature is missing: It should check if the same costumer number/ID has already been generated before. If so, it should walk through the process again, so a new random number is generated which then is unique. How can I do that with this code? As a programming newbie I unfortunately have NO clue how I could do that. Maybe a while loop and storing the generated number in a variable? Would be totally awesome if you can provide the code, combined with mine or build in the duplicate-checking feature.
function generateCostumerNum() {
// generating a random 8-digit number with numbers from 1 to 9
var zeroToNine = "";
for (counter = 0; counter <= 7; counter++) {
var randomNumber = Math.floor(Math.random() * 9) + 1;
zeroToNine += randomNumber;
}
// calculating the cross-sum of the generated number above
var numberforCrossSum = zeroToNine,
crossSum = 0;
while (numberforCrossSum) {
crossSum += numberforCrossSum % 10;
numberforCrossSum = Math.floor(numberforCrossSum / 10);
}
// building together the final costumer ID string.
var finalCostumerNum = "ID" + zeroToNine + crossSum;
console.log(finalCostumerNum);
};
generateCostumerNum();
You can use a simple while loop that runs as long as the generated number has already been generated:
var already_generated_nums = []; // an array of the numbers already generated
//...
var new_num = generateCostumerNum();
while (already_generated_nums.includes(new_num)) {
new_num = generateCostumerNum();
}
already_generated_nums.push(new_num);

Loop through jQuery arrays / Output values to a div

I have a button that dynamically creates 2 inputs per click
Data of Input 1: string
Data of Input 2: number (float) (0-100)
I am creating an array of each like this.
var recipe_flavour_name = $("input[name='flav-name']").map(function() {return $(this).val();}).get();
var recipe_flavour_percent = $("input[name='flav-percent']").map(function(){return $(this).val();}).get();
As far as I can tell, the arrays are comma separated values.
Let's for simplicity's sake say:
recipe_flavour_name = a,b,c
recipe_flavour_percent = 5,6,7
I then want to take the number value to use in a function and then loop through all the values and use jQuery's .html() to add the values to a div.
I have tried this: flavPercent1 is just recipe_flavour_percent
var arrayLength = flavPercent1.Length;
for (var i = 0; i < arrayLength; i++) {
var flavML = (flavPercent1[0] / 100 * 100 * 1000) / 1000;
var flavGrams = (flavML * .98 * 100) / 100;
var flavPercent = (flavML / 100 * 1E4) / 100;
$('.live-flavours').html('<tr>'+flavName[0]+'<td></td>'+parseFloat(flavML).toFixed(2)+'<td>'+parseFloat(flavGrams).toFixed(2)+'</td><td>'+parseFloat(flavPercent1[0]).toFixed(2)+'</td></tr>');
};
But I only get flavGrams and flavPercent returned, dynamically adding more data to the array does nothing.
What do I want to achieve?
Grab the values of specified inputs in an array.
Pass them to a function.
Loop through the values and output them in HTML using jQuery.
I hope that makes sense and thanks in advance.
Ok, so assuming that you don't have a problem getting the arrays you need, the problem lies within your for loop.
YOUR CODE:
for (var i = 0; i < arrayLength; i++) {
var flavML = (flavPercent1[0] / 100 * AMOUNT * 1000) / 1000;
var flavGrams = (flavML * .98 * 100) / 100;
var flavPercent = (flavML / AMOUNT * 1E4) / 100;
$('.live-flavours').html('<tr>'+flavName[0]+'<td></td>'+parseFloat(flavML).toFixed(2)+'<td>'+parseFloat(flavGrams).toFixed(2)+'</td><td>'+parseFloat(flavPercent1[0]).toFixed(2)+'</td></tr>');};
You put everything in the for loop, yet make no reference to the index. I'm assuming everywhere you put [0] you actually want [i]. This means that every time the index increases, you are getting the next array element.
You should use .append instead of .html. .html means that the current html will be replaced by what you are adding.
Finally, although making it dynamic is possible, I'm not sure that JQuery is the best libary to use in this case. I'd suggest taking a look at libraries such as Vue or MoonJs (both are very light and very simple libraries) etc... to find a much easier, and frankly better way to do this. They allow for dynamic rendering, and what you are trying to do becomes insanely simplified.
Hope this helps.
(hopefully) WORKING CODE:
for (var i = 0; i < arrayLength; i++) {
var flavML = (flavPercent1[i] / 100 * AMOUNT * 1000) / 1000;
var flavGrams = (flavML * .98 * 100) / 100;
var flavPercent = (flavML / AMOUNT * 1E4) / 100;
$('.live-flavours').append('<tr>'+flavName[i]+'<td></td>'+parseFloat(flavML).toFixed(2)+'<td>'+parseFloat(flavGrams).toFixed(2)+'</td><td>'+parseFloat(flavPercent1[i]).toFixed(2)+'</td></tr>');};

Applying Fibonacci, working with large numbers

I am trying to successfully complete this challenge on the Rosalind page. The challenge is:
Given: Positive integers n≤40 and k≤5.
Return: The total number of rabbit pairs that will be present after n months if we begin with 1 pair and in each generation, every pair of reproduction-age rabbits produces a litter of k rabbit pairs (instead of only 1 pair).
The exercise gives a text file of two numbers, the n and k mentioned above.
My code, which attempts to implement Fibonacci, works as expected for lower numbers of months. However, the result begins to become extremely large for higher numbers of months, and in each case I am given, my answer is Infinity.
Is my formula applied incorrectly? Or is Javascript a bad choice of language to use for such an exercise?
My code:
function fibonacciRabbits(months, pairs){
var months = months;
var numberOfPairs = pairs;
var result = 0;
// Declare parent & child arrays with constants
var parentArr = [1, numberOfPairs + 1]
var childArr = [numberOfPairs, numberOfPairs]
var total = []
// Loop from the point after constants set above
for(var i = 2; i < months - 2 ; i++){
parentArr.push(parentArr[i-1] + childArr[i-1])
childArr.push(parentArr[i-1] * childArr[i-2])
total.push(parentArr[i-1] + childArr[i-1])
}
result = childArr[childArr.length - 1] + parentArr[parentArr.length - 1]
console.log(months + ' months and ' + numberOfPairs + ' pairs:\n')
console.log('parentArr:\n', parentArr)
console.log('childArr:\n', childArr)
console.log('total\n', total)
console.log('result:', result)
console.log('\n\n\n')
}
fibonacciRabbits(5, 3)
fibonacciRabbits(11, 3)
fibonacciRabbits(21, 3)
fibonacciRabbits(31, 2)
And here is a REPL
Here is a more brief solution that doesn't produce such large numbers, and handles the maximum case without hitting infinity in Javascript. I think your solution was getting too big too fast.
function fibonacciRabbits(months, reproAmount){
var existingAdults = 0;
var adultPairs = 0;
var childPairs = 1;
for(var i = 2; i <= months; i++){
adultPairs = childPairs; //children mature
childPairs = (existingAdults * reproAmount); //last month's adults reproduce
existingAdults += adultPairs; //new adults added to the reproduction pool
}
console.log(existingAdults + childPairs);
}
To make sure you are on the right track, test your function with:
fibonacciRabbits(1, 1);
fibonacciRabbits(2, 1);
Which from the website says: f(1)=f(2)=1. So these should both produce "1" no matter what. Your code produces "3" for both of these.

d3 how to turn a set of numbers into a larger set representative of the first set

Say I have array [1,2,5,18,17,8] and I want to turn that into an array of length 40 that follows the same path.
a = [1,2,5,18,17,8];
stepSize = 1 / (40 / a.length);
then i think i could do something like
steps = [];
for( var i = 0; i < 1; i+= stepSize) {
steps.push(d3.interpolate(a[0],a[1])(i));
}
and then repeat that for all the elements. My question is there a better way to do this?
I can only guess what your real problem is but I think you want to plot these values and have a smooth curve. In that case use line.interpolate() https://github.com/mbostock/d3/wiki/SVG-Shapes#line_interpolate
In case you DO know what you need and your solution works for you, take this tip:
Never iterate over stepSize. Calculate it once and multiply it with i in every loop where i goes from 0 to 40. This way you work around precision problems.
Your algorithm cleaned up, tested and working:
var a = [1,5,12,76,1,2];
var steps = 24;
var ss = (a.length-1) / (steps-1);
var result = new Array(steps);
for (var i=0; i<steps; i++) {
var progress = ss * i;
var left = Math.floor(progress);
var right = Math.ceil(progress);
var factor = progress - left;
result[i] = (1 - factor) * a[left] + (factor) * a[right];
// alternative that actually works the same:
//result[i] = d3.interpolateNumber(a[left], a[right], factor);
}
console.log(result);

Categories

Resources