In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

'15 puzzle'にコメントを付けてみました

photo: Ville Miettinen's Grundvik main house
http://www.flickr.com/photos/wili/214317898/
コメントを付けたり、関数をまとめたりしながら勉強させてもらっています
/**
 * Copyright ongaeshi ( http://wonderfl.net/user/ongaeshi )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/29bH
 */

// forked from 5ivestar's forked from: 15 puzzle
// forked from flashrod's 15 puzzle
// photo: Ville Miettinen's Grundvik main house
// http://www.flickr.com/photos/wili/214317898/

// コメントを付けたり、関数をまとめたりしながら勉強させてもらっています

package {
    import flash.display.Sprite;
    import flash.display.Loader;
    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    import caurina.transitions.Tweener;
    public class Fifteen extends Sprite {
        // 画像サイズ(渡された画像が大きかったり小さかった場合は、圧縮をかけてこのサイズにする)
	private static const W:int = 465;
	private static const H:int = 465;

        // ピースサイズ
	private static const U:int = int(W/4);
	private static const V:int = int(H/4);
        
        // ボード情報
	private var board:Array = [];
        
        // ローダー
	private var loader:Loader;

        // コンストラクタ
        // 
        // Webから画像を読み込む
        // 画像読み込みにはそれなりに制約があり、単純にURLを変えても絵が変わらない
        // 
        // Loader ... ロードする人
        // LoaderContext ... ロード時のオプション設定等
        // Loader.contentLoaderInfo ... ロードの進行状況に関する情報と、ロードされたファイルに関する統計
        // URLRequest ... URL処理
	public function Fifteen() {
	    loader = new Loader();
	    var context:LoaderContext = new LoaderContext(true);
	    loader.contentLoaderInfo.addEventListener("complete", loadingComplete);
	    loader.load(new URLRequest("http://farm1.static.flickr.com/57/214317898_596c96ecb6.jpg"), context);
	}

        // ロード完了後に呼び出されるコールバック
        //
	public function loadingComplete(e:Event):void {
            // 大元の一枚絵
	    var source:BitmapData = new BitmapData(W, H, false);

            // 画像のスケーリング
            scalePicture(source);

            // ピースの生成
            createPiece(source);

            // 適当な回数パネルを動かし、画像がグチャグチャになった状態から始める
            shuffle(0);
            
            // マウスがクリックされた時に、スライドさせるためのコールバック
	    stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
		    shift(e.stageX/U, e.stageY/V);
		    repaint();
		});

            // 再描画
	    repaint();
 	}

        // 画像のスケール調整
        // 
        // 色々な方法があると思うが、ここでは画像のアスペクト比を維持しながら、
        // 余白を作らない方法でスケーリングしている。
        //
        // MaxOSXの言葉で言うと、'Aspect Fill'
        // Aspect Fill以外の例もいくつか挙げておく
        //
        private function scalePicture(source:BitmapData):void {
            // 目標画像サイズ / 元画像サイズ
	    var sx:Number = W / loader.width;
	    var sy:Number = H / loader.height;

            // 一枚絵の生成
            //
            // Matrixは a, b, c, d, tx, ty の順番であることに注意、行列で書くと・・・
            // [a, b, tx]
            // [c, d, ty]
            // えー。
            var mtx:Matrix;

            // 行列を使ってスケール調整

            // Aspect Fill
 	    if (sx > sy) {
                 // [sx,  0, 0]
                 // [ 0, sx, (H - loader.height * sx) / 2)]
                 mtx = new Matrix(sx, 0, 0, sx, 0, (H - loader.height * sx) / 2);
 		source.draw(loader, mtx, null, null, null, true);

 	    } else {
                 // [sy,  0, (W - loader.width * sy) / 2]
                 // [ 0, sy, 0]
                 mtx = new Matrix(sy, 0, 0, sy, (W - loader.width * sy) / 2, 0);
 		source.draw(loader, mtx, null, null, null, true);
 	    }

/*
            // Scale To Fit
            mtx = new Matrix(sx, 0, 0, sy, 0, 0);
            source.draw(loader, mtx, null, null, null, true);
*/

/*
            // Aspect Fit
 	    if (sx > sy) {
                 mtx = new Matrix(sy, 0, 0, sy, 0, 0);
 		source.draw(loader, mtx, null, null, null, true);

 	    } else {
                mtx = new Matrix(sx, 0, 0, sx, 0, 0);
 		source.draw(loader, mtx, null, null, null, true);
 	    }
*/
        }

        // パネルの生成
        private function createPiece(source:BitmapData):void {
	    for (var k:int = 1; k < 17; ++k) {
		var p:Piece = new Piece(k, source);
		addChild(p);
		board.push(p);
	    }
        }

        // シャッフル
        private function shuffle(num:int):void {
	    var i:int, j:int = 3;

	    for (var k:int = 0; k < num; ++k) {
		i = int(Math.random()*3);
		shift(i, j);
		j = int(Math.random()*3);
		shift(i, j);
	    }

        }
        
        // パネルの移動処理
	private function shift(x:int, y:int):void {
	    if (x>=0 && x<4 && y>=0 && y<4) {
                // 横方向へのスライド処理
		for (var i:int = 0; i < 4; ++i) {
		    var p:Piece = getPiece(i, y);
		    if (p.value == 16) {
			for (; i>x; --i) setPiece(i, y, getPiece(i - 1, y));
			for (; i<x; ++i) setPiece(i, y, getPiece(i + 1, y));
                        setPiece(x, y, p);
			return;
		    }
		}

                // 縦方向へのスライド処理
		for (var j:int = 0; j<4; ++j) {
		    p = getPiece(x, j);
		    if (p.value == 16) {
			for (; j>y; --j) setPiece(x, j, getPiece(x, j - 1));
			for (; j<y; ++j) setPiece(x, j, getPiece(x, j + 1));
                        setPiece(x, y, p);
			return;
		    }
		}
	    }
	}

        private function setPiece(x:int, y:int, p:Piece):void {
            board[y*4+x] = p;
        }

        private function getPiece(x:int, y:int):Piece {
            return board[y*4+x];
        }

        // 再描画
	private function repaint():void {
	    for (var j:int = 0; j < 4; ++j) {
		for (var i:int = 0; i < 4; ++i) {
		    var p:Piece = board[j*4+i];
                    // こっちだとダイレクト移動
		    // p.x = i*U;
		    // p.y = j*V;
                    
                    // こっちだと補完付き移動
		    Tweener.addTween(p, {x:i*U, y:j*V, time:0.1, transition:"easeOutQuad"});
		}
	    }
	}
    }
}

import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;

// 15パズルにおける、一つのピースを表す
class Piece extends Sprite {
    public var value:int;

    // コンストラクタ
    // 
    // @param value 大元の絵を16分割した際、何番目のピースかを表すインデックス(1〜16)
    // @param source 大元の一枚絵
    public function Piece(value:int, source:BitmapData) {
	this.value = value;

        // 16は空の意味、ビットマップは作成しない
	if (value == 16) return;

        // このピース用のビットマップのサイズ
	var w:Number = source.width / 4;
	var h:Number = source.height / 4;
        
        // このピース用のビットマップ
	var bitmap:BitmapData = new BitmapData(w, h, false);

        // 切り取り用の矩形
        // 1〜15のインデックスに対して、切り取り開始位置を決定
	var rect:Rectangle = new Rectangle((value-1)%4*w, Math.floor(value/4)*h, w, h);

        // ビットマップを作成!!
	bitmap.copyPixels(source, rect, new Point());

        // 自身の子供に、作成したビットマップを接続
	addChild(new Bitmap(bitmap));
    }
}