2009年03月07日
15パズルの作り方
慣れた方にはそれほど難しくはないわけですが
-----
あれ? どうしたらいいんだったっけ と lsl の特徴的な機能を使うプログラムのような気もするので
-----
サンプルとして使ってみようと思います w
-----
とりあえず初回の今回は全リストを上げておきます
-----
ちなみに ものは こんな感じに作ってあります
-----
-----
ベースを ルートのプリム とし 15個の ピース と シャッフル と リセット 用のボタン をそれにリンクしています
-----
-----
HUD に装着して使えるくらいの大きさにしておきました
-----
まず 各ピースの中には以下のスクリプトを入れておきます
-----
でもって ルートのプリムに以下のスクリプトを入れます
-----
解説は次回以降に ^^
-----
(続く)
-----
あれ? どうしたらいいんだったっけ と lsl の特徴的な機能を使うプログラムのような気もするので
-----
サンプルとして使ってみようと思います w
-----
とりあえず初回の今回は全リストを上げておきます
-----
ちなみに ものは こんな感じに作ってあります
-----
-----
ベースを ルートのプリム とし 15個の ピース と シャッフル と リセット 用のボタン をそれにリンクしています
-----
-----
HUD に装着して使えるくらいの大きさにしておきました
-----
まず 各ピースの中には以下のスクリプトを入れておきます
-----
//-----
// File: 15puzzle_piece.lsl
// Date Author number of nodes
// 2009/2/16 walkinglint 11
//
integer SET_POS = -1;
vector pos;
default {
link_message(integer sender_num, integer num, string str, key id) {
if (num == SET_POS) {
pos = (vector)str;
llSetPos(pos);
}
}
}
でもって ルートのプリムに以下のスクリプトを入れます
-----
//-----
// File: 15puzzle_game.lsl
// Date Author number of nodes
// 2009/3/5 walkinglint 109
//
integer SET_POS = -1;
integer LINK_SHUFFLE = 16;
integer LINK_RESET = 17;
integer SP = 16;
list cur_state;
list goal = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
integer sp = -1;
integer count;
integer i;
integer j;
vector pos;
integer distance(integer from, integer to) {
return llAbs((from / 4) - (to / 4)) + llAbs((from % 4) - (to % 4));
}
integer is_movable(integer num, integer sp) {
integer idx = llListFindList(cur_state, [num]);
return (distance(idx, sp) <= 1);
}
integer move_piece(integer num) {
integer prev_sp = llListFindList(cur_state, [SP]);
integer idx = llListFindList(cur_state, [num]);
cur_state = llListReplaceList(cur_state, [num], sp, sp);
cur_state = llListReplaceList(cur_state, [SP], idx, idx);
sp = llListFindList(cur_state, [SP]);
return prev_sp;
}
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);
}
}
}
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;
}
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]);
}
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();
}
}
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);
}
}
解説は次回以降に ^^
-----
(続く)
Posted by walkinglint at 18:02│Comments(0)
│walking のスクリプティング講座