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,624
Reaction score
502
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,486
Reaction score
2,630
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,967
Reaction score
4,548
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,486
Reaction score
2,630
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,967
Reaction score
4,548
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,486
Reaction score
2,630
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,967
Reaction score
4,548
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,486
Reaction score
2,630
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,967
Reaction score
4,548
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,486
Reaction score
2,630
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 Profile Posts

angel3.gif
Angels sprite redo came out so cute! I had to add hair so her sprite matches the new faceart :LZSexcite:
Even if you made 1% progress today in your making-game, that's 100% success!
This is Ralph from VX!
index.php

Always be consistent with your project.

Forum statistics

Threads
121,858
Messages
1,144,710
Members
160,113
Latest member
MisakiSakura
Top