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>
Related
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
I'm creating an function that can shuffle and deal poker deck to user based on number of player provided by the user in a input field. I've completed the shuffling function but I'm having issue with dealing the card. How can I deal the entire deck equally based on the number_of_people value given in html, for example if the number_of_people = 3 :
Person 1 : S-Q, D-J, D-K, C-7, S-J....
Person 2 : H-6, D-X, D-A, H-2, S-6....
Person 3 : D-Q, H-5, D-8, S-2, S-8....
also if user insert more than 52 number_of_people it will still deal and display but the 53rd and above player will have an empty hand e.g :
Person 53 :
Person 54 :
Person 55 :
Below is my code :
HTML :
<div class="position-ref full-height">
<div class="content">
<div class="title m-b-md">
Let's Play
</div>
<div>
<input id="number_of_people" type="number" max="99" placeholder="No. of People"></input>
<button onclick="shuffleCards()">Shuffle</button>
</div>
<div class="results">
</div>
</div>
Javascript :
// Create a function to distribute card
function shuffleCards() {
// Get input value
var number_of_people = document.getElementById("number_of_people").value
// Declare card elements
const card_types = ["S", "D", "C", "H"];
const card_values = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "X", "J", "Q", "K",];
// Create deck array
let deck = [];
// Validate the value inserted by user
if (number_of_people > 0 && number_of_people !== null) {
// Create a deck of cards
for (let i = 0; i < card_types.length; i++) {
for (let x = 0; x < card_values.length; x++) {
let card = { cardValue: card_values[x], cardTypes: card_types[i] };
deck.push(card);
}
}
// Shuffle the cards
for (let i = deck.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * i);
let temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
// Clear content
$(".results").html(``);
// Distribute the card
for (let i = 0; i < deck.length; i++) {
console.log(`${deck[i].cardTypes}-${deck[i].cardValue}`)
$(".results").append( `<p>${deck[i].cardTypes}-${deck[i].cardValue}, </p>` );
}
}
else {
$(".results").html( `<h3>Input value does not exist or value is invalid</h3>` );
return;
}
}
</script>
You can replace the "Distribute the cards" loop, with the following loop:
for (let person = 0; person < number_of_people; person++) {
$(".results").append(
$("<p>").append(
`Person ${person+1}: `,
deck.splice(-Math.ceil(deck.length / (number_of_people - person))).map(card =>
`${card.cardTypes}-${card.cardValue}`
).join(", ")
)
);
}
This actually extracts the right amount of cards from the end of the deck in one go, and displays them on a single line. Since the deck of cards is shuffled, it doesn't matter from where in the deck you pull the cards, so you might as well do it like this.
A remark about your code:
if (number_of_people > 0 && number_of_people !== null) {
If the first of these two conditions is true, then the second is always true as well, so there is no need to have that second condition. Moreover, the .value property of an input element is never null, but potentially an empty string.
You should really convert the input from string to a number. For instance with the unary plus:
var number_of_people = +document.getElementById("number_of_people").value;
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?
Okay, so this is the idea.
1.I got an array with 12 numbers (a=[1,2,3,4,5,6,7,8,9,10,11,12]
2.I want to split it into 4 chunks so i did this...
a=[1,2,3,4,5,6,7,8,9,10,11,12];
var b = [];
while(a.length) {
b.push(a.splice(0,3));
}
This gave me an array with 4 elements with 3 values inside each element
i.e. [1,2,3,4] = [ 1 2 3 , 4 5 6 , 7 8 9 , 10 11 12 ]
3.Now my problem is that i would like it to be organized in a way that the first value goes into the first element, the second into the second, the third into the third, and the fourth into the fourth and it repeats the process until i got something like this:
i.e. [1,2,3,4] = [ 1 5 9 , 2 6 10 , 3 7 11 , 4 8 12 ]
This should do it;
var a = [1,2,3,4,5,6,7,8,9,10,11,12];
var chunksize = 3;
var numOfChunks = Math.ceil(a.length/ chunksize);
var b = new Array(numOfChunks);
for(var i=0; i<a.length; i++) {
var pos = i%numOfChunks;
if(!b[pos]) b[pos] = [];
b[pos].push(a[i]);
}
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);