自分すら予測できない
以前に条件分岐を紹介しましたが、条件の分岐だけでは、
初めて利用する者はわからくて当然ですが、触ったことがある者には、
この先に起こる事が予測できてしまいます。
今回は、開発者すらもどうなるのかがわからない「乱数」について説明します。
取得した乱数 = rnd(乱数の範囲)
取得した乱数発生させた乱数。
乱数の範囲32,768以下の指定した種類の乱数を発生する。得られる数は0〜[指定数-1]。
HSP3より関数化されたrnd関数ですが、関数化以外には変更ありません。
例えば、3パターン内から発生させた値を取得したいなら、rnd関数のパラメータに3を指定します。
気をつけることは、3パターンの数値は0からである為、
得られるのは「0」「1」「2」のうちのいずれかになります。
つまりは紹介欄に書いた「0〜[指定した値-1]」の範囲から取得ができるってことです。
 1
 2
 3
 4
	r = rnd(10) // 0〜9の乱数を発生
	mes "乱数は:" + r
	mes "関数のために変数に入れなくてもOK:" + rnd(10) // 0〜9の乱数を代入
	mes "このようにランダムな数が入ります:" + rnd(10) // 0〜9の乱数を代入
上記を実行すると、確かに10パターンの値から3回無作為に取得して表示しています。
しかし、実行ウィンドウを閉じて、再度スクリプトを実行させると、全く同じ値が表示されます。
rnd関数のパラメータを変えれば、当然のこと得られる値は変わりますが、
その状態でも、そのまま再実行すると、同じ値が得られるようになっています。
つまり、リセットしても不正ができないような毎回同じ値となる乱数はできても、
実行の度にも変わる乱数の発生ができないのです。
コレはコレで不便極まりないですよね。
こういった場合に使われるのが下記命令になります。
randomize 初期化パターン番号
初期化パターン番号乱数の初期化パターンを指定する。指定しない場合はWindowsタイマから設定。
randomize命令のパラメータに「0〜」の数値を指定すると、その数値を元にしたパターンで初期化し、
以後は、常にそのパターンを基にした乱数が生成されるようになる…とあります。
上限値は書かれていませんが、実際に幾らを指定しても決まっていない模様。
また、0からとありますがマイナス値の指定もできますし、実数値でも動作しているようです。
実数値はHSP3以降でなければ概念自体がありませんからHSP2.61以前だとエラーになりますが、
数値であれば何を指定しても問題は見当たりません。
 1
 2
 3
 4
	repeat 10
		randomize 12345 // パターン[12345]で初期化
		mes "[" + (cnt + 1) + "] " + rnd(999)
	loop
もし、上記要領で実行すると、実行ウィンドウを立ち上げなすまでもなく、全て同一値になります。
コレは、ループのたびに同じパターンで初期化している(2行目)からなんですね。
通常は、スクリプト内で一度だけ実行させるものですので、スクリプトの初めの方に一回だけ行います。
形としては下記イメージです。
 1
 2
 3
 4
	randomize 12345 // パターン[12345]で一度だけ初期化
	repeat 10
		mes "[" + (cnt + 1) + "] " + rnd(999)
	loop
ただ、コレでは既に書いているように、指定した数値パターンで初期化してしまうので、
実行ウィンドウを立ち上げなおすと、rnd関数だけを使用したのと同じ状態になります。
一定パターンを用いない通常のよく言われる乱数を発生させるには、
Windowsタイマを使用するタイプのパラメータ省略で記述します。
 1
 2
 3
 4
	randomize // 不定パターン
	repeat 10
		mes "[" + (cnt + 1) + "] " + rnd(999)
	loop
どうでしょうか?
上記サンプルでは乱数範囲が広すぎる為に探すのも困難ですが、
下記の少数サンプルでもパターン化されてないことは分かるかと思います。
実行ウィンドウを立ち上げなおして、仮に同じ数値が現れたとしても、
同じパターンとなっていない唯一無二であることは確認できることでしょう。
 1
 2
 3
 4
	randomize
	repeat 1000
		pos cnt \ 40 * 16, cnt / 40 * 18 : mes rnd(5)
	loop
ランダムなものは数字しか発生させることができません。
ランダムな数値は大抵、条件分岐時に使用する程度でしょう。
時には、カラフルな演出を施す為に下記のようにも使われる時があるかもしれませんが…。
 1
 2
 3
 4
 5
 6
 7
 8
 9
	randomize
	redraw 0
	repeat 1000
		color rnd(255), rnd(255), rnd(255) // それぞれの色要素をランダムに決定
		repeat 200
			pset rnd(640), rnd(480) // ランダムで決めた色をウィンドウ内にランダムでセット
		loop
	loop
	redraw // 一括更新
もしも、ランダムな文字列を発生させたい場合は、ある程度の枠を用意しておくのです。
つまり、文字列型配列を利用して、そのテキスト配列要素番号を乱数にすればよいということです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
	// 初期化
	sdim aisatsu, 12, 3
	sdim kugiri, 3, 2
	dim flag, 24
	randomize
	aisatsu = "おはよう", "こんにちは", "こんばんは"
	kugiri = "朝", "昼", "晩"
	flag = 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 //0:朝 1:昼 2:晩
	// 実行
	r = rnd(3)
	mes "やあ" + aisatsu(r) + "。"
	// 話したセリフが合っているかチェック
	if r = 0 && r != flag(gettime(4)) : goto *fault
	if r = 1 && r != flag(gettime(4)) : goto *fault
	if r = 2 && r != flag(gettime(4)) : goto *fault
	stop
// 間違っていた場合に処理する
*fault
	mes "…と言っても、今は" + kugiri(r) + "じゃないんだけどねぇ。"
この章までに説明した内容が入り混じってるので
分からない命令名・関数名は名称をクリックして理解してくださいね。
新しい命令はないけど、7行目の書き方が新しいやり方なのでココだけ補足で説明します。
配列変数flagは要素が24個ありますが、コレは各時間に見立てています。
11、12、13行目のgettime関数で現在時間を取得すると、0〜23の値が返ります。
その取得した値をそのままflagの要素としているわけです。
例えば…現在時刻が9時なら、flagの要素9の値(=0)が対象となるわけですね。
右側コメントにも書いてますが、0を朝、1を昼、2を晩としているので9時なら朝を示す0で、
乱数で取得した数値0〜2が、現在のflagと合っているかを判定して、
もし合っていないのなら、今は違うという別メッセージも出力しているわけです。
文字列のサンプルでしたが、ランダムな文字の場合は、
数値をそのまま文字コードとして使うことで実現できますが、高度なので今はまだ書きません。
配列変数に使用したい文字を各々用意して先ほどのサンプル同様のやり方でも実現できます。
 1
 2
 3
 4
 5
 6
 7
 8
	sdim moji, 2, 10
	moji = "A", "S", "X", "2", "7", "0", "c", "w", "*", "@"
	pass = ""
	randomize
	repeat 5
		pass += moji(rnd(10))
	loop
	mes "生成したパスワード:" + pass
ツール系ソフトでの用途はかなり少ないでしょうが、
ゲーム系ソフトでは利用者の操作するキャラクター以外は必ずと言っていいほど乱数が必要になってきます。
意図しないことをさせたい時はどうする必要があるのか…乱数の存在を忘れないようにしてください。