4 Placed in the public domain.
6 This code is designed for use with Perlenspiel, by Brian Moriarty,
7 which is released under the terms of the GNU LGPL version 3 or
28 [0, 2], [1, 2], [2, 2],
29 [0, 1], [1, 1], [2, 1],
30 [0, 0], [1, 0], [2, 0]
33 var state
= LEVEL_SELECT
;
36 var current_level
= 1;
37 var current_level_inst
= null;
39 function QueueChange(bead
, sound
) {
42 bead_change
.push(bead
)
47 for (var i
= a
.length
- 1; i
>= 1; --i
) {
48 var j
= PS
.Random(i
) - 1;
57 return a
[PS
.Random(a
.length
) - 1];
60 function CheckExact(pos
) {
61 for (var n
= 1; n
<= 9; ++n
) {
62 var x
= LEVEL_POS
[n
][0];
63 var y
= LEVEL_POS
[n
][1];
64 var on
= PS
.BeadColor(x
, y
) != PS
.COLOR_WHITE
;
65 var should
= pos
.indexOf(n
) >= 0;
66 if ((on
&& !should
) || (!on
&& should
)) {
73 function FollowMe () {
75 PS
.BeadColor(PS
.Random(3) - 1, PS
.Random(3) - 1, PS
.COLOR_BLACK
);
77 this.Press = function (x
, y
) {
78 if (PS
.BeadColor(x
, y
) == PS
.COLOR_BLACK
) {
79 PS
.BeadColor(x
, y
, PS
.COLOR_WHITE
);
84 PS
.BeadColor(PS
.Random(3) - 1, PS
.Random(3) - 1,
86 PS
.AudioPlay(PS
.Xylophone(count
== 3 ? 14 : 13), 0.5);
95 function Enumerate () {
96 this.Press = function (x
, y
) {
97 for (var n
= 1; n
< LEVEL_IDX
[y
][x
]; ++n
) {
98 if (PS
.BeadColor(LEVEL_POS
[n
][0], LEVEL_POS
[n
][1])
104 if (PS
.BeadColor(x
, y
) == PS
.COLOR_BLACK
) {
107 PS
.BeadColor(x
, y
, PS
.COLOR_BLACK
);
108 if (LEVEL_IDX
[y
][x
] == 9)
110 else if (LEVEL_IDX
[y
][x
] == 3)
111 PS
.AudioPlay(PS
.Xylophone(15), 0.5);
112 else if (LEVEL_IDX
[y
][x
] == 6)
113 PS
.AudioPlay(PS
.Xylophone(16), 0.5);
114 else if (LEVEL_IDX
[y
][x
] > 6)
115 PS
.AudioPlay(PS
.Xylophone(15), 0.5);
116 else if (LEVEL_IDX
[y
][x
] > 3)
117 PS
.AudioPlay(PS
.Xylophone(14), 0.5);
119 PS
.AudioPlay(PS
.Xylophone(13), 0.5);
125 var repeatorder
= Shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9]).slice(0, 6);
127 for (var n
= 0; n
< repeatorder
.length
; ++n
) {
128 QueueChange([[PS
.COLOR_BLACK
, repeatorder
[n
]]],
129 [PS
.Xylophone(2 + n
)]);
131 this.Press
= function Press (x
, y
) {
132 var n
= repeatorder
.shift();
133 if (LEVEL_IDX
[y
][x
] == n
) {
134 PS
.BeadColor(x
, y
, PS
.COLOR_GREEN
);
135 if (repeatorder
.length
== 0) {
138 PS
.AudioPlay(PS
.Xylophone(9 + repeatorder
.length
), 0.5);
139 PS
.AudioPlay(PS
.Xylophone(9 + repeatorder
.length
), 0.5);
148 function TickMissing() {
156 repeatorder
= Shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9]).slice(0, 6);
157 repeatorder
= Shuffle(repeatorder
.concat(repeatorder
));
158 for (var n
= 0; n
< repeatorder
.length
; ++n
) {
159 if (d
[repeatorder
[n
]]) {
160 QueueChange([[PS
.COLOR_WHITE
, repeatorder
[n
]]],
161 [PS
.Xylophone(15 - n
)]);
163 d
[repeatorder
[n
]] = true;
164 QueueChange([[PS
.COLOR_RED
, repeatorder
[n
]]],
165 [PS
.Xylophone(13 + n
)]);
169 for (var n
= 1; n
<= 9; ++n
)
170 if (repeatorder
.indexOf(n
) < 0)
171 missing_valid
.push(n
);
173 this.Press = function (x
, y
) {
174 if (missing_valid
.indexOf(LEVEL_IDX
[y
][x
]) < 0) {
177 PS
.BeadColor(x
, y
, PS
.COLOR_BLACK
);
178 if (CheckExact(missing_valid
)) {
182 PS
.AudioPlay(PS
.Xylophone(count
== 2 ? 14 : 13), 0.5);
188 function ThreeRow () {
194 function Generate() {
195 third_row
= Shuffle(Choose([
196 [1, 2, 3], [4, 5, 6], [7, 8, 9],
197 [1, 4, 7], [2, 5, 8], [3, 6, 9],
198 [1, 5, 9], [3, 5, 7]]));
199 QueueChange([[PS
.COLOR_BLACK
, third_row
[0]]], [PS
.Xylophone(13)]);
200 QueueChange([[PS
.COLOR_BLACK
, third_row
[1]]], [PS
.Xylophone(13)]);
203 this.Press = function (x
, y
) {
204 if (LEVEL_IDX
[y
][x
] == third_row
[2]) {
206 PS
.BeadColor(x
, y
, PS
.COLOR_BLACK
);
207 PS
.Clock(PS
.Clock());
211 PS
.AudioPlay(PS
.Xylophone(14), 0.5);
212 QueueChange([[PS
.COLOR_GREEN
, third_row
[2]],
213 [PS
.COLOR_GREEN
, third_row
[1]],
214 [PS
.COLOR_GREEN
, third_row
[0]]],
216 QueueChange([[PS
.COLOR_WHITE
, third_row
[2]],
217 [PS
.COLOR_WHITE
, third_row
[1]],
218 [PS
.COLOR_WHITE
, third_row
[0]]]);
228 function SudokuRow () {
234 function Generate() {
235 sudoku_row
= Shuffle(
236 Choose([[1, 8, 6], [4, 8, 3], [4, 2, 9], [7, 2, 6]]));
237 QueueChange([[PS
.COLOR_RED
, sudoku_row
[0]]],
239 QueueChange([[PS
.COLOR_RED
, sudoku_row
[1]]],
243 this.Press = function (x
, y
) {
244 if (LEVEL_IDX
[y
][x
] == sudoku_row
[2]) {
246 PS
.BeadColor(x
, y
, PS
.COLOR_BLACK
);
250 PS
.AudioPlay(PS
.Xylophone(13), 0.5);
251 QueueChange([[PS
.COLOR_GREEN
, sudoku_row
[2]],
252 [PS
.COLOR_GREEN
, sudoku_row
[1]],
253 [PS
.COLOR_GREEN
, sudoku_row
[0]]],
255 QueueChange([[PS
.COLOR_WHITE
, sudoku_row
[2]],
256 [PS
.COLOR_WHITE
, sudoku_row
[1]],
257 [PS
.COLOR_WHITE
, sudoku_row
[0]]]);
268 QueueChange([[PS
.COLOR_BLACK
, 1]], ["perc_hihat_closed"]);
269 QueueChange([[PS
.COLOR_WHITE
, 1],
270 [PS
.COLOR_BLACK
, 4]], ["perc_hihat_closed"]);
271 QueueChange([[PS
.COLOR_WHITE
, 4],
272 [PS
.COLOR_BLACK
, 7]], ["perc_hihat_closed"]);
273 QueueChange([[PS
.COLOR_WHITE
, 7]]);
275 QueueChange([[PS
.COLOR_BLACK
, 2],
277 [PS
.COLOR_BLACK
, 8]],
279 QueueChange([[PS
.COLOR_GREEN
, 2],
281 [PS
.COLOR_GREEN
, 8]],
283 QueueChange([[PS
.COLOR_WHITE
, 2],
285 [PS
.COLOR_WHITE
, 8]]);
288 this.Press = function (x
, y
) {
289 if (PS
.BeadColor(x
, y
) == PS
.COLOR_WHITE
) {
290 PS
.BeadColor(x
, y
, PS
.COLOR_BLACK
);
292 PS
.BeadColor(x
, y
, PS
.COLOR_WHITE
);
295 if (count
== 4 && ApproveIfExact([7, 9, 4, 5, 6, 3]))
297 if (count
== 7 && (CheckExact([7, 8, 9, 6, 3])
298 || CheckExact([7, 8, 9, 6, 2]))) {
303 if (PS
.BeadColor(x
, y
) == PS
.COLOR_WHITE
) {
304 PS
.AudioPlay(PS
.Xylophone(10), 0.5);
306 PS
.AudioPlay(PS
.Xylophone(13), 0.3);
313 QueueChange([[PS
.COLOR_BLACK
, 1]], [PS
.Xylophone(13)]);
314 QueueChange([[PS
.COLOR_GREEN
, 1]], [PS
.Xylophone(14)]);
315 QueueChange([[PS
.COLOR_BLACK
, 1]]);
316 QueueChange([[PS
.COLOR_BLACK
, 4]], [PS
.Xylophone(13)]);
317 QueueChange([[PS
.COLOR_BLACK
, 7]], [PS
.Xylophone(13)]);
319 QueueChange([[PS
.COLOR_GREEN
, 1],
321 [PS
.COLOR_GREEN
, 7]],
323 QueueChange([[PS
.COLOR_BLACK
, 1],
325 [PS
.COLOR_BLACK
, 7]]);
328 this.Press = function (x
, y
) {
329 if (PS
.BeadColor(x
, y
) == PS
.COLOR_WHITE
) {
330 PS
.BeadColor(x
, y
, PS
.COLOR_BLACK
);
332 PS
.BeadColor(x
, y
, PS
.COLOR_WHITE
);
336 && (ApproveIfExact([1, 4, 7, 2, 5, 3], PS
.COLOR_BLACK
)
337 || ApproveIfExact([1, 4, 7, 8, 5, 3], PS
.COLOR_BLACK
))) {
339 if (PS
.BeadColor(x
, y
) == PS
.COLOR_WHITE
)
340 PS
.AudioPlay(PS
.Xylophone(10), 0.3);
342 PS
.AudioPlay(PS
.Xylophone(13), 0.5);
343 } else if (count
== 4 && CheckExact([1, 2, 3, 4, 5, 6, 7, 8, 9])) {
346 if (PS
.BeadColor(x
, y
) == PS
.COLOR_WHITE
)
347 PS
.AudioPlay(PS
.Xylophone(10), 0.3);
349 PS
.AudioPlay(PS
.Xylophone(13), 0.5);
354 function ApproveIfExact(a
, color
) {
356 color
= PS
.COLOR_WHITE
;
360 for (var n
= 0; n
< a
.length
; ++n
) {
361 green
.push([PS
.COLOR_GREEN
, a
[n
]]);
362 white
.push([color
, a
[n
]]);
364 QueueChange(green
, [PS
.Xylophone(14)]);
366 PS
.Clock(PS
.Clock());
367 if (PS
.StatusText() != "…")
377 QueueChange([[PS
.COLOR_BLACK
, 5]], [PS
.Xylophone(13)]);
378 QueueChange([[PS
.COLOR_GREEN
, 5]], [PS
.Xylophone(14)]);
379 QueueChange([[PS
.COLOR_WHITE
, 5]]);
380 QueueChange([[PS
.COLOR_BLACK
, 1]], [PS
.Xylophone(13)]);
381 QueueChange([[PS
.COLOR_BLACK
, 9]], [PS
.Xylophone(13)]);
382 QueueChange([[PS
.COLOR_GREEN
, 1],
383 [PS
.COLOR_GREEN
, 9]], [PS
.Xylophone(14)]);
384 QueueChange([[PS
.COLOR_WHITE
, 1],
385 [PS
.COLOR_WHITE
, 9]]);
388 this.Press = function (x
, y
) {
389 if (PS
.BeadColor(x
, y
) == PS
.COLOR_WHITE
) {
390 PS
.BeadColor(x
, y
, PS
.COLOR_BLACK
);
392 PS
.BeadColor(x
, y
, PS
.COLOR_WHITE
);
396 if (ApproveIfExact([1, 5, 9]) || ApproveIfExact([7, 5, 3]))
400 if (ApproveIfExact([1, 3, 7, 9]))
404 if (ApproveIfExact([1, 3, 5, 7, 9]))
408 if (CheckExact([1, 2, 3, 7, 8, 9])
409 || CheckExact([1, 4, 7, 3, 6, 9])) {
415 if (PS
.BeadColor(x
, y
) == PS
.COLOR_WHITE
) {
416 PS
.AudioPlay(PS
.Xylophone(14), 0.5);
418 PS
.AudioPlay(PS
.Xylophone(13), 0.3);
436 function Reset(color
) {
437 if (max_level
< 10 && PS
.StatusText() != "?")
439 if (max_level
== 10 && PS
.StatusText() != ".")
444 PS
.BeadColor(PS
.ALL
, PS
.ALL
, color
);
448 Reset(PS
.COLOR_GREEN
);
451 if (max_level
< current_level
) {
452 max_level
= current_level
;
453 if (max_level
== 10) {
454 setTimeout(function() {
455 PS
.AudioPlay(PS
.Xylophone(25), 0.5)
457 setTimeout(function() {
458 PS
.AudioPlay(PS
.Xylophone(30), 0.5)
460 setTimeout(function() {
461 PS
.AudioPlay(PS
.Xylophone(30), 0.5)
463 setTimeout(function() {
464 PS
.AudioPlay(PS
.Xylophone(31), 0.5)
466 setTimeout(function() {
467 PS
.AudioPlay(PS
.Xylophone(37), 0.5)
470 PS
.AudioPlay(PS
.Xylophone(34), 0.5);
471 PS
.AudioPlay(PS
.Xylophone(38), 0.5);
472 PS
.AudioPlay(PS
.Xylophone(39), 0.5);
475 PS
.AudioPlay(PS
.Xylophone(34), 0.5);
476 PS
.AudioPlay(PS
.Xylophone(38), 0.5);
477 PS
.AudioPlay(PS
.Xylophone(39), 0.5);
483 PS
.AudioPlay(PS
.Xylophone(2), 0.5);
484 PS
.AudioPlay(PS
.Xylophone(8), 0.5);
485 PS
.AudioPlay(PS
.Xylophone(22), 0.5);
490 PS
.Init = function (options
) {
491 var path
= window
.location
.href
;
492 PS
.AudioPath(path
.substr(0, path
.lastIndexOf("/")) + "/audio/");
496 for (var i
= 1; i
< 39; ++i
)
497 PS
.AudioLoad(PS
.Xylophone(i
));
498 PS
.AudioLoad("perc_hihat_closed");
501 function StartLevel(level
) {
502 if (level
> max_level
)
504 PS
.AudioPlay(PS
.Xylophone(1), 0.5);
505 Reset(PS
.COLOR_WHITE
);
506 current_level
= level
;
507 current_level_inst
= new LEVELS
[current_level
]();
511 function LevelSelect() {
512 Reset(PS
.COLOR_WHITE
);
513 for (var n
= 1; n
<= 9; ++n
) {
514 var x
= LEVEL_POS
[n
][0];
515 var y
= LEVEL_POS
[n
][1];
517 PS
.BeadColor(x
, y
, PS
.COLOR_VIOLET
);
518 else if (n
< max_level
)
519 PS
.BeadColor(x
, y
, PS
.COLOR_BLUE
);
522 PS
.BeadColor(PS
.ALL
, PS
.ALL
, PS
.COLOR_BLUE
);
523 state
= LEVEL_SELECT
;
526 PS
.Click = function (x
, y
, data
, options
) {
527 if (PS
.Clock() > 0 && bead_change
.length
)
531 StartLevel(LEVEL_IDX
[y
][x
]);
534 current_level_inst
.Press(x
, y
);
540 StartLevel(current_level
);
547 PS
.Release = function (x
, y
, data
, options
) {
550 PS
.Enter = function (x
, y
, data
, options
) {
551 if (state
== LEVEL_SELECT
&& PS
.BeadColor(x
, y
) != PS
.COLOR_WHITE
) {
552 PS
.AudioPlay( "fx_click" , 0.5);
556 PS
.Leave = function (x
, y
, data
, options
) {
559 PS
.KeyDown = function (key
, shift
, ctrl
, options
) {
560 if (ctrl
&& key
== 32) {
565 case PS
.KEYPAD_1
: case 49: PS
.Click(0, 2); break;
566 case PS
.KEYPAD_2
: case 50: PS
.Click(1, 2); break;
567 case PS
.KEYPAD_3
: case 51: PS
.Click(2, 2); break;
568 case PS
.KEYPAD_4
: case 52: PS
.Click(0, 1); break;
569 case PS
.KEYPAD_5
: case 53: PS
.Click(1, 1); break;
570 case PS
.KEYPAD_6
: case 54: PS
.Click(2, 1); break;
571 case PS
.KEYPAD_7
: case 55: PS
.Click(0, 0); break;
572 case PS
.KEYPAD_8
: case 56: PS
.Click(1, 0); break;
573 case PS
.KEYPAD_9
: case 57: PS
.Click(2, 0); break;
574 case PS
.KEY_ESCAPE
: LevelSelect(); break;
578 PS
.KeyUp = function (key
, shift
, ctrl
, options
) {
581 PS
.Wheel = function (dir
, options
) {
584 PS
.Tick = function (options
) {
585 var beads
= bead_change
.shift();
587 if (PS
.StatusText() != "…")
589 for (var n
= 0; n
< beads
.length
; ++n
) {
591 var x
= LEVEL_POS
[bead
[1]][0];
592 var y
= LEVEL_POS
[bead
[1]][1];
593 PS
.BeadColor(x
, y
, bead
[0]);
597 var sound
= sounds
.shift();
599 for (var n
= 0; n
< sound
.length
; ++n
) {
600 PS
.AudioPlay(sound
[n
], 0.5);
604 if (bead_change
.length
== 0 && PS
.StatusText() != "?")