I want to give the user a prize when he signs in; but it needs to be there some rare prizes so I want to appear prizes with different chances to appear using percents
i w
'Right off the top of my head'-approach would be to prepare an array where each source item occurs the number of times that corresponds to respective probability and pick random item out of that array (assuming probability value has no more than 2 decimal places):
// main function
const getPseudoRandom = items => {
const {min, random} = Math,
commonMultiplier = 100,
itemBox = []
for(item in items){
for(let i = 0; i < items[item]*commonMultiplier; i++){
const randomPosition = 0|random()*itemBox.length
itemBox.splice(randomPosition, 0, item)
}
}
return itemBox[0|random()*itemBox.length]
}
// test of random outcomes distribution
const outcomes = Array(1000)
.fill()
.map(_ => getPseudoRandom({'flower': 0.5, 'book': 0.3, 'mobile': 0.2})),
distribution = outcomes.reduce((acc, item, _, s) =>
(acc[item] = (acc[item]||0)+100/s.length, acc), {})
console.log(distribution)
.as-console-wrapper{min-height:100%;}
While above approach may seem easy to comprehend and deploy, you may consider another one - build up the sort of probability ranges of respective width and have your random value falling into one of those - the wider the range, the greater probability:
const items = {'flower': 0.5, 'book': 0.2, 'mobile': 0.2, '1mUSD': 0.1},
// main function
getPseudoRandom = items => {
let totalWeight = 0,
ranges = [],
rnd = Math.random()
for(const itemName in items){
ranges.push({
itemName,
max: totalWeight += items[itemName]
})
}
return ranges
.find(({max}) => max > rnd*totalWeight)
.itemName
},
// test of random outcomes distribution
outcomes = Array(1000)
.fill()
.map(_ => getPseudoRandom(items)),
distribution = outcomes.reduce((acc, item, _, s) =>
(acc[item] = (acc[item]||0)+100/s.length, acc), {})
console.log(distribution)