Reputation: 99
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.
Upvotes: 2
Views: 88
Reputation: 48600
With the makeItem
function below, you could make cakes until your run out of resources by using a try-catch
and throwing an Error
when the minimum number of required resources cannot be met.
const player = {
"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 }
};
const recipes = [
{ "Name": "Cake", "Milk": 1, "Eggs": 2, "Flour": 1 },
{ "Name": "Cookies", "Eggs": 1, "Flour": 1 }
];
const retrieveRecipe = (name) =>
recipes.find(({ Name }) => Name === name);
const canMake = (player, recipe) => {
const found = retrieveRecipe(recipe);
if (found == null) return false;
const { Name, ...ingredients } = found;
const { Resources } = player;
return Object.entries(ingredients)
.every(([ name, amount ]) => amount <= Resources[name]);
}
const makeItem = (player, recipe) => {
if (!canMake(player, recipe)) throw new Error('Insufficient resources');
const found = retrieveRecipe(recipe);
const { Name, ...ingredients } = found;
Object.entries(ingredients).forEach(([name, amount]) => {
player.Resources[name] -= amount;
});
player.Inventory[Name]++;
}
// Make cakes until required resources cannot be met.
try {
while (true) {
makeItem(player, 'Cake');
}
} catch (e) {
console.log('Ran out of resources!');
}
console.log(player);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Upvotes: 0
Reputation: 13892
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);
Upvotes: 1
Reputation: 1912
This should work:
function reduceResources(info){
let bakeInfoKeys = Object.keys(info);
// check if there is enough resources
bakeInfoKeys.forEach(key => {
if(mainObj.Resources[key] !== undefined){
if(mainObj.Resources[key] < info[key])
return false; // return false if there is not enough resources
}
});
// reduce the resource amount
bakeInfoKeys.forEach(key => {
if(mainObj.Resources[key] !== undefined){
mainObj.Resources[key] -= info[key];
}
});
// add the item to the inventory
mainObj.Inventory[info['Name']] += 1;
return true;
}
The function will return true if it was successful, and false if the resources are not enough.
You can use it like this:
if(reduceResources(bakeInfo[0]))
console.log("Success!")
else
console.log("Fail!")
Upvotes: 0