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

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

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

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

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

// 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();
	}
	
}