Penn- Penn- - 1 month ago 6
Javascript Question

Find item in array using weighed probability and a value

Last week I had some problems with a simple program I am doing and somebody here helped me. Now I have run into another problem.
I currently have this code:



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 === 'diamond') break;
console.log("Dang! A " + lootedItem + " was found...");
}
console.log("Lucky! A " + desiredItem + " was found!");
}

findItem('diamond');





Now I would like to expand on this by adding another value called
category
to the
items
array. I want the categories to have a value of either
2
,
5
or
10
. So let's say the
diamond
item would belong to
category: 10
, and when
findItem
is executed only items that belong to the same category can be found. I have been trying for a couple of days now but can't seem to get my head around it. Maybe someone can help push me in the right direction? Thanks in advance

Answer

You could use this update to that code:

// Pass the item list and the desired category as arguments:
var findItem = function(items, category, desiredItem) {
    // apply filter to items, so only those of the given category remain:
    items = items.filter( item => item.category == category );
    // rest of code remains the same:
    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 );
    var t = 10;
    while (true) {
        var value = Math.random() * sum;
        var lootedItem = items.find( 
                ({item, probability}) => (value -= probability) <= 0 ).item;
        if (lootedItem === desiredItem) break; // fixed this condition!
        console.log("Dang! A " + lootedItem + " was found...");
        t--; if (t <= 0) throw "loop";
    }
    console.log("Lucky! A " + desiredItem + " was found!");
}

// Define items here with their category
var items = [
    { item: "rusty nail", probability: 0.25, category:  2 },
    { item: "stone",      probability: 0.23, category:  2 },
    { item: "banana",     probability: 0.20, category:  2 },
    { item: "leaf",       probability: 0.17, category:  5 },
    { item: "mushroom",   probability: 0.10, category:  5 },
    { item: "diamond",    probability: 0.05, category: 10 }
];

// Call function with extra arguments:
findItem(items, 5, 'mushroom');

console.log('second run:');
// This will obviously give a hit immediately, as there is only one possible item:
findItem(items, 10, 'diamond');

The changes are:

  • Pass more arguments to your function: the items list and the desired category
  • Apply a filter on the items list as first action in the function
  • Fix an issue concerning the lootedItem test -- it had "diamond" hard-coded.
  • Define the items list outside of the function and add category values to each element.
  • Adapt the call of the function to pass the extra arguments.
Comments