(p5js) how can i structure an if then statement so that a few but not all conditions are met?

Imagine you have ten boolean (or otherwise) variables. You want three of the ten variables to be true, but no more than 3, and no less. You do not want to create a complicated nested if-then function that requires writing out a similar string of code hundreds of times. How do you do it?

Visual Example (I’m pulling this straight from a program i’m writing. Don’t mind the meaning of the variables, just the structure):

if (frameCount % 60 == 0 && (sw1.collect === true || sw2.collect === true || sw3.collect === true || sw4.collect=== true || sw5.collect === true || sw6.collect === true || sw7.collect === true || sw8.collect === true || sw9.collect === true || sw10.collect === true){this.firstCounter = this.firstCounter + 1}

How can i write the above conditional to only accept (no more and no less than) 3 of these “collect” variables as true?

1 Like
"use strict";

class SW {
  constructor() {
    this.randomCollect();
  }

  randomCollect() {
    this.collect = Math.random() < .5;
  }

  static reducer(trues, { collect }) {
    return trues + collect;
  }

  static getNumTrues(swArr) {
    return swArr.reduce(SW.reducer, 0);
  }
}

const TRUES = 3, SWS = 10, sws = Array.from({ length: SWS }, () => new SW);
console.log(sws);

const swTrues = SW.getNumTrues(sws);
console.log(`We've got ${ swTrues } true collects.`);

if (swTrues === TRUES) console.log(`We have exactly ${ TRUES } true collects!`);
else                   console.log(`We don't have ${ TRUES } true collects.`);
1 Like

I’m having a hard time digesting your write-up. To give you more context, sw1, sw2, etc… are variables in setup that reference classes in and of themselves. Are you saying i need to create a new class outside of these? My main confusion is how does this get included in my conditional statement?

Basically count how much are true:

counter =0;

if(sw1) counter++;
if(sw2…

and then

if(counter==3) …

Whenever we’ve got a sequence of variables like this: var0, var1, var2, var3

The most practical & sane thing to do is to create a single array container to replace them all:
const arr = [];

In my posted example I’ve chosen [u]Array[/u].from() in order to both create & populate the sws[] array:

But given there are many ways to create & populate a JS array, you can easily pick some other technique:

My posted class SW is merely an attempt mockup of your currently unrevealed class.

Most I can dig up from your post is that your secret class got a boolean property named collect, nothing more.

Obviously your actual class probably got a diff. name and much more stuff in it.

BtW, my posted example is fully runnable, w/o any need of additional libraries, not even p5js!
Just open a browser’s console, then copy & paste my code in it.

The coolest thing about containers is that once we’ve got all of our values stored in 1, we can easily iterate over them using all kinds of for () loops and even call methods such as Array::forEach() and many others like it:

And as @Chrisir’s stated in his reply:

In my own example code I’ve written a static method inside class SW named getNumTrues(), which requires a passed array argument of datatype SW, and then returns how many true values it had found stored in the property collect of each SW element of the passed array:

As you can see, I’ve chosen the method Array::reduce() in order to iterate on each SW element of the passed array:

But I coulda easily picked something else.
For example, here’s the same method rewritten using a for..of loop instead:

static getNumTrues(swArr) {
  let trues = 0;
  for (const { collect } of swArr)  collect && ++trues;
  return trues;
}

Now that we’ve got ourselves a functioning getNumTrues() method, you can rewrite your original posted conditional statement like this:
if (!(frameCount % 60) && SW.getNumTrues(sws) === 3) ++this.firstCounter;

1 Like

Man i’d really like a simpler solution than this, especially since im wanting to reproduce this 3 or 4 times for the same classes sw1, sw2, etc…

I was inspired to use a for loop, but it didn’t seem to work the way i thought it would. It doesn’t seem to be reading the code right. Is there a way to do it more like this?:

for (swx2 = 1; swx2 <=10; swx2=swx2+1){
for (swx = 1; swx <= 10; swx=swx+1){
if (‘sw’+swx+‘collect’ === true && ‘sw’+swx2+‘collect’ === true) {console.log(‘it works’)}
}}

My console woudn’t log the “it works”. Although if it did then i could plug in the rest. Is there something fundamentally wrong with this piece of code, or just with the way i’ve written it?

Ru sure sw1, sw2, etc… are indeed classes? They seem like variables to me.
Aren’t you mixing up what is a class and what is an object created by a class?

I see 2 for ( ; ; ) loops and not just 1. Why do you need a double loop for there?

  • I see you’re concatenating strings to a variable: 'sw' + swx + 'collect'.
  • Then using the strict identity version of the equality comparison operator ===.
  • In order to compare the resultant string to the boolean value true.
  • B/c a string isn’t a boolean, the operator === will always evaluate those operands as false!
  • In short, there’s no way your conditional will ever log “it works”!

Didn’t you like my approach?

When it doesn’t matter which variables are true but only that there are 3 that are true, just count them and evaluate the result.

1 Like

Thank you so much for your replies. My code is too dispersed to cleanly share it, but basically, i was able to do as suggested, and count how many of the variables are true. I ended up having to use nested timers (to ensure i was counting my variables once and not repeatedly), and i had to attribute a timer to each variable. To do what i was trying to do, i had to compare ordinal timers with the specific ones. The point of this was for me to structure a three-slot visual template, where performing some event 1-15 (since this is a computer game, it was collecting secondary weapons), and recording the results in the first unfilled slot (showing what sw you have, and the details of such) So far ive got everything working expectedly now. :smile: If you are curious of my game so far, you can see the game itself (not the code) in active development. Its a slow progress, but if you’re curious: https://editor.p5js.org/cryptacritic17/full/oaswueydz

Hmm. I’m confused by what all of this (nested timers, 15 variables, etc.) has to do with populating three slots with falling objects. It sounds extremely complex. Can’t you just compare a randomly generated object to the slot contents on spawn and/or on touch?

Your code is still using variables w/ numbered names instead of creating 1 array for them. :neutral_face:

Although written for Processing Java, the article below explains how to convert multiple variables into an array: :nerd_face: