〜 ナンバー 〜
重複結果の出ない乱数

ビンゴの玉は通常、同じものが二度出ることはありませんね。
一組のトランプも同様に、一枚取り出すと同じものは入っていません(ジョーカーを除いて)。
ランダムで指定範囲内から値を取得した後、同じ数値が出ないようにするには、
何らかの重複チェックを付けて事前にダブることを防ぐのが、プログラムにおける対策法です。
出る可能性がある値と同じ要素数を持つ重複チェック用の配列変数を用意し、
ランダムで取得した値を重複チェック配列変数の要素番号に見立てて、
その要素に既に取り出したことを示す重複防止用の値を入れておくのです。
次回以降に取り出したランダムな値が、既に取り出した値であるかの判定は、
取り出した値と重複チェック用配列変数の同値要素に、重複防止用の値が入っているかを確認するだけ。
既に取り出したことを示す値が入っているならば、もう一度乱数取得からやり直し、
重複チェック用配列に全て取り出した値が埋まるまで繰り返せば、一意な値を埋めることが出来ます。
重複防止方法はいろいろありますが、重複チェックを行わず重複させないやり方も実は存在します。
やり方はまず、出る可能性がある値を全て配列変数に代入します。
そして、その配列要素自体をランダムに入れ替えるのです。
値は、別の要素と入れ替えるだけなので、重複することはなく、重複チェックも必要ないというわけです。
この方法だと、重複によるやり直し処理が発生しないので、処理速度は一定(入れ替え回数に比例)です。
言葉でイメージし辛い場合は、下記のサンプルモジュールをご覧ください。
尚、HSP2側は、パラメータの配列変数要素数を知る為、PVAL(PVAL2)構造体にアクセスしてます。
やっていることは、コチラgetvarsize命令と同じことで、配列変数の1次元目だけを取得しています。
	

unqrnd 乱数一覧格納変数
乱数一覧格納変数配列要素数を乱数の範囲として、各要素に重複しない値を代入する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#module
#deffunc unqrnd val
	mref record, 48 : mref pval, 1024
	// 変数の要素数分だけ初期値をセット
	repeat pval.2
		record.cnt = cnt
	loop
	// 入替
	repeat pval.2
		rnd r, pval.2
		if cnt = r : continue // 同じ要素なら処理しない
		record.cnt = record.cnt ^ record.r
		record.r   = record.cnt ^ record.r
		record.cnt = record.cnt ^ record.r
	loop
	return
#global

	dim data, 10
	randomize
	unqrnd data // 「0〜9」を各要素にランダムセット
	repeat 10
		pos 10, cnt * 20 + 10 : mes "" + cnt + "."
		pos 40, cnt * 20 + 10 : mes data.cnt
	loop
	stop

unqrnd 乱数一覧格納変数
乱数一覧格納変数配列要素数を乱数の範囲として、各要素に重複しない値を代入する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#module
#deffunc unqrnd array record, local r
	// 変数の要素数分だけ初期値をセット
	foreach record
		record.cnt = cnt
	loop
	// 入替
	foreach record
		r = rnd(length(record))
		if cnt = r : continue // 同じ要素なら処理しない
		record(cnt) = record(cnt) ^ record(r)
		record(r)   = record(cnt) ^ record(r)
		record(cnt) = record(cnt) ^ record(r)
	loop
	return
#global

	dim data, 20
	randomize
	unqrnd data // 「0〜20」を各要素にランダムセット
	foreach data
		pos 10, cnt * 20 + 10 : mes "" + cnt + "."
		pos 40, cnt * 20 + 10 : mes data.cnt
	loop