Javascript: Using Math.random in functions nested in arrays - javascript

I'm trying to write an app that will deliver combined results from multiple random selections. I am using 2 dimensional arrays. The first element of each secondary array is the number to 'roll' less than, to return the secondary array, which contains a string as its second element.
Further, inside the string is usually another function which calls another array.
All the returned strings are concatenated into a random phrase.
My expectation was that each time every function was called a new random result would be given. But what seems to be happening is once the first function call returns a result all nested function calls return the same result each time. What I would like is for each nested function call to return a new random result each time.
I hope I'm explaining this well enough. Here is some of the code I'm using with some 'sample' arrays to try to make clear what I'm doing.
// ROLL()
// times = NUMBER OF TIMES TO ROLL
// high = SIZE OF THE DIE / HIGHEST VALUE TO ROLL
// low = LOWEST VALUE (OPTIONAL)
// modifier = MODIFIER TO ROLL (OPTIONAL)
function roll(times, high, low, modifier) {
low = low || 1;
modifier = modifier || 0;
var result = 0;
for (var i = 0; i < times; i++) {
result += (Math.floor(Math.random() * ((high - low) + 1) + low));
}
result += modifier;
return result;
}
// RANDOMRESULT()
// array = A 2 DIM ARRAY
// modifier = MODIFIER TO ROLL (FOR THE ROLL() FUNCTION)
// dieSize = SIZE OF THE DIE (FOR THE ROLL() FUNCTION)
function randomResult(array, modifier, dieSize) {
var die = dieSize || array[array.length - 1][0];
var finalRoll = roll(1, die, 1, modifier);
for (i = 0; i <= array.length - 1; i++) {
if (finalRoll <= array[i][0]) {
return array[i];
}
}
}
//ASSUME MULTIPLE ARRAYS SET UP SIMILARLY
var array1 = [
[3, "You find " + roll(1, 10) + " dollars."],
[5, "You find " + roll(1, 20) + " dollars."],
[9, "You find " + roll(1, 30) + " dollars."]
];
var array2 = [...]
var someArray = [
[2, "Random result from array1. " + randomResult(array1)],
[4, "Random result from array2. " + randomResult(array2)],
[10, "Random result from array3. " + randomResult(array3)]
];
console.log(randomResult(someArray));
console.log(randomResult(someArray));
EDIT: The results are always random for each page refresh but when the randomResult() is called multiple times the same results occur from the nested array functions.
example of muliptle console.log returns...
(2) [2, "Random result from array1. 9,You find 1 dollars."]
(2) [10, "Random result from array3. 9,You find 2 dollars."]
(2) [10, "Random result from array3. 9,You find 2 dollars."]
(2) [2, "Random result from array1. 9,You find 1 dollars."]
(2) [10, "Random result from array3. 9,You find 2 dollars."]
(2) [4, "Random result from array2. 9,You find 2 dollars."]
So every time a '2' or less is rolled the roll() function from array1 always returns the same value. Same with the other results and the other arrays.
So my questions are first, why is this happening? Maybe because the first function call hasn't finished when the second is made?
Second are there any suggestions to fix this. Using object methods instead of 2 dim arrays maybe?
Any commentary or help is appreciated. Thanks.

When you call randomResult() multiple time, it refer back to the array1 and the value of array1 is already calculated when the script is loaded.
If you want a different value each time, put it inside a function and call the function to get the value.
function getRandomArray() {
return [
[3, "You find " + roll(1, 10) + " dollars."],
[5, "You find " + roll(1, 20) + " dollars."],
[9, "You find " + roll(1, 30) + " dollars."]
];
}
console.log(getRandomArray());
console.log(getRandomArray());

Related

Removing Numbers From An Array - Javascript

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!');
}
}

How can I us a single var for multiple values?

I am trying to get random values, getting random array elements.
The problem that when i generate them, they are the same.
This may be a stupid question, but how can I get a random value for each instance.
my HTML looks like this
Our Array consists of:<br>
<span id="massParts"></span><br><br>
Generating a word from syllables:<br>
<span id="oneWord"></span><br><br>
Generating a sentence from several words<br>
<span id="oneSentence"></span>
What I am trying to achieve is getting a sentence of randomly generated words. I seethe only solution to create multiple words and then putting them together. But this is not the solution for a bigger text.
my script is:
<script>
// creating an array of syllables
var parts = ["ing", "er", "a", "on", "po", "i", "re", "tion"];
var partsAsString = parts.join(', ');
// display syllables array elements
document.getElementById("massParts").innerHTML = partsAsString;
// getting random element from an array
var a = Math.floor(Math.random() * parts.length);
var b = Math.floor(Math.random() * parts.length);
var c = Math.floor(Math.random() * parts.length);
// making a word with one, two and three syllables
var oneSylWord = parts[a];
var twoSylWord = parts[a]+parts[b];
var threeSylWord = parts[a]+parts[b]+parts[c];
//putting three words into an array
var newWord = [oneSylWord, twoSylWord, threeSylWord];
// taking one of those free words fron the new array
var randWord = newWord[Math.floor(Math.random() * newWord.length)];
// display a random 1,2,3 syllable word
document.getElementById("oneWord").innerHTML = randWord;
// generating a sentence
var sentence = randWord + " " + randWord + " " + randWord + ".";
document.getElementById("oneSentence").innerHTML = sentence;
</script>
I understand that I display the same var randWord and that causes the repetition. but how can I avoid using multiple variables for it.
Thank you.
here is a jsfiddle https://jsfiddle.net/2j9jpcoo/
Put the code into a function and call it multiple times to get a (potentially) different value every time it is called:
function getRandomValue(arr);
return arr[Math.floor(Math.random() * arr.length)];
}
var sentence = getRandomValue(newWord) + " " + getRandomValue(newWord) + " " + getRandomValue(newWord) + ".";
Functions allow you to organize and reuse code. From the above link:
Functions are the bread and butter of JavaScript programming. The concept of wrapping a piece of program in a value has many uses. It is a tool to structure larger programs, to reduce repetition, to associate names with subprograms, and to isolate these subprograms from each other.
I liked the following algorithm in generating random numbers, according to this article where it mentions it is even better in performance but to be honest I did not benchmark it but you could check this in jsfiddle demo, just run it and see the benchmark results
// the initial seed
Math.seed = 6;
// in order to work 'Math.seed' must NOT be undefined,
// so in any case, you HAVE to provide a Math.seed
Math.seededRandom = function(max, min) {
max = max || 1;
min = min || 0;
Math.seed = (Math.seed * 9301 + 49297) % 233280;
var rnd = Math.seed / 233280;
return min + rnd * (max - min);
}
I re-organized your code a bit and created some re-usable functions to get a different random word each time. In this case we can skip the variable and use the return value from the function directly:
// creating an array of syllables
var a, b, c, newWord;
var parts = ["ing", "er", "a", "on", "po", "i", "re", "tion", "con", "de", "sta"];
var partsAsString = parts.join(', ');
// display syllables array elements
document.getElementById("massParts").innerHTML = partsAsString;
function shuffleLetters() {
// getting random element from an array
a = Math.floor(Math.random() * parts.length);
b = Math.floor(Math.random() * parts.length);
c = Math.floor(Math.random() * parts.length);
var oneSylWord = parts[a];
var twoSylWord = parts[a]+parts[b];
var threeSylWord = parts[a]+parts[b]+parts[c];
//putting three words into an array
newWord = [oneSylWord, twoSylWord, threeSylWord];
}
function getRandomWord() {
shuffleLetters();
// taking one of those free words fron the new array
return newWord[Math.floor(Math.random() * newWord.length)];
}
// making a word with one, two and three syllables
shuffleLetters();
// display a random 1,2,3 syllable word
document.getElementById("oneWord").innerHTML = getRandomWord();
// generating a sentence
var sentence = getRandomWord() + " " + getRandomWord() + " " + getRandomWord() + ".";
document.getElementById("oneSentence").innerHTML = sentence;

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.

Math.max method on array with equal values

I'm working on some coderbyte code, and noticed that when I try to get the max item in an array of equal values undefined is returned. When logging the min value is logs 80 and not undefined. Why is this?
Updated Code:
function noRepeat(arr) {
tmp = []
if (arr.length === 2 && arr[0] === arr[1]) {
return arr;
}
for (var i = 0;i<arr.length;i++) {
if (tmp.indexOf(arr[i]) === -1) {
tmp.push(arr[i])
}
}
return tmp
}
function SecondGreatLow(arr) {
arr = noRepeat(arr).sort(function (a,b) {return a-b;});
var low = arr[arr.indexOf(Math.min.apply(Math,arr))+1];
console.log("low",low);
var high = arr[arr.indexOf(Math.max.apply(Math,arr))-1];
console.log("high",high);
return low +" "+high;
}
console.log(SecondGreatLow([80,80]));
Output:
"low" 80
"high" undefined
"80 undefined"
That's, actually, ok. How do you want to find the second largest \ smallest number in an array of two similar numbers?
It should output "no solution" or something else. Just like there is no solution for an empty array.
function SecondGreatLow(arr)
{
arr = noRepeat(arr).sort(function (a,b) {return a-b;});
if (arr.length < 2)
return "No solution";
console.log("low ", arr[1]);
console.log("high ", arr[arr.length - 2]);
return low + " " + high;
}
You don't need Math min and max functions as your array is sorted and values are unique. You need to take the second from beginning and the second from the end.
Also, you don't need this part as it is calculated right by algorithm.
if (arr.length === 2)
{
return arr[1] + " " + arr[0];
}
For example, you have an array [1, 1, 2].
You remove repetitions and get [1, 2].
Now your algorithms returns low = arr[1] = 2 and high = arr[2 - 2] = arr[0] = 1.
The answer is correct - 2 is the second minimum number and 1 is the second largest.

Find subset of elements in an array that when summed equal any other element in the array

I'd like to write an algorithm in Javascript for the following problem.
Given the following array [1,2,3,4,6], provide the number of subsets that equal any other element in the array.
For instance:
1+2 = 3
1+3 = 4
2+4 = 6
1+2+3 = 6
Answer: 4 subsets
I can calculate the sum of pairs of numbers that equal any other element in the array; however, I cannot find the sum of 2 or more elements (1+2+3) that equal any other element in the array.
How would I write an algorithm for this? Thanks!
Here's a very simple solution that should be easy to grasp. Note that this is not a very fast algorithm, but for shorter arrays it works well.
The idea is to generate a bit mask for every combination, and then for each mask add the numbers in the array indicated by a 1 in the bit mask string:
console.log("Number of subsets: " + getNumberOfSubsets([1, 2, 3, 4, 6], 2));
function getNumberOfSubsets(numbers, minimumNumbersInSubset) {
var numberOfBits = Math.pow(2, numbers.length);
var numOfSubsets = 0;
for (var i=0;i<numberOfBits;i++) {
var bitField = i.toString(2);
while(bitField.length < numbers.length) {
bitField = "0" + bitField;
}
var sum = 0;
var addedNumbers = [];
for (j=0;j<bitField.length;j++) {
if (bitField.charAt(j) == "1") {
sum += numbers[j];
addedNumbers.push(numbers[j]);
}
}
if (addedNumbers.length >= minimumNumbersInSubset && numbers.indexOf(sum) !== -1) {
numOfSubsets += 1;
console.log("Iteration " + i + ": " +
bitField+", " + (addedNumbers.join("+") + "=" + sum));
}
}
return numOfSubsets;
}
Outputs the following in the console to show the successful combinations:
Iteration 10: 01010, 2+4=6
Iteration 20: 10100, 1+3=4
Iteration 24: 11000, 1+2=3
Iteration 28: 11100, 1+2+3=6
Number of subsets: 4
Here's a jsfiddle: http://jsfiddle.net/9HhSs/

Categories

Resources