0

I am making some chemistry game as a Telegram bot in JavaScript where you have an inventory and you need to mix the right chemicals. I have the inventory contained in an array, and in order to prevent brute-forcing your way to a level by simply pasting your inventory, I need to check if the user input contains the needed chemicals exclusively, and not any of the others in the array.

For example:

users[id].inventory = ["Beaker", "Water", "Baking soda", "Heating plate", "Hydrochloric acid"];

if (users[id].level === 1 && 
    msg.text.toLowerCase().indexOf('baking soda') !== -1 &&
    msg.text.toLowerCase().indexOf('hydrochloric acid') !== -1 && 
    msg.text.toLowerCase().indexOf('beaker') === -1 && 
    msg.text.toLowerCase().indexOf('water') === -1 && 
    msg.text.toLowerCase().indexOf('heating plate') === -1) {

    msg.answer("You mix some baking soda with hydrochloric acid.\nSome fun fizzing happens and you produce useless CO2 gas.");
}

At higer levels you will get a much larger inventory and this will lead to very large if-statements this way. This looks bad and there must be a better way. Is there such thing like an exclusive indexOf() or any other solution? I have checked out arr.filter() for example but I can't find out a good way to implement this.

1
  • 1
    Have you tried using a loop to iterate over the array? Commented Jul 12, 2016 at 10:43

2 Answers 2

1

Checking for every ingredient manually is not a good idea, as you point out it will become very tedious if the requirements for a recipe are long and the inventory is also long.

I suggest creating a function rightIngredients that takes two arrays: the requirements and the items used.

Considering that only the items in the recipe should be used, the first thing I'd do inside the function is to check the length of both arrays. If they are different then it should return false and nothing else needs to be checked.

If the length of the arrays is the same, then we check each of the items used to see if they are in the requirements. If one of them is not, then we return false as well.

requirements = ["baking soda", "hydrochloric acid"];

function rightIngredients(req, uses) {
    if (uses.length != req.length) {
    console.log(uses.join(', ')+' are not even the right amount of ingredients');
    missing = true;
  } else {
    var i = 0;
    var missing = false;
    while (i<uses.length && !missing) {
        if (req.indexOf(uses[i].toLowerCase())===-1) missing = true;
      ++i;
    }
    if (missing) console.log(uses.join(', ')+' are not the right ingredients');
    else console.log(uses.join(', ')+' are the right ingredients');
  }
  return !missing;
}
rightIngredients(requirements, ["Beaker", "Baking Soda", "Hydrochloric Acid"]);
// Beaker, Baking Soda, Hydrochloric Acid are not even the right amount of ingredients
rightIngredients(requirements, ["Beaker", "Baking Soda"]);
// Beaker, Baking Soda are not the right ingredients
rightIngredients(requirements, ["Baking Soda", "Hydrochloric Acid"]);
// Baking Soda, Hydrochloric Acid are the right ingredients
Sign up to request clarification or add additional context in comments.

1 Comment

This is a really elegant solution and it works for me. This was what I was looking for. I hope to develop the skills to come up with this myself.
1

You can create an array of all disallowed chemicals and then use Array.every to check if all elements satisfy this condition. Also you will have different combination based on level, so I would suggest to create a map of level and disallowed chemicals and make the function generic.

Following is a sample:

// Map object of Level and Chemicals
var map = [{
  level: 1,
  disallowed_chemicals: ['baking soda', 'hydrochloric acid', 'beaker', 'water', 'heating plate']
}];

// getter function to get map object for current level.
// If this returns undefined you can assume, incorrect level is entered
function getLevelMap(u_level) {
  return map.find(function(o) {
    return o.level === u_level;
  });
}

var m_level = getLevelMap(users[id].level);
if (m_level &&
  m_level.every(function(ch) {
    return msg.toLowerCase().indexOf(ch) < 0;
  })) {

  msg.answer("You mix some baking soda with hydrochloric acid.\nSome fun fizzing happens and you produce useless CO2 gas.");
}

1 Comment

There are multiple steps in a level, so Marc Copte's answer is my favourite, since it's shorter to write required chemicals instead of disallowed chemicals for each step. +1 for the effort.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.