How to populate array with numbers based on odds? - javascript

I recently saw a roulette wheel of sorts which contained the following possible numbers. 1, 2, 9, 16, 24, 49j and 49f. Each number has odds of itself over 1. So the odds of rolling a 2 are 2/1 and a 9 is 9/1. I thought it would be a fun (and simple) exercise to populate an array with the right amount of each type of number but it's proved anything but. My first idea was to build a name/value array to hold each numbers odds and then a second one to hold a counter value.
let numbers = {
"1": "1",
"2": "2",
"9": "9",
"16": "16",
"24": "24",
"49f": "49",
"49j": "49"
};
let counter = {
"1": "0",
"2": "0",
"9": "0",
"16": "0",
"24": "0",
"49f": "0",
"49j": "0"
};
let tc = {
"1": "0",
"2": "0",
"9": "0",
"16": "0",
"24": "0",
"49f": "0",
"49j": "0"
};
That last one tc is just to tally how many of each number is in the final array and confirm my mathematical genius. So from here it should be a simple matter of looping 50 times and looping through each number, incrementing its counter by 1 and when the counter value equals the odds value, push that number into the array and reset its counter to 0. So each iteration I should get a 1 and every 3rd iteration I should get a 2 and so on.
var wheel = [];
function load_numbers( ) {
for(let number in numbers) {
var count = parseInt(counter[number], 10);
var odd = parseInt(numbers[number], 10);
var t = parseInt(tc[number], 10);
count++;
if (count == odd) {
wheel.push(number);
count = 0;
t++; tc[number] = t;
}
counter[number] = count;
}
}
function load_wheel( ) {
for (i = 0; i < 50; i++) {
load_numbers();
}
for(let mc in tc) {
document.write(mc + ": " + tc[mc] + " of " + wheel.length + " <br>");
}
}
However that code produces the following
1: 50 of 87
2: 25 of 87
9: 5 of 87
16: 3 of 87
24: 2 of 87
49f: 1 of 87
49j: 1 of 87
These odds are clearly wrong but I can't see what's wrong with the method, I've tried doubling the odds and looping 100 times, still wrong. Setting a breakpoint after 49j == 1 also gives me these odds. In desperation I tried calculating the percentage of each numbers odds and adding them together (ie 1 = 50%, 2 = 33%) and that procedure keeps giving me 108%! So at this point I have to conclude I've been wrong about math my whole life or the Casino is pulling a fast one! Or is there something I'm overlooking?

Related

Select a random element out of an object/array based on the percent chance of it showing up [duplicate]

This question already has answers here:
How to choose a weighted random array element in Javascript?
(7 answers)
Closed 1 year ago.
I have an object that looks like this:
"rarity": {
"Common": "60",
"Uncommon": "25",
"Rare": "10",
...
"Legendary": "0.01",
"Mythical": "0.001",
}
The object is set up as 'Name': '% chance', so Common has a 60% chance of showing up, whereas Mythical has a 1 in 100,000 chance of showing up (0.001%)
I want to be able to (Quickly) select a random element based on the percentage chance of it showing up, but I have zero ideas where to begin.
If this is in the wrong StackExchange please let me know, it's programming-related but heavily math-based.
Let's start by taking a random number between 0 and 100000:
const rnd = Math.random() * 100000;
Now, you need to divide the number by 1000 since you want to take into account up to 3 decimals after comma for "Mythical": "0.001"
const percent = rnd / 1000;
Last, just take the key of the number that contains the percent variable.
Example
const rarity = {
"Common": "60",
"Uncommon": "25",
"Rare": "10",
"More rare": "4.989", // to fill the rest of percentage
"Legendary": "0.01",
"Mythical": "0.001"
}
const rnd = Math.random() * 100000;
const percent = rnd / 1000;
let result = null, acc = 0;
Object.keys(rarity).forEach(key => {
if (result === null && percent > 100 - rarity[key] - acc)
result = key;
acc += parseFloat(rarity[key]);
});
console.log(percent + " %", result);
Here you can test how many times each possibility appears in a 100000 loop
const rarity = {
"Common": "60",
"Uncommon": "25",
"Rare": "10",
"More rare": "4.989", // to fill the rest of percentage
"Legendary": "0.01",
"Mythical": "0.001"
}
let testNumber = 100000;
const testResults = {};
while (0 < testNumber--) {
const rnd = Math.random() * 100000;
const percent = rnd / 1000;
let result = null, acc = 0;
Object.keys(rarity).forEach(key => {
if (result === null && percent > 100 - rarity[key] - acc)
result = key;
acc += parseFloat(rarity[key]);
});
if (!testResults[result])
testResults[result] = 0;
testResults[result]++;
}
console.log(testResults);
You can achieve that by:
dividing the 0 to 1 segment into sections for each element based on their probability (For example, an element with probability 60% will take 60% of the segment).
generating a random number and check in which segment it lands.
STEP 1
make a prefix sum array for the probability array, each value in it will signify where its corresponding section ends.
For example:
If we have probabilities: 60% (0.6), 30%, 5%, 3%, 2%. the prefix sum array will be: [0.6,0.9,0.95,0.98,1]
so we will have a segment divided like this (approximately): [ | | ||]
STEP 2
generate a random number between 0 and 1, and find it's lower bound in the prefix sum array. the index you'll find is the index of the segment that the random number landed in
Here's how you can implement this method:
let obj = {
"Common": "60",
"Uncommon": "25",
"Rare": "10",
"Legendary": "0.01",
"Mythical": "0.001"
}
// turning object into array and creating the prefix sum array:
let sums = [0]; // prefix sums;
let keys = [];
for(let key in obj) {
keys.push(key);
sums.push(sums[sums.length-1] + parseFloat(obj[key])/100);
}
sums.push(1);
keys.push('NONE');
// Step 2:
function lowerBound(target, low = 0, high = sums.length - 1) {
if (low == high) {
return low;
}
const midPoint = Math.floor((low + high) / 2);
if (target < sums[midPoint]) {
return lowerBound(target, low, midPoint);
} else if (target > sums[midPoint]) {
return lowerBound(target, midPoint + 1, high);
} else {
return midPoint + 1;
}
}
function getRandom() {
return lowerBound(Math.random());
}
console.log(keys[getRandom()], 'was picked!');
hope you find this helpful. If you need any clarifications please ask
Note:
(In Computer Science) the lower bound of a value in a list/array is the smallest element that is greater or equal to it. for example, array:[1,10,24,99] and value 12. the lower bound will be the element with value 24.
When the array is sorted from smallest to biggest (like in our case) finding the lower bound of every value can be done extremely quickly with binary searching (O(log(n))).
EDIT: added code example

Identify in which range a given number falls in array of object

I have an array of objects like
const score_card = [
{ "range":"0.6-1.5", "point":"10"},
{ "range":"1.6-2.5", "point":"20"},
{ "range":"2.6-3.5", "point":"30"},
{ "range":"3.6-4.5", "point":"40"},
{ "range":"4.6+", "point":"50"}
]
Now if I receive a number 1.7 then I need to find out that in which range it falls, so in my example it falls in 1.6-2.5 and associated points for it is 20.
Since the score_card array will be the same all the time, I have used switch case as follows:
let number = 1.7
switch(number) {
case (number>=0.6 || number<=1.5):
console.log('points : 10')
break;
case (number>=1.6 || number <=2.5):
console.log('points : 20')
break;
case (number >=2.6 || number <=3.5):
console.log('points : 30')
break;
case (number>=3.6 || number<=4.5):
console.log('points : 40')
break;
case (number>=4.6):
console.log('points : 50')
break;
default:
console.log('none')
}
Now the problem is the number (in our example 1.7) which we have passed in switch case is a part of an array and this switch case is written inside loop to get number one by one.Which makes code longer and possibly slower And I have to do this 4 more time for different cases.
So can anyone help me and suggest me a way to handle this efficiently?
You have to make changes for your last last condition/range
const score_card = [
{ "range": "0.6-1.5", "point": "10" },
{ "range": "1.6-2.5", "point": "20" },
{ "range": "2.6-3.5", "point": "30" },
{ "range": "3.6-4.5", "point": "40" },
{ "range": "4.6+", "point": "50" }
]
const getPoints = score => {
let points = 0;
score_card.some(slab => {
let [low, high] = slab.range.split('-');
if (score >= +low && score <= +high) points = +slab.point;
})
return points;
}

Javascript shif left or right bidirectional

Thanks to this great site using excellent code from Nope i get this code:
var myStringArray = ["1","2","3","4","5","6","7","8","9","10"];
var loopByX = function(x){
var y = myStringArray.splice(0,x);
myStringArray = myStringArray.concat(y);
return y;
}
console.log(loopByX(3));
console.log(loopByX(3));
console.log(loopByX(3));
console.log(loopByX(3));
console.log(loopByX(3));
That works great...i added it to HTML5 application and see that i have a little wrong describe example of output so i need to get this output:
1
2
3
2
3
4
3
4
5
4
5
6
5
6
7
6
7
8
7
8
9
8
9
10
9
10
1
10
1
2
1
2
3
so to get value minus one or plus one (pressing up or down buttons so it is called bidirection) using above code i get 3 items up or down and it works..but i see when i copy paste the code i need to get one item up or down in loop...if can be done to modify code to do that...i try to do x-1 in function and y-1 but it is not going to give me above example output...
So i need function that i can call loopByX(3) and multiple calling function it will be shifting left by one place in loop and calling multiple function loopByX(-3) shifting right by one place in loop...what needs to be modified to archieve above output?
Many Thanks.
You could take the double array and the adjusted index.
function take(direction) {
index += direction + array.length;
index %= array.length;
console.log(array.concat(array).slice(index, index + 3).join(' '));
}
var array = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
index = 0;
<button onclick="take(-1)">-</button>
<button onclick="take(1)">+</button>
With <div> ... </div>
function take(direction) {
index += direction + array.length;
index %= array.length;
console.log(
array
.concat(array)
.slice(index, index + 3)
.map(v => `<div>${ v }</div>`)
.join('')
);
}
var array = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
index = 0;
<button onclick="take(-1)">-</button>
<button onclick="take(1)">+</button>

Sort Json and Get Up down data from Current Postion

I want sort the json object and then get Grade up down and down from current position.
I have following json object.
[
{
"Grade": "1+"
},
{
"Grade": "1"
},
{
"Grade": "1-"
},
{
"Grade": "10"
},
{
"Grade": "11"
},
{
"Grade": "12"
},
{
"Grade": "2+"
},
{
"Grade": "2"
},
{
"Grade": "2-"
},
{
"Grade": "3+"
},
{
"Grade": "3"
},
{
"Grade": "3-"
}
]
Example 01:
suppose My current location is 1+
If i click on down word button then 1 minus and get result 1
If i again click on down word button then 1 minus and get result
1-
If i again click on down word button then 1 minus and get result
2+
If i click on up word button then 1 minus and get result 1-
I tried
var arr = [];
for(var jj in RatingGrade)
arr.push([jj, RatingGrade [jj]]);
console.log(RatingGrade);
var start = "1+";
var counter = 0;//work on up down button by increase and decrease
if( counter < 0 ){
$('#gen_override_gradename').text(arr[i - (counter)].GradeNo);
$('#pd_GradeName').text(arr[i - (counter)].GradeName);
$('#gen_avg_pd').text(arr[i - (counter)].AveragePD);
} else {
if(counter == 0){
$('#gen_override_gradename').text($('#rating_grade').text());
$('#pd_GradeName').text($('#base_pd_score').text());
} else {
$('#gen_override_gradename').text(arr[i - (1 + (counter))].GradeNo);
$('#pd_GradeName').text(arr[i - (1 + (counter))].GradeName);
$('#gen_avg_pd').text(arr[i - (1 + (counter))].AveragePD);
}
}
but its working fine.
The following code snippet will sort your json:
json.sort(function (a, b) {
return = a.id - b.id;
});
However, the + and - signs will need to be handled with additional logic as you're voiding out the "integer value" by including the symbol. Now it's a string and 1+ hold no value when you are trying to compare it to 1. Basically, parse out the symbols and throw them back in after the sorting is completed.

Javascript replacing numbers 10-15 with a-f

I'm new to coding and I've been searching for hours and haven't really found a definitive answer to my problem. A few suggestions have been close to what I want to achieve which I think has helped a little but still not getting the outcome I want.
I've been using codepen.io a lot for seeing an instant output to my code as opposed to jsfiddle, just because I prefer how it works.
This is the code in question:
var x;
var y;
var z;
var arrayFiller;
var betaArray = new Object(256);
betaArray[0] = 0 + " " + 0;
for(var i=1; i<256; i++)
{
x = i;
y = x % 16;
x = x / 16;
x = Math.floor(x);
z = x % 16;
x = i;
arrayFiller = z + "" + y + " ";
$(
function()
{
var hexDerp =
{
'0' : "0",
'1' : "1",
'2' : "2",
'3' : "3",
'4' : "4",
'5' : "5",
'6' : "6",
'7' : "7",
'8' : "8",
'9' : "9",
'10': "A",
'11': "B",
'12': "C",
'13': "D",
'14': "E",
'15': "F"
};
var hexDerp1 = /(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15)/g;
var arrayFillerHex = arrayFiller.replace
(
hexDerp1,
function(s)
{
if(s in hexDerp)
{
return hexDerp[s];
}
}
);
}
);
betaArray[i] = arrayFiller;
document.write(betaArray[i]);
}
My apologies if it is poorly formatted, I find this to be the clearest method for myself.
The bit that currently doesn't work is the function part which is an amalgamation of what I've found in order to replace the 10-15 with a-f.
There may be other ways of getting this inputted and outputted, but I want to keep this for what I am going to end up using this for.
tl;dr: what I wanted to do with this code, is get an array that is 256 elements large, and populate the elements with the hexadecimal version of the element number, to later be used in a unique alphabet that I am making.
You can convert decimal numbers to hexadecimal numbers using this:
(anyNumber).toString(16);

Categories

Resources