3
\$\begingroup\$

I'm attempting to create a function that will give me a "fish" at random, though a bias random depending on the weight value for the "fish".

var FISH = {
    "level1": [
          //["name",      xp, weight] 
            ["Shrimp",    10, 95],
            ["Sardine",   20, 85],
            ["Herring",   30, 75],
            ["Anchovies", 40, 65],
            ["Mackerel",  40, 55]
        ]
};

function randomRange(min, max) {
    return Math.random() * (max - min) + min;
}

function getRandomFish(level) {
    var fishForLevel = FISH[level],
        numberOfFish = fishForLevel.length,
        chance = randomRange(0, 100);

    if (numberOfFish > 1) {

        var fish = fishForLevel[Math.floor(randomRange(0, numberOfFish))];

        if (chance <= fish[2]) {
            return fish;
        } else {
            return getRandomFish(level);
        }

    } else {
        return fishForLevel[0];
    }
}

Example of outcome: http://jsfiddle.net/qAvAs/

If this could be made more efficient, how would one do so?

\$\endgroup\$
5
\$\begingroup\$

I'd suggest you select a random number that's from 0 to the total weight of your fish. Then, each fish can have a piece of that random range according to it's weight which gives it the weighting you want. This ends up giving each fish a number of buckets that corresponds to it's weighting value and then you pick a random number from 0 to the total number of buckets and find out who's bucket the random number landed in.

It's the same idea as turning each weighting number into a percentage change and then picking a random number from 0 to 99.

This code should do that:

var FISH = {
    "level1": [
          //["name",      xp, weight] 
            ["Shrimp",    10, 95],
            ["Sardine",   20, 85],
            ["Herring",   30, 75],
            ["Anchovies", 40, 65],
            ["Mackerel",  40, 55]
        ]
};


function getRandomFish(level) {
    var fishForLevel = FISH[level];
    var fishTotalWeight = 0, fishCumWeight = 0, i;
    // sum up the weights
    for (i = 0; i < fishForLevel.length; i++) {
        fishTotalWeight += fishForLevel[i][2];
    }
    var random = Math.floor(Math.random() * fishTotalWeight);
    // now find which bucket out random value is in

    for (i = 0; i < fishForLevel.length; i++) {
        fishCumWeight += fishForLevel[i][2];
        if (random < fishCumWeight) {
            return(fishForLevel[i]);
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ I like this. Certainly seems more efficient then what I was using. :) \$\endgroup\$ – Shaz Aug 20 '11 at 17:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.