我有这个:
var users = [user1, user2, user3];
var chances = [20, 20, 60];
var total = 100;
var random = Math.floor((Math.random() * total) + 1);
if (random > 40 && random < 100) {
console.log('winner:', users[2]);
}
if (random > 20 && random < 40) {
console.log('winner:', users[1]);
}
if (random > 0 && random < 20) {
console.log('winner:', users[0]);
}
这将为每个用户提供公平的获胜机会。 (60%的几率为20%,20%的几率为20%)。
但我真正需要的是,这是每个(或其他任何)功能的动态。
我的想法示例:
chances.forEach(function(entry) {
if (unknownValue > unkownValue2 && unknownValue3 < unknownValue4) {
console.log('winner:', unknownUser);
};
});
所以基本上,如果机会数组的值是50,100和20,那么数字100获胜的几率必须比50高出2倍,比20高出5倍。
我很满意每一个答案,请不要将此标记为老虎机百分比的重复,这不是我需要的。
答案 0 :(得分:1)
//put chances and user object in the same object, in an array
let userChances = [
{userObj: 'user1', chance: 20},
{userObj: 'user2', chance: 40},
{userObj: 'user2', chance: 60}
];
//we loop the items and turn the chance into a running total...
for (let i = 0; i < userChances.length; i++) {
if (i > 0) {
userChances[i] = {
userObj: userChances[i].userObj,
chance: userChances[i].chance + userChances[i - 1].chance
};
}
}
//now data looks like this:
//let userChances = [
// {userObj: user1, chance: 20},
// {userObj: user2, chance: 60},
// {userObj: user2, chance: 120}
//];
//we get the total available chance, which is now the value of the chance property of the last element in the array
let totalChances = userChances[userChances.length - 1].chance;
let yourChance = Math.floor((Math.random() * totalChances) + 1);
//loop one last time
for (let i= 0; i < userChances.length; i ++) {
//if our number is less than the current user chance, we found the user! return it! otherwise, proceed to check the next user...
if (yourChance <= userChances[i].chance) {
console.log('Winner', userChances[i].userObj);
break;
}
//please note that if this does not return or break the loop, every user after this will be logged as a winner too!
}
答案 1 :(得分:1)
将比率转换为百分比。显然,他们的总和应该是1,每个的值是val/total
:
function transformRatiosToAccPercentages(ratios) {
const total = ratios.reduce((sum, el) => sum += el, 0);
let acc = 0;
const accPercentages = ratios.map(rat => acc += rat / total);
return accPercentages;
}
function chooseBiasedRandom(accPercentages) {
const random = Math.random();
const index = accPercentages.findIndex(acc => random < acc);
return index;
}
// And that's how it can be used:
const users = {
Alpha: 50,
Bravo: 100,
Charlie: 10
};
const userNames = Object.keys(users);
const ratios = Object.values(users);
const attempts = 1E6;
const counter = Array(userNames.length).fill(0);
const accPercentages = transformRatiosToAccPercentages(ratios);
for (let i = 1; i <= attempts; i++) {
const index = chooseBiasedRandom(accPercentages);
counter[index]++;
// console.log(`Attempt ${i}: user ${userNames[index]} wins!`);
}
console.log(counter);
答案 2 :(得分:1)
您可以使用具有概率的数组,并根据随机值进行检查和计数。
此函数首先将返回值设置为最后一个可能的索引,然后迭代,直到随机值的其余部分小于实际概率。此外,所有概率的总和应该等于一。
实现时,您只需要获取用于获取用户数组索引的函数。
var users = ['user1', 'user2', 'user3'],
probabilities = [0.2, 0.2, 0.6],
selectedUser = users[getRandomIndexByProbability(probabilities)];
然后,代码显示索引的分布。
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.2, 0.2, 0.6],
count = {},
index;
probabilities.forEach(function (_, i) { count[i] = 0; });
for (i = 0; i < 1e6; i++) {
index = getRandomIndexByProbability(probabilities);
count[index]++;
}
console.log(count);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
答案 3 :(得分:1)
作为概率解决方案的替代方案,您还可以创建具有重复用户的阵列,以使其计数对应于关联的百分比。然后要求你的百分比是正整数,而不是分数。
像这样:
const users = [
{name: "Jim", pct: 20},
{name: "Helen", pct: 20},
{name: "Anna", pct: 60}
];
const expanded = [].concat(...users.map(user => Array(user.pct).fill(user)));
const winner = expanded[Math.floor(Math.random() * expanded.length)];
console.log("winner: " + winner.name);
这些数字实际上不一定是百分比。如果您需要更高的精度,只需使用可能加起来为1000或10000的更大数字。