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

forked from: エクストリーム・ソリティア

エクストリーム・ソリティア
あそびかた
[Enter]キーでゲームを始めると山札のカードを自動的にめくって
どんどん場に下ろしたり右上に移動したりします
・[↓]を押すと一時的に右上から場に下ろすモードになります
・[↑]を押すと右上にどんどん重ねていくモードに戻ります
・[スペース]を押すと全てをあきらめてカードを配りなおします
一分間で3回くらいクリアできるはず

細かい操作ができない上にあまり頭も良くないので
時々本来クリアできる配置がクリアできなかったりします
考えないで配りなおしてください

@author kaikoga
/**
 * Copyright dimcim ( http://wonderfl.net/user/dimcim )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/oxb7
 */

// forked from kaikoga's エクストリーム・ソリティア
// forked from kaikoga's 憑かれたようにゆとりソリティアを解き続ける何か
package {
    
    /*
     * エクストリーム・ソリティア
     * あそびかた
     * [Enter]キーでゲームを始めると山札のカードを自動的にめくって
     * どんどん場に下ろしたり右上に移動したりします
     * ・[↓]を押すと一時的に右上から場に下ろすモードになります
     * ・[↑]を押すと右上にどんどん重ねていくモードに戻ります
     * ・[スペース]を押すと全てをあきらめてカードを配りなおします
     * 一分間で3回くらいクリアできるはず
     * 
     * 細かい操作ができない上にあまり頭も良くないので
     * 時々本来クリアできる配置がクリアできなかったりします
     * 考えないで配りなおしてください
     * 
     * @author kaikoga
     */
    
    import com.bit101.components.Label;
    import com.bit101.components.PushButton;
    
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.net.navigateToURL;
    import flash.net.URLRequest;
    import flash.ui.Keyboard;
    import flash.utils.escapeMultiByte;
    
    public class ExtremeSolitaire extends Sprite {
        
        private var solitaire:Solitaire;
        private var shardsLayer:ShardsLayer;
        private var startButton:PushButton;
        private var directionButton:PushButton;
        private var dealButton:PushButton;
        private var tweetButton:PushButton;
        private var timeLabel:Label;
        private var scoreLabel:Label;
        private var helpLabel:Label;
        
        private var gameRunning:Boolean = false;
        
        private var frame:int = 0;
        private var _time:int = 0;
        public function get time():int {
            return this._time;
        }
        public function set time(value:int):void {
            if (this._time != value) this.timeLabel.text = "Time: " + value;
            this._time = value;
        }
        private var _score:int = 0;
        public function get score():int {
            return this._score;
        }
        public function set score(value:int):void {
            if (this._score != value) this.scoreLabel.text = "Score: " + value;
            this._score = value;
        }
        
        private var _direction:Boolean = true;
        public function get direction():Boolean {
            return this._direction;
        }
        public function set direction(value:Boolean):void {
            if (this._direction != value) this.directionButton.label = value ? "^ Up ^" : "v Down v";
            this._direction = value;
            this.solitaire.direction = value;
        }
        
        public function ExtremeSolitaire() {
            this.startButton = new PushButton(this, 5, 5, "Start");
            this.startButton.addEventListener(MouseEvent.CLICK, this.onClickStart);
            this.directionButton = new PushButton(this, 230, 5, "^ up ^");
            this.directionButton.addEventListener(MouseEvent.CLICK, this.onClickDirection);
            this.dealButton = new PushButton(this, 120, 5, "Deal Cards");
            this.dealButton.addEventListener(MouseEvent.MOUSE_DOWN, this.onDealMouseDown);
            this.dealButton.addEventListener(MouseEvent.MOUSE_UP, this.onDealMouseUp);
            this.tweetButton = new PushButton(this, 360, 5, "Send to twitter");
            this.tweetButton.addEventListener(MouseEvent.CLICK, this.onClickTwitter);
            this.tweetButton.visible = false;
            this.timeLabel = new Label(this, 300, 25, "Time: 0");
            this.scoreLabel = new Label(this, 400, 25, "Score: 0");
            this.solitaire = new Solitaire();
            this.shardsLayer = new ShardsLayer(this.stage.stageWidth, this.stage.stageHeight);
            this.addChild(this.solitaire);
            this.addChild(this.shardsLayer);
            this.solitaire.reset();
            this.solitaire.addEventListener(Event.COMPLETE, this.onSolitaireComplete);
            this.helpLabel = new Label(this, 10, 380, "<keyboard controls>\nenter: [Start] or [Abort] game\nup: [Up] to foundation\ndown: [Down] to tableau\nspace: [Deal Cards] and resume");
            this.stage.addEventListener(KeyboardEvent.KEY_DOWN, this.onKeyDown);
            this.stage.addEventListener(KeyboardEvent.KEY_UP, this.onKeyUp);
        }
        
        private function onKeyDown(event:KeyboardEvent):void {
            switch (event.keyCode) {
                case Keyboard.ENTER:
                this.startGame();
                break;
                case Keyboard.SPACE:
                this.resetSolitaire();
                break;
                case Keyboard.DOWN:
                this.direction = false;
                break;
                case Keyboard.UP:
                this.direction = true;
                break;
            }
        }
        
        private function onKeyUp(event:KeyboardEvent):void {
            switch (event.keyCode) {
                case Keyboard.SPACE:
                this.restartSolitaire();
                break;
            }
        }
        
        private function onEnterFrame(event:Event):void {
            if (--this.frame <= 0) {
                this.frame = 30;
                if (this.time-- <= 0) {
                    this.startGame();
                }
            }
        }
        
        private function onClickStart(event:MouseEvent):void {
            this.startGame();
        }
        
        private function onClickDirection(event:MouseEvent):void {
            this.direction = !this.direction;
        }
        
        private function onClickTwitter(event:MouseEvent):void {
            var url: String = "http://twitter.com/home/?status=" + escapeMultiByte("ツールの力を借りて、ソリティアを一分間で") + this.score + escapeMultiByte("回クリアしました。 http://wonderfl.net/c/c5gn #ExtremeSolitaire");
            navigateToURL(new URLRequest(url), "_blank");
         }
        
        private function onDealMouseDown(event:MouseEvent):void {
            this.resetSolitaire();
        }
        private function onDealMouseUp(event:MouseEvent):void {
            this.restartSolitaire();
        }
        
        private function onSolitaireComplete(event:Event):void {
            this.score++;
            this.resetSolitaire();
            this.restartSolitaire();
        }
        
        private function startGame():void {
            if (!this.gameRunning) {
                this.tweetButton.visible = false;
                this.startButton.label = "Abort";
                this.gameRunning = true;
                this.helpLabel.visible = false;
                this.solitaire.reset();
                this.solitaire.isRunning = true;
                this.time = 60;
                this.score = 0;
                this.addEventListener(Event.ENTER_FRAME, this.onEnterFrame);
            } else {
                this.tweetButton.visible = this.time < 0;
                this.startButton.label = "Start";
                this.gameRunning = false;
                this.solitaire.isRunning = false;
                this.removeEventListener(Event.ENTER_FRAME, this.onEnterFrame);
            }
        }
        
        private function resetSolitaire():void {
            if ((this.gameRunning && this.solitaire.isRunning) || this.solitaire.cleared) {
                this.shardsLayer.capture(this.solitaire);
                this.solitaire.reset();
                this.solitaire.isRunning = false;
                this.direction = true;
            }
        }
        
        private function restartSolitaire():void {
            if (this.gameRunning) {
                this.solitaire.isRunning = true;
            }
        }
        
    }
    
}

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Graphics;
import flash.display.IBitmapDrawable;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
import flash.geom.Matrix;
import flash.system.Capabilities;
import flash.text.TextField;
import flash.text.TextFormat;
//import net.kaikoga.sampler.StackTraceSampler;

class ShardsLayer extends Sprite {
    
    private var gridWidth:int;
    private var gridHeight:int;
    
    private var shards:Array;
    
    private static const GRIDS_X:int = 10;
    private static const GRIDS_Y:int = 10;
    
    public function ShardsLayer(gridWidth:int, gridHeight:int) {
        this.gridWidth = gridWidth / GRIDS_X;
        this.gridHeight = gridHeight / GRIDS_Y;
        this.shards = [];
        for (var i:int = 0; i < 10; i++) {
            var array:Array = [];
            for (var j:int = 0; j < 10; j++) {
                var shard:Shard = new Shard(this.gridWidth, this.gridHeight);
                this.addChild(shard);
                array[j] = shard;
            }
            this.shards[i] = array;
        }
    }
    
    public function capture(target:IBitmapDrawable):void {
        for (var i:int = 0; i < GRIDS_X; i++) {
            for (var j:int = 0; j < GRIDS_Y; j++) {
                var shard:Shard = this.shards[i][j];
                shard.capture(target, i * this.gridWidth, j * this.gridHeight);
            }
        }
    }
    
    
}

class Shard extends Bitmap {
    
    private var matrix:Matrix;
    private var dx:Number;
    private var dy:Number;
    private var dr:Number;
    private var ds:Number;
    private var life:int = 0;
    
    public function Shard(width:int, height:int) {
        super(new BitmapData(width, height, true, 0x00000000));
        this.matrix = new Matrix();
        this.addEventListener(Event.ENTER_FRAME, this.onEnterFrame);
    }
    
    private static var workRect:Rectangle = new Rectangle();
    private static var workMatrix:Matrix = new Matrix();
    private static var workColorTransform:ColorTransform = new ColorTransform(1, 1, 1, 0.5);
    public function capture(target:IBitmapDrawable, x:Number, y:Number):void {
        workRect.width = this.bitmapData.width;
        workRect.height = this.bitmapData.height;
        this.bitmapData.fillRect(workRect, 0x00000000);
        workMatrix.tx = -x;
        workMatrix.ty = -y;
        this.bitmapData.draw(target, workMatrix, workColorTransform);
        this.matrix.a = 1;
        this.matrix.b = 0;
        this.matrix.c = 0;
        this.matrix.d = 1;
        this.matrix.tx = x;
        this.matrix.ty = y;
        this.transform.matrix = this.matrix;
        this.dx = Math.random() * 20 - 10;
        this.dy = Math.random() * 20 - 10;
        this.dr = Math.random() - 0.2;
        this.ds = 0.9 + Math.random() / 20;
        this.life = 100;
        this.visible = true;
    }
    
    private function onEnterFrame(event:Event):void {
        if (this.life > 0) {
            var tx:int = this.matrix.tx + this.dx;
            var ty:int = this.matrix.ty + this.dy;
            this.dy += 1;
            this.matrix.rotate(this.dr);
            this.matrix.scale(this.ds, this.ds);
            this.matrix.tx = tx;
            this.matrix.ty = ty;
            this.transform.matrix = matrix;
            if (--this.life <= 0) {
                this.visible = false;
            }
        }
    }

}

class Solitaire extends Sprite {
    
    private var deck:CardPile;
    private var trash:CardPile;
    private var floatingLayer:FloatingLayer;
    
    private var columns:Vector.<CardPile>;
    private var goals:Vector.<CardPile>;
    
    public var direction:Boolean = true;
    public var cleared:Boolean = true;
    
    private static const UPPER_Y:int = 60;
    private static const LOWER_Y:int = 160;
    private static const PILE_DY:int = -1;
    
    private var _isRunning:Boolean = false;
    public function get isRunning():Boolean {
        return this._isRunning;
    }
    public function set isRunning(value:Boolean):void {
        if (!this.isRunning && value) {
            this.addEventListener(Event.ENTER_FRAME, this.onEnterFrame);
        } else if (this.isRunning && !value) {
            this.removeEventListener(Event.ENTER_FRAME, this.onEnterFrame);
        }
        this._isRunning = value;
    }
    
    private function createFloatingLayer():void {
        this.floatingLayer = new FloatingLayer();
    }
    private function createDeck():void {
        var result:CardPile = new CardPile(this.floatingLayer, 20, UPPER_Y, 0, PILE_DY, true);
        for (var num:int = 1; num <= 13; num++) {
            for (var suit:int = 0; suit < 4; suit++) {
                result.$addChild(new Card(num, suit, false, 0, 0));
            }
        }
        result.shuffle();
        this.addChild(result);
        this.deck = result;
    }
    private function createTrash():void {
        var result:CardPile = new CardPile(this.floatingLayer, 90, UPPER_Y, 0, PILE_DY, true);
        this.addChild(result);
        this.trash = result;
    }
    private function createColumns():void {
        var result:Vector.<CardPile> = new Vector.<CardPile>();
        for (var i:int = 0; i < 7; i++) {
            var column:CardPile = new CardPile(this.floatingLayer, i*65 + 5, LOWER_Y, 0, 18, true);
            result.push(column);
            for (var j:int = i; j >= 0; j--) {
                var card:Card = this.deck.removeTop();
                card.isFaceUp = (j == 0);
                column.addChild(card);
            }
            this.addChild(column);
        }
        this.columns = result;
    }
    private function createGoals():void {
        var result:Vector.<CardPile> = new Vector.<CardPile>();
        for (var i:int = 0; i < 4; i++) {
            var goal:CardPile = new CardPile(this.floatingLayer, 180+i*70, UPPER_Y, 0, PILE_DY, true);
            result.push(goal);
            this.addChild(goal);
        }
        this.goals = result;
    }
    
    public function Solitaire() {
        super();
    }
    
    public function reset():void {
        //StackTraceSampler.clear();
        this.isRunning = false;
        this.cleared = false;
        while (this.numChildren > 0) {
            this.removeChildAt(0);
        }
        this.createFloatingLayer();
        this.createDeck();
        this.createTrash();
        this.createColumns();
        this.createGoals();
        this.addChild(this.floatingLayer);
    }
    
    private function goalsTryAccept(card:Card):Boolean {
        for each (var goal:CardPile in this.goals) {
            if (goal.isEmpty) {
                if (card.num == 1) {
                    goal.addChild(card);
                    return true;
                }
            } else {
                var goalTop:Card = goal.top;
                if (goalTop.suit == card.suit && goalTop.num == card.num - 1) {
                    goal.addChild(card);
                    return true;
                }
            }
        }
        return false;
    }
    
    private function columnsTryAccept(card:Card):Boolean {
        for each (var column:CardPile in this.columns) {
            if (column.isEmpty) {
                if (card.num == 13) {
                    column.addChild(card);
                    return true;
                }
            } else {
                var columnTop:Card = column.top;
                if (columnTop.color != card.color && columnTop.num == card.num + 1) {
                    column.addChild(card);
                    return true;
                }
            }
        }
        return false;
    }
    
    private function tryMoveColumns():void {
        for each (var column:CardPile in this.columns) {
            if (column.top && this.goalsTryAccept(column.top)) {
                if (column.top) {
                    //trace("/", column.top, "[" + column.numChildren + "]", column.describeSelf());
                    column.top.isFaceUp = true;
                }
            } else if (column.bottom && (!column.bottom.isFaceUp || column.bottom.num < 13)) {
                var faceUpBottom:Card = column.faceUpBottom;
                //StackTraceSampler.capture();
                if (!faceUpBottom) {
                    //trace(column.describeSelf());
                    //trace(StackTraceSampler.samples.toXMLString());
                    //throw new ArgumentError();
                }
                if (columnsTryAccept(faceUpBottom)) {
                    column.moveTo(CardPile(faceUpBottom.parent));
                }
                if (column.top) {
                    //trace("/", column.top, "[" + column.numChildren + "]", column.describeSelf());
                    column.top.isFaceUp = true;
                }
            }
        }
    }
    
    private function tryMoveGoals():void {
        for each (var goal:CardPile in this.goals) {
            if (goal.numChildren != 0 && this.columnsTryAccept(goal.top)) {
            }
        }
    }
    
    private function checkComplete():void {
        var count:int = 0;
        for each (var goal:CardPile in this.goals) {
            if (goal.numChildren == 13 && !goal.hasCardsFloating) {
                count++;
            }
        }
        if (count == 4 && this.isRunning) {
            this.cleared = true;
            this.isRunning = false;
            this.dispatchEvent(new Event(Event.COMPLETE))
        }
    }
    
    private function onEnterFrame(event:Event):void {
        /*
        trace(
                this.columns[0], "|",
                this.columns[1], "|",
                this.columns[2], "|",
                this.columns[3], "|",
                this.columns[4], "|",
                this.columns[5], "|",
                this.columns[6], "| |",
                this.goals[0], "|",
                this.goals[1], "|",
                this.goals[2], "|",
                this.goals[3], "|"
                );
        /**/
        if (this.deck.isEmpty) {
            //this.trash.dumpTo(this.deck, false);
            this.trash.dumpTo(this.deck, true);
        } else {
            var card:Card = this.deck.removeTop();
            card.isFaceUp = true;
            if (this.goalsTryAccept(card)) {
                return;
            }
            if (this.columnsTryAccept(card)) {
                return;
            }
            this.trash.$addChild(card);
        }
        if (this.direction) {
            this.tryMoveColumns();
        } else {
            this.tryMoveGoals();
        }
        this.checkComplete();
    }
    
}

class FloatingLayer extends Sprite {
    
    private var objects:Vector.<DisplayObject>;
    private var targets:Vector.<CardPile>;
    private var durations:Vector.<int>;
    
    public function FloatingLayer() {
        super();
        this.objects = new Vector.<DisplayObject>();
        this.targets = new Vector.<CardPile>();
        this.durations = new Vector.<int>();
        this.addEventListener(Event.ADDED_TO_STAGE, this.onAddedToStage);
        this.addEventListener(Event.REMOVED_FROM_STAGE, this.onRemovedFromStage);
    }
    
    public function startFloat(target:CardPile, child:DisplayObject):DisplayObject {
        if (child.parent) {
            child.parent.removeChild(child);
        }
        this.objects.push(child);
        this.targets.push(target);
        this.durations.push(6);
        return super.addChild(child);
    }
    
    public function abortFloat(child:DisplayObject):DisplayObject {
        //StackTraceSampler.capture(child);
        var index:int = this.objects.indexOf(child);
        if (index >= 0) {
            this.objects.splice(index, 1);
            this.targets.splice(index, 1);
            this.durations.splice(index, 1);
        }
        return this.removeChild(child);
    }
    
    private function onAddedToStage(event:Event):void {
        this.addEventListener(Event.ENTER_FRAME, this.onEnterFrame);
    }
    private function onRemovedFromStage(event:Event):void {
        this.removeEventListener(Event.ENTER_FRAME, this.onEnterFrame);
    }
    private function onEnterFrame(event:Event):void {
        var c:int = this.objects.length;
        for (var i:int = 0; i < c; i++) {
            var object:DisplayObject = this.objects[i];
            var target:CardPile = this.targets[i];
            var duration:int = this.durations[i];
            if (this.hasChild(object)) {
                object.x = (object.x + target.x) / 2;
                object.y = (object.y + target.bottomY) / 2;
                duration = --this.durations[i];
            } else {
                duration = 0;
            }
            if (duration <= 0) {
                target.$addChild(object);
                this.objects.splice(i, 1);
                this.targets.splice(i, 1);
                this.durations.splice(i, 1);
                i--;
                c--;
            }
        }
    }
    
    public function hasChild(displayObject:DisplayObject):Boolean {
        try {
            this.getChildIndex(displayObject);
            return true;
        } catch (e:Error) {
            ;
        }
        return false;
    }
    
}

class CardPile extends Sprite {
    
    override public function toString():String {
        return (this.top || "<->") + "[" + super.numChildren + "+" + this.floatingChildren.length + "]";
        return (this.top || "<->") + "[" + super.numChildren + "+" + this.floatingChildren.length + "]";
    }
    public function describeSelf():String {
        var result:String = "";
        for (var i:int = 0; i < this.numChildren; i++) {
            result += this.getChildAt(i);
        }
        return result + "[" + super.numChildren + "+" + this.floatingChildren.length + "]";
    }
    private var floatingChildren:Vector.<DisplayObject>;
    private var floatingLayer:FloatingLayer;
    private var dx:Number = 0;
    private var dy:Number = 0;
    
    public function CardPile(floatingLayer:FloatingLayer, x:Number, y:Number, dx:Number, dy:Number, showBase:Boolean = false) {
        super();
        this.floatingChildren = new Vector.<DisplayObject>();
        this.floatingLayer = floatingLayer;
        this.x = x;
        this.y = y;
        this.dx = dx;
        this.dy = dy;
        if (showBase) {
            var g:Graphics = this.graphics;
            g.lineStyle(1, 0x999999);
            g.beginFill(0xeeeeee);
            g.drawRect(0, 0, 60 - 1, 80 - 1);
        }
    }
    
    public function get bottomY():Number {
        return this.y + this.dy * super.numChildren;
    } 
    public function get hasCardsFloating():Boolean {
        return this.floatingChildren.length > 0;
    }
    
    public function get isEmpty():Boolean {
        return this.numChildren == 0;
    }
    
    public function get top():Card {
        if (this.numChildren > 0) {
            return Card(this.getChildAt(this.numChildren - 1));
        }
        return null;
    }
        
    public function get bottom():Card {
        if (this.numChildren > 0) {
            return Card(this.getChildAt(0));
        }
        return null;
    }
        
    public function get faceUpBottom():Card {
        var result:Card;
        for (var index:int = this.numChildren - 1; index >= 0; index--) {
            var card:Card = Card(this.getChildAt(index));
            if (card.isFaceUp) {
                result = card;
            } else {
                break;
            } 
        }
        return result;
    }
        
    public function removeTop():Card {
        if (this.numChildren == 0) {
            return null;
        }
        return Card(this.removeChildAt(this.numChildren - 1));
    }
        
    public function dumpTo(target:CardPile, faceUp:Boolean = true):void {
        while (this.numChildren > 0) {
            var card:Card = this.removeTop();
            card.isFaceUp = faceUp;
            target.$addChild(card);
        }
    }
        
    public function moveTo(target:CardPile):void {
        var card:Card;
        do {
            card = this.faceUpBottom;
            if (card) {
                target.addChild(this.removeChild(card));
            }
        } while (card);
    }
    
    public function shuffle():void {
        if (this.numChildren < 2) {
            return;
        }
        for (var i:int = 1; i < this.numChildren; i++) {
            var j:int = Math.floor(Math.random() * (i + 1));
            if (i != j) {
                this.swapChildrenAt(i, j);
            }
        }
        this.refresh();
    }
    
    //override DisplayObjectContainer methods to encapsulate floatingChildren
    //some methods are not implemented, because they are not used...
    
    override public function get numChildren():int {
        return super.numChildren + this.floatingChildren.length;
    }
    
    override public function getChildAt(index:int):DisplayObject {
        var result:DisplayObject;
        if (index >= super.numChildren) {
            result = this.floatingChildren[index - super.numChildren];
        } else {
            result = super.getChildAt(index);
        }
        return result;
    }
        
    public final function $addChild(child:DisplayObject):DisplayObject {
        var result:DisplayObject = super.addChild(child);
        var index:int = this.floatingChildren.indexOf(child);
        if (index >= 0) {
            this.floatingChildren.splice(index, 1);
        }
        if (child is Card) {
            Card(child).parentPile = this;
        }
        //trace("$", child, "[" + super.getChildIndex(child) + "]", this.describeSelf());
        this.refresh();
        return result;
    }
    override public function addChild(child:DisplayObject):DisplayObject {
        //abortChild() will be called from removeChild() within startFloat()
        var result:DisplayObject = this.floatingLayer.startFloat(this, child);
        this.floatingChildren.push(result);
        if (child is Card) {
            Card(child).parentPile = this;
        }
        //trace(">", child, "[" + this.numChildren + "]", this.describeSelf());
        return result;
    }
        
    override public function removeChild(child:DisplayObject):DisplayObject {
        var result:DisplayObject;
        if (this.floatingLayer.hasChild(child)) {
            this.floatingChildren.splice(this.floatingChildren.indexOf(child), 1);
            result = this.floatingLayer.abortFloat(child);
        } else if (child.parent == this) {
            result = super.removeChild(child);
            result.x += this.x;
            result.y += this.y;
        } else {
            result = child;
        }
        if (child is Card) {
            Card(child).parentPile = null;
        }
        //trace("x", child, "[" + this.numChildren + "]", this.describeSelf());
        this.refresh();
        return result;
    }
        
    override public function removeChildAt(index:int):DisplayObject {
        var result:DisplayObject;
        if (index >= super.numChildren) {
            index -= super.numChildren;
            result = this.floatingChildren.splice(index, 1)[0];
            this.floatingLayer.abortFloat(result);
        } else {
            result = super.removeChildAt(index);
            result.x += this.x;
            result.y += this.y;
        }
        if (result is Card) {
            Card(result).parentPile = null;
        }
        this.refresh();
        return result;
    }
        
    private function refresh():void {
        var x:Number = 0;
        var y:Number = 0;
        var c:int = super.numChildren;
        for (var i:int = 0; i < c; i++) {
            var child:DisplayObject = super.getChildAt(i);
            child.x = x;
            child.y = y;
            x += this.dx;
            y += this.dy
        }
    }
    
}
        
class Card extends Bitmap {
    
    override public function toString():String {
        return (this._isFaceUp ? "+" : "-") + "shdc".charAt(this._suit) + "0A23456789TJQK".charAt( this._num);
    }
    
    public var parentPile:CardPile;
    override public function get parent():DisplayObjectContainer {
        return this.parentPile;
    }
    
    private var _suit:int = 0;
    public function get suit():int {
        return this._suit;
    }
    public function set suit(value:int):void {
        this._suit = value;
        this.refresh();
    }
        
    public function get color():uint {
        switch (this._suit) {
            case 1:
            case 2:
            return 0xffffff;
            break;
        }
        return 0x000000;
    }
        
    private var _num:int = 0;
    public function get num():int {
        return this._num;
    }
    public function set num(value:int):void {
        this._num = value;
        this.refresh();
    }
        
    private var _isFaceUp:Boolean = true;
    public function get isFaceUp():Boolean {
        return this._isFaceUp;
    }
    public function set isFaceUp(value:Boolean):void {
        this._isFaceUp = value;
        this.refresh();
    }
    private function refresh():void {
        this.bitmapData = CardBitmaps.instance.getCardBitmapData(this._num, this._suit, this._isFaceUp);
    }
        
    public function Card(num:int = 1, suit:int = 0, faceUp:Boolean = true, x:Number = 0, y:Number = 0) {
        super();
        this._suit = suit;
        this._num = num;
        this._isFaceUp = faceUp;
        this.x = x;
        this.y = y;
        this.refresh();
    }

}

class CardBitmaps {
    
    public static var instance:CardBitmaps = new CardBitmaps();
    
    private static function createTextField():TextField {
        var result:TextField = new TextField;
        result.width = 48;
        result.height = 20;
        return result;
    }
    private static function createTextFormat():TextFormat {
        var result:TextFormat = new TextFormat("_等幅", 16);
        result.bold = true;
        result.align = "center";
        return result;
    }
    private static var _textField:TextField = createTextField(); 
    private static var _textFormat:TextFormat = createTextFormat();
    private static var _workBitmapData:BitmapData = new BitmapData(48, 20, true, 0x00000000);
    private static var _matrix:Matrix = new Matrix();
    
    private function stamp(bitmapData:BitmapData, x:int, y:int, text:String, color:uint, norotate:Boolean = false):void {
        _textFormat.color = color;
        _textField.defaultTextFormat = _textFormat;
        _textField.text = text;
        _workBitmapData.fillRect(_workBitmapData.rect, 0x00000000);
        _workBitmapData.draw(_textField);
        if (y <= 40 || norotate) {
            _matrix.a = 1;
            _matrix.b = 0;
            _matrix.c = 0;
            _matrix.d = 1;
            _matrix.tx = x - (_workBitmapData.width >> 1);
            _matrix.ty = y - 10;
        } else {
            _matrix.a = -1;
            _matrix.b = 0;
            _matrix.c = 0;
            _matrix.d = -1;
            _matrix.tx = x + (_workBitmapData.width >> 1) - 1;
            _matrix.ty = y + 10 - 1;
        }
        _textFormat.color = color;
        _textField.defaultTextFormat = _textFormat;
        _textField.text = text;
        bitmapData.draw(_workBitmapData, _matrix);
    }
    
    private static const NUM_CHARS:Array = ["Joker","A","2","3","4","5","6","7","8","9","10","J","Q","K"];
    private static const SUIT_CHARS:Array = ["♠", "♥", "♦", "♣"];
    private static const SUIT_COLORS:Array = [0x000000, 0x990000, 0x990000, 0x000000];
    private var _faceDownBitmapData:BitmapData;
    private var _bitmaps:Array = [];
    public function getCardBitmapData(num:int, suit:int = 0, faceUp:Boolean = true):BitmapData {
        if (!faceUp) {
            if (!_faceDownBitmapData) {
                _faceDownBitmapData = new BitmapData(60, 80, false, 0x000000);
                _faceDownBitmapData.fillRect(new Rectangle(1, 1, 58, 78), 0x33ffcc);
            }
            return _faceDownBitmapData;
        }
        suit &= 3;
        var array:Array = this._bitmaps[suit];
        if (!array) {
            array = [];
            this._bitmaps[suit] = array;
        }
        var result:BitmapData = array[num];
        if (!result) {
            result = new BitmapData(60, 80, false, 0x336633);
            result.fillRect(new Rectangle(1, 1, 58, 78), 0xffffff);
            var char:String = SUIT_CHARS[suit];
            var color:uint = SUIT_COLORS[suit];
            if (num >= 1 && num <= 13) {
                this.stamp(result, 10, 10, NUM_CHARS[num], color);
                this.stamp(result, 10, 25, char, color);
            } else {
                color = 0x000000;
            }
            switch (num) {
                case 1:
                this.stamp(result, 30, 40, char, color);
                break;
                case 2:
                this.stamp(result, 30, 24, char, color);
                this.stamp(result, 30, 56, char, color);
                break;
                case 3:
                this.stamp(result, 30, 16, char, color);
                this.stamp(result, 30, 40, char, color);
                this.stamp(result, 30, 64, char, color);
                break;
                case 4:
                this.stamp(result, 20, 16, char, color);
                this.stamp(result, 40, 16, char, color);
                this.stamp(result, 20, 64, char, color);
                this.stamp(result, 40, 64, char, color);
                break;
                case 5:
                this.stamp(result, 20, 16, char, color);
                this.stamp(result, 40, 16, char, color);
                this.stamp(result, 30, 40, char, color);
                this.stamp(result, 20, 64, char, color);
                this.stamp(result, 40, 64, char, color);
                break;
                case 6:
                this.stamp(result, 20, 16, char, color);
                this.stamp(result, 40, 16, char, color);
                this.stamp(result, 20, 40, char, color);
                this.stamp(result, 40, 40, char, color);
                this.stamp(result, 20, 64, char, color);
                this.stamp(result, 40, 64, char, color);
                break;
                case 7:
                this.stamp(result, 20, 16, char, color);
                this.stamp(result, 40, 16, char, color);
                this.stamp(result, 30, 32, char, color);
                this.stamp(result, 20, 40, char, color);
                this.stamp(result, 40, 40, char, color);
                this.stamp(result, 20, 64, char, color);
                this.stamp(result, 40, 64, char, color);
                break;
                case 8:
                this.stamp(result, 20, 16, char, color);
                this.stamp(result, 40, 16, char, color);
                this.stamp(result, 20, 32, char, color);
                this.stamp(result, 40, 32, char, color);
                this.stamp(result, 20, 48, char, color);
                this.stamp(result, 40, 48, char, color);
                this.stamp(result, 20, 64, char, color);
                this.stamp(result, 40, 64, char, color);
                break;
                case 9:
                this.stamp(result, 20, 16, char, color);
                this.stamp(result, 40, 16, char, color);
                this.stamp(result, 20, 32, char, color);
                this.stamp(result, 40, 32, char, color);
                this.stamp(result, 30, 40, char, color);
                this.stamp(result, 20, 48, char, color);
                this.stamp(result, 40, 48, char, color);
                this.stamp(result, 20, 64, char, color);
                this.stamp(result, 40, 64, char, color);
                break;
                case 10:
                this.stamp(result, 20, 16, char, color);
                this.stamp(result, 40, 16, char, color);
                this.stamp(result, 30, 24, char, color);
                this.stamp(result, 20, 32, char, color);
                this.stamp(result, 40, 32, char, color);
                this.stamp(result, 20, 48, char, color);
                this.stamp(result, 40, 48, char, color);
                this.stamp(result, 30, 56, char, color);
                this.stamp(result, 20, 64, char, color);
                this.stamp(result, 40, 64, char, color);
                break;
                case 11:
                this.stamp(result, 30, 20, char, color);
                this.stamp(result, 30, 40, "JJJ", color, true);
                //this.stamp(result, 30, 40, "(゚Д゚,,)", color, true);
                this.stamp(result, 30, 60, char, color);
                break;
                case 12:
                this.stamp(result, 30, 20, char, color);
                this.stamp(result, 30, 40, "QQQ", color, true);
                //this.stamp(result, 30, 40, "(゚ー゚*)", color, true);
                this.stamp(result, 30, 60, char, color);
                break;
                case 13:
                this.stamp(result, 30, 20, char, color);
                this.stamp(result, 30, 40, "KKK", color, true);
                //this.stamp(result, 30, 40, "(´∀` )", color, true);
                this.stamp(result, 30, 60, char, color);
                break;
                default:
                this.stamp(result, 30, 30, "Joker", color, true);
                //this.stamp(result, 30, 50, "(・∀・ )", color, true);
                break;
            }
            array[num] = result;
        }
        return result;
    }
    
    public function CardBitmaps() {
        super();
    }
    
}