Basic question about using || in script calls

Status
Not open for further replies.

cuby

Perpetual Toil
Veteran
Joined
Jun 20, 2015
Messages
157
Reaction score
38
First Language
English
Primarily Uses
RMMV
Hi all, very quick question.

I have a conditional branch that is checking on the value of a variable. The variable is is a text string, and I am checking this string to see if it says a certain thing before proceeding. However, I'm having some issues with this and since I'm a newbie in this area, I trust I'm doing something wrong and hoping to get some help.

Right now in my conditional branch I'm checking script:

$gameVariables.value(1) == "blah" || "blah2" || "blah3"

If var 1 matches either of those three, hen go to Label "X", else exit the event. However, no matter what the variable is, it's going to Label X. I've done a quick test to confirm that no matter the value of var 1, this test is passing as true.

Could anyone say what I'm doing wrong? Thank you!

c
 

Bex

Veteran
Veteran
Joined
Aug 2, 2013
Messages
1,626
Reaction score
505
First Language
German
Primarily Uses
RMMV
Should it not be written === instead of ==
 

Hisao Shou

Veteran
Veteran
Joined
Jan 8, 2015
Messages
183
Reaction score
28
Primarily Uses
Hi all, very quick question.

I have a conditional branch that is checking on the value of a variable. The variable is is a text string, and I am checking this string to see if it says a certain thing before proceeding. However, I'm having some issues with this and since I'm a newbie in this area, I trust I'm doing something wrong and hoping to get some help.

Right now in my conditional branch I'm checking script:

$gameVariables.value(1) == "blah" || "blah2" || "blah3"

If var 1 matches either of those three, hen go to Label "X", else exit the event. However, no matter what the variable is, it's going to Label X. I've done a quick test to confirm that no matter the value of var 1, this test is passing as true.

Could anyone say what I'm doing wrong? Thank you!

c
You should better make the check separately like this:
JavaScript:
$gameVariables.value(1) == "blah" || $gameVariables.value(1) == "blah2" || $gameVariables.value(1) == "blah 3"
 

cuby

Perpetual Toil
Veteran
Joined
Jun 20, 2015
Messages
157
Reaction score
38
First Language
English
Primarily Uses
RMMV
You should better make the check separately like this:
JavaScript:
$gameVariables.value(1) == "blah" || $gameVariables.value(1) == "blah2" || $gameVariables.value(1) == "blah 3"

Thanks, this worked!!

:LZSgrin: :LZSgrin:
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
3,538
Reaction score
2,660
First Language
EN
Primarily Uses
RMMZ
To explain a bit:
  1. The === operator only ever checks one pair of values, i.e. A === B.
  2. Equality comparison also has higher precedence than logical OR, i.e. === evaluates before ||.
  3. JavaScript treats any non-empty string as "truthy".
Putting it all together, this condition:

$gameVariables.value(1) == "blah" || "blah2" || "blah3"
...will reduce to this every time:

something OR true OR true
...which is always true. :kaoswt:

In case it helps, here's a slightly more concise way of writing your 3-value comparison using Array#indexOf:
JavaScript:
["blah", "blah2", "blah3"].indexOf($gameVariables.value(1)) >= 0;
I.e. "is the value of game variable 1 found in the list ["blah", "blah2", "blah3"]?"

Is this thread solved?
 

Trihan

Speedy Scripter
Veteran
Joined
Apr 12, 2012
Messages
4,969
Reaction score
4,553
First Language
English
Primarily Uses
RMMZ
One thing that might benefit from elaboration is == vs ===, since both work but slightly differently.

== is an equality operator that does type coercion; that is to say, if there's a way to make the two things being compared the same type, the interpreter will do so for you. So 1 == "1" will evaluate to true, since they're both converted to the same type before comparison. === is a type-strict equality operator that does not perform coercion, so 1 === "1" returns false because one is a Number and one is a String.
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
3,538
Reaction score
2,660
First Language
EN
Primarily Uses
RMMZ
Whoops, yes, I use === so much that I didn't notice the original post used ==. The logic I described still applies, except that indexOf uses strict equality, ===.
 

Trihan

Speedy Scripter
Veteran
Joined
Apr 12, 2012
Messages
4,969
Reaction score
4,553
First Language
English
Primarily Uses
RMMZ
Whoops, yes, I use === so much that I didn't notice the original post used ==. The logic I described still applies, except that indexOf uses strict equality, ===.
I could just console.time it, but since you're here you might already know: do you know if using the indexOf method is faster than using .contains or .includes?
 
  • Like
Reactions: Bex

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
3,538
Reaction score
2,660
First Language
EN
Primarily Uses
RMMZ
@Trihan: I haven't tested, no. contains in MZ is just an alias for ES6 includes; in MV it invokes indexOf. ES6 includes might have some compiler-level optimisation, but there's probably not much difference, especially for small arrays.
 
  • Like
Reactions: Bex

Trihan

Speedy Scripter
Veteran
Joined
Apr 12, 2012
Messages
4,969
Reaction score
4,553
First Language
English
Primarily Uses
RMMZ
I know contains is just an alias. The backfill for includes is apparently

JavaScript:
Array.includes = function(val,arr) {
    for(i=0;i<arr.length;i++){
       if (!ret || ret == false){ret = val == arr[i] ? true: false;}
    }
    return ret;
  }

which doesn't use indexOf. Obviously that's probably not the same native code as ES6's implementation, though. I might console.time it and see which is faster. :D
 
  • Like
Reactions: Bex

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
3,538
Reaction score
2,660
First Language
EN
Primarily Uses
RMMZ
@Trihan: I don't think I'd use that for a polyfill! ret == false will never be checked; == returns a boolean so the ? true : false is redundant; no early break when val is found; no support for the fromIndex parameter; ret should be declared locally. :kaoback:

Also, a nit-pick: ES6 is a specification, the implementation is browser-dependent.

I just ran a few tests using some of my in-progress code (see spoiler) in a new RMMZ project via the console. Repeat 10000-trial tests using indexOf vs includes to search the same, ordered 1000-element array for a random value yielded results of both around 13~16 ms per approach (excluding setup), neither consistently faster than the other. Your results may vary, but I'd say it's OK to use whichever you prefer. :kaophew:
Test method:
JavaScript:
const test = function(fArr, setup, trials = 10000, labels = [], sFigs = 6) {
    // Check
    if (!Array.isArray(fArr) || fArr.some(
            f => typeof f !== 'function'
        )) return null;
    // Initialise
    const L = fArr.length;
    let t  = 0;
    let tS = 0;
    let tF = (new Array(L)).fill(0);
    // Measure
    let tT = -performance.now();
    for (let n = Math.max(trials, 0); n--;) {
        t = performance.now();
        const data = setup?.();
        tS += performance.now() - t;
        for (let m = L; m--;) {
            t = performance.now();
            fArr[m](data);
            tF[m] += performance.now() - t;
        }
    }
    tT += performance.now();
    // Format
    const [
        lF = 'fn',
        lS = 'setup',
        lO = 'other',
        lT = 'total',
        pt = 'time (ms)',
        pp = 'time %'
    ] = labels;
    const res = {};
    for (let n = 0; n < L; n++) {
        const k = `${lF}${n} ${fArr[n].name}`.trim();
        res[k] = tF[n];
    }
    res[lS] = tS;
    res[lO] = tT - tS - tF.reduce((a, c) => a + c, 0);
    const mag = v => 10 ** (sFigs - 1 - Math.floor(Math.log10(v)));
    for (const [k, v] of Object.entries(res)) {
        const ord = mag(v);
        res[k] = {
            [pt]: Math.round(ord * v) / ord,
            [pp]: Math.round(ord * 100 * v / tT) / ord
        };
    }
    (ord => res[lT] = { [pt]: Math.round(ord * tT) / ord, [pp]: 100 })(mag(tT));
    // Present
    SceneManager.showDevTools();
    console.table(res);
    return res;
};
Test run:
JavaScript:
test(
    [       // tests
        arr => arr.indexOf(Math.randomInt(1000)) >= 0,
        arr => arr.includes(Math.randomInt(1000))
    ],
    () => { // setup
        const a = new Array(1000);
        for (var n = 1000; n--;)
            a[n] = n;
        return a;
    }
);
(Sorry for derailing~ :kaoswt:)
 
  • Like
Reactions: Bex

Trihan

Speedy Scripter
Veteran
Joined
Apr 12, 2012
Messages
4,969
Reaction score
4,553
First Language
English
Primarily Uses
RMMZ
@Trihan: I don't think I'd use that for a polyfill! ret == false will never be checked; == returns a boolean so the ? true : false is redundant; no early break when val is found; no support for the fromIndex parameter; ret should be declared locally. :kaoback:

Also, a nit-pick: ES6 is a specification, the implementation is browser-dependent.

I just ran a few tests using some of my in-progress code (see spoiler) in a new RMMZ project via the console. Repeat 10000-trial tests using indexOf vs includes to search the same, ordered 1000-element array for a random value yielded results of both around 13~16 ms per approach (excluding setup), neither consistently faster than the other. Your results may vary, but I'd say it's OK to use whichever you prefer. :kaophew:
Test method:
JavaScript:
const test = function(fArr, setup, trials = 10000, labels = [], sFigs = 6) {
    // Check
    if (!Array.isArray(fArr) || fArr.some(
            f => typeof f !== 'function'
        )) return null;
    // Initialise
    const L = fArr.length;
    let t  = 0;
    let tS = 0;
    let tF = (new Array(L)).fill(0);
    // Measure
    let tT = -performance.now();
    for (let n = Math.max(trials, 0); n--;) {
        t = performance.now();
        const data = setup?.();
        tS += performance.now() - t;
        for (let m = L; m--;) {
            t = performance.now();
            fArr[m](data);
            tF[m] += performance.now() - t;
        }
    }
    tT += performance.now();
    // Format
    const [
        lF = 'fn',
        lS = 'setup',
        lO = 'other',
        lT = 'total',
        pt = 'time (ms)',
        pp = 'time %'
    ] = labels;
    const res = {};
    for (let n = 0; n < L; n++) {
        const k = `${lF}${n} ${fArr[n].name}`.trim();
        res[k] = tF[n];
    }
    res[lS] = tS;
    res[lO] = tT - tS - tF.reduce((a, c) => a + c, 0);
    const mag = v => 10 ** (sFigs - 1 - Math.floor(Math.log10(v)));
    for (const [k, v] of Object.entries(res)) {
        const ord = mag(v);
        res[k] = {
            [pt]: Math.round(ord * v) / ord,
            [pp]: Math.round(ord * 100 * v / tT) / ord
        };
    }
    (ord => res[lT] = { [pt]: Math.round(ord * tT) / ord, [pp]: 100 })(mag(tT));
    // Present
    SceneManager.showDevTools();
    console.table(res);
    return res;
};
Test run:
JavaScript:
test(
    [       // tests
        arr => arr.indexOf(Math.randomInt(1000)) >= 0,
        arr => arr.includes(Math.randomInt(1000))
    ],
    () => { // setup
        const a = new Array(1000);
        for (var n = 1000; n--;)
            a[n] = n;
        return a;
    }
);
(Sorry for derailing~ :kaoswt:)
That's fair, I just found the apparent polyfill in a SO post, I never actually read the code. :p
 

cuby

Perpetual Toil
Veteran
Joined
Jun 20, 2015
Messages
157
Reaction score
38
First Language
English
Primarily Uses
RMMV
In case it helps, here's a slightly more concise way of writing your 3-value comparison using Array#indexOf:
JavaScript:
["blah", "blah2", "blah3"].indexOf($gameVariables.value(1)) >= 0;
I.e. "is the value of game variable 1 found in the list ["blah", "blah2", "blah3"]?"

Is this thread solved?

I totally get it now, thank you very much for explaining it so clearly.

The array you suggested is very obviously the optimal solution, since I actually have lots and lots of values to check against, and this is surely the most efficient. Let me just run a quick test of it, though as with everything you suggest, I'm sure it works :)

EDIT: Confirmed, works. You're the best @caethyril. Solved!
 
Last edited:

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
3,538
Reaction score
2,660
First Language
EN
Primarily Uses
RMMZ
Great! Happy RPG Making~

This thread is being closed, due to being solved. If for some reason you would like this thread re-opened, please report this post and leave a message why. Thank you.

 
Status
Not open for further replies.

Latest Threads

Latest Posts

Latest Profile Posts

It has been brought to my attention that the name of my main robot protagonist in bio-Synthetica (R3-M1) is a Star Wars character LOL Woops. Always Google search names. The new name of my robot is now K0-R1. :kaophew:
I'm considering making my own battlers from scratch, it seems like a daunting task, but I like the look of it so much...A_Miriam3.png
I picked up running again after a long time and managed to get from 2.25km to 7km in two weeks :3 Time to get rid of those covid kilos!
Have you ever wondered what the lives of the NPC's are like in your hero's story? Come an find out with us as we play, "A Story Beside" by Wayward Prophet :LZSexcite:

Never in my life did I dream that I would be the proud owner of 5 jellyfish.

Forum statistics

Threads
122,091
Messages
1,146,457
Members
160,382
Latest member
Francis187
Top