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

Neural Network BlackJack Trainer

Dealer - No learn. stand on soft 17.
Player - learn. 
if output >0.5 (hit), else (stand).

number of inputNeuron is 38(no biased one).
It's for input of my score(2~20) and dealer score(2~20).
number of hiddenNeuron is 6(5 + biased one).
number of outputNeuron is only one. It's for hit/stand.
/**
 * Copyright greentec ( http://wonderfl.net/user/greentec )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/xOgx
 */

package {
    
    import com.bit101.charts.LineChart;
    import com.bit101.components.Label;
    import com.bit101.components.PushButton;
    import com.bit101.components.Style;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.ColorTransform;
    import flash.geom.Matrix;
    import flash.utils.ByteArray;
    import flash.display.Sprite;
    
    
    public class FlashTest extends Sprite {
        
        public var _backBitmap:Bitmap;
        public var playerHand:Array = [];
        public var dealerHand:Array = [];
        public static const blackJack:int = 21;
        public static const dealerStandPoint:int = 17;
        public var cardArray:Array = ["SA", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "SJ", "SQ", "SK",
                                      "DA", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10", "DJ", "DQ", "DK",
                                      "HA", "H2", "H3", "H4", "H5", "H6", "H7", "H8", "H9", "H10", "HJ", "HQ", "HK",
                                      "CA", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "CJ", "CQ", "CK"];
        //public var originalCard:Array = [];
        public var nowCard:Array;
        public static const initHandNum:int = 2;
        
        public var inputNeuronNum:int = 38;
        public var hiddenNeuronNum:int = 5;
        public var outputNeuronNum:int = 1;
        
        public var inputLayer:Layer;
        public var hiddenLayer:Layer;
        public var outputLayer:Layer;
        
        
        public var learnRate:Number = 0.25;
        public var _alpha:Number = 0.9; //for momentum
        public var beta:Number;
        
        public var playerWinGameNum:int = 0;
        public var totalGameNum:int = 0;
        
        public var winPercentLabel:Label;
        public var errorChart:LineChart;
        
        public var lineShape:Shape;
        public var cardShape:Shape;
        
        public var spadeShape:Shape;
        public var diamondShape:Shape;
        public var heartShape:Shape;
        public var cloverShape:Shape;
        
        public var dealerNumberLabelArray:Array;
        public var playerNumberLabelArray:Array;
        public var cardNumberRed:ColorTransform;
        public var cardNumberBlack:ColorTransform;
        public var labelWhite:ColorTransform;
        
        public var cardBitmap:Bitmap;
        public var cardBitmapData:BitmapData;
        
        public var mat:Matrix;
        
        public var pauseButton:PushButton;
        public var makeTurnButton:PushButton;
        
        public var dealerStatusLabel:Label;
        public var playerStatusLabel:Label;
        
        public function FlashTest() {
            // write as3 code here..
            stage.scaleMode = "noScale";
            
            
            var i:int;
            
            labelWhite = new ColorTransform();
            labelWhite.color = 0xCCCCCC;
            //cardNumberLabel = new Label(this, 0, 0, "");
            //cardNumberLabel.scaleX = cardNumberLabel.scaleY = 2;
            cardNumberRed = new ColorTransform();
            cardNumberRed.color = 0xa5091e;
            cardNumberBlack = new ColorTransform();
            cardNumberBlack.color = 0x000000;
            
            _backBitmap = new Bitmap(new BitmapData(465, 465, false, 0x185e3a));
            var goldRect:Shape = new Shape();
            goldRect.graphics.lineStyle(1, 0xf7b519);
            goldRect.graphics.drawRoundRect(20, 20, 465 - 40, 465 - 40, 20, 20);
            goldRect.graphics.drawRoundRect(15, 15, 465 - 30, 465 - 30, 30, 30);
            _backBitmap.bitmapData.draw(goldRect);
            addChild(_backBitmap);
            
            lineShape = new Shape();
            addChild(lineShape);
            
            var _label:Label = new Label(this, 30, 30, "Dealer");
            _label.transform.colorTransform = labelWhite;
            dealerStatusLabel = new Label(this, 100, 30, "");
            dealerStatusLabel.transform.colorTransform = labelWhite;
            _label = new Label(this, 30, 465 / 3 - 10, "Player");
            _label.transform.colorTransform = labelWhite;
            playerStatusLabel = new Label(this, 100, _label.y, "");
            playerStatusLabel.transform.colorTransform = labelWhite;
            
            cardShape = new Shape();
            cardShape.graphics.lineStyle(1, 0);
            cardShape.graphics.beginFill(0);
            cardShape.graphics.drawRoundRect(0, 0, 70, 94, 15, 15);
            cardShape.graphics.beginFill(0xffffff);
            cardShape.graphics.drawRoundRect(0, 0, 68, 93, 15, 15);
            //cardShape.y = 45;
            //cardShape.x = 30;
            //addChild(cardShape);
            
            spadeShape = new Shape();
            spadeShape.graphics.lineStyle(1, 0x404b51);
            spadeShape.graphics.beginFill(0);
            //spadeShape.graphics.moveTo(12, 0);
            //spadeShape.graphics.lineTo(3, 18);
            //spadeShape.graphics.lineTo(12, 18);
            //spadeShape.graphics.lineTo(8, 24);
            //spadeShape.graphics.lineTo(16, 24);
            //spadeShape.graphics.lineTo(12, 18);
            //spadeShape.graphics.lineTo(21, 18);
            //spadeShape.graphics.lineTo(12, 0);
            //spadeShape.graphics.endFill();
            
            spadeShape.graphics.moveTo(12, 0);
            spadeShape.graphics.lineTo(3, 16);
            spadeShape.graphics.lineTo(8, 20);
            spadeShape.graphics.lineTo(12, 16);
            spadeShape.graphics.lineTo(10, 24);
            spadeShape.graphics.lineTo(14, 24);
            spadeShape.graphics.lineTo(12, 16);
            spadeShape.graphics.lineTo(16, 20);
            spadeShape.graphics.lineTo(21, 16);
            spadeShape.graphics.lineTo(12, 0);
            spadeShape.graphics.endFill();
            //spadeShape.x = 30;
            //spadeShape.y = 45;
            //addChild(spadeShape);
            
            diamondShape = new Shape();
            diamondShape.graphics.lineStyle(1, 0xc24117);
            diamondShape.graphics.beginFill(0xa5091e);
            diamondShape.graphics.moveTo(12, 0);
            diamondShape.graphics.lineTo(6, 12);
            diamondShape.graphics.lineTo(12, 24);
            diamondShape.graphics.lineTo(18, 12);
            diamondShape.graphics.lineTo(12, 0);
            diamondShape.graphics.endFill();
            //diamondShape.x = 30;
            //diamondShape.y = 45;
            //addChild(diamondShape);
            
            heartShape = new Shape();
            heartShape.graphics.lineStyle(1, 0xc24117);
            heartShape.graphics.beginFill(0xa5091e);
            heartShape.graphics.moveTo(12, 24);
            heartShape.graphics.lineTo(3, 8);
            heartShape.graphics.lineTo(8, 4);
            heartShape.graphics.lineTo(12, 8);
            heartShape.graphics.lineTo(16, 4);
            heartShape.graphics.lineTo(21, 8);
            heartShape.graphics.lineTo(12, 24);
            heartShape.graphics.endFill();
            //heartShape.x = 30;
            //heartShape.y = 45;
            //addChild(heartShape);
            
            cloverShape = new Shape();
            cloverShape.graphics.lineStyle(1, 0x404b51);
            cloverShape.graphics.beginFill(0);
            cloverShape.graphics.drawCircle(12, 7, 4);
            cloverShape.graphics.drawCircle(7, 14, 4);
            cloverShape.graphics.drawCircle(17, 14, 4);
            cloverShape.graphics.moveTo(12, 16);
            cloverShape.graphics.lineTo(8, 24);
            cloverShape.graphics.lineTo(16, 24);
            cloverShape.graphics.lineTo(12, 16);
            //cloverShape.x = 30;
            //cloverShape.y = 45;
            //addChild(cloverShape);
            
            
            
            cardBitmapData = new BitmapData(300, 300, true, 0x00ffffff);
            cardBitmap = new Bitmap(cardBitmapData);
            addChild(cardBitmap);
            
            errorChart = new LineChart(this, 30, 465 - 180);
            errorChart.height = 150;
            errorChart.data = [0];
            errorChart.lineColor = 0xff00ff;
            
            winPercentLabel = new Label(this, errorChart.x, errorChart.y - 20, "");
            winPercentLabel.transform.colorTransform = labelWhite;
            
            pauseButton = new PushButton(this, 465 - 100 - 40, 465 - 70, "Pause", onPause);
            pauseButton.toggle = true;
            makeTurnButton = new PushButton(this, pauseButton.x, pauseButton.y + pauseButton.height + 2, "Make Turn", onMakeTurn);
            makeTurnButton.enabled = false;
            
            dealerNumberLabelArray = [];
            for (i = 0; i < 11; i += 1)
            {
                _label = new Label(this, 0, 0, "");
                _label.x = 38 + i * 28;
                _label.y = 52;
                dealerNumberLabelArray.push(_label);
            }
            
            playerNumberLabelArray = [];
            for (i = 0; i < 11; i += 1)
            {
                _label = new Label(this, 0, 0, "");
                _label.x = 38 + i * 28;
                _label.y = 167;
                playerNumberLabelArray.push(_label);
            }
            
            initNeuron();
            initWeight();
            
            //initNewGame();
            
            addEventListener(Event.ENTER_FRAME, onLoop);
        }
        
        private function onMakeTurn(e:Event):void
        {
            onLoop();
        }
        
        private function onPause(e:Event):void
        {
            if (pauseButton.selected == true)
            {
                if (hasEventListener(Event.ENTER_FRAME) == true)
                {
                    removeEventListener(Event.ENTER_FRAME, onLoop);
                    pauseButton.label = "Resume";
                    makeTurnButton.enabled = true;
                }
            }
            else
            {
                if (hasEventListener(Event.ENTER_FRAME) == false)
                {
                    addEventListener(Event.ENTER_FRAME, onLoop);
                    pauseButton.label = "Pause";
                    makeTurnButton.enabled = false;
                }
            }
            
        }
        
        private function onLoop(e:Event=null):void
        {
            initNewGame();
            doGame();
            drawLine();
        }
        
        private function drawLine():void
        {
            var i:int, j:int;
            //graphic update
            var lineThick:Number;
            var lineColor:uint;
            
            lineShape.graphics.clear();
            for (i = 0; i < inputNeuronNum; i += 1)
            {
                for (j = 0; j < hiddenNeuronNum; j += 1)
                {
                    lineColor = inputLayer.neurons[i].w[j] >= 0 ? 0x2a80b9 : 0xa31605;
                    lineThick = Math.abs(inputLayer.neurons[i].w[j]);
                    lineThick = lineThick/10 > 3 ? 3 : ( lineThick < 0.1 ? 0.1 : lineThick/10 );
                    lineShape.graphics.lineStyle(lineThick, lineColor);
                    lineShape.graphics.moveTo(inputLayer.neurons[i].x, inputLayer.neurons[i].y);
                    lineShape.graphics.lineTo(hiddenLayer.neurons[j].x, hiddenLayer.neurons[j].y);
                }
            }
            
            for (i = 0; i < hiddenNeuronNum + 1; i += 1)
            {
                for (j = 0; j < outputNeuronNum; j += 1)
                {
                    lineColor = hiddenLayer.neurons[i].w[j] >= 0 ? 0x2a80b9 : 0xa31605;
                    lineThick = Math.abs(hiddenLayer.neurons[i].w[j]);
                    lineThick = lineThick/10 > 3 ? 3 : ( lineThick < 0.1 ? 0.1 : lineThick/10 );
                    lineShape.graphics.lineStyle(lineThick, lineColor);
                    lineShape.graphics.moveTo(hiddenLayer.neurons[i].x, hiddenLayer.neurons[i].y);
                    lineShape.graphics.lineTo(outputLayer.neurons[j].x, outputLayer.neurons[j].y);
                }
            }
        }
        
        private function doGame():void
        {
            var playerWin:Boolean = false;
            var dealerWin:Boolean = false;
            var playerLose:Boolean = false;
            var dealerLose:Boolean = false;
            var gamedraw:Boolean = false;
            var gameEnd:Boolean = false;
            var turnCount:int = 0;
            var playerPoint:Array = [];
            var dealerPoint:Array = [];
            var playerPointMax:int;
            var dealerPointMax:int;
            var playerPosition:String = "";
            var dealerPosition:String = "";
            var playRecord:Array = [];
            var oneTurnRecord:Array = [];
            //var playerInputArray:Array;
            var i:int;
            var j:int;
            var k:int;
            var str:String;
            var len:int;
            var end:int;
            var sumError:Number = 0;
            
            while (gameEnd == false && playerWin == false && dealerWin == false && playerLose == false && dealerLose == false && gamedraw == false) //until whoever win or lose
            {
                turnCount += 1;
                
                //dealer Turn
                    //Point calc.
                dealerPoint = [0];
                dealerPointMax = -1;
                
                for (i = 0; i < dealerHand.length; i += 1)
                {
                    str = dealerHand[i].substr(1, dealerHand[i].length - 1);
                    if (str == "J" || str == "Q" || str == "K")
                    {
                        for (j = 0; j < dealerPoint.length; j += 1)
                        {
                            dealerPoint[j] += 10;
                        }
                        
                    }
                    else if (str == "A")
                    {
                        len = dealerPoint.length;
                        for (j = 0; j < len; j += 1)
                        {
                            dealerPoint[j] += 1; //first Ace +1
                            dealerPoint.push(clone(dealerPoint[j])); //get double.. for all number of cases
                        }
                        for (j = len; j < dealerPoint.length; j += 1)
                        {
                            dealerPoint[j] += 10; //Ace +10. finally adding 11
                        }
                    }
                    else
                    {
                        for (j = 0; j < dealerPoint.length; j += 1)
                        {
                            dealerPoint[j] += parseInt(str);
                        }
                    }
                }
                
                    //game lose Judge
                for (i = dealerPoint.length - 1; i > -1; i -= 1)
                {
                    if (dealerPoint[i] > blackJack) //over 21 -> delete!
                    {
                        dealerPoint.splice(i, 1);
                    }
                    else if (dealerPoint[i] == blackJack)
                    {
                        dealerWin = true;
                        dealerStatusLabel.text = "WIN";
                        gameEnd = true;
                        dealerPosition = "stand";
                        break;
                    }
                }
                
                if (dealerPoint.length == 0) // no point -> all over 21 -> dealer lose.
                {
                    dealerPointMax = -1;
                    dealerLose = true;
                    dealerStatusLabel.text = "LOSE";
                    gameEnd = true;
                    dealerPosition = "stand";
                }
                else if(gameEnd == false) //점수가 있으니까 hit-stand 판단
                {
                    dealerPointMax = -1;
                    
                    for (j = 0; j < dealerPoint.length; j += 1)
                    {
                        if (dealerPoint[j] > dealerPointMax)
                        {
                            dealerPointMax = dealerPoint[j];
                        }
                    }
                    
                    if (dealerPointMax >= dealerStandPoint)
                    {
                        dealerPosition = "stand";
                        dealerStatusLabel.text = "STAND";
                    }
                    else
                    {
                        dealerPosition = "hit";
                        dealerStatusLabel.text = "HIT";
                    }
                }
                    
                
                //player Turn - NN 계산, hit or stand 결정
                    //Point 계산
                playerPoint = [0];
                playerPointMax = -1;
                
                for (i = 0; i < playerHand.length; i += 1)
                {
                    str = playerHand[i].substr(1, playerHand[i].length - 1);
                    if (str == "J" || str == "Q" || str == "K")
                    {
                        for (j = 0; j < playerPoint.length; j += 1)
                        {
                            playerPoint[j] += 10;
                        }
                        
                    }
                    else if (str == "A")
                    {
                        len = playerPoint.length;
                        for (j = 0; j < len; j += 1)
                        {
                            playerPoint[j] += 1; //1을 더한다.
                            playerPoint.push(clone(playerPoint[j])); //2배로 늘린다..
                        }
                        for (j = len; j < playerPoint.length; j += 1)
                        {
                            playerPoint[j] += 10; //10을 더한다. 결국 마지막으로 추가된 것들에는 11을 더하는 꼴
                        }
                    }
                    else
                    {
                        for (j = 0; j < playerPoint.length; j += 1)
                        {
                            playerPoint[j] += parseInt(str);
                        }
                    }
                }
                
                //game lose 판단
                for (i = playerPoint.length - 1; i > -1; i -= 1)
                {
                    if (playerPoint[i] > blackJack) //21을 넘으면 과감하게 다 지운다.
                    {
                        playerPoint.splice(i, 1);
                    }
                    else if (playerPoint[i] == blackJack)
                    {
                        playerWin = true;
                        playerStatusLabel.text = "WIN";
                        gameEnd = true;
                        playerPosition = "stand";
                        break;
                    }
                }
                
                if (playerPoint.length == 0) //점수가 아무 것도 안 남아있다면, 다 21을 넘었다는 뜻이므로 dealer는 패배 확정.
                {
                    playerPointMax = -1;
                    playerLose = true;
                    playerStatusLabel.text = "LOSE";
                    playerPosition = "stand";
                    gameEnd = true;
                }
                else if(gameEnd == false) //점수가 있으니까 hit-stand 판단
                {
                    
                    playerPointMax = -1;
                    
                    for (j = 0; j < playerPoint.length; j += 1) //여기도 플레이어 포인트 Max를 계산해 놓는다. 나중에 비교해서 계산.
                    {
                        if (playerPoint[j] > playerPointMax)
                        {
                            playerPointMax = playerPoint[j];
                        }
                    }
                    
                        //input Layer
                    for (i = 0; i < inputNeuronNum; i += 1)
                    {
                        inputLayer.neurons[i].output = 0; //일단 0으로 초기화
                    }
                    
                    for (i = 0; i < playerPoint.length; i += 1)
                    {
                        inputLayer.neurons[blackJack - playerPoint[i] - 1].output = 1; //블랙잭(21)과 현재 점수의 차이를 input으로. 1~19 -> 0~18
                    }
                    
                    if (dealerPoint.length > 0)
                    {
                        for (i = 0; i < dealerPoint.length; i += 1)
                        {
                            inputLayer.neurons[18 + blackJack - dealerPoint[i] - 1].output = 1; //딜러 점수에는 19~37번 Neuron 배정
                        }
                    }
                    
                        //hidden Layer
                    for (i = 0; i < hiddenNeuronNum; i += 1)
                    {
                        hiddenLayer.neurons[i].input = 0;
                        for (j = 0; j < inputNeuronNum; j += 1)
                        {
                            hiddenLayer.neurons[i].input += inputLayer.neurons[j].output * inputLayer.neurons[j].w[i];
                        }
                        hiddenLayer.neurons[i].output = sigmoid(hiddenLayer.neurons[i].input);
                        
                    }
                    hiddenLayer.neurons[hiddenNeuronNum].output = 1;
                    
                        //ouput Layer
                    for (i = 0; i < outputNeuronNum; i += 1)
                    {
                        outputLayer.neurons[i].input = 0;
                        
                        for (j = 0; j < hiddenNeuronNum + 1; j += 1)
                        {
                            outputLayer.neurons[i].input += hiddenLayer.neurons[j].output * hiddenLayer.neurons[j].w[i];
                        }
                        
                        outputLayer.neurons[i].output = sigmoid(outputLayer.neurons[i].input);
                        
                        if (outputLayer.neurons[i].output > 0.5)
                        {
                            playerPosition = "hit";
                            playerStatusLabel.text = "HIT";
                        }
                        else
                        {
                            playerPosition = "stand";
                            playerStatusLabel.text = "STAND";
                        }
                        
                        
                    }
                    
                    //save record. 카드를 내는 상황에서 점수를 저장
                    oneTurnRecord = [];
                    for (i = 0; i < inputNeuronNum; i += 1)
                    {
                        oneTurnRecord.push(inputLayer.neurons[i].output);
                    }
                    oneTurnRecord.push(outputLayer.neurons[0].output);
                    
                    playRecord.push(oneTurnRecord);
                    
                }
                
                
                
                
                //win - lose judge
                if (dealerPosition == "stand" && playerPosition == "stand")
                {
                    if (dealerPointMax > playerPointMax)
                    {
                        if (dealerLose == false)
                        {
                            dealerWin = true;
                            dealerStatusLabel.text = "WIN";
                            if (playerWin == false)
                            {
                                playerLose = true;
                                playerStatusLabel.text = "LOSE";
                            }
                            
                            gameEnd = true;
                        }
                        else
                        {
                            playerStatusLabel.text = "LOSE";
                            gameEnd = true;
                        }
                    }
                    else if (dealerPointMax < playerPointMax)
                    {
                        if (playerLose == false)
                        {
                            playerWin = true;
                            playerStatusLabel.text = "WIN";
                            if (dealerWin == false)
                            {
                                dealerLose = true;
                                dealerStatusLabel.text = "LOSE";
                            }
                            
                            gameEnd = true;
                        }
                        else
                        {
                            dealerStatusLabel.text = "LOSE";
                            gameEnd = true;
                        }
                    }
                    else
                    {
                        gamedraw = true;
                        gameEnd = true;
                        
                        dealerStatusLabel.text = "DRAW";
                        playerStatusLabel.text = "DRAW";
                        
                    }
                }
                
                if(gameEnd == false) //card get
                {
                    if (dealerPosition == "hit") 
                    {
                        str = getOneCard();
                        dealerHand.push(str);
                        drawCardBitmap(true, dealerHand.length - 1, str);
                        
                        dealerStatusLabel.text = "HIT";
                    }
                    if (playerPosition == "hit")
                    {
                        str = getOneCard();
                        playerHand.push(str);
                        drawCardBitmap(false, playerHand.length - 1, str);
                        
                        playerStatusLabel.text = "STAND";
                    }
                }
                
                //trace(dealerHand, playerHand);
                //trace(dealerPoint, playerPoint);
                //trace(dealerWin, dealerLose, playerWin, playerLose);
                //trace(dealerPosition, playerPosition);
            }
            
            //player가 blackjack이 아니라도 busted가 아니고, dealer가 busted라면 player win
            if (playerLose == false && dealerLose == true)
            {
                playerWin = true;
                playerStatusLabel.text = "WIN";
                dealerStatusLabel.text = "LOSE";
            }
            if (playerWin == true && dealerWin == true)
            {
                playerStatusLabel.text = "DRAW";
                dealerStatusLabel.text = "DRAW";
            }
            
            //Evaluation & Back-propagation
            if (playerWin == false)
            {
                for (k = 0; k < playRecord.length; k += 1)
                {
                    end = playRecord[k].length - 1;
                    outputLayer.neurons[0].error = playRecord[k][end] > 0.5 ? 0 - playRecord[k][end] : 1 - playRecord[k][end]; //했던 행동과 반대로 이끌기
                    outputLayer.neurons[0].error *= (k + 1) / turnCount;
                    
                    sumError += outputLayer.neurons[0].error * outputLayer.neurons[0].error;
                    
                    outputLayer.neurons[0].nodeDelta = outputLayer.neurons[0].error * outputLayer.neurons[0].output * (1 - outputLayer.neurons[0].output);
                    
                    
                    for (i = 0; i < hiddenNeuronNum + 1; i += 1) // +1 for biased Neuron
                    {
                        hiddenLayer.neurons[i].nodeDelta = 0;
                        
                        for (j = 0; j < outputNeuronNum; j += 1)
                        {
                            hiddenLayer.neurons[i].deltaW[j] = learnRate * hiddenLayer.neurons[i].output * outputLayer.neurons[j].nodeDelta + _alpha * hiddenLayer.neurons[i].deltaW[j];
                            hiddenLayer.neurons[i].w[j] += hiddenLayer.neurons[i].deltaW[j]; //weight update;
                            
                            hiddenLayer.neurons[i].nodeDelta += outputLayer.neurons[j].nodeDelta * hiddenLayer.neurons[i].w[j]; //get hidden neuron's nodeDelta
                        }
                        
                        hiddenLayer.neurons[i].nodeDelta *= hiddenLayer.neurons[i].output * (1 - hiddenLayer.neurons[i].output);
                    }
                    
                    for (i = 0; i < inputNeuronNum; i += 1)
                    {
                        for (j = 0; j < hiddenNeuronNum; j += 1)
                        {
                            inputLayer.neurons[i].deltaW[j] = learnRate * inputLayer.neurons[i].output * hiddenLayer.neurons[j].nodeDelta + _alpha * inputLayer.neurons[i].deltaW[j];
                            inputLayer.neurons[i].w[j] += inputLayer.neurons[i].deltaW[j]; //weight update;
                        }
                    }
                }
            }
            else //playerWin == true
            {
                for (k = 0; k < playRecord.length; k += 1)
                {
                    end = playRecord[k].length - 1;
                    outputLayer.neurons[0].error = playRecord[k][end] > 0.5 ? 1 - playRecord[k][end] : 0 - playRecord[k][end]; //했던 행동으로 이끌기
                    outputLayer.neurons[0].error *= (k + 1) / turnCount;
                    
                    sumError += outputLayer.neurons[0].error * outputLayer.neurons[0].error;
                    
                    outputLayer.neurons[0].nodeDelta = outputLayer.neurons[0].error * outputLayer.neurons[0].output * (1 - outputLayer.neurons[0].output);
                    
                    
                    for (i = 0; i < hiddenNeuronNum + 1; i += 1) // +1 for biased Neuron
                    {
                        hiddenLayer.neurons[i].nodeDelta = 0;
                        
                        for (j = 0; j < outputNeuronNum; j += 1)
                        {
                            hiddenLayer.neurons[i].deltaW[j] = learnRate * hiddenLayer.neurons[i].output * outputLayer.neurons[j].nodeDelta + _alpha * hiddenLayer.neurons[i].deltaW[j];
                            hiddenLayer.neurons[i].w[j] += hiddenLayer.neurons[i].deltaW[j]; //weight update;
                            
                            hiddenLayer.neurons[i].nodeDelta += outputLayer.neurons[j].nodeDelta * hiddenLayer.neurons[i].w[j]; //get hidden neuron's nodeDelta
                        }
                        
                        hiddenLayer.neurons[i].nodeDelta *= hiddenLayer.neurons[i].output * (1 - hiddenLayer.neurons[i].output);
                    }
                    
                    for (i = 0; i < inputNeuronNum; i += 1)
                    {
                        for (j = 0; j < hiddenNeuronNum; j += 1)
                        {
                            inputLayer.neurons[i].deltaW[j] = learnRate * inputLayer.neurons[i].output * hiddenLayer.neurons[j].nodeDelta + _alpha * inputLayer.neurons[i].deltaW[j];
                            inputLayer.neurons[i].w[j] += inputLayer.neurons[i].deltaW[j]; //weight update;
                        }
                    }
                }
            }
            
            
            //stats
            totalGameNum += 1;
            if (playerWin == true)
            {
                playerWinGameNum += 1;
            }
            
            //errorChart.data.push(sumError);
            errorChart.data.push(playerWinGameNum / totalGameNum);
            errorChart.draw();
            winPercentLabel.text = String(totalGameNum) + " Games, " + String(playerWinGameNum) + " WIN. (win Rate : " + String(int(playerWinGameNum / totalGameNum * 10000) / 100) + "%)";
            
            //trace(dealerHand, playerHand);
        }
        
        public function sigmoid(n:Number):Number
        {
            return 1 / (1 + 1 / Math.exp(n));
        }
        
        private function initNeuron():void
        {
            var neuron:Neuron;
            var i:int;
            
            inputLayer = new Layer();
            for (i = 0; i < inputNeuronNum; i += 1)
            {
                neuron = new Neuron(hiddenNeuronNum);
                inputLayer.neurons.push(neuron);
                neuron.x = 465 / 2 + 30 ;
                neuron.y = (465 - 80) / inputNeuronNum * i + 40;
                addChild(neuron);
            }
            
            hiddenLayer = new Layer();
            for (i = 0; i < hiddenNeuronNum; i += 1)
            {
                neuron = new Neuron(outputNeuronNum);
                hiddenLayer.neurons.push(neuron);
                neuron.x = 465 / 4 * 3;
                neuron.y = (465 - 300) / (hiddenNeuronNum) * i + 150;
                addChild(neuron);
                
            }
            
            neuron = new Neuron(outputNeuronNum); //biased One for hidden Layer
            neuron.biased = true;
            hiddenLayer.neurons.push(neuron);
            neuron.x = 465 / 4 * 3;
            neuron.y = (465 - 300) / (hiddenNeuronNum) * hiddenNeuronNum + 150;
            addChild(neuron);
            
            outputLayer = new Layer();
            for (i = 0; i < outputNeuronNum; i += 1)
            {
                neuron = new Neuron(0);
                outputLayer.neurons.push(neuron);
            }
            neuron.x = 465 - 30;
            neuron.y = 465 / 2;
            addChild(neuron);
            
            beta = 0.7 * Math.pow(hiddenNeuronNum, (1 / inputNeuronNum));
            
            
            
        }
        
        private function initWeight():void
        {
            // Nguyen-Widrow Initialization - for all Input to Hidden w
            var normHidden:Number;
            var i:int;
            var j:int;
            
            normHidden = 0;
            for (i = 0; i < hiddenNeuronNum; i += 1)
            {
                for (j = 0; j < inputNeuronNum; j += 1)
                {
                    normHidden += inputLayer.neurons[j].w[i] * inputLayer.neurons[j].w[i];
                }
                
                normHidden = Math.sqrt(normHidden);
                
                for (j = 0; j < inputNeuronNum; j += 1)
                {
                    inputLayer.neurons[j].w[i] *= beta / normHidden;
                }
            }
        }
        
        private function initNewGame(e:Event=null):void
        {
            var str:String;
            cardBitmapData.fillRect(cardBitmapData.rect, 0x00ffffff);
            
            var _label:Label;
            var i:int;
            
            for (i = 0; i < 11; i += 1)
            {
                _label = dealerNumberLabelArray[i];
                _label.text = "";
                
                _label = playerNumberLabelArray[i];
                _label.text = "";
            }
            
            nowCard = clone(cardArray);
            
            playerHand = [];
            dealerHand = [];
            
            str = getOneCard();
            playerHand.push(str);
            drawCardBitmap(false, 0, str);
            str = getOneCard();
            playerHand.push(str);
            drawCardBitmap(false, 1, str);
            str = getOneCard();
            dealerHand.push(str);
            drawCardBitmap(true, 0, str);
            str = getOneCard();
            dealerHand.push(str);
            drawCardBitmap(true, 1, str);
            
            //trace(playerHand, dealerHand);
            
        }
        
        private function drawCardBitmap(isDealer:Boolean, index:int, str:String):void
        {
            var number:String = str.substr(1, str.length - 1);
            var mark:String = str.substr(0, 1);
            var label:Label;
            
            //trace(str, mark, number, index)
            
            mat = new Matrix();
            if (isDealer == true)
            {
                mat.translate(30 + index * 28, 50);
                label = dealerNumberLabelArray[index];
            }
            else
            {
                mat.translate(30 + index * 28, 165);
                label = playerNumberLabelArray[index];
            }
            
            cardBitmapData.draw(cardShape, mat);
            //mat.translate(8, 2);
            
            label.text = number;
            switch(mark)
            {
                case "S":
                case "C":
                    //cardNumberLabel.transform.colorTransform = cardNumberBlack;
                    //cardBitmapData.draw(label, mat, cardNumberBlack); trace(label.text);
                    label.transform.colorTransform = cardNumberBlack;
                    break;
                    
                case "D":
                case "H":
                    //cardNumberLabel.transform.colorTransform = cardNumberRed;
                    //cardBitmapData.draw(label, mat, cardNumberRed); trace(label.text);
                    label.transform.colorTransform = cardNumberRed;
                    break;
            }
            //cardBitmapData.draw(String(number), mat);
            
            mat.translate(2, 22);
            switch(mark)
            {
                case "S":
                    cardBitmapData.draw(spadeShape, mat);
                    break;
                
                case "D":
                    cardBitmapData.draw(diamondShape, mat);
                    break;
                    
                case "H":
                    cardBitmapData.draw(heartShape, mat);
                    break;
                    
                case "C":
                    cardBitmapData.draw(cloverShape, mat);
                    break;
                
            }
            
            
        }
        
        private function getOneCard():String
        {
            var arr:Array = printRandomNumber(nowCard.length, 1);
            var str:String = nowCard[arr[0]];
            nowCard.splice(arr[0], 1);
            return str;
            
        }
        
        private function printRandomNumber(n:int, k:int) : Array
        {
            var original:Array=[];
            var result:Array=[];
            var i:int;
            var randInt:int;
            var temp:Object;
            
            for(i=0;i<n;i+=1)
            {
                original.push(i);
            }
            
            for(i=0;i<k;i+=1)
            {
                randInt = Math.random()*(n-i) + i;
                temp = original[i];
                original[i] = original[randInt];
                original[randInt] = temp;
                result.push(original[i]);
            }
            
            return result;
        }
        
        public function clone(source:Object):*
        {
            var myBA:ByteArray = new ByteArray();
            myBA.writeObject(source);
            myBA.position = 0;
            return(myBA.readObject()); 
        }
        
        
    }
}

Class
{
    import flash.display.Shape;
    /**
     * ...
     * @author ypc
     */
    class Neuron extends Shape
    {
        public var w:Object;
        public var deltaW:Object;
        public var updateValue:Object;
        public var prevGradient:Object;
        public var input:Number;
        public var output:Number;
        public var error:Number;
        public var nodeDelta:Number;
        public var gradient:Object;
        public var gradientChanged:Object;
        public var biased:Boolean = false;
        
        public function Neuron(n:int)
        {
            this.graphics.lineStyle(2, 0);
            this.graphics.beginFill(0xffffff);
            this.graphics.drawCircle(0, 0, 6);
            this.graphics.endFill();
            
            this.w = new Object();
            this.deltaW = new Object();
            this.updateValue = new Object();
            this.prevGradient = new Object();
            this.gradient = new Object();
            this.gradientChanged = new Object();
            
            if (n > 0)
            {
                var i:int;
                
                for (i = 0; i < n; i += 1)
                {
                    this.w[i] = Math.random() * 2 - 1;
                    this.deltaW[i] = 0;
                    this.updateValue[i] = 0.01;
                    
                    this.gradient[i] = 0;
                    this.prevGradient[i] = 0;
                    this.gradientChanged[i] = 0;
                }
            }
        }
        
        public function resetW(n:int):void
        {
            var i:int;
            
            for (i = 0; i < n; i += 1)
            {
                this.w[i] = Math.random() * 2 - 1;
                this.deltaW[i] = 0;
                this.updateValue[i] = 0.01;
                
                this.gradient[i] = 0;
                this.prevGradient[i] = 0;
                this.gradientChanged[i] = 0;
                
                this.error = 0;
                this.nodeDelta = 0;
            }
        }
        
    }

}

Class
{
    /**
     * ...
     * @author ypc
     */
    class Layer 
    {
        public var neurons:Array;
        
        public function Layer() 
        {
            this.neurons = [];
        }
        
    }

}