How to call a function when 3 out of 7 boolean values evaluates to true

Viewed 110

I am trying to create a quest giving system this way:

There are 7 boolean values and a method that should be called only when any 3 out of the 7 boolean values evaluates to true. What is the most efficient/better way to accomplish this task? I am a bit new to programming so here is a code snippet:

private bool a;
private bool b;
private bool c;
private bool d;
private bool e;
private bool f;
private bool g;

private void Start() {
    //How do I call TheMethod() when any 3 of the 7 booleans evaluates to true?
}

private void TheMethod() {
   //DO SOMETHING
}

Do I have to create multiple if conditions that checks this?

4 Answers

The most efficient way is to change how you do this; consider instead:

private uint bits;

and use bit math to detect individual flags, for example:

private bool A => (values & 1) != 0;
private bool B => (values & 2) != 0;
private bool C => (values & 4) != 0;
// etc, powers of 2

Now you can use

var setBits = BitOperations.PopCount(bits);

and test that, i.e. if (setBits == 3). This then uses a CPU intrinsic when possible, falling back to a decently-optimized software implementation otherwise.

Without the need for an array you could do

private void Start() 
{
    if(Exactly3True())
    {
        TheMethod();
    }
}

private void TheMethod() 
{
   //DO SOMETHING
}

private bool Exactly3True()
{
    var checkSum =    (a ? 1 : 0)
                    + (b ? 1 : 0)
                    + (c ? 1 : 0)
                    + (d ? 1 : 0)
                    + (e ? 1 : 0) 
                    + (f ? 1 : 0)
                    + (g ? 1 : 0);

    return checkSum == 3;
}

(see ternary operator ?)

not that this is the best thing regarding maintainability ;)

using array or list with Linq could simplify your test:

using System.Linq;
using System.Collections.Generic;    

// using array a = trig[0], b = trig[1] and so on
private bool[] trig = new bool[7] { true, false, false, true, true, false, true };

//or using list a = trig1[0], b = trig1[1] and so on
private List<bool> trig1 = new List<bool>{ true, false, false, true, true, false, true };


 void Start(){  
        //same syntax array or list
        trig[0] = false; // change value for fun
        if(trig.Count(p => p) ==3)// result = 3
        {
           TheMethod(); 
        }

        trig1[0] = false;// change value for fun
        if(trig1.Count(p => p) ==3) //result = 3
        {
           TheMethod(); 
        }


        //if you want to keep your boolean variable outside a collection
        //you add your boolean variables to list (or array) 
        var list = new List<Bool>() {a,b,c,d,e,f,g};
        if (list.Count(p => p) == 3)
        {
           TheMethod();
        }     
}

If you are using Unity, you can try

[SerializeField]
private bool[] values;

And attach this code to any existing GameObject, you can set the length of values in the inspecter. Set it to 7, and

private void Start()
{
    int boolCount = 0;
    foreach (var b in values)
    {
        if (b == true) boolCount++;

        if (boolCount == 3)
        {
            TheMethod(); 
            break;
        }
    }
}

It's just example code, but using Unity's serialize feature will much more increase the readability of your code.

Related