使用概率遍历项目数组

Loop through array of items using probability

我是 JavaScript 的新手,我一直在制作 while 循环,它可以掷骰子并在掷 6 时跳出循环。

var rollDice = function() {
  var dice = Math.floor(Math.random() * 6 + 1);

  while (dice !== 6) {
    console.log("A " + dice + " was rolled!");
    var dice = Math.floor(Math.random() * 6 + 1)
  }
  console.log("Lucky! You rolled a 6!");
}

现在我想遍历项目数组,并在找到所需项目时退出。我希望能够像这样声明所需的项目:

var desiredItem = "Diamond";

但是,每个项目都有自己的概率值,我想将其包含在此 while 循环中。这意味着您有 25% 的机会得到生锈的钉子,而只有 5% 的机会得到钻石。所以从统计上看,你会得到比钻石更多的生锈钉子。我还想在循环内将所有内容输出给用户,如下所示:

console.log("Dang! A " + lootedItem + " was found...");

当您最终收到想要的物品并打破循环时:

console.log("Lucky! A" + desiredItem + "was found!");

我已经自己尝试了一段时间,但似乎无法得到它,所以任何帮助将不胜感激。谢谢!

您可以使用与在 dice while 循环中使用的相同方法来解决钻石问题。只需生成一个 1-20 之间的随机数,如果生成的数字是 1,则告诉用户他们找到了钻石,因为生成 1 的几率是 5%。

下面是一个允许任意加权概率的一般答案...我在我编写的一些游戏中成功地使用了它。

  1. 对于每个项目,给它一个正概率。它不需要是一个 整数,它们的总和不需要为 1。
  2. 求和所有概率。称其为总计。
  3. 生成一个介于 0 和 Total 之间的数字,又名 Math.random() * total
  4. 对于每个项目,查看数字是否小于该项目的概率。如果是,return 那个项目。如果,不减去概率,进行下一项。

这是一个 ES6 实现:

var findItem = function(desiredItem) {
    var items = [
        { item: "rusty nail", probability: 0.25 },
        { item: "stone", probability: 0.23 },
        { item: "banana", probability: 0.20 },
        { item: "leaf", probability: 0.17 },
        { item: "mushroom", probability: 0.10 },
        { item: "diamond", probability: 0.05 }
    ];
    var possible = items.some( ({item, probability}) => 
          item === desiredItem && probability > 0 );
    if (!possible) {
        console.log('There is no chance you\'ll ever find a ' + desiredItem);
        return;
    }
    var sum = items.reduce( (sum, {item, probability}) => sum+probability, 0 );
    while (true) {
        var value = Math.random() * sum;
        var lootedItem = items.find( 
                ({item, probability}) => (value -= probability) <= 0 ).item;
        if (lootedItem === desiredItem) break;
        console.log("Dang! A " + lootedItem + " was found...");
    }
    console.log("Lucky! A " + desiredItem + " was found!");
}

findItem('diamond');

const DIAMOND = 1,
      TRASH = 0;

var treasures = [DIAMOND, TRASH, TRASH, TRASH, DIAMOND],
    len = treasures.length;

function searchForDiamond() {
    while (true) {
        var j = Math.floor(getRandomArbitrary(0, len)),
            discovery = treasures[j];

        if (discovery === DIAMOND) {
            console.log("I am a lucky pirate!");
            break;
        } else {
            console.log("I am a crappy pirate!");
        }
    }
}

// FROM MDN
// Returns a random number between min (inclusive) and max (exclusive)
function getRandomArbitrary(min, max) {
    return Math.random() * (max - min) + min;
}


searchForDiamond();