ソラマメブログ

2009年03月08日

15パズルの作り方(その3)

解説 2回目 で 多分 これで最後まで...
-----
show_state(list stat, integer prev_sp) {
llSetText((string)count + " steps", <1.0, 1.0, 1.0>, 1.0);
integer num;
for (i = 0; i < 16; i++) {
num = llList2Integer(stat, i);
if ((num != 16) && ((prev_sp == -1) || (prev_sp == i))) {
pos.x = (i % 4) * 0.1 - 0.15;
pos.y = -0.01;
pos.z = 0.15 - (i / 4) * 0.1;
llMessageLinked(LINK_ROOT + num, SET_POS, (string)pos, NULL_KEY);
}
}
}
-----
今の状態と前に空白のあった場所(もしくは -1)を受け取り盤面に反映(し 今のステップ数も表示)する関数
-----
ステップ数は count に入れられてあるので それを llSetText で表示
-----
今の状態を頭から見ていき
-----
そのピースが 空白でなく -1 が渡されたか それが 前にスペースのあった場所にある場合
-----
そのピースに そのピースの位置を SET_POS(-1 に定義されている)のメッセージを渡してやる
-----
渡されたピースは その相対位置に動くことになるので 今の状態が 盤面に反映されることになる
-----
list swap(list stat, integer i, integer k) {
integer a = llList2Integer(stat, i);
integer b = llList2Integer(stat, k);
stat = llListReplaceList(stat, [b], i, i);
stat = llListReplaceList(stat, [a], k, k);
return stat;
}
-----
状態と 2つのピースのシーケンス位置を渡し 位置を入れ替える関数
-----
次のシャッフルを行う関数で用いる
-----
shuffle() {
integer count_parity = 0;
for (j = 0; j < 10; j++) {
for (i = 0; i < 16; i++) {
integer k = llFloor(llFrand(16.0));
if (i != k) {
cur_state = swap(cur_state, i, k);
count_parity++;
}
}
}
integer prev_sp = llListFindList(cur_state, [SP]);
if (prev_sp != 15) {
cur_state = swap(cur_state, prev_sp, 15);
count_parity++;
}
if (count_parity % 2 == 1) {
cur_state = swap(cur_state, 0, 1); // hack
}
count = 0;
show_state(cur_state, -1);
sp = llListFindList(cur_state, [SP]);
}
-----
状態を頭から見ていき 位置を入れ替える場所を乱数で選び入れ替えることを 10回繰り返す
-----
最後に 空白が右下に来るよう入れ替える
-----
入れ替えの回数が偶数になるよう 調製する(15パズルは何故解けないのか? - やねうらお-よっちゃんイカを食べながら年収1億円稼げる(かも知れない)仕事術 参照)
-----
まとめて盤面に反映するため -1 を渡し show_state を呼ぶ
-----
process_touch(integer num) {
if (num <= 15) {
if (is_movable(num, sp)) {
integer prev_sp = move_piece(num);
count++;
show_state(cur_state, prev_sp);
if (llList2CSV(cur_state) == llList2CSV(goal)) {
llOwnerSay("completed with " + (string)count + " steps");
}
} else {
llOwnerSay((string)num + " is not movable");
}
} else if (num == LINK_SHUFFLE) {
shuffle();
} else if (num == LINK_RESET) {
llResetScript();
}
}
-----
タッチされたプリムのリンク番号の ルートプリムのリンク番号からのオフセットを受け取り オブジェクトがタッチされた場合の処理を行う
-----
15以下の場合(sp には空白の位置が入れられるようになっているので)ピースを動かすことができる場合
-----
ピースを動かし 盤面に反映する
-----
終了状態に達していた場合 メッセージ出力
-----
動かすことができないものであった場合 動かせないむね メッセージ出力
-----
シャッフル用のボタンが押された場合 シャッフル
-----
リセット用のボタンが押された場合 リセット
-----
default {
state_entry() {
cur_state = goal;
sp = llListFindList(cur_state, [SP]);
show_state(cur_state, -1);
}
touch_start(integer total_number) {
process_touch(llDetectedLinkNumber(0) - LINK_ROOT);
}
}
-----
rez 時 リセット時 終了状態に設定する
-----
タッチされた場合 タッチ処理の関数を呼び出す
-----
以上 ^^

同じカテゴリー(walking のスクリプティング講座)の記事
 プロフィール写真の表示に問題 (2009-11-30 20:55)
 ミニ太陽系 (2009-03-21 06:03)
 関数から文字列を返したら何か問題になる? (2009-03-18 18:02)
 llListFindList って型って関係ないんだったっけ (2009-03-18 14:02)
 夏時間(PDT)の実験 (2009-03-08 22:04)
 15パズルの作り方(その2) (2009-03-07 22:02)
上の画像に書かれている文字を入力して下さい
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。