乱数あれこれ・2
(prev. 乱数あれこれ はこちら)
RYOMAさんからコメントを頂いたので、その内容に沿って、補足的な説明も加えつつ具体的な実装例を考えてみたいと思います。
ビュワーを開始する度に1回だけのランダムで起こすアクションを組む場合はこれで全然行けそうなんやけど、 例えば5種のアクションをキーを押す度にとか、列車の周回毎に特定のセンサーにタッチする度にランダムで動作させる場合はタイマーイベントの方が簡単じゃない?そう言った場合のランダムアクションをタイマーレスで起こす場合の見本を書いてくれると有難いよ(^^ゞ
どうもビュワーを開いてから特定の動作の度に、“ランダムアクションをタイマーレスで起こさせると言う内容を簡単に記述する”と言うところまで至れんかったww 乱数系はあんまり分からんもんやから、未だタイマーを使ったルーレット式でやってるしwww
―RYOMA November 1st 2013 20:52(太字は引用者による)
ということでありました。
まずは「タイマーを使ったルーレット式」についてざっくりと。
おそらくは次の方法のいづれかかと思います。
- 「タイマーイベントでビュワー起動から闇雲に乱数列を進めて、"何か"が起きたら止める」(ここと同じ方法)
- 「ルーレットを回すセンサーと止めるセンサーの2つを用意して区間を作り編成を通過させる」
この2つの「ランダム性」は、
- 人間が"何か"を起こすまでの時間は、やる度毎に一定になり得ない
- 編成の運転操作が必ずいつも一緒ではないから、区間の通過時間は一定にはなり得ない
ということに由来し、確かにランダムです。(後者については若干の疑問もなくはないですが、ランダムとしてよいでしょう。)
VRMスクリプトでは無駄なイベントは削減すべきというのが定石なので、これらの方法はあまりスマートではありません。特に1番目は、半無限ループを組むことになりことさら良くありません。
(サンプルコードについては、VRM入道「乱数初期化話」に使えそうなものがありますので参照されたし。)
★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜★
ではここから、前回の乱数あれこれの内容を踏まえて、エレガントでない方法の回避を考えます。
その前に(まだ前置きか)、「乱数列」についての補足です。乱数列というのは、基本的には、「漸化式で定義される数列」ということになります。(VRMの乱数列は、どうやらかなり違う方法で計算しているっぽいのですが、簡略化した「イメージ」として見てみてください。)
//背景黒いけど許してね ・簡単な例として、「もらった数を二乗する」計算くんAを考えます。 計算くんAは、数をもらうと何も言わずに二乗して返してくれます。 2→→[計算くんA]→→4 ・・・2を渡したら4を返してくれた 3→→[計算くんA]→→9 ・・・3を渡したら9を返してくれた a→→[計算くんA]→→a^2 ・次に、正体不明な覆面をかぶった計算くんXを考えます。 計算くんXは、どんな計算をして返してくれるのかよく分かりません。 x→→[計算くんX]→→y ・・・何かしらないが渡したのと違うものが返ってきた y→→[計算くんX]→→z ・・・また得体のしれないものを… きっとこの次も、さらに得体のしれないものを返してくるはずです。 この計算くんXが、云わば「乱数計算くん」ということです。
ということで、ある計算くんXと、乱数列のはじめの1個を決めると、以降の乱数列すべてが決まります。(数列がランダムに見えるようにするために、計算くんXにはかなり複雑な計算をさせます。)
VRMの「普通の」乱数は式と1個目がいつビュワーを起動しても変わらないために、「微妙な」乱数だったということになります。
★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜★
さて、ここからが本題(?)ということで具体的な実装について検討していきます。あくまでサンプルということで、前回の記事にちなんで次のようなものを考えます。
- お題は「じゃんけんマシン」
- 乱数を3で割って、その余り(0,1,2)をグー・チョキ・パーに見立てる(見立てるだけ)
- (タイマールーレットは使わない)
- (簡略化のため、三回勝負とする。けど、勝ち負けは今回関係ない)
- 要は乱数を3で割った余りをログウィンドウに3回表示させるだけ
実用上は、割った余りに応じて動作を分岐させることが多いと思いますが、今回は「割った余りをログウィンドウに出す」ところまでと、「それが本当にランダムであることを確かめる」ことに重点を置いていきます。
では、はじめのたたき台として次のように書いてみます。まずは、ただ乱数を取得して3で割った余りを表示させるだけにします。書き込む場所はレイアウトスクリプトが適当です。
Var eid SetEventTime this MtdTestStart eid 500 // 500msにスタート BeginFunc MtdTestStart //ゲームスタート。3回戦一気にやります。 call this MtdJanken call this MtdJanken call this MtdJanken EndFunc BeginFunc MtdJanken // じゃんけん1回分 Var r irnd r //乱数の取得 mod r 3 // 3で割った余り DrawVar r EndFunc
ログウィンドウをスクロールしなくても見えるように、ビュワー起動から0.5秒後にログウィンドウに書き出しています。
さて、試しにこのゲームを、ビュワーを再起動させて複数回行ってみます。するとじゃんけんマシンは何度やっても0,1,2の順でしか出しません。
(ランダムさが感じられませんが、これでも一応「ランダム」です。MtdTestStartのcallを増やして10回戦くらいにすると分かります。が、毎回同じパターンなのは同じです。)
毎回同じ0,1,2のパターンであることが分かってしまうと、このじゃんけんマシンはゲームとして成立しなくなってしまいます。プレイヤー側がパターンを覚えてしまうからです。
★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜★
そこで、先ほどのスクリプトを次のように改めます。
Var eid SetEventTime this MtdTestStart eid 500 // 500msにスタート Var ut GetUnixTime ut // UnixTimeを取得 and ut 1023 rndseed ut BeginFunc MtdTestStart //ゲームスタート。3回戦。 call this MtdJanken call this MtdJanken call this MtdJanken EndFunc BeginFunc MtdJanken // じゃんけん1回分 Var r irnd r mod r 3 // 3で割った余り DrawVar r EndFunc
太字が加筆した箇所です。ここで、rndseed命令で標準の乱数列のシード値を、UnixTime(国際標準時)ベースのものに変更しています。UnixTimeとは、1970年1月1日0時0分0秒から起算した秒数のことです。そのままだと気が遠くなるほど大きく、rndseed命令が受け入れられる値の範囲を超えているため、適当な範囲に丸める処理をand命令で行っています。
時刻は当たり前ながら刻一刻と過ぎていくので、ビュワーを起動するごとに違うシード値が与えられるようになります。シード値そのものも、DrawVar命令で見てみると面白いかもしれません。
(実際は0~1023までに丸めているので1024秒ごとに一回同じパターンが現れます。が、1024秒毎にきっかりビュワーを再起動する=ゲームに再挑戦する人はそうはいないので、これで構わないということになります。)
実際に何度かビュワーを再起動してゲームに再挑戦すると、毎回違うパターンで0,1,2が現れることが分かります。
以上のようなGetUnixTimeの利用が、ビュワー起動毎にランダムな動きをするカラクリの基本形になります。
じゃんけんマシンのサンプルでは、実験の結果がすぐ得られるように3回戦を一気にやって結果を表示させていますが、これはキーイベントなどを設定して1回戦ずつ行う場合でも、同様なランダムな結果が得られます。
また太字で示されたGetUnixTimeがらみのセクションは、レイアウト内にただ一箇所記述し、ビュワー起動時に1回だけ実行させるようにしてください。(メソッド内には入れないでください。入れても問題はありませんが無駄の極みです。)
実用上は、割った余りの結果0,1,2に応じて、if文を立てて異なった動作をさせることになります。
| 固定リンク
「VRM:研究」カテゴリの記事
- VRMNXの時間系イベントが使いにくいなあと思っているアナタへ(2019.12.24)
- [VRMNX] フレーム同期の話(2019.07.18)
- [Python] リスト型をベクトルに見立てて計算したい(2019.06.16)
- VRMNXのレイヤーベース地形を使ってみよう(前編)(2019.05.18)
- [VRMNX]自動踏切モジュール(2019.01.25)
この記事へのコメントは終了しました。


コメント
おおーーーーー!!
rndseedって決まっているrud系の乱数列パターンの種と言うか源と言うか
何と言うか・・・要はこの種やら源の部分がSEEDに当り、このSEED値を
UnixTimeを使ってバラ付かせる事で乱数列パターンを変動させると言う
イメージなんやったんやね。
rndseedの使い方を根本的に間違うとったわww
でもおかげで目覚めたし(何のこっちゃwww
これならもうタイマーレスで全然行けるね。
ホンマ、ありがとう。
投稿: RYOMA | 2013年11月 3日 (日) 14時01分