ff: [betweenAS3]BubbleSort And SelectionSort
---- Original comment by applicott --------------------
* クリックするたびに動きます。
* 上手く可視化出来なかった。。。
* シャッフル > BubbleSort > Shuffle > SelectionSort >>>....
*
* ---- Additional comment by matacat --------------------
* Click the stage to toggle motions.
* shuffle -> selection sort ->
* shuffule -> bubble sort ->
* shuffle -> selection sort -> ...
*
* 大体こんな感じでしょうか?ソートの解釈間違えてるかもです...
* 今回初めて BetweenAS3 を使わせていただきましたが、
* たのしいですねこれ!調整しては眺めるのを繰り返していたら
* いつの間にか一日が終わってました。
/**
* Copyright matacat ( http://wonderfl.net/user/matacat )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/pswp
*/
// forked from applicott's [betweenAS3]BubbleSort And SelectionSort
/*
* ---- Original comment by applicott --------------------
* クリックするたびに動きます。
* 上手く可視化出来なかった。。。
* シャッフル > BubbleSort > Shuffle > SelectionSort >>>....
*
* ---- Additional comment by matacat --------------------
* Click the stage to toggle motions.
* shuffle -> selection sort ->
* shuffule -> bubble sort ->
* shuffle -> selection sort -> ...
*
* 大体こんな感じでしょうか?ソートの解釈間違えてるかもです...
* 今回初めて BetweenAS3 を使わせていただきましたが、
* たのしいですねこれ!調整しては眺めるのを繰り返していたら
* いつの間にか一日が終わってました。
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(backgroundColor = 0x000000, frameRate = 60)]
public class Main extends Sprite
{
// 配列に関する定数・変数
private const NUM:uint = 30; // 配列の要素数
private var list:Vector.<Bar>; // 棒の配列
private var curId:int; // ソートに用いる。現在注目している要素など
private var selId:int; // ソートに用いる。比較対象の要素など
// モーションに関する変数
private var standby:Boolean; // モーションが完了したかどうかのフラグ
private var curMotion:int; // 現在のモーション
// 背景
private var shuffleName:MotionName;
private var ssortName:MotionName;
private var bsortName:MotionName;
public function Main()
{
var wz:int = stage.stageWidth;
var hi:int = stage.stageHeight;
graphics.beginFill(0);
graphics.drawRect(0, 0, wz, hi);
MotionName.centerY = hi / 2;
shuffleName = addChild(new MotionName("Shuffle")) as MotionName;
ssortName = addChild(new MotionName("Selection Sort")) as MotionName;
bsortName = addChild(new MotionName("Bubble Sort")) as MotionName;
// Bar クラスの初期設定
Bar.centerY = hi / 2; // ステージ中央の Y 座標で棒の高さをそろえる
Bar.interval = wz / NUM; // 棒の間隔はステージの幅を棒の総数で割った数
Bar.lengthMin = 25; // 棒の長さの最小値
Bar.lengthInc = (hi / 2 - 25) / NUM; // 棒の長さの増分
// リスト初期設定
list = new Vector.<Bar>(NUM, true);
for (var i:int = 0; i < NUM; i++) {
list[i] = new Bar(i, hue2rgb(i / NUM * 360));
addChild(list[i]);
}
getReady();
curMotion = 0;
stage.addEventListener(MouseEvent.CLICK, click);
}
private function click(e:MouseEvent):void
{
if (standby) {
// モーション実行中に別のモーションを実行しないように
standby = false;
// モーション切り替え。名前を表示し、ソート(シャッフル)を実行する
switch (curMotion) {
case 0: shuffleName.appear(); shuffle(); break;
case 1: ssortName.appear(); ssort(); break;
case 2: shuffleName.appear(); shuffle(); break;
case 3: bsortName.appear(); bsort(); break;
}
if (++curMotion > 3) curMotion = 0;
}
}
private function getReady():void
{
// ソート(シャッフル)を実行する前の準備
curId = 0;
selId = 0;
standby = true;
}
private function shuffle():void
{
// リストのシャッフル
// curId: 現在注目している要素。リストを前方から後方へ走査する
// selId: curId と交換する要素。 curId より前方の要素からランダムに選ぶ
while (++curId < NUM) {
selId = Math.random() * curId >> 0;
if (curId == selId) continue;
var b:Bar = list[curId];
list[curId] = list[selId];
list[selId] = b;
}
// シャッフルモーションを徐々に開始させる
curId = -1;
selId = -1;
addEventListener(Event.ENTER_FRAME, sMotion);
// 一斉に動かすならこの一行だけ
//for (curId = 0; curId < NUM; curId++) list[curId].goto(curId);
}
private function sMotion(e:Event):void
{
if (++selId % 5 != 0) return;
// 位置はそのままで配列だけをシャッフルしたので、
// インデックスに対応した位置に移動させれば良い
if (++curId < NUM - 1) {
list[curId].goto(curId);
} else if (curId == NUM - 1) {
list[curId].goto(curId, getReady);
} else {
removeEventListener(Event.ENTER_FRAME, sMotion);
shuffleName.disappear();
}
}
private function ssort():void
{
// リストの選択ソート(一回ずつモーションさせる)
// curId: 現在の注目インデックス。リストを前方から後方へ走査する
// selId: curId に収まるべき要素の候補。 i の長さの方が短い場合 i に置き換わる
// i: curId より後方を走査し、一番短い棒を探す
if (curId >= NUM - 1) { // 終了条件
getReady();
ssortName.disappear();
return;
}
selId = curId;
for (var i:int = curId + 1; i < NUM; i++) {
if (list[selId].length > list[i].length) selId = i;
}
var b:Bar = list[curId];
list[curId] = list[selId];
list[selId] = b;
// ソートモーション。完了する度このメソッド自身を呼び出させる
list[curId].goto(curId);
list[selId].goto(selId, ssort);
curId++;
}
private function bsort():void
{
// リストのバブルソート(一回ずつモーションさせる)
// curId: selId の上限インデックス。リストを前方から後方へ走査する
// selId: リストの後ろから curId まで走査する。ひとつ前の棒と長さを比較し、短い場合入れ替える
if (selId <= curId) {
if (++curId > NUM - 1) { // 終了条件
getReady();
bsortName.disappear();
return;
}
selId = NUM;
}
selId--;
if (list[selId - 1].length > list[selId].length) {
var b:Bar = list[selId];
list[selId] = list[selId - 1];
list[selId - 1] = b;
// ソートモーション。完了する度このメソッド自身を呼び出させる
list[selId].goto(selId);
list[selId - 1].goto(selId - 1, bsort);
} else {
bsort();
}
}
private function hue2rgb(hue:Number):uint
{
// 色相(単位: 度)から RGB を返すユーティリティ。輝度・彩度は常に最大
hue = hue >= 360 ? hue % 360 : (hue < 0 ? hue % 360 + 360 : hue);
var i:int = hue / 60 >> 0;
var j:Number = hue / 60 - i;
var k:Number = 1 - j;
var rgb:uint = 0;
switch (i) {
case 0: rgb = 0xFF0000 | 0xFF * j << 8 | 0; break;
case 1: rgb = 0xFF * k << 16 | 0x00FF00 | 0; break;
case 2: rgb = 0 | 0x00FF00 | 0xFF * j << 0; break;
case 3: rgb = 0 | 0xFF * k << 8 | 0x0000FF; break;
case 4: rgb = 0xFF * j << 16 | 0 | 0x0000FF; break;
case 5: rgb = 0xFF0000 | 0 | 0xFF * k << 0; break;
}
return rgb;
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Shape;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFormat;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.easing.Bounce;
import org.libspark.betweenas3.easing.Elastic;
import org.libspark.betweenas3.easing.Quad;
import org.libspark.betweenas3.easing.Sine;
import org.libspark.betweenas3.tweens.ITween;
class Bar extends Bitmap
{
private static const THICKNESS:int = 2;
private static const EDGE:int = 2;
public static var centerY:Number;
public static var interval:Number;
public static var lengthMin:Number;
public static var lengthInc:Number;
public var length:Number;
private var upT:ITween;
private var downT:ITween;
public function Bar(index:int, color:uint)
{
length = lengthMin + lengthInc * index;
var totalThick:int = THICKNESS + EDGE * 2;
var ofsX:Number = interval / 2;
var line:Shape = new Shape();
var g:Graphics = line.graphics;
g.lineStyle(totalThick, 0, 0.5, true);
g.moveTo(ofsX, totalThick / 2);
g.lineTo(ofsX, length);
g.lineStyle(THICKNESS, color, 1, true);
g.moveTo(ofsX, totalThick / 2);
g.lineTo(ofsX, length);
bitmapData = new BitmapData(interval, length + totalThick, true, 0);
bitmapData.draw(line);
x = index * interval;
y = centerY - totalThick / 2;
upT = BetweenAS3.tween(this, { y: centerY - totalThick / 2 - length }, null, 0.4, Elastic.easeOut);
downT = BetweenAS3.tween(this, { y: centerY - totalThick / 2 }, null, 0.8, Bounce.easeOut);
}
public function goto(index:Number, onComplete:Function = null):void
{
var slideT:ITween = BetweenAS3.tween(this, { x: index * interval }, null, 0.4, Quad.easeInOut);
if (onComplete != null) slideT.onComplete = onComplete;
BetweenAS3.serial(
BetweenAS3.parallel(
upT,
BetweenAS3.delay(slideT, 0.2)
),
downT
).play();
}
}
class MotionName extends Bitmap
{
public static var centerY:Number;
private var fadeIn:ITween;
private var fadeOut:ITween;
private var blink:ITween;
public function MotionName(name:String)
{
var mx:Matrix = new Matrix();
var tf:TextField = new TextField();
tf.defaultTextFormat = new TextFormat("_serif", 72, 0xFFFFFF);
tf.autoSize = "left";
tf.text = name;
var wz:int = tf.width;
var hi:int = tf.height * 0.9;
mx.createGradientBox(wz, hi, Math.PI / 2);
var gd:Shape = new Shape();
gd.graphics.beginGradientFill("linear", [0, 0], [0, 0.8], [63, 255], mx);
gd.graphics.drawRect(0, 0, wz, hi);
var temp:BitmapData = new BitmapData(wz, hi, true, 0);
temp.draw(tf);
temp.draw(gd);
temp.applyFilter(temp, temp.rect, new Point(), new BlurFilter(4, 4, 3));
super(new BitmapData(wz, hi * 1.75, false, 0));
bitmapData.draw(temp);
mx.createBox(1, -0.75, 0, 0, hi * 1.75);
bitmapData.draw(temp, mx, new ColorTransform(0.3, 0.3, 0.3));
y = centerY - hi;
alpha = 0;
temp.dispose();
fadeIn = BetweenAS3.tween(this, { alpha: 1.0 }, null, 1, Sine.easeInOut);
fadeOut = BetweenAS3.tween(this, { alpha: 0.0 }, null, 1, Sine.easeInOut);
blink = BetweenAS3.serial(
BetweenAS3.tween(this, { alpha: 0.6 }, null, 1, Sine.easeInOut),
BetweenAS3.tween(this, { alpha: 1.0 }, null, 1, Sine.easeInOut)
);
fadeIn.onComplete = blink.play;
}
public function appear():void
{
blink.stopOnComplete = false;
blink.onComplete = null;
fadeIn.play();
}
public function disappear():void
{
blink.stopOnComplete = true;
blink.onComplete = fadeOut.play;
}
}