RGSS2の条件分岐についての質問

開拓者

ユーザー
こんにちは、現在ヘルプのRGSS3講座を見ながら
RGSS3の基本的な動きについて勉強しているのですが

条件分岐の or を試していると不可解な現象が起きました。

#------------------------------------

# or
# || ~ または ~である
# andとは違い、一つが間違っていても もう一つが合っていればtrueである

print "100は50以上 または 25*4である\n\n"
p (100 >= 50 or 25 * 4)

print "\n"

print "100は50以上 または 5+5である\n\n"
p (100 >= 50 or 5 + 5)

print "\n"

print "1は50以上 または 5+5である\n\n"
p (1 >= 50 or 5 + 5)

print "\n"

#---------------------------------------


コンソールで勉強しているので"\n"で見やすくしているのですが
3番目の条件分岐がtrueやfalse ではなく5+5の結果が表示されてしまいます。

2番目をコピーして0を削るだけでも同じ現象が起きてしまうので
文法の間違いなのか、RGSS3の不具合なのか分からないのが現状です……

これは、どこか間違えているのでしょうか?
勉強中のデータもアップするので誰か教えてください。
https://www.axfc.net/u/3868211
 

ツミオ

ユーザー
こんにちは。
Rubyは門外漢ですが、わかる範囲でお答えします。

最初の条件分岐を見てみます。
コード:
(100 >= 50 || 25 * 4)
100は50以上であるため、この条件式はtrueになります。
このとき、100 >= 50がtrueであるため、or以降は判定されません(100 >= 50がtrueなら、or以降が何であっても条件式全体は必ずtrueになるため)。
つまり25 * 4は演算されません。
これをショートサーキットと言います。
大切なので、このショートサーキットを念頭に置いて続きを読んでいただけると助かります。

二番目の条件分岐を見てみます。
コード:
(100 >= 50 || 5 + 5)
これも100は50以上がtrueであるため、5 + 5は評価されません。
一番目と同じです。

では三番目の条件分岐はどうでしょうか。
コード:
p(1 >= 50 || 5 + 5)
「1は50以上である」はfalseなので(falseならば続く条件式を見なければならない)、次に5+5が評価されます。
この結果として10が表示されています。

簡単ですが、以上で説明を終わります。


以下は「あまり参考にならないかもしれない解説」です。

JavaScriptのイディオムの一つに以下のようなものがあります。
コード:
var hoge = hoge || defaultValue;
これは「hogeがfalseとして扱える値を返すなら、defaultValueを代入せよ」と命令しています。
おそらくRGSS2のorもこれと同じ使い方ができるのではないでしょうか?
つまり上の例で言うと、「1が50以上でなければ5+5の結果を表示せよ」ということです。

ただ僕がRubyに詳しくないため、上記の説明は単なる予想であることを書き添えておきます。
間違っていたら申し訳ありません;_;

追記:
トップの書き込みを見て思ったのですが、or演算子が何と何を区切っているのかを確認してみてください。
塊は以下のような感じです。
コード:
((100 >= 50) || (5 + 5))
 
最後に編集:

開拓者

ユーザー
なるほど……
ショートサーキットという仕様は初めて知りました。

複雑な文章が読めないのでJavaScriptのほうは分かりませんが
1回目と2回目は最初の分岐でTrueだったから
それ以降の間違いを感知していなかったという訳ですね。

andで作った文章とorで作った文章をじっくり比べてみたのですが

コード:
p (100 >= 20 and 1+1 == 2)
100は20以上であり、1+1は2である は
100は20以上か? と 1+1は2か? を別々に調べているけれど

コード:
p (1 >= 50 or 5 + 5)
1は50以上 または 5+5である は 
1は50以上か、それとも5+5なのかを区切らないで調べようとしていて

1は50以上か、5+5は1か のように2つに分ける必要があったんですね。
コード:
p ((1 >= 50 ) or (5 + 5 == 1))
だとちゃんとfalseと表示されました!

完成されたRPGを作れないのは苦しいと思っていたけど
RGSSの勉強をしていると考えがガラッと変わりました。
1つの課題をクリアするのが1個の作品を作るのに等しくて
ちゃんと結果が残るし、知らない事を学んで成長しているんですよね。

RGSSを勉強しようと思って良かったです。
それと相談してみてよかったです、ありがとうございました!
 
最後に編集:
どうも、開拓者さん。
説明すべきことは、ほぼすべてツミオさんが説明してくれているので、
蛇足的な説明をいくつか。

if ( a > 5 && b > 2) {
// ...
}

のように、&& または and がついた構文の場合、前から評価していき、
ひとつでも false が出たらそこで評価を打ち切ります。
なぜなら、ひとつでも false があれば、もう false が確定だからです。
このため、仮に a > 5 が成り立たない場合、 b > 2 は無視されます。

逆に || または or の場合を考えましょう。

if (a > 5 || b > 2) {
// ...
}

この場合、a > 5 が trueになったら、そこで評価を打ち切り、 b > 2 の評価は行われません。
なぜなら、|| や or はひとつでもtrueがあれば成り立つのですから、
どれかひとつが成り立った時点で、残りの処理は冗長ですからね。

僕が知っている限りの言語では、皆、これと同じメカニズムで判断しています。

なお、これが一番役に立つのが、プラグイン作成です。
プラグインに新しい変数を追加して、バージョンアップを行う場合、
前のバージョンのプラグインが入ったゲームだと、新しい変数の値が undefined になります。

そうでなくても、「制作中に新しいプラグインを作って入れた」場合も
該当するでしょう。

この場合、this.newValue = 5; などと initialize で宣言するだけでなく、
この値を参照する直前に
this.newValue = this.newValue || 5;
と書く必要があります。

この場合、すでにthis.newValueが与えられていればそのまま、
そうでない場合、初期値の5が入ります。

セーブデータをロードした場合、initializeは呼び出されませんので、
こう書かないと、this.newValue が undefined のままで、
処理がおかしくなてしまいます。

以上、何かご参考になれば幸いです。
 
トップ