Skip to content
Advertisement

Reducing object values based on values pulled from array?

I am building an idle game with JavaScript.

It is a game where you run a bakery.

The resources of the bakery are represented within an object ‘mainObj’.

let mainObj = {
  "Money": 100,
  "Resources": {
    "Milk": 10,
    "Eggs": 10,
    "Flour": 10,
    "Water": 10,
    "Sugar": 10
  },
  "Employees": {
    "Bakers": 1,
    "Cooks": 0,
    "Servers": 0,
    "Farmers": 0
  },
  "Inventory": {
    "Cake": 0,
    "Cookies": 0
  }
}

The associated costs to bake an item, such as a cake or cookies, are stored in the array ‘bakeInfo’.

let bakeInfo = [{
  "Name": "Cake",
  "Milk": 1,
  "Eggs": 2,
  "Flour": 1
}, {
  "Name": "Cookies",
  "Eggs": 1,
  "Flour": 1
}]

I want to write a function that takes the info from bakeInfo, such as for baking a cake (1 Milk, 2 Eggs, 1 Flour) checks the mainObj for the required ingredients (and throws an error if there isn’t enough) and if there is enough of each, it reduces the ingredients in resources by the amount in bakeInfo, and then adds the appropriate item (cake/cookies) to the mainObj inventory.

I’ve tried a few different ways to go about it, which pretty much entails an individual function for each ingredient type, which seems extremely inefficient to me.

Also, some items that will be baked omit some ingredients (cookies don’t require milk). So if the function checked this/only removed required items from the mainObj inventory that would be ideal, in fact, it is necessary.

If someone could point me in the right direction that would be great.

Advertisement

Answer

Marko’s solution above is for adding one item at a time. However, if you want to check multiple items at a time, and error if there isn’t enough ingredients for all of them, this solution might be better:

let mainObj = {
  Money: 100,
  Resources: {
      Milk: 10,
      Eggs: 10,
      Flour: 10,
      Water: 10,
      Sugar: 10
  },
  Employees: {
      Bakers: 1,
      Cooks: 0,
      Servers: 0,
      Farmers: 0
  },
  Inventory: {
      Cake: 0,
      Cookies: 0
  },
}

let bakeInfo = [
  {Name: 'Cake', Milk: 1, Eggs: 2, Flour: 1},
  {Name: 'Cookies', Eggs: 1, Flour: 1} 
]

function bakeOrError(bakeInfo, mainObj) {
  // first make a copy of resources
  const resources = Object.assign({}, mainObj.Resources); 
  // now, iterate over all the bakeInfo and reduce resources
  bakeInfo.forEach(bi => {
    Object.keys(bi)
      .filter(k => k !== 'Name') // don't operate on the Name key, everything else is an ingredient
      .forEach(k => {
        resources[k] -= bi[k];
        if (resources[k] < 0) throw new Error('insufficient resources');
      })
  })

  // if we haven't errored by here, there were enough ingredients to support everything.
  // update the resources object
  mainObj.Resources = resources;
  // then add to inventory
  bakeInfo.forEach(bi => mainObj.Inventory[bi.Name]++);
}

bakeOrError(bakeInfo, mainObj);
console.log(mainObj);
Advertisement