シーンインした時に侵蝕率を計算するスクリプト(1)

スクリプトが無事「シーンイン」や「リザレクト」という言葉に反応するようになったところで、もう少し欲張ってみることにしました。


DX2ndの侵蝕率は1セッションの中で増えていく一方です。つまりずーっと足し算が発生し続けます。特に、ほぼ戦闘でしか使わない「リザレクト」と違って、シーンに登場するたびに使用することになる「シーンイン」は、その度に手元のレコードシートに1〜10までの数の足し算をし続けるのです。これはめんどい。*1
というわけで、せめて「シーンイン」の時だけは現在の侵蝕率にダイスを振った結果を自動的に足して結果を表示してくれるスクリプトを作ることにしました。

入力の書式は

「#シーンイン+現在侵蝕率(半角整数)」という形に決めようと思います。
「#シーンイン」までは全角。「+現在侵蝕率」は半角の決めうち。
「+」を全角も半角も認める形にすべきか悩ましいところですが、まずは半角だけで。

正規表現

すでに「#シーンイン」に反応する関数として使ってますが、

■ 文字列のマッチング
◆ string.match(regexp) (e4/N4)

正規表現 regexp に最初にマッチした部分の文字列を返します。マッチしなかった時は空文字ではなく、null という特殊な値を返します。マッチングについては「正規表現」を参照してください。

とほほのJavaScriptリファレンス

だそうなので、「#シーンイン+現在侵蝕率(半角整数)」のうちの「+現在侵蝕率(半角整数)」はこの関数で拾ってくることにします。
問題は拾ってくるための正規表現

ここで、「すぐ使える!正規表現サンプル集」というサイト様からそれっぽいのを拾ってきました!www

abc[^0-9]+
ABCの後に数字が来ないABCを表します。abcxyz には一致、abc123 には一致しません。

[ ] 内の ^ は否定を表します。また [ ] は、中に書かれた文字のいずれか1文字を表します。

http://hodade.adam.ne.jp/seiki/index.php

だそうなので、ということは

  1. 「abc」を「#シーンイン+」に変更
  2. 「[^0-9]+」から否定の意味の「^」を削除

すれば入手したい数値が発言から抜き出せるはず!


……ところで、match()の戻り値ってなんでしょう?

match()の戻り値を表示するスクリプト

何かこうものすごい回り道でぐだぐだなのですが、そういえば今までその辺知らないで使ってました。
ので、今までの進行はちょっと横に置いといて、以下のようなスクリプトを書いて実行してみました。

function event::onChannelText(prefix, channel, text)
{
	var testText = 'aaaaabc11aaaaaaabcccccccccccccc';
	if (text.match(/#/)) {
		send(channel, testText.match(/abc[^0-9]+/));
	}
   }

その実行結果。

23:59 (ten-you) #
23:59 (ten-you) abcccccccccccccc

なぜこういう結果になるのかよく分かりませんorz
「abc」と出るもんだとばかり思ってました。……が、そういや正規表現の最後に「+」ついてるんですよね。これがcを文の最後まで延々拾った理由か。


ということで正規表現から「+」を削除して実行。結果↓

00:04 (ten-you) #
00:04 (ten-you) abcc

……うーん、これは。
指定の方で「abc」の後に「[^0-9]」とついてるから、結果の方で「abc」の後ろにもう一個「c」がついてる、と解釈していいんでしょうかね?
ということは、当初の予定通り「#シーンイン\+[0-9]+」と指定する*2と、「#シーンイン+45」という文字列が返ってくる?
そこで、

	var testText = 'aaaaabc99aaaaaaabcccccccccccccc';
	if (text.match(/#/)) {
		send(channel, testText.match(/abc[^0-9]+/));

の部分を

	var testText = 'aaaaabc99aaaaaaa#シーンイン+45cccc88cc';
	if (text.match(/#/)) {
		send(channel, testText.match(/#シーンイン\+[0-9]+/));

と変更して実行。
結果↓

09:27 (ten-you) #
09:27 (ten-you) #シーンイン+45

よしよし。
というわけで、
string.match(regexp)は、regexp正規表現)にマッチした文字列を返す。
ことが分かりました。


と、ここまできて、そういえば同じ文章中で「#シーンイン+任意の数」が何度も出てきたらどうなるんだろう?という疑問が。
実プレイではありえないシチュエーションだと思いますが、一応。

	var testText = 'aaaaabc99aaaaaaa#シーンイン+45cccc88cc';

	var testText = 'aaaaabc#シーンイン+11aaaaaaa#シーンイン+22cccc#シーンイン+33cc';

と変更して実行してみました。結果↓

09:33 (ten-you) #
09:33 (ten-you) #シーンイン+11

一番最初の「#シーンイン+(半角数字)」を拾ってきました。なるほど。これは実際使う時には周知しとこう。
なお、指定した正規表現に、文字列がまったくマッチしない場合、この関数はNull値を返すそうです。


ところでここで、if文はいったい何を判定してるんでしょう?という新たな疑問が。
……というか疑問が次々沸いてきりがないんですが、どうしよう。

ifについて、改めて。

if文をここまで何度も使っておりますが、条件式である()内で、match()がどういう結果だったらTrueか? {}内を実行するか?ってこと記述してませんよね。
そもそもmatch()の戻り値は上記のとおり文字列であって、TrueやFalseではありません。
ということは「Null値かそうでないか」で判断してるんでしょうか?

というわけでリファレンスを再度確認。

■ 条件分岐(if)
◆ if (expression) statements1 else statements2 (e3/N2)

expression が真であれば statements1 を、さもなくば statements2 を実行します。例えば次の例では、変数 n の値が 10 より小さければ、SMALL を、さもなくば BIG を表示します。

構文- とほほのJavaScriptリファレンス

……つまり、()内が成立する時、ということ?
併記されてる例文はこんな感じです。

if (n < 10) {
    alert("SMALL");
} else {
    alert("BIG");
}

「変数 n の値が 10 より小さければ、SMALL を、さもなくば BIG を表示します。」とのこと。
つまり、「n < 10が成立する時」と「match()で文字列が返ってくる時」は同じく真だとみなされてる。
同様に、「n < 10が成立しない時」と「match()でNull値が返ってくる時」は同じく真ではないとみなされる。
ということは、ifの条件式では、Null値が返ってくる結果は真ではないと判定するんですね。
これは覚えておこう。

今日のまとめ(?)

長くなってきたので、ここでいったんまとめます。

match()
対象となる文字列.match(拾いたい文字列の正規表現)は、拾いたい文字列の正規表現にマッチした文字列を返す関数。
    • マッチする文字列がない場合はNull値を返す
正規表現
「+」は正規表現としても使う記号なので、単なる文字列として使いたい場合は、「+」の前に「¥」を付ける
ifの条件式
Null値が返ってくる結果は真ではないと判定する


続きはまた明日。
……前段階ですでに長くなってるなあ。

*1:これをめんどくさがる人にはTRPGは向きません(笑)。TRPGのプレイは細かな足し算引き算の連続でもあります。

*2:「シーンイン+」ではなく「シーンイン\+」と書いてるのは、「+」がエスケープしないといけない文字だから、とのこと