Menu
So for my game there are many occasions where I want to mark a percent for each item. Example:
“`javascript
const items = [“Test”, “Test 2”, “Another Test”]
const rarities = [“Common”, “Rare”, “Legendary”]
const percents = [“80%”, “19%”, “1%”]
// “Test” would be Common with 80% chance, “Test 2” would be Rare with 19% chance, etc.
// Then here, somehow get a random item based on their percentages.
I’m wondering how I could do something like that. Thanks!
``<i>
</i> const items = ["Test", "Test 2", "Another Test"]
const rarities = ["Common", "Rare", "Legendary"]
const percents = ["80%", "19%", "1%"]
let helpArray = [],
iHelpArray = 0
// for each entry in array "percents":
percents.forEach((item, idx) => {
// enter current item from "items" multiplely into
// helpArray. Number according to percentage in "percents":
for (let j = 0; j < parseInt(item); j++, iHelpArray++) {
helpArray[iHelpArray] = items[idx]
}
})
console.log(helpArray)
// Get item from random position in helpArray:
function pickItem() {
const idx = Math.floor(Math.random() * helpArray.length)
return helpArray[idx];
}
// for testing:
for (let k = 0; k < 100; k++) {
console.log(pickItem())
}<i>
</i>
``
>So basically, helpArray just duplicates them for me and the other function just gets random one?
``<i>
</i><5CRIPT>
var a, b=0, c=0, d=0
for(let i=0;i<2000;i++){
a = Math.random();
if(a < .1)a=1;
if(a < .4)a=2;
switch(a){
case 1: //about 10%
b++;
break;
case 2: //about 30%
c++;
break;
default: //about 60%
d++;
}
}
alert( b + 'n' + c + 'n' + d )
</5CRIPT><i>
</i>
`</CODE>
<POSTMENTION discussionid="398832" displayname="Bost" id="1641767" number="7" username="Bost">@Bost#1641767</POSTMENTION> <br/>
by adjusting these lines you can have any %s you like
<CODE>
`<i>
</i> if(a < .1)a=1;
if(a < .4)a=2;<i>
</i>
``
const items = ["item2", "item1", "item2", "item3", "item1", "item2", "item1", "item1", "item2", "item1"];
`[code=php]
// group items by rarity in sub-arrays:
$items = [
"common" => ["this", "that", "the other thing"],
"rare" => ["cool stuff", "pretty thing"],
"legendary" => ["awesome", "omg"]
];
$dice = rand(1, 100);
if($dice == 1) { $key = "legendary"; }
elseif($dice <= 20) { $key = "rare"; }
else { $key = "common"; }
// grab a random element of the applicable sub-array:
$item = $items[$key][array_rand($items[$key])];
echo "You rolled a $dice and recevied a '$item'.n";
[/code]
[code=text]
01:16 $ php -f random_item.php
You rolled a 65 and recevied a 'this'.
~
01:17 $ php -f random_item.php
You rolled a 58 and recevied a 'this'.
~
01:17 $ php -f random_item.php
You rolled a 6 and recevied a 'pretty thing'.
~
[/code]
>@Bost#1642119 is there a better way to calculate percentages than distributing them manually
``<i>
</i><sctipt>
var targets=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'];
var num=targets.length;
var step = 1/num;
var steps = [];
var offset;
steps.push(Math.sin(step));
for(let i=1;i<num;i++){
steps.push((Math.sin(step*i)+steps[i-1]));
}
offset = 1 / steps[num-1];
var obj={};
for(let i=0;i<num;i++)obj[targets[i]]=0;
for(let i=0;i<2000;i++){
var rnd = Math.random();
for(let i=0;i<num;i++){
if(rnd<steps[i]*offset){
obj[targets[i]]++;
break;
}
}
}
console.log(obj)
</sctipt><i>
</i>
``
items
</C> was just an example and in reality there are much more items.
<CODE>
`<i>
</i> const percents = [
"80.5%", // rarity is higher than 18.5 % but lower than 80.5 %
"18.5%", // rarity is higher than 1% but lower than 18.5 %
"1%" // rarity is lower than 1%
];<i>
</i>
``>@Bost#1642178 would I just replace each letter with an item
>@Bost#1642178 If it's big to small, then why are the numbers not like that?
>@DaveyErwin#1642157 with the highest index given the most calls
``<i>
</i> const rarities = ["Common", "Rare", "Legendary"];
const percents = [
"70%", // rarity is higher than 28 % but lower than 70 %
"28%", // rarity is higher than 2% but lower than 28 %
"2%" // rarity is lower than 2%
];
// First we get the number of each item:
let nrs = {};
items.forEach(item => {
if (nrs[item]) {
nrs[item].nr++
} else {
nrs[item] = {};
nrs[item].nr = 1;
}
});
// Now we determine the rarity for each item:
for (item in nrs) {
// get percentage of this item:
itemPercent = nrs[item].nr / items.length * 100;
let limit = 0;
// loop through percentages for the rarities:
for (i = percents.length - 1; i >= 0; i--) {
// update limit:
limit += parseFloat(percents[i]);
// if item's percentage is lower than limit:
if (itemPercent < limit) {
// add the rarity to the record in "nrs":
nrs[item].rarity = rarities[i];
// leave loop;
break;
}
};
};
console.log(nrs);<i>
</i>
``
``<i>
</i><scripr>
var targets=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'];
var num=targets.length;
var step = 1/num;
var steps = [];
var offset;
steps.push(Math.sin(step));
for(let i=1;i<num;i++){
steps.push((Math.sin(step*i)+steps[i-1]));
}
offset = 1 / steps[num-1];
var obj={};
for(let i=0;i<num;i++)obj[targets[i]]=0;
for(let i=0;i<10000;i++){
var rnd = Math.random();
for(let i=0;i<num;i++){
if(rnd<steps[i]*offset){
obj[targets[i]]++;
break;
}
}
}
for (key in obj) console.log(key,'=',obj[key]/100,'%');
}
</scripr> <i>
</i>
``
>@Sempervivum#1642180 Now it seems to me that I understood the question in your first posting completely wrong: You did not intend to have a function that picks an item with a rarity given but instead you need to calculate the rarity for a given set of items.
>Wait I am confused. Where did you get the percentages in the beginning variable? That's what I'm trying to calculate.
``<i>
</i> const items = [
// item60 60 times:
'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60',
'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60',
'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60',
'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60',
'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60',
'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60', 'item60',
// item20 20 times:
'item20', 'item20', 'item20', 'item20', 'item20', 'item20', 'item20', 'item20', 'item20', 'item20',
'item20', 'item20', 'item20', 'item20', 'item20', 'item20', 'item20', 'item20', 'item20', 'item20',
// item02 2 times:
'item02', 'item02'
];
console.log(items);
const rarities = ["Common", "Rare", "Legendary"];
const percents = [
"70%", // rarity is higher than 25 % but lower than 70 %
"25%", // rarity is higher than 5% but lower than 25 %
"5%" // rarity is lower than 5%
];
// First we get the number of each item:
let nrs = {};
items.forEach(item => {
if (nrs[item]) {
nrs[item].nr++
} else {
nrs[item] = {};
nrs[item].nr = 1;
}
});
// Now we determine the rarity for each item:
for (item in nrs) {
// get percentage of this item:
itemPercent = nrs[item].nr / items.length * 100;
let limit = 0;
// loop through percentages for the rarities:
for (i = percents.length - 1; i >= 0; i--) {
// update limit:
limit += parseFloat(percents[i]);
// if item's percentage is lower than limit:
if (itemPercent < limit) {
// add the rarity to the record in "nrs":
nrs[item].rarity = rarities[i];
break;
}
};
};
console.log(nrs);<i>
</i>
``
>Object
item02: {nr: 2, rarity: 'Legendary'}
item20: {nr: 20, rarity: 'Rare'}
item60: {nr: 60, rarity: 'Common'}
``<i>
</i>'use strict';
var targets = ['a','b','c','d','e','f','g','h','i','j','k','l','m'];
var num = targets.length;
var step = 1/num;
var steps = [];
var offset=Math.sin(step);
steps.push(offset);
for(let i = 1; i < num; i++){
let a = Math.sin(step*i)+steps[i-1];
offset += a;
steps.push(a);
}
offset = 100/(offset);
for(let i=0;i<num;i++){
steps[i]=steps[i]*offset;
var s = 'common';
if(steps[i]<1)s='legend';
else if(steps[i]<6)s='rare';
console.log(targets[i],'---> perCent =',steps[i],s)
}<i>
</i>
``
>@Bost#1642379 Is there some way I can round them
>@Bost#1642378 If I had, for example, 3 uncommon items, 3 rare items, and 2 legendary items, I want to find out the percentage that each one would get,
>@DaveyErwin#1642382 I can't imagine why you would display them in your program?
>@Bost#1642385 users probably need to know the percentage of each item to know how rare it is to get.
>@Bost#1642390 So how can I pick a random one based on percentage if these numbers have so much after the decimal?
``<i>
</i><!DOCTYPE html>
<button onclick=clicked()>click</button>
<div id=dsply></div>
<__script>
var targets=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'];
var num=targets.length;
var step = 1/num;
var steps = [];
var offset=Math.sin(step);
steps.push(offset);
for(let i=1;i<num;i++){
let a = Math.sin(step*i)+steps[i-1];
offset += a;
steps.push(a);
}
offset = 100 / offset;
for(let i=0;i<num;i++)steps[i]=steps[i]*offset;
var obj={};
for(let i=0;i<num;i++){
let a=obj[targets[i]]={};
a.perCent=steps[i];
let b="common";
if(steps[i] < .6)b="legendary";///////
else if(steps[i] < 3.5)b="rare";///////
a.rareity=b;
}
function clicked(){
let rnd=Math.random()*steps[steps.length-1];
for(let i=0;i<num;i++){
if(rnd<steps[i]){
dsply.textContent=targets[i]+' '+obj[targets[i]].rareity+" "+obj[targets[i]].perCent.toFixed(2);
break;
}
}
}
</__script> <i>
</i>
``
>@Bost#1642414 But I don't want a whole script to pick them
>@DaveyErwin#1642416 the distribution of the perCentages is based on the
> first 90 degrees of a sine wave
>@DaveyErwin#1642388 so use toFixed()
>[https://www.w3schools.com/jsref/jsref_tofixed.asp](https://www.w3schools.com/jsref/jsref_tofixed.asp)
``<i>
</i>Number.prototype.roundTo = function(decimal) {
return +(Math.round(this + "e+" + decimal) + "e-" + decimal);
}<i>
</i>
`</CODE>
<CODE>
`<i>
</i>var num = 9.7654;
console.log( num.roundTo(2)); //output 9.77<i>
</i>
``
>@DaveyErwin#1642388 yeah I get it
> so use toFixed()
``<i>
</i>Number.prototype.roundTo = function(decimal) {
return +(Math.round(this + "e+" + decimal) + "e-" + decimal);
}
var num = 9.7654;
console.log( num.roundTo(2)); //output 9.77<i>
</i>
``
0.1.9 — BETA 4.29