〜 ナンバー 〜
論理的なデータ入れ替え

通常のソートはもちろん、ある程度ソートされた塊ごとをソートしたい場合はこの方法が有効でしょう。
尚、文中にポインタという書き方をしておりますが、ここでいうポインタはメモリアドレスではなく、
配列変数の要素番号のことです。難しく考えないで行きましょう。
例えば、既に順番に並んでいる「あ」〜「ん」までのデータ(1要素に1文字が入っている)があるとします。
これの入れ替えを行いたいが、完全なランダムではなく、
1つの行(「あ」〜「お」や「か」〜「こ」など)を1つの塊として入れ替えたい場合、
バブルソート等で実際のデータを入れ替えると、1回の入れ替えにつき5データを入れ替える必要があります。
他の具体的な例、クイズゲームで考えてみましょう。
1問に付き1要素として質問データと解答データは別々の配列にするとします。
クイズをランダムに出題したい場合、質問と解答を同時に入れ替える必要がありますし、
テキストのデータの入れ替えは、文字化けや文字欠け、余分な文字が付く等の障害要因になりかねません。
先の例、後の例のどちらにも言えますが、こういう場合は実際にデータを入れ替えるのではなく、
表示するデータの要素番号を入れ替えるのです。
わかりにくい書き方ですが、先の例だと、データと同じ要素数分のポインタ用配列を用意しておきます。
完全に1つの行(「あ」〜「お」や「か」〜「こ」など)単位で扱う場合は、その5分の1でもいいでしょう。
そのポインタ用の配列には、次に表示したい要素番号を予め入れておき、
並べ替えたい箇所だけ別の行位置の要素番号を設定します。
後は、そのポインタ配列を表示データの要素番号として利用すれば1つの行単位に扱うことが出来ます。
後の例だと、ポインタ用の配列に出題番号を示す番号を設定し、ランダムに入れ替えます。
実際に出題する時、解答を表示する時は、そのポインタ配列の要素を小さい順から使用していくだけです。
質問も解答も同じポインタ配列要素を使うことでズレが生じることはありませんよね。
下記、HSP2のサンプルは先の例を、HSP3は後の例をスクリプト化したものです。
	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define arrangement 10 // 1つの行を1つと数え、10行分

	sdim char, 2, arrangement * 5
	dim pointer, arrangement
	char.0  = "あ", "い", "う", "え", "お"
	char.5  = "か", "き", "く", "け", "こ"
	char.10 = "さ", "し", "す", "せ", "そ"
	char.15 = "た", "ち", "つ", "て", "と"
	char.20 = "な", "に", "ぬ", "ね", "の"
	char.25 = "は", "ひ", "ふ", "へ", "ほ"
	char.30 = "ま", "み", "む", "め", "も"
	char.35 = "や", " ", "ゆ", " ", "よ"
	char.40 = "ら", "り", "る", "れ", "ろ"
	char.45 = "わ", " ", "を", " ", "ん"
	// 並べ替え「あ」「か」「な」「は」「ら」「わ」「さ」「た」「ま」「や」
	pointer = 1, 4, 5, 8, 9, 2, 3, 6, 7 // 終端は0
	repeat
		pos cnt \ 5 * 40, cnt / 5 * 20 : mes char.tmp // 並び替えたデータ表示
		if cnt \ 5 = 4 : tmp = cnt / 5 : tmp = pointer.tmp * 5 : else : tmp++
		if tmp = 0 : break
	loop
	stop
 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#define QNUM 10 // 問題数
#define ANUM 4  // 選択肢数

	randomize
	sdim q, 8, QNUM // 問題用の配列変数
	sdim a, 8, QNUM // 解答用の配列変数
	dim qp, QNUM    // 問題と解答の並べ替え用配列変数
	dim ap, ANUM    // 選択肢(4択)の並べ替え用配列変数
	q = "質問1", "質問2", "質問3", "質問4", "質問5", "質問6", "質問7", "質問8", "質問9", "質問10"
	a = "正解1", "正解2", "正解3", "正解4", "正解5", "正解6", "正解7", "正解8", "正解9", "正解10"
	now = 0
	gosub *getquestions // 問題・解答セットをランダムにする
	button gosub "出題", *question
	stop

*question
	redraw 0
	color 255, 255, 255 : boxf : color
	if now < QNUM {
		// 問題を表示する
		pos 50, 50 : mes "問. " + q(qp.now)
		// 選択肢を表示
		gosub *getanswers // 選択肢を取得する
		repeat ANUM
			pos 60, cnt * 25 + 80 : mes "解答" + (cnt + 1) + "."
			pos 120, cnt * 25 + 80
			if ap.cnt : mes "偽解" : else : mes a(qp.now)
		loop
		now++ // 次の問題へ
	}
	redraw
	return

*getquestions
	repeat QNUM
		r = rnd(QNUM)
		if qp(r) : continue cnt : else : qp(r) = cnt
	loop
	return

*getanswers
	// 選択肢をクリアする(問題数×4バイト分)
	memset ap, 0, ANUM * 4
	// 選択肢をランダムに決定する
	repeat ANUM
		r = rnd(4)
		if ap(r) : continue cnt : else : ap(r) = cnt
	loop
	return