I am creating a spinning wheel of luck. So I have numbers 1 to 6.
Here is some code:
First I get a random number between 0 and 7, so (1,2,3,4,5,6)
var random = Math.floor(Math.random() * 6) + 1;
What I want to do is to set percentage like this:
var goldChance = 10;
var blueChance = 40;
var grayChance = 50;
goldChance are numbers 2 and 5,
blueChance are numbers 6 and 3, and
graychance are numbers 4 and 1.
So when the wheel starts to spin it should show numbers 4 and 1 for 50% of the spin, numbers 6 and 3 for 40% and only rare numbers 2 and 5 should show 10% of the time. That way if you are lucky you will get that gold numbers.
Is there any way to set Math.random() to includes chances?
Thanks in advance!
Don't get a random number 1 <= n <= 6, instead get a random number 0 <= n <= 19 and pick from an array of twenty entries with your distribution of numbers in it:
const numbers = [2, 5, 6, 3, 6, 3, 6, 3, 6, 3, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1];
const result = numbers[Math.floor(Math.random() * numbers.length)];
Example:
const numbers = [2, 5, 6, 3, 6, 3, 6, 3, 6, 3, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1];
const tbody = document.getElementById("results");
const rows = [1, 2, 3, 4, 5, 6].map(number => {
const row = document.createElement("tr");
row.insertAdjacentHTML("beforeend",
`<td>${number}</td><td>0</td><td>0%</td>`);
tbody.appendChild(row);
return row;
});
let draws = 0;
let timer = 0;
doDraw();
function doDraw() {
const number = numbers[Math.floor(Math.random() * numbers.length)];
++draws;
const row = rows[number - 1];
const countCell = row.cells[1];
countCell.textContent = Number(countCell.textContent) + 1;
rows.forEach(row => {
row.cells[2].textContent = (Number(row.cells[1].textContent) / draws * 100).toFixed(2) + "%";
});
timer = setTimeout(doDraw, 1);
}
document.getElementById("stop").addEventListener("click", function() {
clearTimeout(timer);
timer = 0;
});
body {
font-family: sans-serif;
}
td {
text-align: right;
}
The percentages approach the gold (5% each for 2 and 5 [total of 10%]), blue (20% each for 3 and 6 [total of 40%]), and grey (25% each for 1 and 4 [total of 50%]) levels over time as the randomness works itself out...
<table>
<thead>
<tr>
<th>Number</th>
<th>Occurrences</th>
<th>%</th>
</tr>
</thead>
<tbody id="results"></tbody>
</table>
<input id="stop" value="Stop" type="button">
You could use an array with probabilities and check and count against a random value.
This function sets first the return value to the last possible index and iterates until the rest of the random value is smaller than the actual probability.
The probabilities have to sum to one.
function getRandomIndexByProbability(probabilities) {
var r = Math.random(),
index = probabilities.length - 1;
probabilities.some(function (probability, i) {
if (r < probability) {
index = i;
return true;
}
r -= probability;
});
return index;
}
var i,
probabilities = [0.25, 0.05, 0.2, 0.25, 0.05, 0.2],
count = {},
index;
probabilities.forEach(function (_, i) { count[i + 1] = 0; });
for (i = 0; i < 1e6; i++) {
index = getRandomIndexByProbability(probabilities);
count[index + 1]++;
}
console.log(count);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I answered a similar problem for a coding challenge by generating a number 1 <= n <= 100, and then assigning portions of that range to represent the probability desired.
So, for example, to get 1 ~50% of the time, 2 10% of the time, etc.:
if (n > 0 && n <= 50) {
return 1;
} else if (n > 50 && n <= 60) {
return 2;
} else if ...
Related
I found a code golf challenge that requires you to calculate Conway's Constant to the first 1000 digits. The problem is I couldn't find any place that tells how to calculate this, just websites showing polynomials with a variable x that I do not know what is.
I calculated the first 30 numbers in the Look-and-say sequence with this code:
const nums = ["1"],
trailingSequences = seq => {
const num = seq[0];
let counter = 1;
let idx = 0;
for (let i = 1; i < seq; i++) {
if (num == seq[i]) {
counter++
idx = i;
} else {
break
};
}
return [`${counter}${num}`, idx + 1];
},
getNext = previous => {
let next = "";
while (true) {
if (previous == "") {
break
};
const part = trailingSequences(previous);
next += part[0];
previous = previous.slice(part[1]);
}
return next;
}
for (let i = 0; i < 30; i++)
nums.push(getNext(nums[nums.length - 1]))
console.log(nums.join("\n\n\n"));
But I still do not know how to extract Conway's constant regardless.
So, how to calculate Conway's Constant to a modifiable precision in JavaScript?
Conway's Constant is the unique real positive root of an order-71 polynomial. As you might expect it is irrational1, and cannot be expressed as a finite continued fraction.
One of the easiest, and generally speaking most efficient methods to compute polynomial roots is with Newton's method:
where xn is the current guess and f(xn) is a function that evaluates the target polynomial at xn.
In the case that arbitrary precision reals/rationals are not available, the result can instead be scaled by a large power of 10 to compute the desired precision. The implementation below uses V8's BigInts to compute Conway's Constant to 1000 places.
/**
* Evaluates a polynomial given by coeffs at x,
* or the derivative thereof, scaled by a factor.
*/
function evalpoly(x, coeffs, scale, deriv) {
let ret = 0n;
const d = deriv ? 1 : 0;
for(let i = coeffs.length - 1; i >= d; i--) {
ret = x*ret / scale + BigInt(coeffs[i] * [1, i][d]) * scale;
}
return ret;
}
const poly = [
-6, 3, -6, 12, -4, 7, -7, 1, 0, 5, -2, -4, -12, 2, 7, 12, -7, -10,
-4, 3, 9, -7, 0, -8, 14, -3, 9, 2, -3, -10, -2, -6, 1, 10, -3, 1,
7, -7, 7, -12, -5, 8, 6, 10, -8, -8, -7, -3, 9, 1, 6, 6, -2, -3,
-10, -2, 3, 5, 2, -1, -1, -1, -1, -1, 1, 2, 2, -1, -2, -1, 0, 1]
const scale = 10n**1000n
// initial guess 1.333333...
let x = scale * 4n / 3n
for(let i = 0; i < 14; i++) {
x -= evalpoly(x, poly, scale, 0) * scale / evalpoly(x, poly, scale, 1)
}
x
1 Finch, Steven R., Mathematical Constants, pp. 642, Cambridge University Press, 2003.
The Conway Constant is the ratio between the length of digits of n and n-1 as n approaches inf.
const nums = ["1"],
trailingSequences = seq => {
const num = seq[0];
let counter = 1;
let idx = 0;
for (let i = 1; i < seq; i++) {
if (num == seq[i]) {
counter++
idx = i;
} else {
break
};
}
return [`${counter}${num}`, idx + 1];
},
getNext = previous => {
let next = "";
while (true) {
if (previous == "") {
break
};
const part = trailingSequences(previous);
next += part[0];
previous = previous.slice(part[1]);
}
return next;
}
for (let i = 0; i < 30; i++){
let prev = (nums[nums.length - 1] + '').length;
let current = (getNext(nums[nums.length - 1]) + '').length;
nums.push(getNext(nums[nums.length - 1]))
// ratio of n / n-1, this is the approx of Conway's Constant
console.log(current / prev);
}
//console.log(nums.join("\n\n\n"));
I've a JavaScript array and sum as input
array = [4,8,2,4,2,2,8,12,4,2, 2]
sum = 12 // all the time sum will be 12
I want 2d array, the numbers in batches should be sum equals or less than 12
The output array should look like
[
[4,8],
[2,4,2,2,2],
[8, 4],
[12],
[2]
]
4 + 8 = 12
2 + 4 + 2 + 2 + 2 = 12
...
2 is left at the end
Other examples
1) array = [6,5,3,3,3,2,2,2,2]
sum = 12
output: [ [6,3,3], [5,3,2,2], [2,2] ]
One the number is allotted to subset, it should not used to other subset
remaining numbers can be added to the last but sum should be less than 12, else add one more array and add remaining ones
The input array can have any integer from 1 - 12
How can I get the output I want?
Try this function. I commented the code as much as possible to clarify it.
const example1 = [4, 8, 2, 4, 2, 2, 8, 12, 4, 2, 2];
const example2 = [6, 5, 3, 3, 3, 2, 2, 2, 2];
const example3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
const example4 = [5,12,3,4,4,1,1,1,5,8,12,6,9,11,6];
const example5 = [4, 2, 1, 2, 3, 3, 5, 7, 8, 9];
const lookAhead = function(array, searchFor) {
return array.some(val => {
return val <= searchFor;
});
}
function findPairs(inputArray) {
// First sort array in descending order
inputArray.sort((a, b) => b - a);
console.log("input", JSON.stringify(inputArray.slice(0)));
// set variables
const pairArray = [];
const max = 12;
inputArray.forEach(function(num, index) {
// when looping the array we will replace values with null once completed,
// Therefore if value is null no need to go futher
if (num == null)
return;
// initiate pair value with current number
const pair = [num];
// set it to null in input array
inputArray[index] = null;
// if number equals to max (ie. 12) no need to go futher
if (num == max) {
pairArray.push(pair);
return;
}
let total = num;
// Loop through array again to see matching numbers
for (let i = 0; i < inputArray.length; i++) {
// Don't go futher if it is a null value
if (inputArray[i] == null)
continue;
const add = total + inputArray[i];
/* if the total is less than max (12) then we check if we have an edge case
* For example in an array like [6, 5, 3, 3, 3], 6 + 5 is 11 but in next loops we
* will not find any "1" to get to 12. Therefore we escape this iteration and check
* next numbers. In this case the result would be 6 + 3 + 3
*/
if (add < max) {
const found = lookAhead(inputArray.slice(i), max - add);
if (found) {
pair.push(inputArray[i]);
total = add;
inputArray[i] = null;
}
} else if (add == max) {
// The addition is equals to max. Push the number and set it to null in input array
pair.push(inputArray[i]);
inputArray[i] = null;
total = 0;
break;
}
}
// Push pair array from this iteration to pairArray
pairArray.push(pair);
});
console.log("output", JSON.stringify(pairArray));
console.log("-------");
}
findPairs(example1);
findPairs(example2);
findPairs(example3);
findPairs(example4);
findPairs(example5);
A little complex to understand but here you go...
let originalArray = [7, 7, 7, 7, 7]
let sum = 12;
let twoDiArray = [];
let CalculateSum = (array, element) => {
array = [...array, element]
return array.reduce((x, y) => {
return x + y;
})
}
twoDiArray.push([]);
originalArray.forEach(element => {
for (let i = 0; i < twoDiArray.length; i++) {
if (CalculateSum(twoDiArray[i], element) <= 12) {
twoDiArray[i].push(element);
break;
} else {
if (twoDiArray.length - 1 === i) {
twoDiArray.push([element]);
break;
}
}
}
})
console.log(twoDiArray)
Here you... I will keep both answers open for future use of others...
let originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
let sum = 12;
let twoDiArray = [];
let CalculateSum = (array, element) => {
array = [...array, element]
return array.reduce((x, y) => {
return x + y;
})
}
twoDiArray.push([originalArray[0]]);
originalArray.splice(0, 1);
do {
originalArray.forEach((element, index) => {
for (let i = 0; i < twoDiArray.length; i++) {
let summ = CalculateSum(twoDiArray[i], element);
if (summ === 12) {
twoDiArray[i].push(element);
originalArray.splice(index, 1);
break;
} else {
if (index === originalArray.length - 1) {
if (CalculateSum(twoDiArray[twoDiArray.length - 1], originalArray[0]) <= 12) {
twoDiArray[twoDiArray.length - 1].push(originalArray[0]);
break;
} else {
twoDiArray.push([originalArray[0]]);
}
originalArray.splice(0, 1);
}
}
}
})
}
while (originalArray.length > 0);
console.log(twoDiArray)
I'm trying to write a function that will identify the longest period of variance in an array of numbers. Variance begins when the previous number is higher than the current, and ends when the next number is the same as the current; however, if variance doesn't end, then it is assumed the variance began with the last two numbers.
For example: [10, 5, 3, 11, 8, 9, 9, 2, 10] The longest period of variance in this array is [5, 3, 11, 8, 9], or just 5 (the length). A variance ends when the following number is the same as the current, in this case, 9.
The function I've written works on this case; however, it doesn't when the entire array has variance, such as [10, 5, 10, 5, 10, 5, 10, 5, 10], which returns 8, when it should be 9.
In the case where the previous number is number is always lower, or always higher than the variance would be 2, because it never ended. For example [2, 4, 6, 8] and [8, 6, 4, 2].
I know the issue with the entire array variance can be solved by starting the for loop at 0, but then the other cases become invalid. Any help is greatly appreciated.
Without further ado, here is my code:
function findVariance(numbers) {
if ([0,1].includes(numbers.length)) return numbers.length;
const variance = [[0]];
let greater = numbers[1] > numbers[0];
let lesser = numbers[1] < numbers[0];
for (let i = 1; i < numbers.length; i++) {
let previous = variance.length - 1;
let previousVarianceGroup = variance[previous];
let previousVarianceGroupValue = previousVarianceGroup[previousVarianceGroup.length - 1];
if (greater) {
if (numbers[i] < numbers[previousVarianceGroupValue]) {
previousVarianceGroup.push(i);
greater = false;
lesser = true;
} else {
greater = numbers[i] < numbers[previousVarianceGroupValue];
lesser = numbers[i] < numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
} else if (lesser) {
if (numbers[i] > numbers[previousVarianceGroupValue]) {
previousVarianceGroup.push(i);
greater = true;
lesser = false;
} else {
greater = numbers[i] > numbers[previousVarianceGroupValue];
lesser = numbers[i] > numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
} else {
greater = numbers[i] > numbers[previousVarianceGroupValue];
lesser = numbers[i] < numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
}
const result = [];
for (let i = 0; i < variance.length; i++) {
result[i] = variance[i].length;
}
result.sort();
return result[result.length - 1];
}
console.log(findVariance([10, 5, 3, 11, 8, 9, 9, 2, 10]));
console.log(findVariance([10, 5, 10, 5, 10, 5, 10, 5, 10]));
console.log(findVariance([2, 4, 6, 8]));
Here's what I got (trying to understand the question as best i could)
function calculateVariance(arr) {
// trivial cases
if (arr.length <= 1) { return arr.length; }
// store the difference between each pair of adjacent numbers
let diffs = [];
for (let i = 1; i < arr.length; i++) {
diffs.push(arr[i] - arr[i - 1]);
}
let max = 0;
// if the difference between two numbers is 0, they're the same.
// the base max variance encountered is 1, otherwise it's 2.
// the boolean zen here is that diffs[0] is falsy when it's 0, and truthy otherwise
let count = diffs[0] ? 2 : 1;
// go through the array of differences,
// and count how many in a row are alternating above/below zero.
for (i = 1; i < diffs.length; i++) {
if ((diffs[i] < 0 !== diffs[i - 1] < 0) && diffs[i] && diffs[i - 1]) {
count++;
} else {
max = Math.max(count, max);
// see above
count = diffs[i] ? 2 : 1;
}
}
// account for the maximum variance happening at the end
return Math.max(count, max);
}
You are overcomplicating things a bit, just increase a counter as long as an element equals the next one, reset on equal:
const counts = [];
let count = 0;
for(let i = 0; i < numbers.length - 1; i++) {
if(numbers[i] === numbers[i + 1]) {
counts.push(count);
count = 0;
} else {
count++;
}
}
counts.push(count);
return counts.sort()[counts.length - 1];
Change the given amount of money into minimum number of bills.
Inputs:
Amount: positive integer;
Bills: a sorted list of distinct positive integers (e.g. [1, 5, 10]).
Assumptions:
Amount does not exceed 100.
At most 4 bill values.
Must return 0 if the amount cannot be changed.
Examples:
Amount: 17, bills: [1, 5, 10], answer: 4 -> 10+5+1+1
Amount: 17, bills: [2, 4], answer: 0
Here's the code I have so far
function sort(array) {
for (var i = array.length - 1; i >= 0; i--) {
for (var j = 0; j < i; j++) {
if (array[j + 1] > array[j]) {
var z = array[j];
array[j] = array[j + 1];
array[j + 1] = z;
}
}
}
return array;
}
function change(amount, bills) {
sort(bills);
var result = [];
while (amount > 0) {
for (var i = 0; i < bills.length; i++) {
if (amount >= bills[i]) {
amount -= bills[i];
result.push(bills[i]);
i--;
}
}
}
return result.length;
}
console.log(change(17, [1, 5, 10])); // Expect: 4
console.log(change(17, [2, 4])); // Expect: 0
console.log(change(18, [2, 4])); // Expect: 5
//console.log(change(17, [3, 5])); // Expect: 5
There are 2 problems
One is that if the amount cannot be divided it doesn't return 0 but just lags out because it's an infinite loop.
Second is that in the last example, 17,[3,5] my code takes the 5 3 times and then realises that it can't do the remaining 2 and lags out, instead of doing 3 4 times and adding a 5.
Would really appreciate suggestions, or fixed code. Please keep it fairly simple I am just a starter.
If fixed your change function and added comments to explain my changes, let me know if you have any doubts
function change (amount, bills) {
//Asign sorted array of bills to possibleBills
var possibleBills = sort(bills);
var result = [];
//Asign amount to currentAmount
var currentAmount = amount;
//Sort through possibleBills
for (var i = 0; i < possibleBills.length; i++) {
//Perform action inside while loop if the current bill value can be substracted from currentAmount
while (currentAmount - possibleBills[i] >= 0) {
currentAmount -= possibleBills[i];
result.push(possibleBills[i]);
//End loop and return the length of result if currentAmount reaches 0
if (currentAmount === 0) {
return result.length;
}
}
}
//Return 0 if the amount couldn't be changed with the given bills
if (currentAmount > 0) {
return 0;
}
return result.length;
};
function change(amount, bills) {
const billsDesc = bills.sort((a, b) => b - a);
const give = {}
let remaining = amount;
for (const bill of billsDesc) {
const qty = Math.floor(remaining/bill);
give[bill] = qty;
remaining -= qty*bill;
}
give.totalQty = Object.values(give).reduce((curr, prev) => curr + prev, 0);
return remaining === 0? give.totalQty : 0;
}
console.log(`${change(17, [1, 5, 10])} should equal 4`);
console.log(`${change(17, [2, 4])} should equal 0`);
console.log(`${change(18, [2, 4])} should equal 5`);
The power (x+y)n can be expanded into a sum of terms of the form ai xb yc where the coefficient ai of each term is a positive integer.
I'm looking for a function that computes the Array of all these coefficients ai given n.
Example 1: For n = 1: (x+y)1 = 1x + 1y => return [1, 1]
Example 2: For n = 2: (x+y)2 = 1x2 + 2xy + 1y2 => return [1, 2, 1]
For n = 3 the result would be [1, 3, 3, 1] and so on.
A simple implementation of this could be:
function Tartaglia(n) {
var row = new Array(2);
row[0] = [1];
for (i=1; i<= n; i++) {
if (i > 1) {
row[0] = row[1];
}
row[1] = new Array(i+1);
row[1][0] = 1;
row[1][i] = 1;
for (j=1; j<i; j++){
row[1][j] = row[0][j-1] + row[0][j];
}
}
return row[1];
}
window.onload = function() {
document.getElementById('compute').addEventListener('click', function (e) {
var n = document.getElementById('iVal').value;
document.getElementById('result').innerHTML = JSON.stringify(Tartaglia(n), 4, 4);
}, false);
}
<input id="iVal" type="number">
<button id="compute">Compute</button>
<div id="result"></div>
Suffice it to build a pascal triangle and return the last row :
function powMatrix(n){
var result = [];
result[0] = [1];
result[1] = [1,1];
for (var row = 2; row < n+1; row++){
result[row] = [1];
for (var col = 1; col <= row -1; col++){
result[row][col] = result[row-1][col] + result[row-1][col-1];
result[row].push(1);
}
}
return result[n];
}
console.log(powMatrix(3)); //-->[ 1, 3, 3, 1 ]
console.log(powMatrix(4)); //-->[ 1, 4, 6, 4, 1 ]
console.log(powMatrix(5)); //-->[ 1, 5, 10, 10, 5, 1 ]
We can exploit fact that the coefficients ai are - according to the Binomial theorem - binomial coefficients. Those can easily be computed in O(n) as:
function binomial_coeffs(n) {
var half = n >> 1, coeffs = new Array(n + 1);
coeffs[0] = coeffs[n] = 1;
for (var i = 1, coef = 1; i <= half; ++i) {
coeffs[n - i] = coeffs[i] = coef *= (n - i + 1) / i;
}
return coeffs;
}
console.log(...binomial_coeffs(0)); // 1
console.log(...binomial_coeffs(1)); // 1 1
console.log(...binomial_coeffs(2)); // 1 2 1
console.log(...binomial_coeffs(3)); // 1 3 3 1
console.log(...binomial_coeffs(10)); // 1 10 45 120 210 252 210 120 45 10 1